From 2540c2b76138b988629b48f54381835f13f18792 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 22 Feb 2023 01:26:01 +0000 Subject: [PATCH] Make higher-ranked projections in object types work in new solver --- .../src/solve/project_goals.rs | 3 +- .../src/solve/trait_goals.rs | 3 +- .../solve/trait_goals/structural_traits.rs | 43 ++++++++++++------- .../new-solver/higher-ranked-dyn-bounds.rs | 17 ++++++++ 4 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 807527e8660..88fd8bb8bd0 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -151,7 +151,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }; nested_goals.extend( structural_traits::predicates_for_object_candidate( - tcx, + ecx, + goal.param_env, goal.predicate.projection_ty.trait_ref(tcx), bounds, ) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 9aded080f20..6048082228b 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -110,7 +110,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; nested_goals.extend( structural_traits::predicates_for_object_candidate( - tcx, + ecx, + goal.param_env, goal.predicate.trait_ref, bounds, ) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 3fcf96be203..bd4950d8067 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -1,5 +1,5 @@ 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_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>( - tcx: TyCtxt<'tcx>, + ecx: &EvalCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, object_bound: &'tcx ty::List>, ) -> Vec> { + let tcx = ecx.tcx(); let mut requirements = vec![]; requirements.extend( 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(); 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 { + if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); - let old_ty = replace_projection_with.insert( - proj.projection_ty, - proj.term.ty().expect("expected only types in dyn right now"), - ); + let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); assert_eq!( old_ty, 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> { - tcx: TyCtxt<'tcx>, - mapping: FxHashMap, Ty<'tcx>>, +struct ReplaceProjectionWith<'a, 'tcx> { + ecx: &'a EvalCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + mapping: FxHashMap>, } -impl<'tcx> TypeFolder> for ReplaceProjectionWith<'tcx> { +impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { fn interner(&self) -> TyCtxt<'tcx> { - self.tcx + self.ecx.tcx() } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { 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 { ty.super_fold_with(self) } diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs new file mode 100644 index 00000000000..c886aeeda3e --- /dev/null +++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs @@ -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 Trait<'a> + ?Sized>) {} + +fn foo(x: Box Trait<'a, Item = ()>>) { + needs_trait(x); +} + +fn main() {}