Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1593,6 +1593,45 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}

/// Whether `error`, a projection goal, only failed because the trait goal it rests on
/// did: `<T as Trait>::Assoc == U` cannot hold when `T: Trait` doesn't, so an error on
/// the latter says everything the former would.
pub(super) fn trait_error_implies_projection_error(
&self,
cond: Goal<'tcx, ty::Predicate<'tcx>>,
error: Goal<'tcx, ty::Predicate<'tcx>>,
) -> bool {
if cond.param_env != error.param_env {
return false;
}
let Some(error) = error.predicate.as_projection_clause() else {
return false;
};

self.enter_forall(error, |error| {
if !error.projection_term.kind.is_trait_projection() {
return false;
}
let trait_pred = ty::TraitPredicate {
trait_ref: error.projection_term.trait_ref(self.tcx),
polarity: ty::PredicatePolarity::Positive,
};
// Elaborating is what pairs a failing `C: FnMut(..)` with the
// `<C as FnOnce<..>>::Output` projection resting on it. A supertrait can hold
// while `cond` fails though, so the projection is only covered if its own trait
// goal is unproven too, otherwise it failed for its own reasons.
elaborate(self.tcx, std::iter::once(cond.predicate))
.filter_map(|implied| implied.as_trait_clause())
.any(|implied| self.can_match_trait(cond.param_env, trait_pred, implied))
&& !self.predicate_must_hold_modulo_regions(&Obligation::new(
self.tcx,
ObligationCause::dummy(),
cond.param_env,
trait_pred,
))
})
}

#[instrument(level = "debug", skip_all)]
pub(super) fn report_projection_error(
&self,
Expand Down
20 changes: 18 additions & 2 deletions compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// We do this in 2 passes because we want to display errors in order, though
// maybe it *is* better to sort errors by span or something.
let mut is_suppressed = vec![false; errors.len()];
// A failing trait goal also fails every projection goal resting on it. Ambiguity
// errors are exempt: they get merged into a single diagnostic whose notes list all
// the constraints the annotation has to satisfy, so their projections still say
// something the trait error doesn't.
let covered_by_trait_error =
|cond: &ErrorDescriptor<'tcx>, error: &ErrorDescriptor<'tcx>| {
let is_definite = |error: &ErrorDescriptor<'tcx>| {
error.index.is_some_and(|index| {
!matches!(errors[index].code, FulfillmentErrorCode::Ambiguity { .. })
})
};
is_definite(cond)
&& is_definite(error)
&& self.trait_error_implies_projection_error(cond.goal, error.goal)
};
for (_, error_set) in error_map.iter() {
// We want to suppress "duplicate" errors with the same span.
for error in error_set {
Expand All @@ -239,9 +254,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
continue;
}

if self.error_implies(error2.goal, error.goal)
if (self.error_implies(error2.goal, error.goal)
&& !(error2.index >= error.index
&& self.error_implies(error.goal, error2.goal))
&& self.error_implies(error.goal, error2.goal)))
|| covered_by_trait_error(error2, error)
{
info!("skipping {:?} (implied by {:?})", error, error2);
is_suppressed[index] = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ fn main() {
let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
//[current]~^ ERROR type mismatch in closure arguments
//[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found
//[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool`
let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
//[current]~^ ERROR type mismatch in closure arguments
//[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found
//[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool`
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
| +

error[E0631]: type mismatch in closure arguments
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:24
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24
|
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
| ^^^^ ----------- found signature defined here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,20 @@ LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0);
note: required by a bound in `find`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL

error[E0271]: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool`
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:38
|
LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0);
| ---- -------- ^^^^^^^^^^^^^^^ types differ
| | |
| | this closure
| required by a bound introduced by this call
|
note: required by a bound in `find`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL

error[E0277]: expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:10:29: 10:40}`
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:29
error[E0277]: expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29
|
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:10:29: 10:40}`
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&{integer})` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> FnMut(&'a {integer})` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:10:29: 10:40}`
= help: the trait `for<'a> FnMut(&'a {integer})` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}`
= note: expected a closure with signature `for<'a> fn(&'a {integer})`
found a closure with signature `fn(&&&i32)`
note: required by a bound in `find`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL

error[E0271]: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool`
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:41
|
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
| ---- ----------- ^^^^^^^^^^^^^^^ types differ
| | |
| | this closure
| required by a bound introduced by this call
|
note: required by a bound in `find`
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL

error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ fn main() {
let _ = (-10..=10).find(|x: i32| x.signum() == 0);
//[current]~^ ERROR type mismatch in closure arguments
//[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found
//[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool`
let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
//[current]~^ ERROR type mismatch in closure arguments
//[next]~^^ ERROR: expected an `FnMut(&{integer})` closure, found
//[next]~| ERROR: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool`
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const fn with_positive<F: for<'a> [const] Fn(&'a ())>() {}
const _: () = {
with_positive::<()>();
//~^ ERROR expected an `Fn(&'a ())` closure, found `()`
//~| ERROR type mismatch resolving `<() as FnOnce<(&(),)>>::Output == ()`
};

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,6 @@ note: required by a bound in `with_positive`
LL | const fn with_positive<F: for<'a> [const] Fn(&'a ())>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `with_positive`

