Bubble up nested goals from equation in predicates_for_object_candidate
This commit is contained in:
parent
4734ac0943
commit
57407a3555
@ -153,16 +153,12 @@ fn consider_object_bound_candidate(
|
|||||||
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
||||||
bug!("expected object type in `consider_object_bound_candidate`");
|
bug!("expected object type in `consider_object_bound_candidate`");
|
||||||
};
|
};
|
||||||
ecx.add_goals(
|
ecx.add_goals(structural_traits::predicates_for_object_candidate(
|
||||||
structural_traits::predicates_for_object_candidate(
|
|
||||||
&ecx,
|
&ecx,
|
||||||
goal.param_env,
|
goal.param_env,
|
||||||
goal.predicate.trait_ref(tcx),
|
goal.predicate.trait_ref(tcx),
|
||||||
bounds,
|
bounds,
|
||||||
)
|
));
|
||||||
.into_iter()
|
|
||||||
.map(|pred| goal.with(tcx, pred)),
|
|
||||||
);
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::{def_id::DefId, Movability, Mutability};
|
use rustc_hir::{def_id::DefId, Movability, Mutability};
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
use rustc_middle::traits::solve::Goal;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
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>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
) -> Vec<ty::Clause<'tcx>> {
|
) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
let mut requirements = vec![];
|
let mut requirements = vec![];
|
||||||
requirements.extend(
|
requirements.extend(
|
||||||
@ -376,17 +377,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requirements.fold_with(&mut ReplaceProjectionWith {
|
let mut folder =
|
||||||
ecx,
|
ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] };
|
||||||
param_env,
|
let folded_requirements = requirements.fold_with(&mut folder);
|
||||||
mapping: replace_projection_with,
|
|
||||||
})
|
folder
|
||||||
|
.nested
|
||||||
|
.into_iter()
|
||||||
|
.chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause)))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReplaceProjectionWith<'a, 'tcx> {
|
struct ReplaceProjectionWith<'a, 'tcx> {
|
||||||
ecx: &'a EvalCtxt<'a, 'tcx>,
|
ecx: &'a EvalCtxt<'a, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
|
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
|
||||||
|
nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
|
impl<'tcx> TypeFolder<TyCtxt<'tcx>> 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
|
// but the where clauses we instantiated are not. We can solve this by instantiating
|
||||||
// the binder at the usage site.
|
// the binder at the usage site.
|
||||||
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
|
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
|
||||||
// FIXME: Technically this folder could be fallible?
|
// FIXME: Technically this equate could be fallible...
|
||||||
let nested = self
|
self.nested.extend(
|
||||||
.ecx
|
self.ecx
|
||||||
.eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
|
.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");
|
.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");
|
|
||||||
proj.term.ty().unwrap()
|
proj.term.ty().unwrap()
|
||||||
} else {
|
} else {
|
||||||
ty.super_fold_with(self)
|
ty.super_fold_with(self)
|
||||||
|
@ -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<T: Trait, F: FnOnce(<T as Trait>::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::<u8, dyn FnOnce(<u8 as Trait>::Gat<'_>) + 'static, _>();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user