about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTyler Mandry <tmandry@gmail.com>2020-07-23 01:34:35 -0700
committerTyler Mandry <tmandry@gmail.com>2020-07-23 01:34:35 -0700
commit83a9dc92d58c8145b3fb0cec5ea205ad66c399a7 (patch)
tree48b9b1ae74d3fbe56c5ea296016aa93fc0a97a87
parent8ad7bc3f428300aee6764f6e23527e19eb235e81 (diff)
downloadrust-83a9dc92d58c8145b3fb0cec5ea205ad66c399a7.tar.gz
rust-83a9dc92d58c8145b3fb0cec5ea205ad66c399a7.zip
Normalize bounds fully when checking defaulted types
-rw-r--r--src/librustc_typeck/check/compare_method.rs36
-rw-r--r--src/test/ui/associated-type-bounds/issue-73818.rs25
2 files changed, 58 insertions, 3 deletions
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index a90ed455d04..fac87866b80 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -1196,8 +1196,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,6 +1210,36 @@ 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);
 
+    let param_env = tcx.param_env(impl_ty.def_id);
+
+    // When checking something like
+    //
+    // trait X { type Y: PartialEq<<Self as X>::Y> }
+    // impl X for T { default type Y = S; }
+    //
+    // 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 = if impl_ty.defaultness.is_final() {
+        // If the associated type is final then normalization can already
+        // do this without the explicit predicate.
+        param_env
+    } else {
+        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)
+    };
+
     // Map the predicate from the trait to the corresponding one for the impl.
     // For example:
     //
@@ -1275,9 +1303,11 @@ fn compare_projection_bounds<'tcx>(
                 _ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
             };
 
+            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,
             );
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() {}