Auto merge of #146725 - lcnr:eager-instantiate-binder, r=BoxyUwU

`-Znext-solver` instantiate predicate binder without recanonicalizing goal

This strengthens the leak check to match the old trait solver. The new trait solver now also instantiates higher ranked goals in the same scope as candidate selection, so the leak check in each candidate detects placeholder errors involving this higher ranked goal.

E.g. let's look at tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs
```rust
trait Trait<T, U> {}
impl<'a> Trait<&'a str, &'a str> for () {}
impl<'a> Trait<&'a str, String> for () {}
fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}

fn main() {
    impls_trait::<(), _>();
}
```
Here proving `(): for<'a> Trait<&'a str, ?u>` via `impl<'a> Trait<&'a str, &'a str> for ()` equates `?u` with `&'!a str` which results in a leak check error as `?u` cannot name `'a`. If this leak check error happens while considering candidates we drop the first impl and infer `?u` to `String`. If not, this remains ambiguous.

This behavior is a bit iffy, see the FCP proposal in rust-lang/rust#119820 for more details on why this current behavior is somewhat undesirable. However, considering placeholders from higher-ranked goals for candidate selection does allow more code to compile and a lot of the code *feels like it should compile*. **This caused us to revert the change of rust-lang/rust#119820 in rust-lang/rust#127568.**

I originally expected that we can avoid breakage with the new solver differently here, e.g. by considering OR-region constraints. However, doing so is a significant change and I don't have a great idea for how that should work. Matching the old solver behavior for now should not make this cleaner approach any more difficult in the future, so let's just go with what actually allows us to stabilize the new solver for now.

This PR changing the new solver to match the behavior of the old one wrt the leak check. As the new solver is already used by default in coherence, this allows more code to compile, see `tests/ui/higher-ranked/leak-check/leak-check-in-selection-7-coherence.rs`:
```rust
struct W<T, U>(T, U);

trait Trait<T> {}
// using this impl results in a higher-ranked region error.
impl<'a> Trait<W<&'a str, &'a str>> for () {}
impl<'a> Trait<W<&'a str, String>> for () {}

trait NotString {}
impl NotString for &str {}
impl NotString for u32 {}

trait Overlap<U> {}
impl<T: for<'a> Trait<W<&'a str, U>>, U> Overlap<U> for T {}
impl<U: NotString> Overlap<U> for () {}

fn main() {}
```

This behavior is quite arbitrary and not something I expect users to rely on in practice, however, it should still go through an FCP imo.

r? `@BoxyUwU` originally implemented by `@compiler-errors` in https://github.com/rust-lang/rust/pull/136997. Closes https://github.com/rust-lang/trait-system-refactor-initiative/issues/120.
This commit is contained in:
bors 2025-10-21 21:09:46 +00:00
commit 37ec98f5d3
23 changed files with 114 additions and 213 deletions

View file

