]> 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 21660d817b213f901cd4b2ad54a56f73add8ce86..d10ee358e072846e77be1591c47c141b1f55d4b1 100644 (file)
@@ -278,7 +278,7 @@ 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, _| {
-            self.check_trait_where_clauses(fcx, item.span, trait_def_id);
+            self.check_where_clauses(fcx, item.span, trait_def_id);
             vec![]
         });
     }
@@ -354,23 +354,6 @@ fn check_where_clauses<'fcx, 'tcx>(&mut self,
                                        fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                        span: Span,
                                        def_id: DefId) {
-        self.inner_check_where_clauses(fcx, span, def_id, false)
-    }
-
-    fn check_trait_where_clauses<'fcx, 'tcx>(&mut self,
-                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
-                                       span: Span,
-                                       def_id: DefId) {
-        self.inner_check_where_clauses(fcx, span, def_id, true)
-    }
-
-    /// Checks where clauses and inline bounds that are declared on def_id.
-    fn inner_check_where_clauses<'fcx, 'tcx>(&mut self,
-                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
-                                       span: Span,
-                                       def_id: DefId,
-                                       is_trait: bool)
-    {
         use ty::subst::Subst;
         use rustc::ty::TypeFoldable;
 
@@ -380,22 +363,26 @@ fn inner_check_where_clauses<'fcx, 'tcx>(&mut self,
         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;
-        let defaulted_params = generics.types.iter().cloned().filter(&is_our_default);
-        // Check that defaults are well-formed. See test `type-check-defaults.rs`.
+
+        // 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 defaulted_params.map(|p| p.def_id) {
-            fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
+        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 obviously wrong cases such as `struct Foo<T: Copy = String>`
-        // or cases where defaults don't work together such as:
-        // `struct Foo<T = i32, U = u8> where T: into<U>`
-        // Therefore we check if a predicate in which all type params are defaulted
-        // is WF with those defaults simultaneously substituted.
+        // 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.
@@ -403,30 +390,39 @@ fn inner_check_where_clauses<'fcx, 'tcx>(&mut self,
                 // All regions are identity.
                 fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
             }, |def, _| {
-                if !is_our_default(def) {
-                    // We don't want to use non-defaulted params in a substitution, mark as err.
-                    fcx.tcx.types.err
-                } else  {
-                    // Substitute with default.
-                    fcx.tcx.type_of(def.def_id)
+                // 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);
-            // If there is a non-defaulted param in the predicate, don't check it.
-            if substituted_pred.references_error() {
+            // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+            if substituted_pred.references_error() || param_count.params.len() > 1 {
                 continue;
             }
-            // In trait defs, don't check `Self: Sized` when `Self` is the default.
-            if let ty::Predicate::Trait(trait_pred) = substituted_pred {
-                // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`.
-                let lhs_is_self = trait_pred.skip_binder().self_ty().has_self_ty();
-                let pred_sized = Some(trait_pred.def_id()) == fcx.tcx.lang_items().sized_trait();
-                if is_trait && lhs_is_self && pred_sized {
-                    continue;
-                }
-            }
             // Avoid duplication of predicates that contain no parameters, for example.
             if !predicates.predicates.contains(&substituted_pred) {
                 substituted_predicates.push(substituted_pred);
@@ -540,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(_, _) |