]> git.lizzy.rs Git - rust.git/commitdiff
Consider well-formed predicates in min-specialization
authorMatthew Jasper <mjjasper1@gmail.com>
Mon, 9 Mar 2020 21:59:13 +0000 (21:59 +0000)
committerMatthew Jasper <mjjasper1@gmail.com>
Sun, 15 Mar 2020 13:49:28 +0000 (13:49 +0000)
src/librustc_typeck/impl_wf_check/min_specialization.rs
src/test/ui/specialization/min_specialization/implcit-well-formed-bounds.rs [new file with mode: 0644]
src/test/ui/specialization/min_specialization/specialization_super_trait.rs [new file with mode: 0644]
src/test/ui/specialization/min_specialization/specialization_super_trait.stderr [new file with mode: 0644]

index cd52dae5f9ca20a6ef38e13bff7674b5b33276bd..e96a8c454b8c7b60fc47ae20dbadbe32c42b9666 100644 (file)
@@ -21,8 +21,9 @@
 //!    in the *unconstrained* substs for `impl2`. A parameter is constrained if
 //!    its value is completely determined by an associated type projection
 //!    predicate.
-//! 4. Check that all predicates on `impl1` also exist on `impl2` (after
-//!    matching substs).
+//! 4. Check that all predicates on `impl1` either exist on `impl2` (after
+//!    matching substs), or are well-formed predicates for the trait's type
+//!    arguments.
 //!
 //! ## Example
 //!
@@ -129,7 +130,7 @@ fn check_always_applicable(
         check_static_lifetimes(tcx, &parent_substs, span);
         check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
 
-        check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
+        check_predicates(infcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
     }
 }
 
@@ -282,14 +283,17 @@ fn check_static_lifetimes<'tcx>(
 /// * on the base `impl impl2`
 ///     * Currently this check is done using syntactic equality, which is
 ///       conservative but generally sufficient.
+/// * a well-formed predicate of a type argument of the trait being implemented,
+///   including the `Self`-type.
 fn check_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    infcx: &InferCtxt<'_, 'tcx>,
     impl1_def_id: DefId,
     impl1_substs: SubstsRef<'tcx>,
     impl2_node: Node,
     impl2_substs: SubstsRef<'tcx>,
     span: Span,
 ) {
+    let tcx = infcx.tcx;
     let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
     let mut impl2_predicates = if impl2_node.is_from_trait() {
         // Always applicable traits have to be always applicable without any
@@ -329,6 +333,21 @@ fn check_predicates<'tcx>(
         })
         .copied()
         .collect();
+
+    // Include the well-formed predicates of the type parameters of the impl.
+    for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() {
+        if let Some(obligations) = wf::obligations(
+            infcx,
+            tcx.param_env(impl1_def_id),
+            tcx.hir().as_local_hir_id(impl1_def_id).unwrap(),
+            ty,
+            span,
+        ) {
+            impl2_predicates
+                .predicates
+                .extend(obligations.into_iter().map(|obligation| obligation.predicate))
+        }
+    }
     impl2_predicates.predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits));
 
     for predicate in impl1_predicates.predicates {
diff --git a/src/test/ui/specialization/min_specialization/implcit-well-formed-bounds.rs b/src/test/ui/specialization/min_specialization/implcit-well-formed-bounds.rs
new file mode 100644 (file)
index 0000000..98d7f91
--- /dev/null
@@ -0,0 +1,30 @@
+// Test that specializing on the well-formed predicates of the trait and
+// self-type of an impl is allowed.
+
+// check-pass
+
+#![feature(min_specialization)]
+
+struct OrdOnly<T: Ord>(T);
+
+trait SpecTrait<U> {
+    fn f();
+}
+
+impl<T, U> SpecTrait<U> for T {
+    default fn f() {}
+}
+
+impl<T: Ord> SpecTrait<()> for OrdOnly<T> {
+    fn f() {}
+}
+
+impl<T: Ord> SpecTrait<OrdOnly<T>> for () {
+    fn f() {}
+}
+
+impl<T: Ord, U: Ord, V: Ord> SpecTrait<(OrdOnly<T>, OrdOnly<U>)> for &[OrdOnly<V>] {
+    fn f() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.rs b/src/test/ui/specialization/min_specialization/specialization_super_trait.rs
new file mode 100644 (file)
index 0000000..145f376
--- /dev/null
@@ -0,0 +1,18 @@
+// Test that supertraits can't be assumed in impls of
+// `rustc_specialization_trait`, as such impls would
+// allow specializing on the supertrait.
+
+#![feature(min_specialization)]
+#![feature(rustc_attrs)]
+
+#[rustc_specialization_trait]
+trait SpecMarker: Default {
+    fn f();
+}
+
+impl<T: Default> SpecMarker for T {
+    //~^ ERROR cannot specialize
+    fn f() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr
new file mode 100644 (file)
index 0000000..154c839
--- /dev/null
@@ -0,0 +1,11 @@
+error: cannot specialize on trait `std::default::Default`
+  --> $DIR/specialization_super_trait.rs:13:1
+   |
+LL | / impl<T: Default> SpecMarker for T {
+LL | |
+LL | |     fn f() {}
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+