diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index ab90db6ff58..b1c9d7f3d19 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -153,16 +153,12 @@ fn consider_object_bound_candidate( let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `consider_object_bound_candidate`"); }; - ecx.add_goals( - structural_traits::predicates_for_object_candidate( - &ecx, - goal.param_env, - goal.predicate.trait_ref(tcx), - bounds, - ) - .into_iter() - .map(|pred| goal.with(tcx, pred)), - ); + ecx.add_goals(structural_traits::predicates_for_object_candidate( + &ecx, + goal.param_env, + goal.predicate.trait_ref(tcx), + bounds, + )); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index a2db35e069e..45dbd4b9269 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; +use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -345,7 +346,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, object_bound: &'tcx ty::List>, -) -> Vec> { +) -> Vec>> { let tcx = ecx.tcx(); let mut requirements = vec![]; requirements.extend( @@ -376,17 +377,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( } } - requirements.fold_with(&mut ReplaceProjectionWith { - ecx, - param_env, - mapping: replace_projection_with, - }) + let mut folder = + ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] }; + let folded_requirements = requirements.fold_with(&mut folder); + + folder + .nested + .into_iter() + .chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause))) + .collect() } struct ReplaceProjectionWith<'a, 'tcx> { ecx: &'a EvalCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, mapping: FxHashMap>, + nested: Vec>>, } impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { @@ -402,13 +408,12 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { // but the where clauses we instantiated are not. We can solve this by instantiating // the binder at the usage site. let proj = self.ecx.instantiate_binder_with_infer(*replacement); - // FIXME: Technically this folder could be fallible? - let nested = self - .ecx - .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) - .expect("expected to be able to unify goal projection with dyn's projection"); - // FIXME: Technically we could register these too.. - assert!(nested.is_empty(), "did not expect unification to have any nested goals"); + // FIXME: Technically this equate could be fallible... + self.nested.extend( + self.ecx + .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) + .expect("expected to be able to unify goal projection with dyn's projection"), + ); proj.term.ty().unwrap() } else { ty.super_fold_with(self) diff --git a/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs new file mode 100644 index 00000000000..d02dada72c9 --- /dev/null +++ b/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs @@ -0,0 +1,20 @@ +// compile-flags: -Ztrait-solver=next +// ignore-test + +trait Trait { + type Gat<'lt>; +} +impl Trait for u8 { + type Gat<'lt> = u8; +} + +fn test::Gat<'_>) -> S + ?Sized, S>() {} + +fn main() { + // Proving `dyn FnOnce: FnOnce` requires making sure that all of the supertraits + // of the trait and associated type bounds hold. We check this in + // `predicates_for_object_candidate`, and eagerly replace projections using equality + // which may generalize a type and emit a nested AliasRelate goal. Make sure that + // we don't ICE in that case, and bubble that goal up to the caller. + test::::Gat<'_>) + 'static, _>(); +}