Make higher-ranked projections in object types work in new solver
This commit is contained in:
parent
98525aeee7
commit
2540c2b761
4 changed files with 48 additions and 18 deletions
|
@ -151,7 +151,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
};
|
};
|
||||||
nested_goals.extend(
|
nested_goals.extend(
|
||||||
structural_traits::predicates_for_object_candidate(
|
structural_traits::predicates_for_object_candidate(
|
||||||
tcx,
|
ecx,
|
||||||
|
goal.param_env,
|
||||||
goal.predicate.projection_ty.trait_ref(tcx),
|
goal.predicate.projection_ty.trait_ref(tcx),
|
||||||
bounds,
|
bounds,
|
||||||
)
|
)
|
||||||
|
|
|
@ -110,7 +110,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
};
|
};
|
||||||
nested_goals.extend(
|
nested_goals.extend(
|
||||||
structural_traits::predicates_for_object_candidate(
|
structural_traits::predicates_for_object_candidate(
|
||||||
tcx,
|
ecx,
|
||||||
|
goal.param_env,
|
||||||
goal.predicate.trait_ref,
|
goal.predicate.trait_ref,
|
||||||
bounds,
|
bounds,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::{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::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||||
|
|
||||||
|
@ -236,10 +236,12 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn predicates_for_object_candidate<'tcx>(
|
pub(crate) fn predicates_for_object_candidate<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
ecx: &EvalCtxt<'_, '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::Predicate<'tcx>> {
|
) -> Vec<ty::Predicate<'tcx>> {
|
||||||
|
let tcx = ecx.tcx();
|
||||||
let mut requirements = vec![];
|
let mut requirements = vec![];
|
||||||
requirements.extend(
|
requirements.extend(
|
||||||
tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.substs).predicates,
|
tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.substs).predicates,
|
||||||
|
@ -252,13 +254,9 @@ pub(crate) fn predicates_for_object_candidate<'tcx>(
|
||||||
|
|
||||||
let mut replace_projection_with = FxHashMap::default();
|
let mut replace_projection_with = FxHashMap::default();
|
||||||
for bound in object_bound {
|
for bound in object_bound {
|
||||||
let bound = bound.no_bound_vars().expect("higher-ranked projections not supported, yet");
|
if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
|
||||||
if let ty::ExistentialPredicate::Projection(proj) = bound {
|
|
||||||
let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
|
let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
|
||||||
let old_ty = replace_projection_with.insert(
|
let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
|
||||||
proj.projection_ty,
|
|
||||||
proj.term.ty().expect("expected only types in dyn right now"),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
old_ty,
|
old_ty,
|
||||||
None,
|
None,
|
||||||
|
@ -270,24 +268,37 @@ pub(crate) fn predicates_for_object_candidate<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requirements.fold_with(&mut ReplaceProjectionWith { tcx, mapping: replace_projection_with })
|
requirements.fold_with(&mut ReplaceProjectionWith {
|
||||||
|
ecx,
|
||||||
|
param_env,
|
||||||
|
mapping: replace_projection_with,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReplaceProjectionWith<'tcx> {
|
struct ReplaceProjectionWith<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
ecx: &'a EvalCtxt<'a, 'tcx>,
|
||||||
mapping: FxHashMap<ty::AliasTy<'tcx>, Ty<'tcx>>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'tcx> {
|
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
|
||||||
fn interner(&self) -> TyCtxt<'tcx> {
|
fn interner(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.ecx.tcx()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
|
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
|
||||||
&& let Some(replacement) = self.mapping.get(&alias_ty)
|
&& let Some(replacement) = self.mapping.get(&alias_ty.def_id)
|
||||||
{
|
{
|
||||||
*replacement
|
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
|
||||||
|
// Technically this folder could be fallible?
|
||||||
|
let nested = self
|
||||||
|
.ecx
|
||||||
|
.eq(self.param_env, alias_ty, proj.projection_ty)
|
||||||
|
.expect("expected to be able to unify goal projection with dyn's projection");
|
||||||
|
// Technically we could register these too..
|
||||||
|
assert!(nested.is_empty(), "did not expect unification to have any nested goals");
|
||||||
|
proj.term.ty().unwrap()
|
||||||
} else {
|
} else {
|
||||||
ty.super_fold_with(self)
|
ty.super_fold_with(self)
|
||||||
}
|
}
|
||||||
|
|
17
tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
Normal file
17
tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
trait Trait<'a> {
|
||||||
|
type Item: for<'b> Trait2<'b>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait2<'a> {}
|
||||||
|
impl Trait2<'_> for () {}
|
||||||
|
|
||||||
|
fn needs_trait(_: Box<impl for<'a> Trait<'a> + ?Sized>) {}
|
||||||
|
|
||||||
|
fn foo(x: Box<dyn for<'a> Trait<'a, Item = ()>>) {
|
||||||
|
needs_trait(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue