]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/wfcheck.rs
Merge branch 'refactor-select' of https://github.com/aravind-pg/rust into update...
[rust.git] / src / librustc_typeck / check / wfcheck.rs
index 9c233a7a15d246160c15326a4b010a24eed15f6d..d10ee358e072846e77be1591c47c141b1f55d4b1 100644 (file)
@@ -25,7 +25,6 @@
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
-use rustc::ty::TypeFoldable;
 
 pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -186,10 +185,7 @@ fn check_associated_item(&mut self,
                     reject_shadowing_type_parameters(fcx.tcx, item.def_id);
                     let sig = fcx.tcx.fn_sig(item.def_id);
                     let sig = fcx.normalize_associated_types_in(span, &sig);
-                    let predicates = fcx.tcx.predicates_of(item.def_id)
-                        .instantiate_identity(fcx.tcx);
-                    let predicates = fcx.normalize_associated_types_in(span, &predicates);
-                    this.check_fn_or_method(fcx, span, sig, &predicates,
+                    this.check_fn_or_method(fcx, span, sig,
                                             item.def_id, &mut implied_bounds);
                     let sig_if_method = sig_if_method.expect("bad signature for method");
                     this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
@@ -273,9 +269,7 @@ fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_f
                 }
             }
 
-            let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
-            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
-            this.check_where_clauses(fcx, item.span, &predicates);
+            self.check_where_clauses(fcx, item.span, def_id);
 
             vec![] // no implied bounds in a struct def'n
         });
@@ -283,10 +277,8 @@ fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_f
 
     fn check_trait(&mut self, item: &hir::Item) {
         let trait_def_id = self.tcx.hir.local_def_id(item.id);
-        self.for_item(item).with_fcx(|fcx, this| {
-            let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx);
-            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
-            this.check_where_clauses(fcx, item.span, &predicates);
+        self.for_item(item).with_fcx(|fcx, _| {
+            self.check_where_clauses(fcx, item.span, trait_def_id);
             vec![]
         });
     }
@@ -296,12 +288,8 @@ fn check_item_fn(&mut self, item: &hir::Item) {
             let def_id = fcx.tcx.hir.local_def_id(item.id);
             let sig = fcx.tcx.fn_sig(def_id);
             let sig = fcx.normalize_associated_types_in(item.span, &sig);
-
-            let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
-            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
-
             let mut implied_bounds = vec![];
-            this.check_fn_or_method(fcx, item.span, sig, &predicates,
+            this.check_fn_or_method(fcx, item.span, sig,
                                     def_id, &mut implied_bounds);
             implied_bounds
         })
@@ -344,36 +332,8 @@ fn check_impl(&mut self,
                                                   fcx.body_id,
                                                   &trait_ref,
                                                   ast_trait_ref.path.span);
-
-                    // not registering predicates associcated with a `default impl`
-                    // that doesn't implement all the trait items.
-                    // it's left to the trait selection to select those trait predicates
-                    // and trigger an `Unimplemented` error in case the defaul_impl_check
-                    // is applicable
-                    let impl_not_implement_trait =
-                        if fcx.tcx.impl_is_default(item_def_id) &&
-                           !fcx.tcx.default_impl_implement_all_methods(item_def_id) {
-                            true
-                        } else {
-                            false
-                        };
-
                     for obligation in obligations {
-                        let register = match obligation.predicate {
-                            ty::Predicate::Trait(..)  => {
-                                if impl_not_implement_trait &&
-                                   !obligation.predicate.has_param_types() {
-                                    false
-                                } else {
-                                    true
-                                }
-                            }
-                            _ => true
-                        };
-
-                        if register {
-                            fcx.register_predicate(obligation);
-                        }
+                        fcx.register_predicate(obligation);
                     }
                 }
                 None => {
@@ -383,19 +343,96 @@ fn check_impl(&mut self,
                 }
             }
 