@ -1,7 +1,6 @@
//! A utility module to inspect currently ambiguous obligations in the current context.
use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
use rustc_middle::traits::solve::GoalSource;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_span::Span;
use rustc_trait_selection::solve::Certainty;
@ -127,21 +126,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
let tcx = self.fcx.tcx;
let goal = inspect_goal.goal();
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty)
// We do not push the instantiated forms of goals as it would cause any
// aliases referencing bound vars to go from having escaping bound vars to
// being able to be normalized to an inference variable.
//
// This is mostly just a hack as arbitrary nested goals could still contain
// such aliases while having a different `GoalSource`. Closure signature inference
// however can't really handle *every* higher ranked `Fn` goal also being present
// in the form of `?c: Fn<(<?x as Trait<'!a>>::Assoc)`.
//
// This also just better matches the behaviour of the old solver where we do not
// encounter instantiated forms of goals, only nested goals that referred to bound
// vars from instantiated goals.
&& !matches!(inspect_goal.source(), GoalSource::InstantiateHigherRanked)
{
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) {
self.obligations_for_self_ty.push(traits::Obligation::new(
tcx,
self.root_cause.clone(),

View file

@ -297,9 +297,6 @@ where
// corecursive functions as explained in #136824, relating types never
// introduces a constructor which could cause the recursion to be guarded.
GoalSource::TypeRelating => PathKind::Inductive,
// Instantiating a higher ranked goal can never cause the recursion to be
// guarded and is therefore unproductive.
GoalSource::InstantiateHigherRanked => PathKind::Inductive,
// These goal sources are likely unproductive and can be changed to
// `PathKind::Inductive`. Keeping them as unknown until we're confident
// about this and have an example where it is necessary.
@ -567,66 +564,56 @@ where
pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
let Goal { param_env, predicate } = goal;
let kind = predicate.kind();
if let Some(kind) = kind.no_bound_vars() {
match kind {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
self.compute_host_effect_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
self.compute_projection_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
self.compute_type_outlives_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
self.compute_region_outlives_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
}
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
self.compute_unstable_feature_goal(param_env, symbol)
}
ty::PredicateKind::Subtype(predicate) => {
self.compute_subtype_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Coerce(predicate) => {
self.compute_coerce_goal(Goal { param_env, predicate })
}
ty::PredicateKind::DynCompatible(trait_def_id) => {
self.compute_dyn_compatible_goal(trait_def_id)
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
self.compute_well_formed_goal(Goal { param_env, predicate: term })
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
}
ty::PredicateKind::ConstEquate(_, _) => {
panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
}
ty::PredicateKind::NormalizesTo(predicate) => {
self.compute_normalizes_to_goal(Goal { param_env, predicate })
}
ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
.compute_alias_relate_goal(Goal {
param_env,
predicate: (lhs, rhs, direction),
}),
ty::PredicateKind::Ambiguous => {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
self.enter_forall(kind, |ecx, kind| match kind {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
ecx.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)
}
} else {
self.enter_forall(kind, |ecx, kind| {
let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
ecx.compute_host_effect_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
ecx.compute_projection_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
ecx.compute_type_outlives_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
ecx.compute_region_outlives_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
ecx.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
}
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
ecx.compute_unstable_feature_goal(param_env, symbol)
}
ty::PredicateKind::Subtype(predicate) => {
ecx.compute_subtype_goal(Goal { param_env, predicate })
}
ty::PredicateKind::Coerce(predicate) => {
ecx.compute_coerce_goal(Goal { param_env, predicate })
}
ty::PredicateKind::DynCompatible(trait_def_id) => {
ecx.compute_dyn_compatible_goal(trait_def_id)
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
ecx.compute_well_formed_goal(Goal { param_env, predicate: term })
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
ecx.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
}
ty::PredicateKind::ConstEquate(_, _) => {
panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
}
ty::PredicateKind::NormalizesTo(predicate) => {
ecx.compute_normalizes_to_goal(Goal { param_env, predicate })
}
ty::PredicateKind::AliasRelate(lhs, rhs, direction) => {
ecx.compute_alias_relate_goal(Goal { param_env, predicate: (lhs, rhs, direction) })
}
ty::PredicateKind::Ambiguous => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
})
}
// Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning

View file

@ -231,7 +231,6 @@ impl<'tcx> BestObligation<'tcx> {
nested_goal.source(),
GoalSource::ImplWhereBound
| GoalSource::AliasBoundConstCondition
| GoalSource::InstantiateHigherRanked
| GoalSource::AliasWellFormed
) && nested_goal.result().is_err()
},
@ -523,10 +522,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
));
impl_where_bound_count += 1;
}
// Skip over a higher-ranked predicate.
(_, GoalSource::InstantiateHigherRanked) => {
obligation = self.obligation.clone();
}
(ChildMode::PassThrough, _)
| (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
obligation = make_obligation(self.obligation.cause.clone());

View file

@ -735,9 +735,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
// For bound predicates we simply call `infcx.enter_forall`
// and then prove the resulting predicate as a nested goal.
let Goal { param_env, predicate } = goal.goal();
let trait_ref = match predicate.kind().no_bound_vars() {
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
let predicate_kind = goal.infcx().enter_forall_and_leak_universe(predicate.kind());
let trait_ref = match predicate_kind {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.trait_ref,
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))
if matches!(
infcx.tcx.def_kind(proj.projection_term.def_id),
DefKind::AssocTy | DefKind::AssocConst

View file

@ -78,8 +78,6 @@ pub enum GoalSource {
ImplWhereBound,
/// Const conditions that need to hold for `[const]` alias bounds to hold.
AliasBoundConstCondition,
/// Instantiating a higher-ranked goal and re-proving it.
InstantiateHigherRanked,
/// Predicate required for an alias projection to be well-formed.
/// This is used in three places:
/// 1. projecting to an opaque whose hidden type is already registered in

View file

@ -12,7 +12,7 @@ LL | impl<T> Trait for Box<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
|
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>`
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
error: aborting due to 1 previous error

View file

@ -1,6 +1,7 @@
//@ known-bug: #140609
//@ check-pass
#![feature(with_negative_coherence)]
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![crate_type = "lib"]
trait Trait {}
struct A<const B: bool>;

View file

@ -1,23 +0,0 @@
error[E0277]: the trait bound `for<'a> &'a &T: Trait` is not satisfied
--> $DIR/candidate-from-env-universe-err-1.rs:27:16
|
LL | hr_bound::<&T>();
| ^^ the trait `for<'a> Trait` is not implemented for `&'a &T`
|
note: required by a bound in `hr_bound`
--> $DIR/candidate-from-env-universe-err-1.rs:14:20
|
LL | fn hr_bound<T>()
| -------- required by a bound in this function
LL | where
LL | for<'a> &'a T: Trait,
| ^^^^^ required by this bound in `hr_bound`
help: consider removing the leading `&`-reference
|
LL - hr_bound::<&T>();
LL + hr_bound::<T>();
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,6 +1,7 @@
//@ revisions: old next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@[old] check-pass
//@ check-pass
// cc #119820
@ -24,8 +25,11 @@ where
// but are able to successfully use the impl candidate. Without
// the leak check both candidates may apply and we prefer the
// `param_env` candidate in winnowing.
//
// By doing the leak check for each candidate, we discard the `param_env`
// candidate and use the impl candidate instead, allowing this to
// compile.
hr_bound::<&T>();
//[next]~^ ERROR the trait bound `for<'a> &'a &T: Trait` is not satisfied
}
fn main() {}

View file

@ -1,15 +0,0 @@
error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
--> $DIR/candidate-from-env-universe-err-2.rs:15:15
|
LL | impl_hr::<T>();
| ^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T`
|
note: required by a bound in `impl_hr`
--> $DIR/candidate-from-env-universe-err-2.rs:12:19
|
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,6 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@[current] check-pass
//@ check-pass
// cc #119820
@ -13,7 +14,6 @@ fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
impl_hr::<T>();
//[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
}
fn main() {}

View file

@ -7,7 +7,7 @@ LL | projection_bound::<T>();
= note: expected associated type `<T as Trait<'static>>::Assoc`
found associated type `<T as Trait<'a>>::Assoc`
note: the lifetime requirement is introduced here
--> $DIR/candidate-from-env-universe-err-project.rs:18:42
--> $DIR/candidate-from-env-universe-err-project.rs:19:42
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^

View file

@ -1,26 +1,14 @@
error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
--> $DIR/candidate-from-env-universe-err-project.rs:28:19
|
LL | trait_bound::<T>();
| ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
|
note: required by a bound in `trait_bound`
--> $DIR/candidate-from-env-universe-err-project.rs:17:19
|
LL | fn trait_bound<T: for<'a> Trait<'a>>() {}
| ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound`
error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
--> $DIR/candidate-from-env-universe-err-project.rs:38:24
|
LL | projection_bound::<T>();
| ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
| ^ types differ
|
note: required by a bound in `projection_bound`
--> $DIR/candidate-from-env-universe-err-project.rs:18:24
--> $DIR/candidate-from-env-universe-err-project.rs:19:42
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:52:30
@ -36,6 +24,6 @@ LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 4 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0271`.

View file

@ -1,4 +1,5 @@
//@ revisions: next current
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// cc #119820 the behavior is inconsistent as we discard the where-bound
@ -20,13 +21,12 @@ fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
// We use a function with a trivial where-bound which is more
// restrictive than the impl.
fn function1<T: Trait<'static>>() {
// err
// ok
//
// Proving `for<'a> T: Trait<'a>` using the where-bound does not
// result in a leak check failure even though it does not apply.
// We prefer env candidates over impl candidatescausing this to succeed.
trait_bound::<T>();
//[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
}
fn function2<T: Trait<'static, Assoc = usize>>() {
@ -36,7 +36,7 @@ fn function2<T: Trait<'static, Assoc = usize>>() {
// does not use the leak check when trying the where-bound, causing us
// to prefer it over the impl, resulting in a placeholder error.
projection_bound::<T>();
//[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
//[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
//[current]~^^ ERROR mismatched types
}

