Skip to content

Commit 2540c2b

Browse files
Make higher-ranked projections in object types work in new solver
1 parent 98525ae commit 2540c2b

File tree

4 files changed

+48
-18
lines changed

4 files changed

+48
-18
lines changed

compiler/rustc_trait_selection/src/solve/project_goals.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
151151
};
152152
nested_goals.extend(
153153
structural_traits::predicates_for_object_candidate(
154-
tcx,
154+
ecx,
155+
goal.param_env,
155156
goal.predicate.projection_ty.trait_ref(tcx),
156157
bounds,
157158
)

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
110110
};
111111
nested_goals.extend(
112112
structural_traits::predicates_for_object_candidate(
113-
tcx,
113+
ecx,
114+
goal.param_env,
114115
goal.predicate.trait_ref,
115116
bounds,
116117
)

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

+27-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_data_structures::fx::FxHashMap;
2-
use rustc_hir::{Movability, Mutability};
2+
use rustc_hir::{def_id::DefId, Movability, Mutability};
33
use rustc_infer::traits::query::NoSolution;
44
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
55

@@ -236,10 +236,12 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
236236
}
237237

238238
pub(crate) fn predicates_for_object_candidate<'tcx>(
239-
tcx: TyCtxt<'tcx>,
239+
ecx: &EvalCtxt<'_, 'tcx>,
240+
param_env: ty::ParamEnv<'tcx>,
240241
trait_ref: ty::TraitRef<'tcx>,
241242
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
242243
) -> Vec<ty::Predicate<'tcx>> {
244+
let tcx = ecx.tcx();
243245
let mut requirements = vec![];
244246
requirements.extend(
245247
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>(
252254

253255
let mut replace_projection_with = FxHashMap::default();
254256
for bound in object_bound {
255-
let bound = bound.no_bound_vars().expect("higher-ranked projections not supported, yet");
256-
if let ty::ExistentialPredicate::Projection(proj) = bound {
257+
if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
257258
let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
258-
let old_ty = replace_projection_with.insert(
259-
proj.projection_ty,
260-
proj.term.ty().expect("expected only types in dyn right now"),
261-
);
259+
let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
262260
assert_eq!(
263261
old_ty,
264262
None,
@@ -270,24 +268,37 @@ pub(crate) fn predicates_for_object_candidate<'tcx>(
270268
}
271269
}
272270

273-
requirements.fold_with(&mut ReplaceProjectionWith { tcx, mapping: replace_projection_with })
271+
requirements.fold_with(&mut ReplaceProjectionWith {
272+
ecx,
273+
param_env,
274+
mapping: replace_projection_with,
275+
})
274276
}
275277

276-
struct ReplaceProjectionWith<'tcx> {
277-
tcx: TyCtxt<'tcx>,
278-
mapping: FxHashMap<ty::AliasTy<'tcx>, Ty<'tcx>>,
278+
struct ReplaceProjectionWith<'a, 'tcx> {
279+
ecx: &'a EvalCtxt<'a, 'tcx>,
280+
param_env: ty::ParamEnv<'tcx>,
281+
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
279282
}
280283

281-
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'tcx> {
284+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
282285
fn interner(&self) -> TyCtxt<'tcx> {
283-
self.tcx
286+
self.ecx.tcx()
284287
}
285288

286289
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
287290
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
288-
&& let Some(replacement) = self.mapping.get(&alias_ty)
291+
&& let Some(replacement) = self.mapping.get(&alias_ty.def_id)
289292
{
290-
*replacement
293+
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
294+
// Technically this folder could be fallible?
295+
let nested = self
296+
.ecx
297+
.eq(self.param_env, alias_ty, proj.projection_ty)
298+
.expect("expected to be able to unify goal projection with dyn's projection");
299+
// Technically we could register these too..
300+
assert!(nested.is_empty(), "did not expect unification to have any nested goals");
301+
proj.term.ty().unwrap()
291302
} else {
292303
ty.super_fold_with(self)
293304
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
trait Trait<'a> {
5+
type Item: for<'b> Trait2<'b>;
6+
}
7+
8+
trait Trait2<'a> {}
9+
impl Trait2<'_> for () {}
10+
11+
fn needs_trait(_: Box<impl for<'a> Trait<'a> + ?Sized>) {}
12+
13+
fn foo(x: Box<dyn for<'a> Trait<'a, Item = ()>>) {
14+
needs_trait(x);
15+
}
16+
17+
fn main() {}

0 commit comments

Comments
 (0)