Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4fa5fb6

Browse files
lcnrBoxyUwU
authored andcommittedApr 3, 2024
move leak check out of candidate evaluation
this prevents higher ranked goals from guiding selection
1 parent 98efd80 commit 4fa5fb6

28 files changed

+865
-193
lines changed
 

‎compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
6060
mod candidate_assembly;
6161
mod confirmation;
6262

63+
/// Whether to consider the binder of higher ranked goals for the `leak_check` when
64+
/// evaluating higher-ranked goals. See #119820 for more info.
65+
///
66+
/// While this is a bit hacky, it is necessary to match the behavior of the new solver:
67+
/// We eagerly instantiate binders in the new solver, outside of candidate selection, so
68+
/// the leak check inside of candidates does not consider any bound vars from the higher
69+
/// ranked goal. However, we do exit the binder once we're completely finished with a goal,
70+
/// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail.
71+
#[derive(Debug, Copy, Clone)]
72+
enum LeakCheckHigherRankedGoal {
73+
No,
74+
Yes,
75+
}
76+
6377
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
6478
pub enum IntercrateAmbiguityCause<'tcx> {
6579
DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
@@ -384,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
384398
let mut no_candidates_apply = true;
385399

386400
for c in candidate_set.vec.iter() {
387-
if self.evaluate_candidate(stack, c)?.may_apply() {
401+
if self
402+
.evaluate_candidate(stack, c, LeakCheckHigherRankedGoal::No)?
403+
.may_apply()
404+
{
388405
no_candidates_apply = false;
389406
break;
390407
}
@@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
455472
// is needed for specialization. Propagate overflow if it occurs.
456473
let mut candidates = candidates
457474
.into_iter()
458-
.map(|c| match self.evaluate_candidate(stack, &c) {
475+
.map(|c| match self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::No) {
459476
Ok(eval) if eval.may_apply() => {
460477
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
461478
}
@@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
545562
obligation: &PredicateObligation<'tcx>,
546563
) -> Result<EvaluationResult, OverflowError> {
547564
debug_assert!(!self.infcx.next_trait_solver());
548-
self.evaluation_probe(|this| {
565+
self.evaluation_probe(|this, _outer_universe| {
549566
let goal =
550567
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
551568
let mut result = this.evaluate_predicate_recursively(
@@ -561,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
561578
})
562579
}
563580

581+
/// Computes the evaluation result of `op`, discarding any constraints.
582+
///
583+
/// This also runs for leak check to allow higher ranked region errors to impact
584+
/// selection. By default it checks for leaks from all universes created inside of
585+
/// `op`, but this can be overwritten if necessary.
564586
fn evaluation_probe(
565587
&mut self,
566-
op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
588+
op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result<EvaluationResult, OverflowError>,
567589
) -> Result<EvaluationResult, OverflowError> {
568590
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
569-
let outer_universe = self.infcx.universe();
570-
let result = op(self)?;
591+
let mut outer_universe = self.infcx.universe();
592+
let result = op(self, &mut outer_universe)?;
571593

572594
match self.infcx.leak_check(outer_universe, Some(snapshot)) {
573595
Ok(()) => {}
@@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
586608
})
587609
}
588610

589-
/// Evaluates the predicates in `predicates` recursively. Note that
590-
/// this applies projections in the predicates, and therefore
611+
/// Evaluates the predicates in `predicates` recursively. This may
612+
/// guide inference. If this is not desired, run it inside of a
591613
/// is run within an inference probe.
614+
/// `probe`.
592615
#[instrument(skip(self, stack), level = "debug")]
593616
fn evaluate_predicates_recursively<'o, I>(
594617
&mut self,
@@ -1194,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11941217
}
11951218

11961219
match self.candidate_from_obligation(stack) {
1197-
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
1220+
Ok(Some(c)) => self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::Yes),
11981221
Ok(None) => Ok(EvaluatedToAmbig),
11991222
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
12001223
Err(..) => Ok(EvaluatedToErr),
@@ -1219,6 +1242,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12191242
/// Further evaluates `candidate` to decide whether all type parameters match and whether nested
12201243
/// obligations are met. Returns whether `candidate` remains viable after this further
12211244
/// scrutiny.
1245+
///
1246+
/// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal
1247+
/// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for
1248+
/// more info.
12221249
#[instrument(
12231250
level = "debug",
12241251
skip(self, stack),
@@ -1229,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12291256
&mut self,
12301257
stack: &TraitObligationStack<'o, 'tcx>,
12311258
candidate: &SelectionCandidate<'tcx>,
1259+
leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal,
12321260
) -> Result<EvaluationResult, OverflowError> {
1233-
let mut result = self.evaluation_probe(|this| {
1234-
let candidate = (*candidate).clone();
1235-
match this.confirm_candidate(stack.obligation, candidate) {
1261+
let mut result = self.evaluation_probe(|this, outer_universe| {
1262+
// We eagerly instantiate higher ranked goals to prevent universe errors
1263+
// from impacting candidate selection. This matches the behavior of the new
1264+
// solver. This slightly weakens type inference.
1265+
//
1266+
// In case there are no unresolved type or const variables this
1267+
// should still not be necessary to select a unique impl as any overlap
1268+
// relying on a universe error from higher ranked goals should have resulted
1269+
// in an overlap error in coherence.
1270+
let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
1271+
let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
1272+
match leak_check_higher_ranked_goal {
1273+
LeakCheckHigherRankedGoal::No => *outer_universe = self.infcx.universe(),
1274+
LeakCheckHigherRankedGoal::Yes => {}
1275+
}
1276+
1277+
match this.confirm_candidate(&obligation, candidate.clone()) {
12361278
Ok(selection) => {
12371279
debug!(?selection);
12381280
this.evaluate_predicates_recursively(
@@ -1657,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16571699
stack: &TraitObligationStack<'o, 'tcx>,
16581700
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
16591701
) -> Result<EvaluationResult, OverflowError> {
1660-
self.evaluation_probe(|this| {
1661-
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
1702+
self.evaluation_probe(|this, outer_universe| {
1703+
// Eagerly instantiate higher ranked goals.
1704+
//
1705+
// See the comment in `evaluate_candidate` to see why.
1706+
let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
1707+
let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
1708+
*outer_universe = self.infcx.universe();
1709+
match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) {
16621710
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
16631711
Err(()) => Ok(EvaluatedToErr),
16641712
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// cc #119820
2+
3+
trait Trait {}
4+
5+
impl<T: Trait> Trait for &T {}
6+
impl Trait for u32 {}
7+
8+
fn hr_bound<T>()
9+
where
10+
for<'a> &'a T: Trait,
11+
{
12+
}
13+
14+
fn foo<T>()
15+
where
16+
T: Trait,
17+
for<'a> &'a &'a T: Trait,
18+
{
19+
// We get a universe error when using the `param_env` candidate
20+
// but are able to successfully use the impl candidate. Without
21+
// the leak check both candidates may apply and we prefer the
22+
// `param_env` candidate in winnowing.
23+
hr_bound::<&T>();
24+
//~^ ERROR the parameter type `T` may not live long enough
25+
//~| ERROR implementation of `Trait` is not general enough
26+
}
27+
28+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0310]: the parameter type `T` may not live long enough
2+
--> $DIR/candidate-from-env-universe-err-1.rs:23:5
3+
|
4+
LL | hr_bound::<&T>();
5+
| ^^^^^^^^^^^^^^
6+
| |
7+
| the parameter type `T` must be valid for the static lifetime...
8+
| ...so that the type `T` will meet its required lifetime bounds
9+
|
10+
help: consider adding an explicit lifetime bound
11+
|
12+
LL | T: Trait + 'static,
13+
| +++++++++
14+
15+
error: implementation of `Trait` is not general enough
16+
--> $DIR/candidate-from-env-universe-err-1.rs:23:5
17+
|
18+
LL | hr_bound::<&T>();
19+
| ^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
20+
|
21+
= note: `Trait` would have to be implemented for the type `&'0 &T`, for any lifetime `'0`...
22+
= note: ...but `Trait` is actually implemented for the type `&'1 &'1 T`, for some specific lifetime `'1`
23+
24+
error: aborting due to 2 previous errors
25+
26+
For more information about this error, try `rustc --explain E0310`.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
3+
|
4+
LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
5+
| -- lifetime `'a` defined here
6+
LL | impl_hr::<T>();
7+
| ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
8+
|
9+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
10+
--> $DIR/candidate-from-env-universe-err-2.rs:11:19
11+
|
12+
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: implementation of `Trait` is not general enough
16+
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
17+
|
18+
LL | impl_hr::<T>();
19+
| ^^^^^^^^^^^^ implementation of `Trait` is not general enough
20+
|
21+
= note: `T` must implement `Trait<'0, '_>`, for any lifetime `'0`...
22+
= note: ...but it actually implements `Trait<'1, '_>`, for some specific lifetime `'1`
23+
24+
error: aborting due to 2 previous errors
25+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
2+
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
3+
|
4+
LL | impl_hr::<T>();
5+
| ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T`
6+
|
7+
note: required by a bound in `impl_hr`
8+
--> $DIR/candidate-from-env-universe-err-2.rs:11:19
9+
|
10+
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
11+
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr`
12+
help: consider further restricting this bound
13+
|
14+
LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() {
15+
| +++++++++++++++++++++++
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
3+
|
4+
LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
5+
| -- lifetime `'a` defined here
6+
LL | impl_hr::<T>();
7+
| ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
8+
|
9+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
10+
--> $DIR/candidate-from-env-universe-err-2.rs:11:19
11+
|
12+
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
17+
|
18+
LL | impl_hr::<T>();
19+
| ^^^^^^^^^^^^ one type is more general than the other
20+
|
21+
= note: expected trait `for<'a> Trait<'a, '_>`
22+
found trait `for<'b> Trait<'_, 'b>`
23+
24+
error: aborting due to 2 previous errors
25+
26+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
4+
// cc #119820
5+
6+
trait Trait<'a, 'b> {}
7+
8+
trait OtherTrait<'b> {}
9+
impl<'a, 'b, T: OtherTrait<'b>> Trait<'a, 'b> for T {}
10+
11+
fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
12+
13+
fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
14+
impl_hr::<T>();
15+
//[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
16+
//[current]~^^ERROR lifetime may not live long enough
17+
//[current]~| ERROR implementation of `Trait` is not general enough
18+
}
19+
20+
fn main() {}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error: implementation of `Trait` is not general enough
2+
--> $DIR/candidate-from-env-universe-err-project.rs:31:5
3+
|
4+
LL | trait_bound::<T>();
5+
| ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
6+
|
7+
= note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
8+
= note: ...but it actually implements `Trait<'static>`
9+
10+
error: implementation of `Trait` is not general enough
11+
--> $DIR/candidate-from-env-universe-err-project.rs:41:5
12+
|
13+
LL | projection_bound::<T>();
14+
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
15+
|
16+
= note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
17+
= note: ...but it actually implements `Trait<'static>`
18+
19+
error[E0308]: mismatched types
20+
--> $DIR/candidate-from-env-universe-err-project.rs:41:5
21+
|
22+
LL | projection_bound::<T>();
23+
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
24+
|
25+
= note: expected associated type `<T as Trait<'static>>::Assoc`
26+
found associated type `<T as Trait<'a>>::Assoc`
27+
note: the lifetime requirement is introduced here
28+
--> $DIR/candidate-from-env-universe-err-project.rs:21:42
29+
|
30+
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
31+
| ^^^^^^^^^^^^^
32+
33+
error[E0308]: mismatched types
34+
--> $DIR/candidate-from-env-universe-err-project.rs:56:30
35+
|
36+
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
38+
|
39+
= note: expected associated type `<T as Trait<'static>>::Assoc`
40+
found associated type `<T as Trait<'a>>::Assoc`
41+
42+
error[E0308]: mismatched types
43+
--> $DIR/candidate-from-env-universe-err-project.rs:56:30
44+
|
45+
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
46+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
47+
|
48+
= note: expected associated type `<T as Trait<'static>>::Assoc`
49+
found associated type `<T as Trait<'a>>::Assoc`
50+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
51+
52+
error: aborting due to 5 previous errors
53+
54+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
2+
--> $DIR/candidate-from-env-universe-err-project.rs:31:19
3+
|
4+
LL | trait_bound::<T>();
5+
| ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
6+
|
7+
note: required by a bound in `trait_bound`
8+
--> $DIR/candidate-from-env-universe-err-project.rs:20:19
9+
|
10+
LL | fn trait_bound<T: for<'a> Trait<'a>>() {}
11+
| ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound`
12+
help: consider further restricting this bound
13+
|
14+
LL | fn function1<T: Trait<'static> + for<'a> Trait<'a>>() {
15+
| +++++++++++++++++++
16+
17+
error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
18+
--> $DIR/candidate-from-env-universe-err-project.rs:41:24
19+
|
20+
LL | projection_bound::<T>();
21+
| ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
22+
|
23+
note: required by a bound in `projection_bound`
24+
--> $DIR/candidate-from-env-universe-err-project.rs:21:24
25+
|
26+
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
28+
help: consider further restricting this bound
29+
|
30+
LL | fn function2<T: Trait<'static, Assoc = usize> + for<'a> Trait<'a>>() {
31+
| +++++++++++++++++++
32+
33+
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
34+
--> $DIR/candidate-from-env-universe-err-project.rs:41:24
35+
|
36+
LL | projection_bound::<T>();
37+
| ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
38+
|
39+
note: types differ
40+
--> $DIR/candidate-from-env-universe-err-project.rs:17:18
41+
|
42+
LL | type Assoc = usize;
43+
| ^^^^^
44+
note: required by a bound in `projection_bound`
45+
--> $DIR/candidate-from-env-universe-err-project.rs:21:42
46+
|
47+
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
48+
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
49+
50+
error: higher-ranked subtype error
51+
--> $DIR/candidate-from-env-universe-err-project.rs:56:30
52+
|
53+
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
56+
error: higher-ranked subtype error
57+
--> $DIR/candidate-from-env-universe-err-project.rs:56:30
58+
|
59+
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
60+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
61+
|
62+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
63+
64+
error: aborting due to 5 previous errors
65+
66+
Some errors have detailed explanations: E0271, E0277.
67+
For more information about an error, try `rustc --explain E0271`.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//@ revisions: next current
2+
//@[next] compile-flags: -Znext-solver
3+
4+
// cc #119820 the previous behavior here was inconsistent as we discarded
5+
// the where-bound candidate for trait goals due to the leak check, but did
6+
// not do so for projection candidates and during normalization.
7+
//
8+
// FIXME(-Znext-solver): We currently prefer the impl over the where-bound
9+
// for trait goals because the impl does not result in any constraints.
10+
//
11+
// This results in an inconsistency between `Trait` and `Projection` goals as
12+
// normalizing always constraints the normalized-to term.
13+
trait Trait<'a> {
14+
type Assoc;
15+
}
16+
impl<'a, T> Trait<'a> for T {
17+
type Assoc = usize;
18+
}
19+
20+
fn trait_bound<T: for<'a> Trait<'a>>() {}
21+
fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
22+
23+
// We use a function with a trivial where-bound which is more
24+
// restrictive than the impl.
25+
fn function1<T: Trait<'static>>() {
26+
// ok
27+
//
28+
// Proving `for<'a> T: Trait<'a>` using the where-bound results
29+
// in a leak check failure, so we use the more general impl,
30+
// causing this to succeed.
31+
trait_bound::<T>();
32+
//[current]~^ ERROR mismatched types
33+
}
34+
35+
fn function2<T: Trait<'static, Assoc = usize>>() {
36+
// err
37+
//
38+
// Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>`
39+
// does not use the leak check when trying the where-bound, causing us
40+
// to prefer it over the impl, resulting in a placeholder error.
41+
projection_bound::<T>();
42+
//[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
43+
//[current]~^^ ERROR mismatched types
44+
//[current]~| ERROR mismatched types
45+
}
46+
47+
fn function3<T: Trait<'static, Assoc = usize>>() {
48+
// err
49+
//
50+
// Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)`
51+
// only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already
52+
// instantiated, causing us to prefer the where-bound over the impl
53+
// resulting in a placeholder error. Even if were were to also use the
54+
// leak check during candidate selection for normalization, this
55+
// case would still not compile.
56+
let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
57+
//[current]~^ ERROR mismatched types
58+
//[current]~| ERROR mismatched types
59+
}
60+
61+
fn main() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/leak-check-in-selection-2.rs:16:5
3+
|
4+
LL | impls_trait::<(), _>();
5+
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
6+
|
7+
note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
8+
--> $DIR/leak-check-in-selection-2.rs:9:1
9+
|
10+
LL | impl<'a> Trait<&'a str, &'a str> for () {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL |
13+
LL | impl<'a> Trait<&'a str, String> for () {}
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
note: required by a bound in `impls_trait`
16+
--> $DIR/leak-check-in-selection-2.rs:13:19
17+
|
18+
LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/leak-check-in-selection-2.rs:16:5
3+
|
4+
LL | impls_trait::<(), _>();
5+
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
6+
|
7+
note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
8+
--> $DIR/leak-check-in-selection-2.rs:9:1
9+
|
10+
LL | impl<'a> Trait<&'a str, &'a str> for () {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL |
13+
LL | impl<'a> Trait<&'a str, String> for () {}
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
note: required by a bound in `impls_trait`
16+
--> $DIR/leak-check-in-selection-2.rs:13:19
17+
|
18+
LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ revisions: old next
2+
//@[next] compile-flags: -Znext-solver
3+
4+
// cc #119820
5+
6+
trait Trait<T, U> {}
7+
8+
// using this impl results in a higher-ranked region error.
9+
impl<'a> Trait<&'a str, &'a str> for () {}
10+
11+
impl<'a> Trait<&'a str, String> for () {}
12+
13+
fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
14+
15+
fn main() {
16+
impls_trait::<(), _>();
17+
//~^ ERROR type annotations needed
18+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/leak-check-in-selection-3.rs:18:5
3+
|
4+
LL | impls_leak::<Box<_>>();
5+
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
6+
|
7+
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
8+
--> $DIR/leak-check-in-selection-3.rs:9:1
9+
|
10+
LL | impl Leak<'_> for Box<u32> {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl Leak<'static> for Box<u16> {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: required by a bound in `impls_leak`
15+
--> $DIR/leak-check-in-selection-3.rs:12:18
16+
|
17+
LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
18+
| ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
19+
20+
error[E0283]: type annotations needed
21+
--> $DIR/leak-check-in-selection-3.rs:35:5
22+
|
23+
LL | impls_indirect_leak::<Box<_>>();
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
25+
|
26+
= note: cannot satisfy `for<'a> Box<_>: IndirectLeak<'a>`
27+
note: required by a bound in `impls_indirect_leak`
28+
--> $DIR/leak-check-in-selection-3.rs:25:27
29+
|
30+
LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
32+
33+
error: aborting due to 2 previous errors
34+
35+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/leak-check-in-selection-3.rs:18:5
3+
|
4+
LL | impls_leak::<Box<_>>();
5+
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
6+
|
7+
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
8+
--> $DIR/leak-check-in-selection-3.rs:9:1
9+
|
10+
LL | impl Leak<'_> for Box<u32> {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl Leak<'static> for Box<u16> {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: required by a bound in `impls_leak`
15+
--> $DIR/leak-check-in-selection-3.rs:12:18
16+
|
17+
LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
18+
| ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
19+
20+
error[E0283]: type annotations needed
21+
--> $DIR/leak-check-in-selection-3.rs:35:5
22+
|
23+
LL | impls_indirect_leak::<Box<_>>();
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
25+
|
26+
note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found
27+
--> $DIR/leak-check-in-selection-3.rs:9:1
28+
|
29+
LL | impl Leak<'_> for Box<u32> {}
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
LL | impl Leak<'static> for Box<u16> {}
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
note: required for `Box<_>` to implement `for<'a> IndirectLeak<'a>`
34+
--> $DIR/leak-check-in-selection-3.rs:23:23
35+
|
36+
LL | impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
37+
| -------- ^^^^^^^^^^^^^^^^ ^
38+
| |
39+
| unsatisfied trait bound introduced here
40+
note: required by a bound in `impls_indirect_leak`
41+
--> $DIR/leak-check-in-selection-3.rs:25:27
42+
|
43+
LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
45+
46+
error: aborting due to 2 previous errors
47+
48+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ revisions: old next
2+
//@[next] compile-flags: -Znext-solver
3+
4+
// cc #119820, the previous behavior here was inconsistent,
5+
// using the leak check to guide inference for `for<'a> Box<_>: Leak<'a>`
6+
// but not for `for<'a> Box<_>: IndirectLeak<'a>`
7+
8+
trait Leak<'a> {}
9+
impl Leak<'_> for Box<u32> {}
10+
impl Leak<'static> for Box<u16> {}
11+
12+
fn impls_leak<T: for<'a> Leak<'a>>() {}
13+
fn direct() {
14+
// ok
15+
//
16+
// The `Box<u16>` impls fails the leak check,
17+
// meaning that we apply the `Box<u32>` impl.
18+
impls_leak::<Box<_>>();
19+
//~^ ERROR type annotations needed
20+
}
21+
22+
trait IndirectLeak<'a> {}
23+
impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
24+
25+
fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
26+
fn indirect() {
27+
// error: type annotations needed
28+
//
29+
// While the `Box<u16>` impl would fail the leak check
30+
// we have already instantiated the binder while applying
31+
// the generic `IndirectLeak` impl, so during candidate
32+
// selection of `Leak` we do not detect the placeholder error.
33+
// Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous,
34+
// resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous.
35+
impls_indirect_leak::<Box<_>>();
36+
//~^ ERROR type annotations needed
37+
}
38+
39+
fn main() {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: old next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ check-pass
4+
5+
// cc #119820. While the leak check does not consider the binder
6+
// of the current goal, leaks from higher-ranked nested goals are
7+
// considered.
8+
//
9+
// We enter and exit the binder of the nested goal while evaluating
10+
// the candidate.
11+
12+
trait LeakCheckFailure<'a> {}
13+
impl LeakCheckFailure<'static> for () {}
14+
15+
trait Trait<T> {}
16+
impl Trait<u32> for () where for<'a> (): LeakCheckFailure<'a> {}
17+
impl Trait<u16> for () {}
18+
fn impls_trait<T: Trait<U>, U>() {}
19+
fn main() {
20+
// ok
21+
//
22+
// It does not matter whether candidate assembly
23+
// considers the placeholders from higher-ranked goal.
24+
//
25+
// Either `for<'a> (): LeakCheckFailure<'a>` has no applicable
26+
// candidate or it has a single applicable candidate which then later
27+
// results in an error. This allows us to infer `U` to `u16`.
28+
impls_trait::<(), _>()
29+
}
Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,11 @@
1-
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
2-
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
1+
error: implementation of `Bar` is not general enough
2+
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
33
|
44
LL | want_bar_for_any_ccx(b);
5-
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
6-
| |
7-
| required by a bound introduced by this call
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
86
|
9-
note: required by a bound in `want_bar_for_any_ccx`
10-
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
11-
|
12-
LL | fn want_bar_for_any_ccx<B>(b: &B)
13-
| -------------------- required by a bound in this function
14-
LL | where B : for<'ccx> Bar<'ccx>
15-
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
16-
help: consider further restricting this bound
17-
|
18-
LL | where B : Qux + for<'ccx> Bar<'ccx>
19-
| +++++++++++++++++++++
7+
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
8+
= note: ...but it actually implements `Bar<'static>`
209

2110
error: aborting due to 1 previous error
2211

23-
For more information about this error, try `rustc --explain E0277`.

‎tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,37 @@
11
// Test a trait (`Bar`) with a higher-ranked supertrait.
2+
#![allow(unconditional_recursion)]
23

3-
trait Foo<'tcx>
4-
{
4+
trait Foo<'tcx> {
55
fn foo(&'tcx self) -> &'tcx isize;
66
}
77

8-
trait Bar<'ccx>
9-
: for<'tcx> Foo<'tcx>
10-
{
8+
trait Bar<'ccx>: for<'tcx> Foo<'tcx> {
119
fn bar(&'ccx self) -> &'ccx isize;
1210
}
1311

14-
fn want_foo_for_some_tcx<'x,F>(f: &'x F)
15-
where F : Foo<'x>
16-
{
12+
fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
1713
want_foo_for_some_tcx(f);
18-
want_foo_for_any_tcx(f); //~ ERROR not satisfied
14+
want_foo_for_any_tcx(f);
15+
//~^ ERROR lifetime may not live long enough
16+
//~| ERROR implementation of `Foo` is not general enough
1917
}
2018

21-
fn want_foo_for_any_tcx<F>(f: &F) //~ WARN cannot return without recursing
22-
where F : for<'tcx> Foo<'tcx>
23-
{
19+
fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
2420
want_foo_for_some_tcx(f);
2521
want_foo_for_any_tcx(f);
2622
}
2723

28-
fn want_bar_for_some_ccx<'x,B>(b: &B)
29-
where B : Bar<'x>
30-
{
24+
fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
3125
want_foo_for_some_tcx(b);
3226
want_foo_for_any_tcx(b);
3327

3428
want_bar_for_some_ccx(b);
35-
want_bar_for_any_ccx(b); //~ ERROR not satisfied
29+
want_bar_for_any_ccx(b);
30+
//~^ ERROR lifetime may not live long enough
31+
//~| ERROR implementation of `Bar` is not general enough
3632
}
3733

38-
fn want_bar_for_any_ccx<B>(b: &B) //~ WARN cannot return without recursing
39-
where B : for<'ccx> Bar<'ccx>
40-
{
34+
fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
4135
want_foo_for_some_tcx(b);
4236
want_foo_for_any_tcx(b);
4337

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,50 @@
1-
error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
2-
--> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
1+
error: lifetime may not live long enough
2+
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
33
|
4+
LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
5+
| -- lifetime `'x` defined here
6+
LL | want_foo_for_some_tcx(f);
47
LL | want_foo_for_any_tcx(f);
5-
| -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
6-
| |
7-
| required by a bound introduced by this call
8+
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
89
|
9-
note: required by a bound in `want_foo_for_any_tcx`
10-
--> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
10+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
11+
--> $DIR/hrtb-higher-ranker-supertraits.rs:19:28
1112
|
12-
LL | fn want_foo_for_any_tcx<F>(f: &F)
13-
| -------------------- required by a bound in this function
14-
LL | where F : for<'tcx> Foo<'tcx>
15-
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx`
16-
help: consider further restricting this bound
17-
|
18-
LL | where F : Foo<'x> + for<'tcx> Foo<'tcx>
19-
| +++++++++++++++++++++
13+
LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
14+
| ^^^^^^^^^^^^^^^^^^^
2015

21-
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
22-
--> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
23-
|
24-
LL | want_bar_for_any_ccx(b);
25-
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
26-
| |
27-
| required by a bound introduced by this call
16+
error: implementation of `Foo` is not general enough
17+
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
2818
|
29-
note: required by a bound in `want_bar_for_any_ccx`
30-
--> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
31-
|
32-
LL | fn want_bar_for_any_ccx<B>(b: &B)
33-
| -------------------- required by a bound in this function
34-
LL | where B : for<'ccx> Bar<'ccx>
35-
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
36-
help: consider further restricting this bound
19+
LL | want_foo_for_any_tcx(f);
20+
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
3721
|
38-
LL | where B : Bar<'x> + for<'ccx> Bar<'ccx>
39-
| +++++++++++++++++++++
22+
= note: `F` must implement `Foo<'0>`, for any lifetime `'0`...
23+
= note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1`
4024

41-
warning: function cannot return without recursing
42-
--> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
25+
error: lifetime may not live long enough
26+
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
4327
|
44-
LL | / fn want_foo_for_any_tcx<F>(f: &F)
45-
LL | | where F : for<'tcx> Foo<'tcx>
46-
| |_________________________________^ cannot return without recursing
28+
LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
29+
| -- lifetime `'x` defined here
4730
...
48-
LL | want_foo_for_any_tcx(f);
49-
| ----------------------- recursive call site
31+
LL | want_bar_for_any_ccx(b);
32+
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
33+
|
34+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
35+
--> $DIR/hrtb-higher-ranker-supertraits.rs:34:28
5036
|
51-
= help: a `loop` may express intention better if this is on purpose
52-
= note: `#[warn(unconditional_recursion)]` on by default
37+
LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
38+
| ^^^^^^^^^^^^^^^^^^^
5339

54-
warning: function cannot return without recursing
55-
--> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
40+
error: implementation of `Bar` is not general enough
41+
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
5642
|
57-
LL | / fn want_bar_for_any_ccx<B>(b: &B)
58-
LL | | where B : for<'ccx> Bar<'ccx>
59-
| |_________________________________^ cannot return without recursing
60-
...
61-
LL | want_bar_for_any_ccx(b);
62-
| ----------------------- recursive call site
43+
LL | want_bar_for_any_ccx(b);
44+
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
6345
|
64-
= help: a `loop` may express intention better if this is on purpose
46+
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
47+
= note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1`
6548

66-
error: aborting due to 2 previous errors; 2 warnings emitted
49+
error: aborting due to 4 previous errors
6750

68-
For more information about this error, try `rustc --explain E0277`.

‎tests/ui/higher-ranked/trait-bounds/issue-30786.rs renamed to ‎tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
22

3-
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
3+
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T>`
44
// should act as assertion that item does not borrow from its stream;
55
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
66
// have such an item.
@@ -97,10 +97,6 @@ where
9797

9898
impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
9999

100-
fn identity<T>(x: &T) -> &T {
101-
x
102-
}
103-
104100
fn variant1() {
105101
let source = Repeat(10);
106102

@@ -118,19 +114,7 @@ fn variant1() {
118114
// guess.
119115
let map = source.mapx(|x: &_| x);
120116
let filter = map.filterx(|x: &_| true);
121-
//~^ ERROR the method
122-
}
123-
124-
fn variant2() {
125-
let source = Repeat(10);
126-
127-
// Here, we use a function, which is not subject to the vagaries
128-
// of closure signature inference. In this case, we get the error
129-
// on `countx` as, I think, the test originally expected.
130-
let map = source.mapx(identity);
131-
let filter = map.filterx(|x: &_| true);
132-
let count = filter.countx();
133-
//~^ ERROR the method
117+
//~^ ERROR the method `filterx` exists for struct
134118
}
135119

136120
fn main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@issue-30786-1.rs:115:27}>`, but its trait bounds were not satisfied
2+
--> $DIR/issue-30786-1.rs:116:22
3+
|
4+
LL | pub struct Map<S, F> {
5+
| -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
6+
...
7+
LL | let filter = map.filterx(|x: &_| true);
8+
| ^^^^^^^ method cannot be called on `Map<Repeat, {closure@issue-30786-1.rs:115:27}>` due to unsatisfied trait bounds
9+
|
10+
note: the following trait bounds were not satisfied:
11+
`&'a mut &Map<Repeat, {closure@$DIR/issue-30786-1.rs:115:27: 115:34}>: Stream`
12+
`&'a mut &mut Map<Repeat, {closure@$DIR/issue-30786-1.rs:115:27: 115:34}>: Stream`
13+
`&'a mut Map<Repeat, {closure@$DIR/issue-30786-1.rs:115:27: 115:34}>: Stream`
14+
--> $DIR/issue-30786-1.rs:98:50
15+
|
16+
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
17+
| --------- - ^^^^^^ unsatisfied trait bound introduced here
18+
= help: items from traits can only be used if the trait is implemented and in scope
19+
note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
20+
--> $DIR/issue-30786-1.rs:66:1
21+
|
22+
LL | pub trait StreamExt
23+
| ^^^^^^^^^^^^^^^^^^^
24+
25+
error: aborting due to 1 previous error
26+
27+
For more information about this error, try `rustc --explain E0599`.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
2+
3+
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
4+
// should act as assertion that item does not borrow from its stream;
5+
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
6+
// have such an item.
7+
//
8+
// This tests double-checks that we do not allow such behavior to leak
9+
// through again.
10+
11+
pub trait Stream {
12+
type Item;
13+
fn next(self) -> Option<Self::Item>;
14+
}
15+
16+
// Example stream
17+
pub struct Repeat(u64);
18+
19+
impl<'a> Stream for &'a mut Repeat {
20+
type Item = &'a u64;
21+
fn next(self) -> Option<Self::Item> {
22+
Some(&self.0)
23+
}
24+
}
25+
26+
pub struct Map<S, F> {
27+
stream: S,
28+
func: F,
29+
}
30+
31+
impl<'a, A, F, T> Stream for &'a mut Map<A, F>
32+
where
33+
&'a mut A: Stream,
34+
F: FnMut(<&'a mut A as Stream>::Item) -> T,
35+
{
36+
type Item = T;
37+
fn next(self) -> Option<T> {
38+
match self.stream.next() {
39+
Some(item) => Some((self.func)(item)),
40+
None => None,
41+
}
42+
}
43+
}
44+
45+
pub struct Filter<S, F> {
46+
stream: S,
47+
func: F,
48+
}
49+
50+
impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
51+
where
52+
for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
53+
F: FnMut(&T) -> bool,
54+
{
55+
type Item = <&'a mut A as Stream>::Item;
56+
fn next(self) -> Option<Self::Item> {
57+
while let Some(item) = self.stream.next() {
58+
if (self.func)(&item) {
59+
return Some(item);
60+
}
61+
}
62+
None
63+
}
64+
}
65+
66+
pub trait StreamExt
67+
where
68+
for<'b> &'b mut Self: Stream,
69+
{
70+
fn mapx<F>(self, func: F) -> Map<Self, F>
71+
where
72+
Self: Sized,
73+
for<'a> &'a mut Map<Self, F>: Stream,
74+
{
75+
Map { func: func, stream: self }
76+
}
77+
78+
fn filterx<F>(self, func: F) -> Filter<Self, F>
79+
where
80+
Self: Sized,
81+
for<'a> &'a mut Filter<Self, F>: Stream,
82+
{
83+
Filter { func: func, stream: self }
84+
}
85+
86+
fn countx(mut self) -> usize
87+
where
88+
Self: Sized,
89+
{
90+
let mut count = 0;
91+
while let Some(_) = self.next() {
92+
count += 1;
93+
}
94+
count
95+
}
96+
}
97+
98+
impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
99+
100+
fn identity<T>(x: &T) -> &T {
101+
x
102+
}
103+
104+
fn variant2() {
105+
let source = Repeat(10);
106+
107+
// Here, we use a function, which is not subject to the vagaries
108+
// of closure signature inference. In this case, we get the error
109+
// on `countx` as, I think, the test originally expected.
110+
let map = source.mapx(identity);
111+
let filter = map.filterx(|x: &_| true);
112+
let count = filter.countx();
113+
//~^ ERROR the method
114+
}
115+
116+
fn main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786-2.rs:111:30}>`, but its trait bounds were not satisfied
2+
--> $DIR/issue-30786-2.rs:112:24
3+
|
4+
LL | pub struct Filter<S, F> {
5+
| ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
6+
...
7+
LL | let count = filter.countx();
8+
| ^^^^^^ method cannot be called due to unsatisfied trait bounds
9+
|
10+
note: the following trait bounds were not satisfied:
11+
`&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream`
12+
`&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream`
13+
`&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream`
14+
--> $DIR/issue-30786-2.rs:98:50
15+
|
16+
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
17+
| --------- - ^^^^^^ unsatisfied trait bound introduced here
18+
= help: items from traits can only be used if the trait is implemented and in scope
19+
note: `StreamExt` defines an item `countx`, perhaps you need to implement it
20+
--> $DIR/issue-30786-2.rs:66:1
21+
|
22+
LL | pub trait StreamExt
23+
| ^^^^^^^^^^^^^^^^^^^
24+
25+
error: aborting due to 1 previous error
26+
27+
For more information about this error, try `rustc --explain E0599`.

‎tests/ui/higher-ranked/trait-bounds/issue-30786.stderr

Lines changed: 0 additions & 51 deletions
This file was deleted.

‎tests/ui/implied-bounds/issue-100690.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
use std::io;
55

66
fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
7-
//~^ NOTE required by a bound in this
87
where
98
F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
10-
//~^ NOTE required by this bound in `real_dispatch`
11-
//~| NOTE required by a bound in `real_dispatch`
129
{
1310
todo!()
1411
}
@@ -35,10 +32,10 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl
3532
F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static,
3633
{
3734
real_dispatch(f)
38-
//~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
39-
//~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
40-
//~| NOTE expected a closure with arguments
41-
//~| NOTE required by a bound introduced by this call
35+
//~^ ERROR lifetime may not live long enough
36+
//~| ERROR implementation of `FnOnce` is not general enough
37+
//~| ERROR mismatched types
38+
//
4239
}
4340
}
4441

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,41 @@
1-
error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
2-
--> $DIR/issue-100690.rs:37:23
1+
error: lifetime may not live long enough
2+
--> $DIR/issue-100690.rs:34:9
33
|
4+
LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle<T> {
5+
| -- lifetime `'a` defined here
6+
...
47
LL | real_dispatch(f)
5-
| ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
6-
| |
7-
| required by a bound introduced by this call
8+
| ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
89
|
9-
= note: expected a closure with arguments `(&mut UIView<'a, _>,)`
10-
found a closure with arguments `(&mut UIView<'_, _>,)`
11-
note: required by a bound in `real_dispatch`
12-
--> $DIR/issue-100690.rs:9:8
10+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
11+
--> $DIR/issue-100690.rs:8:8
12+
|
13+
LL | F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error: implementation of `FnOnce` is not general enough
17+
--> $DIR/issue-100690.rs:34:9
18+
|
19+
LL | real_dispatch(f)
20+
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
21+
|
22+
= note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`...
23+
= note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1`
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/issue-100690.rs:34:9
27+
|
28+
LL | real_dispatch(f)
29+
| ^^^^^^^^^^^^^^^^ one type is more general than the other
30+
|
31+
= note: expected associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
32+
found associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
33+
note: the lifetime requirement is introduced here
34+
--> $DIR/issue-100690.rs:8:34
1335
|
14-
LL | fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
15-
| ------------- required by a bound in this function
16-
...
1736
LL | F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
18-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch`
37+
| ^^^^^^^^^^^^^^^^^^^^^
1938

20-
error: aborting due to 1 previous error
39+
error: aborting due to 3 previous errors
2140

22-
For more information about this error, try `rustc --explain E0277`.
41+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)
Please sign in to comment.