View file

@ -1,23 +0,0 @@
error[E0283]: type annotations needed
--> $DIR/leak-check-in-selection-2.rs:17:5
|
LL | impls_trait::<(), _>();
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
--> $DIR/leak-check-in-selection-2.rs:10:1
|
LL | impl<'a> Trait<&'a str, &'a str> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | impl<'a> Trait<&'a str, String> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_trait`
--> $DIR/leak-check-in-selection-2.rs:14:19
|
LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`.

View file

@ -1,6 +1,7 @@
//@ revisions: old next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@[old] check-pass
//@ check-pass
// cc #119820
@ -15,5 +16,4 @@ fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
fn main() {
impls_trait::<(), _>();
//[next]~^ ERROR type annotations needed
}

View file

@ -1,22 +1,3 @@
error[E0283]: type annotations needed
--> $DIR/leak-check-in-selection-3.rs:18:5
|
LL | impls_leak::<Box<_>>();
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
|
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
--> $DIR/leak-check-in-selection-3.rs:9:1
|
LL | impl Leak<'_> for Box<u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl Leak<'static> for Box<u16> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_leak`
--> $DIR/leak-check-in-selection-3.rs:12:18
|
LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
| ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
error[E0283]: type annotations needed
--> $DIR/leak-check-in-selection-3.rs:35:5
|
@ -24,7 +5,7 @@ LL | impls_indirect_leak::<Box<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
|
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
--> $DIR/leak-check-in-selection-3.rs:9:1
--> $DIR/leak-check-in-selection-3.rs:10:1
|
LL | impl Leak<'_> for Box<u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -43,6 +24,6 @@ note: required by a bound in `impls_indirect_leak`
LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
error: aborting due to 2 previous errors
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`.

View file

@ -5,7 +5,7 @@ LL | impls_indirect_leak::<Box<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
|
note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found
--> $DIR/leak-check-in-selection-3.rs:9:1
--> $DIR/leak-check-in-selection-3.rs:10:1
|
LL | impl Leak<'_> for Box<u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,4 +1,5 @@
//@ revisions: old next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// cc #119820, the behavior here is inconsistent,
@ -16,7 +17,6 @@ fn direct() {
// The `Box<u16>` impls fails the leak check,
// meaning that we apply the `Box<u32>` impl.
impls_leak::<Box<_>>();
//[next]~^ ERROR type annotations needed
}
trait IndirectLeak<'a> {}

View file

@ -1,18 +1,18 @@
error[E0283]: type annotations needed
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:32:5
|
LL | impls_trait::<(), _, _>()
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
note: multiple `impl`s satisfying `(): Trait<_, _>` found
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:1
|
LL | impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<V> Trait<u32, V> for () where for<'b> ((),): LeakCheckFailure<'static, 'b, V> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<V> Trait<u16, V> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_trait`
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:19
|
LL | fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
| ^^^^^^^^^^^ required by this bound in `impls_trait`

