From c9ce51b5c78541bef1a3b3de61655629deef77b1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Jul 2023 19:22:22 +0000 Subject: [PATCH] Check GAT, IAT, and weak type where clauses during projection --- .../src/solve/inherent_projection.rs | 14 ++-- .../src/solve/project_goals.rs | 16 +++++ .../src/solve/weak_types.rs | 10 +++ .../src/traits/project.rs | 14 +++- .../traits/new-solver/alias-bound-unsound.rs | 9 ++- .../new-solver/alias-bound-unsound.stderr | 65 +++++++++++++++++-- 6 files changed, 112 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/inherent_projection.rs index 23f38466de1..d10a14ff742 100644 --- a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs +++ b/compiler/rustc_trait_selection/src/solve/inherent_projection.rs @@ -21,12 +21,6 @@ pub(super) fn normalize_inherent_associated_type( inherent.self_ty(), tcx.type_of(impl_def_id).instantiate(tcx, impl_substs), )?; - self.add_goals( - tcx.predicates_of(impl_def_id) - .instantiate(tcx, impl_substs) - .into_iter() - .map(|(pred, _)| goal.with(tcx, pred)), - ); // Equate IAT with the RHS of the project goal let inherent_substs = inherent.rebase_inherent_args_onto_impl(impl_substs, tcx); @@ -37,6 +31,14 @@ pub(super) fn normalize_inherent_associated_type( ) .expect("expected goal term to be fully unconstrained"); + // Check both where clauses on the impl and IAT + self.add_goals( + tcx.predicates_of(inherent.def_id) + .instantiate(tcx, inherent_substs) + .into_iter() + .map(|(pred, _)| goal.with(tcx, pred)), + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 8708b000961..d677fbdc7f4 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -112,6 +112,7 @@ fn probe_and_match_goal_against_assumption( ) -> QueryResult<'tcx> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { + let tcx = ecx.tcx(); ecx.probe_candidate("assumption").enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -122,6 +123,14 @@ fn probe_and_match_goal_against_assumption( )?; ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) .expect("expected goal term to be fully unconstrained"); + + // Add GAT where clauses from the trait's definition + ecx.add_goals( + tcx.predicates_of(goal.predicate.def_id()) + .instantiate_own(tcx, goal.predicate.projection_ty.args) + .map(|(pred, _)| goal.with(tcx, pred)), + ); + then(ecx) }) } else { @@ -160,6 +169,13 @@ fn consider_impl_candidate( .map(|pred| goal.with(tcx, pred)); ecx.add_goals(where_clause_bounds); + // Add GAT where clauses from the trait's definition + ecx.add_goals( + tcx.predicates_of(goal.predicate.def_id()) + .instantiate_own(tcx, goal.predicate.projection_ty.args) + .map(|(pred, _)| goal.with(tcx, pred)), + ); + // In case the associated item is hidden due to specialization, we have to // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). diff --git a/compiler/rustc_trait_selection/src/solve/weak_types.rs b/compiler/rustc_trait_selection/src/solve/weak_types.rs index 2c176d4cfd6..c7717879a4a 100644 --- a/compiler/rustc_trait_selection/src/solve/weak_types.rs +++ b/compiler/rustc_trait_selection/src/solve/weak_types.rs @@ -14,6 +14,16 @@ pub(super) fn normalize_weak_type( let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args); self.eq(goal.param_env, expected, actual)?; + + // Check where clauses + self.add_goals( + tcx.predicates_of(weak_ty.def_id) + .instantiate(tcx, weak_ty.args) + .predicates + .into_iter() + .map(|pred| goal.with(tcx, pred)), + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 783f3569feb..a39fc1f1771 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1402,9 +1402,17 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( let impl_def_id = tcx.parent(alias_ty.def_id); let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id); - let impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args); - let impl_ty = - normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations); + let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args); + if !selcx.infcx.next_trait_solver() { + impl_ty = normalize_with_depth_to( + selcx, + param_env, + cause.clone(), + depth + 1, + impl_ty, + obligations, + ); + } // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs index 959f1afa04e..38d83d289f1 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs @@ -16,12 +16,17 @@ fn copy_me(x: &Self::Item) -> Self::Item { impl Foo for () { type Item = String where String: Copy; + //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy` } fn main() { let x = String::from("hello, world"); drop(<() as Foo>::copy_me(&x)); - //~^ ERROR the type `&<() as Foo>::Item` is not well-formed - //~| ERROR `<() as Foo>::Item` is not well-formed + //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed` + //~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item` + //~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed` + //~| ERROR type annotations needed println!("{x}"); } diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr index 5800e2c4340..abc6677c132 100644 --- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr @@ -1,14 +1,69 @@ -error: the type `&<() as Foo>::Item` is not well-formed - --> $DIR/alias-bound-unsound.rs:23:31 +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy` + --> $DIR/alias-bound-unsound.rs:18:17 + | +LL | type Item = String where String: Copy; + | ^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) +note: required by a bound in `Foo::Item` + --> $DIR/alias-bound-unsound.rs:8:16 + | +LL | type Item: Copy + | ^^^^ required by this bound in `Foo::Item` + +error[E0282]: type annotations needed + --> $DIR/alias-bound-unsound.rs:24:5 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^ cannot infer type of the type parameter `T` declared on the function `drop` + | +help: consider specifying the generic argument + | +LL | drop::(<() as Foo>::copy_me(&x)); + | +++++ + +error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed` + --> $DIR/alias-bound-unsound.rs:24:31 | LL | drop(<() as Foo>::copy_me(&x)); | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) -error: the type `<() as Foo>::Item` is not well-formed - --> $DIR/alias-bound-unsound.rs:23:10 +error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item` + --> $DIR/alias-bound-unsound.rs:24:31 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed` + --> $DIR/alias-bound-unsound.rs:24:10 | LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) -error: aborting due to 2 previous errors +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` + --> $DIR/alias-bound-unsound.rs:24:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Sized` + --> $DIR/alias-bound-unsound.rs:24:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + = note: the return type of a function must have a statically known size + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0275, E0282. +For more information about an error, try `rustc --explain E0275`.