Skip to content

Report better WF obligation leaf obligations in new solver #125191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 17, 2024
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
77 changes: 57 additions & 20 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,39 +384,64 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
return ControlFlow::Break(self.obligation.clone());
}

// FIXME: Could we extract a trait ref from a projection here too?
let tcx = goal.infcx().tcx;
// FIXME: Also, what about considering >1 layer up the stack? May be necessary
// for normalizes-to.
let Some(parent_trait_pred) = goal.goal().predicate.to_opt_poly_trait_pred() else {
return ControlFlow::Break(self.obligation.clone());
let pred_kind = goal.goal().predicate.kind();
let child_mode = match pred_kind.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => {
ChildMode::Trait(pred_kind.rebind(parent_trait_pred))
}
ty::PredicateKind::NormalizesTo(normalizes_to)
if matches!(
normalizes_to.alias.kind(tcx),
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
) =>
{
ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate {
trait_ref: normalizes_to.alias.trait_ref(tcx),
polarity: ty::PredicatePolarity::Positive,
}))
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
ChildMode::WellFormedObligation
}
_ => {
return ControlFlow::Break(self.obligation.clone());
}
};

let tcx = goal.infcx().tcx;
let mut impl_where_bound_count = 0;
for nested_goal in candidate.instantiate_nested_goals(self.span()) {
let make_obligation = |cause| Obligation {
cause,
param_env: nested_goal.goal().param_env,
predicate: nested_goal.goal().predicate,
recursion_depth: self.obligation.recursion_depth + 1,
};

let obligation;
match nested_goal.source() {
GoalSource::Misc => {
match (child_mode, nested_goal.source()) {
(ChildMode::Trait(_), GoalSource::Misc) => {
continue;
}
GoalSource::ImplWhereBound => {
obligation = Obligation {
cause: derive_cause(
tcx,
candidate.kind(),
self.obligation.cause.clone(),
impl_where_bound_count,
parent_trait_pred,
),
param_env: nested_goal.goal().param_env,
predicate: nested_goal.goal().predicate,
recursion_depth: self.obligation.recursion_depth + 1,
};
(ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
obligation = make_obligation(derive_cause(
tcx,
candidate.kind(),
self.obligation.cause.clone(),
impl_where_bound_count,
parent_trait_pred,
));
impl_where_bound_count += 1;
}
GoalSource::InstantiateHigherRanked => {
// Skip over a higher-ranked predicate.
(_, GoalSource::InstantiateHigherRanked) => {
obligation = self.obligation.clone();
}
(ChildMode::WellFormedObligation, _) => {
obligation = make_obligation(self.obligation.cause.clone());
}
}

// Skip nested goals that aren't the *reason* for our goal's failure.
Expand All @@ -436,6 +461,18 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
}
}

#[derive(Copy, Clone)]
enum ChildMode<'tcx> {
// Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
// and skip all `GoalSource::Misc`, which represent useless obligations
// such as alias-eq which may not hold.
Trait(ty::PolyTraitPredicate<'tcx>),
// Skip trying to derive an `ObligationCause` from this obligation, and
// report *all* sub-obligations as if they came directly from the parent
// obligation.
WellFormedObligation,
}

fn derive_cause<'tcx>(
tcx: TyCtxt<'tcx>,
candidate_kind: ProbeKind<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
error: the type `Foo::Bar<Vec<[u32]>>` is not well-formed
--> $DIR/wf-check-skipped.rs:17:14
error[E0277]: the size for values of type `[u32]` cannot be known at compilation time
--> $DIR/wf-check-skipped.rs:17:25
|
LL | fn main() -> Foo::Bar::<Vec<[u32]>> {}
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u32]`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ impl Foo {
}

fn main() -> Foo::Bar::<Vec<[u32]>> {}
//[next]~^ ERROR the type `Foo::Bar<Vec<[u32]>>` is not well-formed
//[next]~^ ERROR the size for values of type `[u32]` cannot be known at compilation time
20 changes: 1 addition & 19 deletions tests/ui/for/issue-20605.next.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,13 @@ help: consider mutably borrowing here
LL | for item in &mut *things { *item = 0 }
| ++++

error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
--> $DIR/issue-20605.rs:6:17
|
LL | for item in *things { *item = 0 }
| ^^^^^^^

error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
--> $DIR/issue-20605.rs:6:17
|
LL | for item in *things { *item = 0 }
| ^^^^^^^

error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
--> $DIR/issue-20605.rs:6:17
|
LL | for item in *things { *item = 0 }
| ^^^^^^^

error[E0614]: type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
--> $DIR/issue-20605.rs:6:27
|
LL | for item in *things { *item = 0 }
| ^^^^^

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

Some errors have detailed explanations: E0277, E0614.
For more information about an error, try `rustc --explain E0277`.
3 changes: 0 additions & 3 deletions tests/ui/for/issue-20605.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
for item in *things { *item = 0 }
//[current]~^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
//[next]~^^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
//[next]~| ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
//[next]~| ERROR the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
//[next]~| ERROR the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
//[next]~| ERROR type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced

// FIXME(-Znext-solver): these error messages are horrible and have to be
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ struct W<T>(T);
// `usize: Foo` doesn't hold. Therefore we ICE, because we don't expect to still
// encounter weak types in `assemble_alias_bound_candidates_recur`.
fn hello(_: W<A<usize>>) {}
//~^ ERROR the type `W<A<usize>>` is not well-formed
//~^ ERROR the size for values of type `A<usize>` cannot be known at compilation time

fn main() {}
7 changes: 5 additions & 2 deletions tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ LL | #![feature(lazy_type_alias)]
= note: see issue #112792 <https://github.com./rust-lang/rust/issues/112792> for more information
= note: `#[warn(incomplete_features)]` on by default

error: the type `W<A<usize>>` is not well-formed
error[E0277]: the size for values of type `A<usize>` cannot be known at compilation time
--> $DIR/alias-bounds-when-not-wf.rs:16:13
|
LL | fn hello(_: W<A<usize>>) {}
| ^^^^^^^^^^^
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `A<usize>`

error: aborting due to 1 previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0282]: type annotations needed
error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
--> $DIR/const-region-infer-to-static-in-binder.rs:4:10
|
LL | struct X<const FN: fn() = { || {} }>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{ || {} }`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`

error: using function pointers as const generic parameters is forbidden
--> $DIR/const-region-infer-to-static-in-binder.rs:4:20
Expand All @@ -23,4 +23,4 @@ LL | struct X<const FN: fn() = { || {} }>;

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0282`.
For more information about this error, try `rustc --explain E0284`.
2 changes: 1 addition & 1 deletion tests/ui/traits/next-solver/issue-118950-root-region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait ToUnit<'a> {
trait Overlap<T> {}

type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
//~^ ERROR: not well-formed
//~^ ERROR the trait bound `*const T: ToUnit<'a>` is not satisfied

impl<T> Overlap<T> for T {}

Expand Down
12 changes: 9 additions & 3 deletions tests/ui/traits/next-solver/issue-118950-root-region.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ LL | #![feature(lazy_type_alias)]
= note: see issue #112792 <https://github.com./rust-lang/rust/issues/112792> for more information
= note: `#[warn(incomplete_features)]` on by default

error: the type `<*const T as ToUnit<'a>>::Unit` is not well-formed
error[E0277]: the trait bound `*const T: ToUnit<'a>` is not satisfied
--> $DIR/issue-118950-root-region.rs:14:21
|
LL | type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToUnit<'a>` is not implemented for `*const T`
|
help: this trait has no implementations, consider adding one
--> $DIR/issue-118950-root-region.rs:8:1
|
LL | trait ToUnit<'a> {
| ^^^^^^^^^^^^^^^^

WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
Expand All @@ -34,5 +40,5 @@ LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {

error: aborting due to 3 previous errors; 1 warning emitted

Some errors have detailed explanations: E0119, E0412.
Some errors have detailed explanations: E0119, E0277, E0412.
For more information about an error, try `rustc --explain E0119`.
17 changes: 0 additions & 17 deletions tests/ui/traits/next-solver/member-constraints-in-root-universe.rs

This file was deleted.

This file was deleted.

3 changes: 1 addition & 2 deletions tests/ui/traits/next-solver/object-unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {

pub fn copy_any<T>(t: &T) -> T {
copy::<dyn Setup<From=T>>(t)
//~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
//~^ ERROR the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
//~| ERROR mismatched types
//~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
//~| ERROR the trait bound `T: Copy` is not satisfied

// FIXME(-Znext-solver): These error messages are horrible and some of them
Expand Down
18 changes: 9 additions & 9 deletions tests/ui/traits/next-solver/object-unsafety.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ help: consider restricting type parameter `T`
LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
| +++++++++++++++++++

error: the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
--> $DIR/object-unsafety.rs:12:31
|
LL | copy::<dyn Setup<From=T>>(t)
| ^

error[E0308]: mismatched types
--> $DIR/object-unsafety.rs:12:31
|
Expand All @@ -37,13 +31,19 @@ note: function defined here
LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
| ^^^^ --------------

error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
--> $DIR/object-unsafety.rs:12:5
|
LL | copy::<dyn Setup<From=T>>(t)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup`
|
= note: required because it appears within the type `dyn Setup<From = T>`
help: consider restricting type parameter `T`
|
LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
| +++++++++++++++++++

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

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
31 changes: 19 additions & 12 deletions tests/ui/wf/wf-normalization-sized.next.stderr
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
error: the type `<[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize` is not well-formed
--> $DIR/wf-normalization-sized.rs:19:10
error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
--> $DIR/wf-normalization-sized.rs:19:11
|
LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`

error: the type `<[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize` is not well-formed
--> $DIR/wf-normalization-sized.rs:19:10
error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
--> $DIR/wf-normalization-sized.rs:19:11
|
LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: the type `<Vec<str> as WellUnformed>::RequestNormalize` is not well-formed
--> $DIR/wf-normalization-sized.rs:22:10
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/wf-normalization-sized.rs:22:11
|
LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Span for this error is preexisting. If we recorded the HirId of the type, we could improve it now, but that's best left for another PR.

| ^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`

error: the type `<Vec<str> as WellUnformed>::RequestNormalize` is not well-formed
--> $DIR/wf-normalization-sized.rs:22:10
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/wf-normalization-sized.rs:22:11
|
LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0277`.
8 changes: 4 additions & 4 deletions tests/ui/wf/wf-normalization-sized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ impl<T: ?Sized> WellUnformed for T {
}

const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
//[next]~^ the type
//[next]~| the type
//[next]~^ the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
//[next]~| the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
//[next]~^ the type
//[next]~| the type
//[next]~^ the size for values of type `str` cannot be known at compilation time
//[next]~| the size for values of type `str` cannot be known at compilation time

fn main() {}
Loading