From 0d71860368094f21b2865c55685fe76a8e4a5874 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 8 Jan 2024 15:29:44 +0100 Subject: [PATCH 1/2] bye bye `assemble_candidates_via_self_ty` --- .../src/solve/assembly/mod.rs | 134 ++++-------------- .../rustc_trait_selection/src/solve/mod.rs | 8 +- .../traits/next-solver/alias-bound-unsound.rs | 2 +- .../next-solver/alias-bound-unsound.stderr | 14 +- .../ambig-projection-self-is-ambig.rs | 19 +++ ...e_of-tait-in-defining-scope.is_send.stderr | 16 +++ ..._of-tait-in-defining-scope.not_send.stderr | 4 +- .../dont-type_of-tait-in-defining-scope.rs | 3 +- .../recursive-self-normalization-2.rs | 1 + .../recursive-self-normalization-2.stderr | 19 ++- .../overflow/recursive-self-normalization.rs | 1 + .../recursive-self-normalization.stderr | 19 ++- .../issue-76202-trait-impl-for-tait.rs | 22 +-- 13 files changed, 129 insertions(+), 133 deletions(-) create mode 100644 tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs create mode 100644 tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index caf9470b4c646..47fc5f007552a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -271,64 +271,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, ) -> Vec> { - debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); - if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { - return vec![ambig]; - } - - let mut candidates = self.assemble_candidates_via_self_ty(goal, 0); - - self.assemble_unsize_to_dyn_candidate(goal, &mut candidates); - - self.assemble_blanket_impl_candidates(goal, &mut candidates); - - self.assemble_param_env_candidates(goal, &mut candidates); - - self.assemble_coherence_unknowable_candidates(goal, &mut candidates); - - candidates - } - - /// `?0: Trait` is ambiguous, because it may be satisfied via a builtin rule, - /// object bound, alias bound, etc. We are unable to determine this until we can at - /// least structurally resolve the type one layer. - /// - /// It would also require us to consider all impls of the trait, which is both pretty - /// bad for perf and would also constrain the self type if there is just a single impl. - fn assemble_self_ty_infer_ambiguity_response>( - &mut self, - goal: Goal<'tcx, G>, - ) -> Option> { - if goal.predicate.self_ty().is_ty_var() { - debug!("adding self_ty_infer_ambiguity_response"); + let dummy_candidate = |this: &mut EvalCtxt<'_, 'tcx>, certainty| { let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); - let result = self - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - .unwrap(); - let mut dummy_probe = self.inspect.new_probe(); + let result = this.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(); + let mut dummy_probe = this.inspect.new_probe(); dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) }); - self.inspect.finish_probe(dummy_probe); - Some(Candidate { source, result }) - } else { - None + this.inspect.finish_probe(dummy_probe); + vec![Candidate { source, result }] + }; + + let Some(normalized_self_ty) = + self.try_normalize_ty(goal.param_env, goal.predicate.self_ty()) + else { + debug!("overflow while evaluating self type"); + return dummy_candidate(self, Certainty::OVERFLOW); + }; + + if normalized_self_ty.is_ty_var() { + debug!("self type has been normalized to infer"); + return dummy_candidate(self, Certainty::AMBIGUOUS); } - } - /// Assemble candidates which apply to the self type. This only looks at candidate which - /// apply to the specific self type and ignores all others. - /// - /// Returns `None` if the self type is still ambiguous. - fn assemble_candidates_via_self_ty>( - &mut self, - goal: Goal<'tcx, G>, - num_steps: usize, - ) -> Vec> { + let goal = + goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty)); debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); - if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { - return vec![ambig]; - } - let mut candidates = Vec::new(); + let mut candidates = vec![]; self.assemble_non_blanket_impl_candidates(goal, &mut candidates); @@ -338,61 +306,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_object_bound_candidates(goal, &mut candidates); - self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates, num_steps); - candidates - } + self.assemble_unsize_to_dyn_candidate(goal, &mut candidates); - /// If the self type of a goal is an alias we first try to normalize the self type - /// and compute the candidates for the normalized self type in case that succeeds. - /// - /// These candidates are used in addition to the ones with the alias as a self type. - /// We do this to simplify both builtin candidates and for better performance. - /// - /// We generate the builtin candidates on the fly by looking at the self type, e.g. - /// add `FnPtr` candidates if the self type is a function pointer. Handling builtin - /// candidates while the self type is still an alias seems difficult. This is similar - /// to `try_structurally_resolve_type` during hir typeck (FIXME once implemented). - /// - /// Looking at all impls for some trait goal is prohibitively expensive. We therefore - /// only look at implementations with a matching self type. Because of this function, - /// we can avoid looking at all existing impls if the self type is an alias. - #[instrument(level = "debug", skip_all)] - fn assemble_candidates_after_normalizing_self_ty>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>, - num_steps: usize, - ) { - let tcx = self.tcx(); - let &ty::Alias(_, alias) = goal.predicate.self_ty().kind() else { return }; - - candidates.extend(self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { - if tcx.recursion_limit().value_within_limit(num_steps) { - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = - goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() }); - ecx.add_goal(GoalSource::Misc, normalizes_to_goal); - if let Err(NoSolution) = ecx.try_evaluate_added_goals() { - debug!("self type normalization failed"); - return vec![]; - } - let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - debug!(?normalized_ty, "self type normalized"); - // NOTE: Alternatively we could call `evaluate_goal` here and only - // have a `Normalized` candidate. This doesn't work as long as we - // use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - ecx.assemble_candidates_via_self_ty(goal, num_steps + 1) - } else { - match ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) { - Ok(result) => vec![Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }], - Err(NoSolution) => vec![], - } - } - })); + self.assemble_blanket_impl_candidates(goal, &mut candidates); + + self.assemble_param_env_candidates(goal, &mut candidates); + + self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + + candidates } #[instrument(level = "debug", skip_all)] diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 7c8f885a1f24c..6984f0ba69473 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -288,11 +288,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// Normalize a type when it is structually matched on. /// - /// For self types this is generally already handled through - /// `assemble_candidates_after_normalizing_self_ty`, so anything happening - /// in [`EvalCtxt::assemble_candidates_via_self_ty`] does not have to normalize - /// the self type. It is required when structurally matching on any other - /// arguments of a trait goal, e.g. when assembling builtin unsize candidates. + /// In nearly all cases this function must be used before matching on a type. + /// Not doing so is likely to be incomplete and therefore unsound during + /// coherence. #[instrument(level = "debug", skip(self), ret)] fn try_normalize_ty( &mut self, diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.rs b/tests/ui/traits/next-solver/alias-bound-unsound.rs index 8fddbd7ecdcc8..633f0e75572c7 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.rs +++ b/tests/ui/traits/next-solver/alias-bound-unsound.rs @@ -16,7 +16,7 @@ trait Foo { impl Foo for () { type Item = String where String: Copy; - //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy` + //~^ ERROR overflow evaluating the requirement `String: Copy` } fn main() { diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr index 874644317ebd3..d5f7e975b1371 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr @@ -1,15 +1,17 @@ -error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy` - --> $DIR/alias-bound-unsound.rs:18:17 +error[E0275]: overflow evaluating the requirement `String: Copy` + --> $DIR/alias-bound-unsound.rs:18:38 | 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 +note: the requirement `String: Copy` appears on the `impl`'s associated type `Item` but not on the corresponding trait's associated type + --> $DIR/alias-bound-unsound.rs:8:10 | +LL | trait Foo { + | --- in this trait LL | type Item: Copy - | ^^^^ required by this bound in `Foo::Item` + | ^^^^ this trait's associated type doesn't have the requirement `String: Copy` error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item` --> $DIR/alias-bound-unsound.rs:24:31 diff --git a/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs b/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs new file mode 100644 index 0000000000000..99a368a746f77 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/ambig-projection-self-is-ambig.rs @@ -0,0 +1,19 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Reader: Default { + fn read_u8_array(&self) -> Result { + todo!() + } + + fn read_u8(&self) -> Result { + let a: [u8; 1] = self.read_u8_array::<_>()?; + // This results in a nested ` as Try>::Residual: Sized` goal. + // The self type normalizes to `?0`. We previously did not force that to be + // ambiguous but instead incompletely applied the `Self: Sized` candidate + // from the `ParamEnv`, resulting in a type error. + Ok(a[0]) + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr new file mode 100644 index 0000000000000..bafc4ba18a7a3 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 + | +LL | needs_send::(); + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 + | +LL | fn needs_send() {} + | ^^^^ required by this bound in `needs_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr index 076dab29d890b..bafc4ba18a7a3 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -1,12 +1,12 @@ error[E0283]: type annotations needed: cannot satisfy `Foo: Send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 + --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 | LL | needs_send::(); | ^^^ | = note: cannot satisfy `Foo: Send` note: required by a bound in `needs_send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:13:18 + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 | LL | fn needs_send() {} | ^^^^ required by this bound in `needs_send` diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs index a1f38e69e53ef..ef0360248b59a 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs @@ -1,6 +1,5 @@ // revisions: is_send not_send // compile-flags: -Znext-solver -//[is_send] check-pass #![feature(type_alias_impl_trait)] @@ -14,7 +13,7 @@ fn needs_send() {} fn test(_: Foo) { needs_send::(); - //[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send` + //~^ ERROR type annotations needed: cannot satisfy `Foo: Send` } fn defines(_: Foo) { diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index 932826519b7d2..983a0fec65349 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -17,6 +17,7 @@ fn test::Assoc2> + Foo2::Assoc //~| ERROR overflow evaluating the requirement `::Assoc1 == _` //~| ERROR overflow evaluating the requirement `::Assoc1 == _` //~| ERROR overflow evaluating the requirement `::Assoc1 == _` + //~| ERROR overflow evaluating the requirement `::Assoc1: Sized` //~| ERROR overflow evaluating the requirement `::Assoc1: Bar` } diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index e4f1f9cf02255..ed87404d57395 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -19,6 +19,23 @@ note: required by a bound in `needs_bar` LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` +error[E0275]: overflow evaluating the requirement `::Assoc1: Sized` + --> $DIR/recursive-self-normalization-2.rs:15:17 + | +LL | needs_bar::(); + | ^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) +note: required by a bound in `needs_bar` + --> $DIR/recursive-self-normalization-2.rs:12:14 + | +LL | fn needs_bar() {} + | ^ required by this bound in `needs_bar` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn needs_bar() {} + | ++++++++ + error[E0275]: overflow evaluating the requirement `::Assoc1 == _` --> $DIR/recursive-self-normalization-2.rs:15:5 | @@ -45,6 +62,6 @@ LL | needs_bar::(); = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs index 32672c08c7e07..40e2aa9e63f31 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs @@ -13,6 +13,7 @@ fn test::Assoc>>() { //~| ERROR overflow evaluating the requirement `::Assoc == _` //~| ERROR overflow evaluating the requirement `::Assoc == _` //~| ERROR overflow evaluating the requirement `::Assoc == _` + //~| ERROR overflow evaluating the requirement `::Assoc: Sized` //~| ERROR overflow evaluating the requirement `::Assoc: Bar` } diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr index da5c8bde568d2..e4ef2f60740f4 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr @@ -19,6 +19,23 @@ note: required by a bound in `needs_bar` LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` +error[E0275]: overflow evaluating the requirement `::Assoc: Sized` + --> $DIR/recursive-self-normalization.rs:11:17 + | +LL | needs_bar::(); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) +note: required by a bound in `needs_bar` + --> $DIR/recursive-self-normalization.rs:8:14 + | +LL | fn needs_bar() {} + | ^ required by this bound in `needs_bar` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn needs_bar() {} + | ++++++++ + error[E0275]: overflow evaluating the requirement `::Assoc == _` --> $DIR/recursive-self-normalization.rs:11:5 | @@ -45,6 +62,6 @@ LL | needs_bar::(); = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs index af1c18bbb59c8..b6906f68ded57 100644 --- a/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +++ b/tests/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -4,20 +4,14 @@ // revisions: current next //[next] compile-flags: -Znext-solver // check-pass - #![feature(type_alias_impl_trait)] -trait Dummy {} -impl Dummy for () {} - -type F = impl Dummy; -fn f() -> F {} - trait Test { fn test(self); } -impl Test for F { + +impl Test for define::F { fn test(self) {} } @@ -27,7 +21,17 @@ impl Test for i32 { fn test(self) {} } +mod define { + use super::*; + + pub trait Dummy {} + impl Dummy for () {} + + pub type F = impl Dummy; + pub fn f() -> F {} +} + fn main() { - let x: F = f(); + let x = define::f(); x.test(); } From ea4e5b8458f80690ee548008350b0c7533b65c62 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 8 Jan 2024 15:38:01 +0100 Subject: [PATCH 2/2] merge builtin unsize candidates again --- .../src/solve/assembly/mod.rs | 31 ------- .../src/solve/normalizes_to/mod.rs | 7 -- .../src/solve/trait_goals.rs | 90 +++++++++---------- 3 files changed, 41 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 47fc5f007552a..915d722dd0206 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -253,17 +253,6 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>; - - /// Consider the `Unsize` candidate corresponding to coercing a sized type - /// into a `dyn Trait`. - /// - /// This is computed separately from the rest of the `Unsize` candidates - /// since it is only done once per self type, and not once per - /// *normalization step* (in `assemble_candidates_via_self_ty`). - fn consider_unsize_to_dyn_candidate( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -306,8 +295,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_object_bound_candidates(goal, &mut candidates); - self.assemble_unsize_to_dyn_candidate(goal, &mut candidates); - self.assemble_blanket_impl_candidates(goal, &mut candidates); self.assemble_param_env_candidates(goal, &mut candidates); @@ -422,24 +409,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] - fn assemble_unsize_to_dyn_candidate>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>, - ) { - let tcx = self.tcx(); - if tcx.lang_items().unsize_trait() == Some(goal.predicate.trait_def_id(tcx)) { - match G::consider_unsize_to_dyn_candidate(self, goal) { - Ok(result) => candidates.push(Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }), - Err(NoSolution) => (), - } - } - } - #[instrument(level = "debug", skip_all)] fn assemble_blanket_impl_candidates>( &mut self, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index ccee6f8eb29b9..9f1b4a09a20ba 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -603,13 +603,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } - fn consider_unsize_to_dyn_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - bug!("`Unsize` does not have an associated type: {:?}", goal) - } - fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index be07927568446..b185e4e5f8eb0 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -490,53 +490,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(certainty) } - fn consider_unsize_to_dyn_candidate( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - ) -> QueryResult<'tcx> { - ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| { - let a_ty = goal.predicate.self_ty(); - // We need to normalize the b_ty since it's destructured as a `dyn Trait`. - let Some(b_ty) = - ecx.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1)) - else { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); - }; - - let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { - return Err(NoSolution); - }; - - let tcx = ecx.tcx(); - - // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { - return Err(NoSolution); - } - - // Check that the type implements all of the predicates of the trait object. - // (i.e. the principal, all of the associated types match, and any auto traits) - ecx.add_goals( - GoalSource::ImplWhereBound, - b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), - ); - - // The type must be `Sized` to be unsized. - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - ecx.add_goal( - GoalSource::ImplWhereBound, - goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), - ); - } else { - return Err(NoSolution); - } - - // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - } - /// ```ignore (builtin impl example) /// trait Trait { /// fn foo(&self); @@ -588,8 +541,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal, a_data, a_region, b_data, b_region, ), - // `T` -> `dyn Trait` unsizing is handled separately in `consider_unsize_to_dyn_candidate` - (_, &ty::Dynamic(..)) => vec![], + // `T` -> `dyn Trait` unsizing. + (_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( + ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data), + BuiltinImplSource::Misc, + ), // `[T; N]` -> `[T]` unsizing (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single( @@ -691,6 +647,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { responses } + fn consider_builtin_unsize_to_dyn_candidate( + &mut self, + goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, + b_data: &'tcx ty::List>, + b_region: ty::Region<'tcx>, + ) -> QueryResult<'tcx> { + let tcx = self.tcx(); + let Goal { predicate: (a_ty, _), .. } = goal; + + // Can only unsize to an object-safe trait. + if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { + return Err(NoSolution); + } + + // Check that the type implements all of the predicates of the trait object. + // (i.e. the principal, all of the associated types match, and any auto traits) + self.add_goals( + GoalSource::ImplWhereBound, + b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + + // The type must be `Sized` to be unsized. + if let Some(sized_def_id) = tcx.lang_items().sized_trait() { + self.add_goal( + GoalSource::ImplWhereBound, + goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), + ); + } else { + return Err(NoSolution); + } + + // The type must outlive the lifetime of the `dyn` we're unsizing into. + self.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn consider_builtin_upcast_to_principal( &mut self, goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,