]> git.lizzy.rs Git - rust.git/commitdiff
default WF: Substitute defaults individually in the clauses.
authorleonardo.yvens <leoyvens@gmail.com>
Thu, 21 Dec 2017 15:36:16 +0000 (13:36 -0200)
committerleonardo.yvens <leoyvens@gmail.com>
Wed, 28 Feb 2018 15:33:14 +0000 (12:33 -0300)
src/librustc_typeck/check/wfcheck.rs
src/test/ui/type-check-defaults.rs
src/test/ui/type-check-defaults.stderr

index 2b004eb53c81e536e93989cf01cc3c245d6c1e5a..0a919eb3b8c15ccb92cf64591e51eae1a63a1b8b 100644 (file)
@@ -375,58 +375,56 @@ fn inner_check_where_clauses<'fcx, 'tcx>(&mut self,
         use ty::subst::Subst;
         use rustc::ty::TypeFoldable;
 
+        let mut predicates = fcx.tcx.predicates_of(def_id);
+        let mut substituted_predicates = Vec::new();
+
         let generics = self.tcx.generics_of(def_id);
         let defaulted_params = generics.types.iter()
                                              .filter(|def| def.has_default &&
                                                      def.index >= generics.parent_count() as u32);
-        // Defaults must be well-formed.
-        for d in defaulted_params.map(|p| p.def_id) {
+        for param_def in defaulted_params {
+            // Defaults must be well-formed.
+            let d = param_def.def_id;
             fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
-        }
-        // Check that each default fulfills the bounds on it's parameter.
-        // We go over each predicate and duplicate it, substituting defaults in the self type.
-        let mut predicates = fcx.tcx.predicates_of(def_id);
-        let mut default_predicates = Vec::new();
-        // In `trait Trait : Super` predicates as `Self: Trait` and `Self: Super` are a problem.
-        // 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 = false;
-            let mut no_default = true;
-            let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
-                // All regions are identity.
-                fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
-            }, |def, _| {
-                // No default or generic comes from parent, identity substitution.
-                if !def.has_default || (def.index as usize) < generics.parent_count() {
-                    fcx.tcx.mk_param_from_def(def)
-                } else {
-                    no_default = false;
-                    // Has a default, use it in the substitution.
-                    let default_ty = fcx.tcx.type_of(def.def_id);
-
-                    match default_ty.sty {
-                        // Skip `Self: Sized` when `Self` is the default. Needed in traits.
-                        ty::TyParam(ref p) if is_trait && p.is_self() => {
-                            if let ty::Predicate::Trait(p) = pred {
-                                if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() {
-                                    skip = true;
-                                }
-                            }
+            // Check the clauses are well-formed when the param is substituted by it's default.
+            // In trait definitions, predicates as `Self: Trait` and `Self: Super` are 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;
+                let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
+                    // 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);
+                    if def.index != param_def.index {
+                        identity_substs
+                    } else {
+                        let sized = fcx.tcx.lang_items().sized_trait();
+                        let pred_is_sized = match pred {
+                            ty::Predicate::Trait(p) => Some(p.def_id()) == sized,
+                            _ => false,
+                        };
+                        let default_ty = fcx.tcx.type_of(def.def_id);
+                        let default_is_self = match default_ty.sty {
+                            ty::TyParam(ref p) => p.is_self(),
+                            _ => false
+                        };
+                        // In trait defs, skip `Self: Sized` when `Self` is the default.
+                        if is_trait && pred_is_sized && default_is_self {
+                            identity_substs
+                        } else {
+                            skip = false;
+                            default_ty
                         }
-                        _ => ()
                     }
-                    default_ty
+                });
+                if !skip {
+                    substituted_predicates.push(pred.subst(fcx.tcx, substs));
                 }
-            });
-
-            if skip || no_default {
-                continue;
             }
-
-            default_predicates.push(pred.subst(fcx.tcx, substs));
         }
 
-        predicates.predicates.extend(default_predicates);
+        predicates.predicates.extend(substituted_predicates);
         let predicates = predicates.instantiate_identity(fcx.tcx);
         let predicates = fcx.normalize_associated_types_in(span, &predicates);
 
index 2264fb860f1552ed26fe96a123885f09e9acd052..a6e475eb1a3b5594f09cdee03300d1baf41a8288 100644 (file)
@@ -29,4 +29,10 @@ trait SelfBound<T:Copy=Self> {}
 
 trait FooTrait<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
 
+trait Trait {}
+struct TwoParams<T, U>(T, U);
+impl Trait for TwoParams<i32, i32> {}
+// Check that each default is substituted individually in the clauses.
+struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
+
 fn main() { }
index 2a9f4eb693caaf6ad77b640c2dc9a416e185ec3f..cf11282f7d20c3d20943a484bee33070427665d1 100644 (file)
@@ -67,5 +67,23 @@ error[E0277]: the trait bound `i32: std::ops::Add<u8>` is not satisfied
    = help: the trait `std::ops::Add<u8>` is not implemented for `i32`
    = note: required by `std::ops::Add`
 
-error: aborting due to 8 previous errors
+error[E0277]: the trait bound `TwoParams<i32, U>: Trait` is not satisfied
+  --> $DIR/type-check-defaults.rs:36:1
+   |
+36 | struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams<i32, U>`
+   |
+   = help: consider adding a `where TwoParams<i32, U>: Trait` bound
+   = note: required by `Trait`
+
+error[E0277]: the trait bound `TwoParams<T, i32>: Trait` is not satisfied
+  --> $DIR/type-check-defaults.rs:36:1
+   |
+36 | struct Bogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Trait;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `TwoParams<T, i32>`
+   |
+   = help: consider adding a `where TwoParams<T, i32>: Trait` bound
+   = note: required by `Trait`
+
+error: aborting due to 10 previous errors