about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/compare_method.rs75
-rw-r--r--src/test/ui/associated-type-bounds/issue-73818.rs25
2 files changed, 52 insertions, 48 deletions
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index a90ed455d04..b739e2fe1fb 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -6,15 +6,14 @@ use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 
 use super::{potentially_plural_count, FnCtxt, Inherited};
-use std::iter;
 
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
@@ -1196,8 +1195,6 @@ fn compare_projection_bounds<'tcx>(
         return Ok(());
     }
 
-    let param_env = tcx.param_env(impl_ty.def_id);
-
     // Given
     //
     // impl<A, B> Foo<u32> for (A, B) {
@@ -1212,20 +1209,30 @@ fn compare_projection_bounds<'tcx>(
         impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
     let impl_ty_value = tcx.type_of(impl_ty.def_id);
 
-    // Map the predicate from the trait to the corresponding one for the impl.
-    // For example:
+    let param_env = tcx.param_env(impl_ty.def_id);
+
+    // When checking something like
     //
-    // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; }
-    // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; }
+    // trait X { type Y: PartialEq<<Self as X>::Y> }
+    // impl X for T { default type Y = S; }
     //
-    // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this
-    // function would translate and partially normalize
-    // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
-    let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| {
-        tcx.mk_substs(
-            iter::once(impl_ty_value.into())
-                .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))),
-        )
+    // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
+    // we want <T as X>::Y to normalize to S. This is valid because we are
+    // checking the default value specifically here. Add this equality to the
+    // ParamEnv for normalization specifically.
+    let normalize_param_env = {
+        let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
+        predicates.push(
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ty::ProjectionTy {
+                    item_def_id: trait_ty.def_id,
+                    substs: rebased_substs,
+                },
+                ty: impl_ty_value,
+            })
+            .to_predicate(tcx),
+        );
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None)
     };
 
     tcx.infer_ctxt().enter(move |infcx| {
@@ -1242,46 +1249,18 @@ fn compare_projection_bounds<'tcx>(
         );
 
         let predicates = tcx.projection_predicates(trait_ty.def_id);
-
         debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
 
         for predicate in predicates {
-            let concrete_ty_predicate = match predicate.kind() {
-                ty::PredicateKind::Trait(poly_tr, c) => poly_tr
-                    .map_bound(|tr| {
-                        let trait_substs = translate_predicate_substs(tr.trait_ref.substs);
-                        ty::TraitRef { def_id: tr.def_id(), substs: trait_substs }
-                    })
-                    .with_constness(*c)
-                    .to_predicate(tcx),
-                ty::PredicateKind::Projection(poly_projection) => poly_projection
-                    .map_bound(|projection| {
-                        let projection_substs =
-                            translate_predicate_substs(projection.projection_ty.substs);
-                        ty::ProjectionPredicate {
-                            projection_ty: ty::ProjectionTy {
-                                substs: projection_substs,
-                                item_def_id: projection.projection_ty.item_def_id,
-                            },
-                            ty: projection.ty.subst(tcx, rebased_substs),
-                        }
-                    })
-                    .to_predicate(tcx),
-                ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
-                    .map_bound(|outlives| {
-                        ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
-                    })
-                    .to_predicate(tcx),
-                _ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
-            };
+            let concrete_ty_predicate = predicate.subst(tcx, rebased_substs);
+            debug!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate);
 
             let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
                 &mut selcx,
-                param_env,
+                normalize_param_env,
                 normalize_cause.clone(),
                 &concrete_ty_predicate,
             );
-
             debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
 
             inh.register_predicates(obligations);
diff --git a/src/test/ui/associated-type-bounds/issue-73818.rs b/src/test/ui/associated-type-bounds/issue-73818.rs
new file mode 100644
index 00000000000..bb890f72a32
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-73818.rs
@@ -0,0 +1,25 @@
+// Test that associated type bounds are correctly normalized when checking
+// default associated type values.
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(specialization)]
+
+#[derive(PartialEq)]
+enum Never {}
+trait Foo {
+    type Assoc: PartialEq; // PartialEq<<Self as Foo>::Assoc>
+}
+impl<T> Foo for T {
+    default type Assoc = Never;
+}
+
+trait Trait1 {
+    type Selection: PartialEq;
+}
+trait Trait2: PartialEq<Self> {}
+impl<T: Trait2> Trait1 for T {
+    default type Selection = T;
+}
+
+fn main() {}