about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs39
-rw-r--r--tests/ui/traits/new-solver/trait-upcast-lhs-needs-normalization.rs18
2 files changed, 51 insertions, 6 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 8af9d090164..a6d118d8cc2 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_infer::traits::util::supertraits;
 use rustc_infer::traits::{
-    Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult,
+    Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
 };
 use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
 use rustc_middle::traits::{
@@ -20,6 +20,8 @@ use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
 use crate::solve::inspect::ProofTreeBuilder;
 use crate::solve::search_graph::OverflowHandler;
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
+use crate::traits::StructurallyNormalizeExt;
+use crate::traits::TraitEngineExt;
 
 pub trait InferCtxtSelectExt<'tcx> {
     fn select_in_new_trait_solver(
@@ -228,18 +230,24 @@ fn rematch_object<'tcx>(
     goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
     mut nested: Vec<PredicateObligation<'tcx>>,
 ) -> SelectionResult<'tcx, Selection<'tcx>> {
-    let self_ty = goal.predicate.self_ty();
-    let ty::Dynamic(data, _, source_kind) = *self_ty.kind() else { bug!() };
-    let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, self_ty);
+    let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
+    let ty::Dynamic(data, _, source_kind) = *a_ty.kind() else { bug!() };
+    let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, a_ty);
 
     let (is_upcasting, target_trait_ref_unnormalized) =
         if Some(goal.predicate.def_id()) == infcx.tcx.lang_items().unsize_trait() {
             assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*");
-            if let ty::Dynamic(data, _, ty::Dyn) = goal.predicate.trait_ref.args.type_at(1).kind() {
+            let b_ty = structurally_normalize(
+                goal.predicate.trait_ref.args.type_at(1),
+                infcx,
+                goal.param_env,
+                &mut nested,
+            );
+            if let ty::Dynamic(data, _, ty::Dyn) = *b_ty.kind() {
                 // FIXME: We also need to ensure that the source lifetime outlives the
                 // target lifetime. This doesn't matter for codegen, though, and only
                 // *really* matters if the goal's certainty is ambiguous.
-                (true, data.principal().unwrap().with_self_ty(infcx.tcx, self_ty))
+                (true, data.principal().unwrap().with_self_ty(infcx.tcx, a_ty))
             } else {
                 bug!()
             }
@@ -447,3 +455,22 @@ fn rematch_unsize<'tcx>(
 
     Ok(Some(ImplSource::Builtin(nested)))
 }
+
+fn structurally_normalize<'tcx>(
+    ty: Ty<'tcx>,
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    nested: &mut Vec<PredicateObligation<'tcx>>,
+) -> Ty<'tcx> {
+    if matches!(ty.kind(), ty::Alias(..)) {
+        let mut engine = <dyn TraitEngine<'tcx>>::new(infcx);
+        let normalized_ty = infcx
+            .at(&ObligationCause::dummy(), param_env)
+            .structurally_normalize(ty, &mut *engine)
+            .expect("normalization shouldn't fail if we got to here");
+        nested.extend(engine.pending_obligations());
+        normalized_ty
+    } else {
+        ty
+    }
+}
diff --git a/tests/ui/traits/new-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/new-solver/trait-upcast-lhs-needs-normalization.rs
new file mode 100644
index 00000000000..79114b93b78
--- /dev/null
+++ b/tests/ui/traits/new-solver/trait-upcast-lhs-needs-normalization.rs
@@ -0,0 +1,18 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+pub trait A {}
+pub trait B: A {}
+
+pub trait Mirror {
+    type Assoc: ?Sized;
+}
+impl<T: ?Sized> Mirror for T {
+    type Assoc = T;
+}
+
+pub fn foo<'a>(x: &'a <dyn B + 'static as Mirror>::Assoc) -> &'a (dyn A + 'static) {
+    x
+}
+
+fn main() {}