Skip to content

Commit 57407a3

Browse files
Bubble up nested goals from equation in predicates_for_object_candidate
1 parent 4734ac0 commit 57407a3

File tree

3 files changed

+44
-23
lines changed

3 files changed

+44
-23
lines changed

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -153,16 +153,12 @@ pub(super) trait GoalKind<'tcx>:
153153
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
154154
bug!("expected object type in `consider_object_bound_candidate`");
155155
};
156-
ecx.add_goals(
157-
structural_traits::predicates_for_object_candidate(
158-
&ecx,
159-
goal.param_env,
160-
goal.predicate.trait_ref(tcx),
161-
bounds,
162-
)
163-
.into_iter()
164-
.map(|pred| goal.with(tcx, pred)),
165-
);
156+
ecx.add_goals(structural_traits::predicates_for_object_candidate(
157+
&ecx,
158+
goal.param_env,
159+
goal.predicate.trait_ref(tcx),
160+
bounds,
161+
));
166162
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
167163
})
168164
}

compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use rustc_data_structures::fx::FxHashMap;
44
use rustc_hir::{def_id::DefId, Movability, Mutability};
55
use rustc_infer::traits::query::NoSolution;
6+
use rustc_middle::traits::solve::Goal;
67
use rustc_middle::ty::{
78
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
89
};
@@ -345,7 +346,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
345346
param_env: ty::ParamEnv<'tcx>,
346347
trait_ref: ty::TraitRef<'tcx>,
347348
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
348-
) -> Vec<ty::Clause<'tcx>> {
349+
) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
349350
let tcx = ecx.tcx();
350351
let mut requirements = vec![];
351352
requirements.extend(
@@ -376,17 +377,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
376377
}
377378
}
378379

379-
requirements.fold_with(&mut ReplaceProjectionWith {
380-
ecx,
381-
param_env,
382-
mapping: replace_projection_with,
383-
})
380+
let mut folder =
381+
ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] };
382+
let folded_requirements = requirements.fold_with(&mut folder);
383+
384+
folder
385+
.nested
386+
.into_iter()
387+
.chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause)))
388+
.collect()
384389
}
385390

386391
struct ReplaceProjectionWith<'a, 'tcx> {
387392
ecx: &'a EvalCtxt<'a, 'tcx>,
388393
param_env: ty::ParamEnv<'tcx>,
389394
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
395+
nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
390396
}
391397

392398
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
@@ -402,13 +408,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
402408
// but the where clauses we instantiated are not. We can solve this by instantiating
403409
// the binder at the usage site.
404410
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
405-
// FIXME: Technically this folder could be fallible?
406-
let nested = self
407-
.ecx
408-
.eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
409-
.expect("expected to be able to unify goal projection with dyn's projection");
410-
// FIXME: Technically we could register these too..
411-
assert!(nested.is_empty(), "did not expect unification to have any nested goals");
411+
// FIXME: Technically this equate could be fallible...
412+
self.nested.extend(
413+
self.ecx
414+
.eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
415+
.expect("expected to be able to unify goal projection with dyn's projection"),
416+
);
412417
proj.term.ty().unwrap()
413418
} else {
414419
ty.super_fold_with(self)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// ignore-test
3+
4+
trait Trait {
5+
type Gat<'lt>;
6+
}
7+
impl Trait for u8 {
8+
type Gat<'lt> = u8;
9+
}
10+
11+
fn test<T: Trait, F: FnOnce(<T as Trait>::Gat<'_>) -> S + ?Sized, S>() {}
12+
13+
fn main() {
14+
// Proving `dyn FnOnce: FnOnce` requires making sure that all of the supertraits
15+
// of the trait and associated type bounds hold. We check this in
16+
// `predicates_for_object_candidate`, and eagerly replace projections using equality
17+
// which may generalize a type and emit a nested AliasRelate goal. Make sure that
18+
// we don't ICE in that case, and bubble that goal up to the caller.
19+
test::<u8, dyn FnOnce(<u8 as Trait>::Gat<'_>) + 'static, _>();
20+
}

0 commit comments

Comments
 (0)