-            let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx);
-            let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
-            this.check_where_clauses(fcx, item.span, &predicates);
+            this.check_where_clauses(fcx, item.span, item_def_id);
 
             fcx.impl_implied_bounds(item_def_id, item.span)
         });
     }
 
+    /// Checks where clauses and inline bounds that are declared on def_id.
     fn check_where_clauses<'fcx, 'tcx>(&mut self,
                                        fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                        span: Span,
-                                       predicates: &ty::InstantiatedPredicates<'tcx>)
-    {
+                                       def_id: DefId) {
+        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 is_our_default = |def: &ty::TypeParameterDef|
+                                def.has_default && def.index >= generics.parent_count() as u32;
+
+        // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
+        // For example this forbids the declaration:
+        // struct Foo<T = Vec<[u32]>> { .. }
+        // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
+        for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
+            let ty = fcx.tcx.type_of(d);
+            // ignore dependent defaults -- that is, where the default of one type
+            // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+            // be sure if it will error or not as user might always specify the other.
+            if !ty.needs_subst() {
+                fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone());
+            }
+        }
+
+        // Check that trait predicates are WF when params are substituted by their defaults.
+        // We don't want to overly constrain the predicates that may be written but we want to
+        // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
+        // Therefore we check if a predicate which contains a single type param
+        // with a concrete default is WF with that default substituted.
+        // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
+        //
+        // First we build the defaulted substitution.
+        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, _| {
+                // If the param has a default,
+                if is_our_default(def) {
+                    let default_ty = fcx.tcx.type_of(def.def_id);
+                    // and it's not a dependent default
+                    if !default_ty.needs_subst() {
+                        // then substitute with the default.
+                        return default_ty;
+                    }
+                }
+                // Mark unwanted params as err.
+                fcx.tcx.types.err
+            });
+        // Now we build the substituted predicates.
+        for &pred in predicates.predicates.iter() {
+            struct CountParams { params: FxHashSet<u32> }
+            impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+                fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+                    match t.sty {
+                        ty::TyParam(p) => {
+                            self.params.insert(p.idx);
+                            t.super_visit_with(self)
+                        }
+                        _ => t.super_visit_with(self)
+                    }
+                }
+            }
+            let mut param_count = CountParams { params: FxHashSet() };
+            pred.visit_with(&mut param_count);
+            let substituted_pred = pred.subst(fcx.tcx, substs);
+            // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+            if substituted_pred.references_error() || param_count.params.len() > 1 {
+                continue;
+            }
+            // Avoid duplication of predicates that contain no parameters, for example.
+            if !predicates.predicates.contains(&substituted_pred) {
+                substituted_predicates.push(substituted_pred);
+            }
+        }
+
+        predicates.predicates.extend(substituted_predicates);
+        let predicates = predicates.instantiate_identity(fcx.tcx);
+        let predicates = fcx.normalize_associated_types_in(span, &predicates);
+
         let obligations =
             predicates.predicates
                       .iter()
@@ -414,7 +451,6 @@ fn check_fn_or_method<'fcx, 'tcx>(&mut self,
                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                       span: Span,
                                       sig: ty::PolyFnSig<'tcx>,
-                                      predicates: &ty::InstantiatedPredicates<'tcx>,
                                       def_id: DefId,
                                       implied_bounds: &mut Vec<Ty<'tcx>>)
     {
@@ -431,7 +467,7 @@ fn check_fn_or_method<'fcx, 'tcx>(&mut self,
         // FIXME(#25759) return types should not be implied bounds
         implied_bounds.push(sig.output());
 
-        self.check_where_clauses(fcx, span, predicates);
+        self.check_where_clauses(fcx, span, def_id);
     }
 
     fn check_method_receiver<'fcx, 'tcx>(&mut self,
@@ -500,7 +536,7 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self,
         let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
         let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
 
-        if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
+        if !fcx.tcx.features().arbitrary_self_types {
             match self_kind {
                 ExplicitSelf::ByValue |
                 ExplicitSelf::ByReference(_, _) |