error[E0271]: type mismatch resolving `<() as FnOnce<(&(),)>>::Output == ()`
--> $DIR/const-host-effect-hrtb-no-ice.rs:9:21
|
LL | with_positive::<()>();
| ^^ types differ
|
note: required by a bound in `with_positive`
--> $DIR/const-host-effect-hrtb-no-ice.rs:6:43
|
LL | const fn with_positive<F: for<'a> [const] Fn(&'a ())>() {}
| ^^^^^^^^^^ required by this bound in `with_positive`

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
error[E0277]: the trait bound `S: Sub` is not satisfied
--> $DIR/dont-suppress-independent-projection-error.rs:28:7
|
LL | f(S);
| - ^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
help: the trait `Sub` is not implemented for `S`
--> $DIR/dont-suppress-independent-projection-error.rs:14:1
|
LL | struct S;
| ^^^^^^^^
help: this trait has no implementations, consider adding one
--> $DIR/dont-suppress-independent-projection-error.rs:12:1
|
LL | trait Sub: Super {}
| ^^^^^^^^^^^^^^^^
note: required by a bound in `f`
--> $DIR/dont-suppress-independent-projection-error.rs:22:8
|
LL | fn f<T>(_: T)
| - required by a bound in this function
LL | where
LL | T: Sub,
| ^^^ required by this bound in `f`

error[E0271]: type mismatch resolving `<S as Super>::Assoc == u32`
--> $DIR/dont-suppress-independent-projection-error.rs:28:7
|
LL | f(S);
| - ^ type mismatch resolving `<S as Super>::Assoc == u32`
| |
| required by a bound introduced by this call
|
note: expected this to be `u32`
--> $DIR/dont-suppress-independent-projection-error.rs:17:18
|
LL | type Assoc = u8;
| ^^
note: required by a bound in `f`
--> $DIR/dont-suppress-independent-projection-error.rs:23:14
|
LL | fn f<T>(_: T)
| - required by a bound in this function
...
LL | T: Super<Assoc = u32>,
| ^^^^^^^^^^^ required by this bound in `f`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
error[E0277]: the trait bound `S: Sub` is not satisfied
--> $DIR/dont-suppress-independent-projection-error.rs:28:7
|
LL | f(S);
| - ^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
help: the trait `Sub` is not implemented for `S`
--> $DIR/dont-suppress-independent-projection-error.rs:14:1
|
LL | struct S;
| ^^^^^^^^
help: this trait has no implementations, consider adding one
--> $DIR/dont-suppress-independent-projection-error.rs:12:1
|
LL | trait Sub: Super {}
| ^^^^^^^^^^^^^^^^
note: required by a bound in `f`
--> $DIR/dont-suppress-independent-projection-error.rs:22:8
|
LL | fn f<T>(_: T)
| - required by a bound in this function
LL | where
LL | T: Sub,
| ^^^ required by this bound in `f`

error[E0271]: type mismatch resolving `<S as Super>::Assoc == u32`
--> $DIR/dont-suppress-independent-projection-error.rs:28:7
|
LL | f(S);
| - ^ type mismatch resolving `<S as Super>::Assoc == u32`
| |
| required by a bound introduced by this call
|
note: expected this to be `u32`
--> $DIR/dont-suppress-independent-projection-error.rs:17:18
|
LL | type Assoc = u8;
| ^^
note: required by a bound in `f`
--> $DIR/dont-suppress-independent-projection-error.rs:23:14
|
LL | fn f<T>(_: T)
| - required by a bound in this function
...
LL | T: Super<Assoc = u32>,
| ^^^^^^^^^^^ required by this bound in `f`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)

// A projection error is only redundant when the trait goal it rests on failed too.
// Here `S: Super` holds, so `<S as Super>::Assoc == u32` failed on its own and has to
// be reported even though the `S: Sub` error at the same span elaborates to `S: Super`.

trait Super {
type Assoc;
}
trait Sub: Super {}

struct S;

impl Super for S {
type Assoc = u8;
}

fn f<T>(_: T)
where
T: Sub,
T: Super<Assoc = u32>,
{
}

fn main() {
f(S);
//~^ ERROR the trait bound `S: Sub` is not satisfied
//~| ERROR type mismatch resolving `<S as Super>::Assoc == u32`
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ trait FooMut {
//~^ ERROR: cannot find value `_I` in this scope
self.bar(collection);
//~^ ERROR: `&'b _` is not an iterator
//~| ERROR: type mismatch resolving `<&_ as Iterator>::Item == &()`
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,32 +40,7 @@ LL | where
LL | for<'b> &'b I: Iterator<Item = &'b ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `FooMut::bar`

error[E0271]: type mismatch resolving `<&_ as Iterator>::Item == &()`
--> $DIR/iterator-item-suggest-no-ice.rs:16:18
|
LL | self.bar(collection);
| --- ^^^^^^^^^^ types differ
| |
| required by a bound introduced by this call
|
note: the method call chain might not have had the expected associated types
--> $DIR/iterator-item-suggest-no-ice.rs:14:35
|
LL | let collection = vec![_I].iter().map(|x| ());
| -------- ^^^^^^ ----------- `Iterator::Item` remains `<{type error} as Iterator>::Item` here
| | |
| | `Iterator::Item` is `<{type error} as Iterator>::Item` here
| this expression has type `Vec<{type error}>`
note: required by a bound in `FooMut::bar`
--> $DIR/iterator-item-suggest-no-ice.rs:7:33
|
LL | fn bar<I>(&self, _: I)
| --- required by a bound in this associated function
LL | where
LL | for<'b> &'b I: Iterator<Item = &'b ()>;
| ^^^^^^^^^^^^^ required by this bound in `FooMut::bar`

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0271, E0277, E0425, E0428.
For more information about an error, try `rustc --explain E0271`.
Some errors have detailed explanations: E0277, E0425, E0428.
For more information about an error, try `rustc --explain E0277`.
Loading