View file

@ -1,18 +1,18 @@
error[E0283]: type annotations needed
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:5
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:32:5
|
LL | impls_trait::<(), _, _>()
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
note: multiple `impl`s satisfying `(): Trait<_, _>` found
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:26:1
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:1
|
LL | impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<V> Trait<u32, V> for () where for<'b> ((),): LeakCheckFailure<'static, 'b, V> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<V> Trait<u16, V> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_trait`
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:28:19
--> $DIR/leak-check-in-selection-6-ambig-unify.rs:30:19
|
LL | fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
| ^^^^^^^^^^^ required by this bound in `impls_trait`

View file

@ -1,4 +1,5 @@
//@ revisions: old next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// The new trait solver does not return region constraints if the goal
@ -21,9 +22,10 @@ impl Id<u16> for u16 {}
trait LeakCheckFailure<'a, 'b, V: ?Sized> {}
impl<'a, 'b: 'a, V: ?Sized + Ambig> LeakCheckFailure<'a, 'b, V> for () {}
impl<'a, 'b, V: ?Sized, T: LeakCheckFailure<'a, 'b, V>> LeakCheckFailure<'a, 'b, V> for (T,) {}
trait Trait<U, V> {}
impl<V> Trait<u32, V> for () where for<'b> (): LeakCheckFailure<'static, 'b, V> {}
impl<V> Trait<u32, V> for () where for<'b> ((),): LeakCheckFailure<'static, 'b, V> {}
impl<V> Trait<u16, V> for () {}
fn impls_trait<T: Trait<U, V>, U: Id<V>, V>() {}
fn main() {

View file

@ -0,0 +1,20 @@
//@ check-pass
// cc #119820
struct W<T, U>(T, U);
trait Trait<T> {}
// using this impl results in a higher-ranked region error.
impl<'a> Trait<W<&'a str, &'a str>> for () {}
impl<'a> Trait<W<&'a str, String>> for () {}
trait NotString {}
impl NotString for &str {}
impl NotString for u32 {}
trait Overlap<U> {}
impl<T: for<'a> Trait<W<&'a str, U>>, U> Overlap<U> for T {}
impl<U: NotString> Overlap<U> for () {}
fn main() {}