about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/fast_reject.rs10
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs2
-rw-r--r--src/librustc/middle/infer/mod.rs21
-rw-r--r--src/librustc/middle/traits/error_reporting.rs2
-rw-r--r--src/librustc/middle/traits/fulfill.rs7
-rw-r--r--src/librustc/middle/traits/project.rs7
-rw-r--r--src/librustc/middle/ty.rs57
-rw-r--r--src/librustc/middle/ty_relate/mod.rs4
8 files changed, 86 insertions, 24 deletions
diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs
index 8ff81635416..11d95120344 100644
--- a/src/librustc/middle/fast_reject.rs
+++ b/src/librustc/middle/fast_reject.rs
@@ -85,11 +85,13 @@ pub fn simplify_type(tcx: &ty::ctxt,
         ty::TyBareFn(_, ref f) => {
             Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
         }
-        ty::TyProjection(_) => {
-            None
-        }
-        ty::TyParam(_) => {
+        ty::TyProjection(_) | ty::TyParam(_) => {
             if can_simplify_params {
+                // In normalized types, projections don't unify with
+                // anything. when lazy normalization happens, this
+                // will change. It would still be nice to have a way
+                // to deal with known-not-to-unify-with-anything
+                // projections (e.g. the likes of <__S as Encoder>::Error).
                 Some(ParameterSimplifiedType)
             } else {
                 None
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index 1919d8ffd29..5f2f4df2f16 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -614,7 +614,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                              snapshot: &CombinedSnapshot,
                              value: &T)
                              -> T
-    where T : TypeFoldable<'tcx>
+    where T : TypeFoldable<'tcx> + ty::HasTypeFlags
 {
     debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());
 
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 578b39af88c..d56a73c3657 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -985,7 +985,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                          snapshot: &CombinedSnapshot,
                          value: &T)
                          -> T
-        where T : TypeFoldable<'tcx>
+        where T : TypeFoldable<'tcx> + HasTypeFlags
     {
         /*! See `higher_ranked::plug_leaks` */
 
@@ -1256,7 +1256,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T {
+    pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
+        where T: TypeFoldable<'tcx> + HasTypeFlags
+    {
         /*!
          * Where possible, replaces type/int/float variables in
          * `value` with their final value. Note that region variables
@@ -1266,6 +1268,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
          * at will.
          */
 
+        if !value.needs_infer() {
+            return value.clone(); // avoid duplicated subst-folding
+        }
         let mut r = resolve::OpportunisticTypeResolver::new(self);
         value.fold_with(&mut r)
     }
@@ -1456,9 +1461,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
         let ty = self.resolve_type_vars_if_possible(&ty);
-        !traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span)
-        // FIXME(@jroesch): should be able to use:
-        // ty.moves_by_default(&self.parameter_environment, span)
+        if ty.needs_infer() {
+            // this can get called from typeck (by euv), and moves_by_default
+            // rightly refuses to work with inference variables, but
+            // moves_by_default has a cache, which we want to use in other
+            // cases.
+            !traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span)
+        } else {
+            ty.moves_by_default(&self.parameter_environment, span)
+        }
     }
 
     pub fn node_method_ty(&self, method_call: ty::MethodCall)
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 467c752499b..3be05c45c4d 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -160,7 +160,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
                                           obligation: &Obligation<'tcx, T>)
                                           -> !
-    where T: fmt::Display + TypeFoldable<'tcx>
+    where T: fmt::Display + TypeFoldable<'tcx> + HasTypeFlags
 {
     let predicate =
         infcx.resolve_type_vars_if_possible(&obligation.predicate);
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 1fca66f1379..99e12b7428d 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -12,11 +12,10 @@ use middle::infer::InferCtxt;
 use middle::ty::{self, RegionEscape, Ty, HasTypeFlags};
 use middle::wf;
 
-use std::collections::HashSet;
 use std::fmt;
 use syntax::ast;
 use util::common::ErrorReported;
-use util::nodemap::NodeMap;
+use util::nodemap::{FnvHashSet, NodeMap};
 
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
@@ -33,7 +32,7 @@ use super::Unimplemented;
 use super::util::predicate_for_builtin_bound;
 
 pub struct FulfilledPredicates<'tcx> {
-    set: HashSet<(RFC1214Warning, ty::Predicate<'tcx>)>
+    set: FnvHashSet<(RFC1214Warning, ty::Predicate<'tcx>)>
 }
 
 /// The fulfillment context is used to drive trait resolution.  It
@@ -540,7 +539,7 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
 impl<'tcx> FulfilledPredicates<'tcx> {
     pub fn new() -> FulfilledPredicates<'tcx> {
         FulfilledPredicates {
-            set: HashSet::new()
+            set: FnvHashSet()
         }
     }
 
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index ef3a217ecdb..cacefbb1a85 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -927,6 +927,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
     }
 }
 
+impl<'tcx, T: HasTypeFlags> HasTypeFlags for Normalized<'tcx, T> {
+    fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
+        self.value.has_type_flags(flags) ||
+            self.obligations.has_type_flags(flags)
+    }
+}
+
 impl<'tcx, T:fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "Normalized({:?},{:?})",
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index d7a58f4cdd0..45225475e6b 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3192,6 +3192,8 @@ impl<'tcx> TraitDef<'tcx> {
         }
     }
 
