about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/wfcheck.rs19
-rw-r--r--src/test/ui/type-check-defaults.rs4
-rw-r--r--src/test/ui/type-check-defaults.stderr39
3 files changed, 52 insertions, 10 deletions
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7648feea457..91c5b8703c2 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -381,12 +381,20 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
         let defaulted_params = generics.types.iter()
                                              .filter(|def| def.has_default &&
                                                      def.index >= generics.parent_count() as u32);
+        // WF checks for type parameter defaults. See test `type-check-defaults.rs` for examples.
         for param_def in defaulted_params {
-            // Defaults must be well-formed.
+            // This parameter has a default value. Check that this default value is well-formed.
+            // For example this forbids the declaration:
+            // struct Foo<T = Vec<[u32]>> { .. }
+            // Here `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
             let d = param_def.def_id;
             fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
+
             // Check the clauses are well-formed when the param is substituted by it's default.
-            // In trait definitions, the predicate `Self: Trait` is problematic.
+            // For example this forbids the following declaration because `String` is not `Copy`:
+            // struct Foo<T: Copy = String> { .. }
+            //
+            // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic.
             // Therefore we skip such predicates. This means we check less than we could.
             for pred in predicates.predicates.iter().filter(|p| !(is_trait && p.has_self_ty())) {
                 let mut skip = true;
@@ -394,9 +402,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                     // All regions are identity.
                     fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
                 }, |def, _| {
-                    let identity_substs = fcx.tcx.mk_param_from_def(def);
+                    let identity_ty = fcx.tcx.mk_param_from_def(def);
                     if def.index != param_def.index {
-                        identity_substs
+                        identity_ty
                     } else {
                         let sized = fcx.tcx.lang_items().sized_trait();
                         let pred_is_sized = match pred {
@@ -410,7 +418,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                         };
                         // In trait defs, skip `Self: Sized` when `Self` is the default.
                         if is_trait && pred_is_sized && default_is_self {
-                            identity_substs
+                            identity_ty
                         } else {
                             skip = false;
                             default_ty
@@ -420,6 +428,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                 if skip { continue; }
                 substituted_predicates.push(match pred {
                     // In trait predicates, substitute defaults only for the LHS.
+                    // See test `defaults-well-formedness.rs` for why substituting the RHS is bad.
                     ty::Predicate::Trait(t_pred) => {
                         let trait_ref = t_pred.map_bound(|t_pred| {
                             let mut trait_subs = t_pred.trait_ref.substs.to_vec();
diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs
index 7c379a1f1bc..8f0714ebc3b 100644
--- a/src/test/ui/type-check-defaults.rs
+++ b/src/test/ui/type-check-defaults.rs
@@ -44,4 +44,8 @@ struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
 //~^ error: the trait bound `TwoParams<i32, U>: Trait` is not satisfied [E0277]
 //~^^ error: the trait bound `TwoParams<T, i32>: Trait` is not satisfied [E0277]
 
+trait Super<T: Copy> { }
+trait Base<T = String>: Super<T> { }
+//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277]
+
 fn main() { }
diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr
index 3ac6e4c26b4..8be46a53370 100644
--- a/src/test/ui/type-check-defaults.stderr
+++ b/src/test/ui/type-check-defaults.stderr
@@ -5,7 +5,11 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfi
    |                   ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32`
    |
    = help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
-   = note: required by `Foo`
+note: required by `Foo`
+  --> $DIR/type-check-defaults.rs:15:1
+   |
+15 | struct Foo<T, U: FromIterator<T>>(T, U);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied
   --> $DIR/type-check-defaults.rs:18:27
@@ -14,7 +18,11 @@ error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfi
    |                           ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32`
    |
    = help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
-   = note: required by `Foo`
+note: required by `Foo`
+  --> $DIR/type-check-defaults.rs:15:1
+   |
+15 | struct Foo<T, U: FromIterator<T>>(T, U);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied
   --> $DIR/type-check-defaults.rs:21:1
@@ -74,7 +82,11 @@ error[E0277]: the trait bound `TwoParams<i32, U>: Trait` is not satisfied
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams<i32, U>`
    |
    = help: consider adding a `where TwoParams<i32, U>: Trait` bound
-   = note: required by `Trait`
+note: required by `Trait`
+  --> $DIR/type-check-defaults.rs:39:1
+   |
+39 | trait Trait {}
+   | ^^^^^^^^^^^
 
 error[E0277]: the trait bound `TwoParams<T, i32>: Trait` is not satisfied
   --> $DIR/type-check-defaults.rs:43:1
@@ -83,7 +95,24 @@ error[E0277]: the trait bound `TwoParams<T, i32>: Trait` is not satisfied
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams<T, i32>`
    |
    = help: consider adding a `where TwoParams<T, i32>: Trait` bound
-   = note: required by `Trait`
+note: required by `Trait`
+  --> $DIR/type-check-defaults.rs:39:1
+   |
+39 | trait Trait {}
+   | ^^^^^^^^^^^
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/type-check-defaults.rs:48:1
+   |
+48 | trait Base<T = String>: Super<T> { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = help: consider adding a `where T: std::marker::Copy` bound
+note: required by `Super`
+  --> $DIR/type-check-defaults.rs:47:1
+   |
+47 | trait Super<T: Copy> { }
+   | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 11 previous errors