+    /// Iterate over every impl that could possibly match the
+    /// self-type `self_ty`.
     pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
                                                    tcx: &ctxt<'tcx>,
                                                    self_ty: Ty<'tcx>,
@@ -3203,18 +3205,29 @@ impl<'tcx> TraitDef<'tcx> {
             f(impl_def_id);
         }
 
-        if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, false) {
+        // simplify_type(.., false) basically replaces type parameters and
+        // projections with infer-variables. This is, of course, done on
+        // the impl trait-ref when it is instantiated, but not on the
+        // predicate trait-ref which is passed here.
+        //
+        // for example, if we match `S: Copy` against an impl like
+        // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
+        // in `Option<T>` with an infer variable, to `Option<_>` (this
+        // doesn't actually change fast_reject output), but we don't
+        // replace `S` with anything - this impl of course can't be
+        // selected, and as there are hundreds of similar impls,
+        // considering them would significantly harm performance.
+        if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
             if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
                 for &impl_def_id in impls {
                     f(impl_def_id);
                 }
-                return; // we don't need to process the other non-blanket impls
             }
-        }
-
-        for v in self.nonblanket_impls.borrow().values() {
-            for &impl_def_id in v {
-                f(impl_def_id);
+        } else {
+            for v in self.nonblanket_impls.borrow().values() {
+                for &impl_def_id in v {
+                    f(impl_def_id);
+                }
             }
         }
     }
@@ -7267,6 +7280,24 @@ impl<'tcx,T:HasTypeFlags> HasTypeFlags for VecPerParamSpace<T> {
     }
 }
 
+impl HasTypeFlags for abi::Abi {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
+impl HasTypeFlags for ast::Unsafety {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
+impl HasTypeFlags for BuiltinBounds {
+    fn has_type_flags(&self, _flags: TypeFlags) -> bool {
+        false
+    }
+}
+
 impl<'tcx> HasTypeFlags for ClosureTy<'tcx> {
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self.sig.has_type_flags(flags)
@@ -7279,6 +7310,12 @@ impl<'tcx> HasTypeFlags for ClosureUpvar<'tcx> {
     }
 }
 
+impl<'tcx> HasTypeFlags for ExistentialBounds<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.projection_bounds.has_type_flags(flags)
+    }
+}
+
 impl<'tcx> HasTypeFlags for ty::InstantiatedPredicates<'tcx> {
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self.predicates.has_type_flags(flags)
@@ -7354,6 +7391,12 @@ impl<'tcx> HasTypeFlags for Ty<'tcx> {
     }
 }
 
+impl<'tcx> HasTypeFlags for TypeAndMut<'tcx> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.ty.has_type_flags(flags)
+    }
+}
+
 impl<'tcx> HasTypeFlags for TraitRef<'tcx> {
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self.substs.has_type_flags(flags)
diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs
index 05b08b356ef..f307f674732 100644
--- a/src/librustc/middle/ty_relate/mod.rs
+++ b/src/librustc/middle/ty_relate/mod.rs
@@ -14,7 +14,7 @@
 //! type equality, etc.
 
 use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
-use middle::ty::{self, Ty, TypeError};
+use middle::ty::{self, HasTypeFlags, Ty, TypeError};
 use middle::ty_fold::TypeFoldable;
 use std::rc::Rc;
 use syntax::abi;
@@ -78,7 +78,7 @@ pub trait TypeRelation<'a,'tcx> : Sized {
         where T: Relate<'a,'tcx>;
 }
 
-pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> {
+pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> + HasTypeFlags {
     fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R,
                                        a: &Self,
                                        b: &Self)