]> git.lizzy.rs Git - rust.git/commitdiff
Port a simplified versions of pcwalton's "quick reject" mechanism for quickly throwin...
authorNiko Matsakis <niko@alum.mit.edu>
Sun, 16 Nov 2014 11:33:31 +0000 (06:33 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 17 Nov 2014 19:25:11 +0000 (14:25 -0500)
Conflicts:
src/librustc/driver/config.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/coherence/mod.rs

src/librustc/lib.rs
src/librustc/middle/fast_reject.rs [new file with mode: 0644]
src/librustc/middle/typeck/check/method/probe.rs

index ce736a344d5a67609ab29da7bf8000f7f07ab345..c9a1d47f55856e18b94f9541b987fe245c9bf008 100644 (file)
@@ -87,6 +87,7 @@ pub mod middle {
     pub mod effect;
     pub mod entry;
     pub mod expr_use_visitor;
+    pub mod fast_reject;
     pub mod graph;
     pub mod intrinsicck;
     pub mod lang_items;
diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs
new file mode 100644 (file)
index 0000000..915f12c
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::ty;
+use syntax::ast;
+
+/** See `simplify_type */
+#[deriving(Clone, PartialEq, Eq, Hash)]
+pub enum SimplifiedType {
+    BoolSimplifiedType,
+    CharSimplifiedType,
+    IntSimplifiedType(ast::IntTy),
+    UintSimplifiedType(ast::UintTy),
+    FloatSimplifiedType(ast::FloatTy),
+    EnumSimplifiedType(ast::DefId),
+    StrSimplifiedType,
+    VecSimplifiedType,
+    PtrSimplifiedType,
+    TupleSimplifiedType(uint),
+    TraitSimplifiedType(ast::DefId),
+    StructSimplifiedType(ast::DefId),
+    UnboxedClosureSimplifiedType(ast::DefId),
+    FunctionSimplifiedType(uint),
+    ParameterSimplifiedType,
+}
+
+pub fn simplify_type(tcx: &ty::ctxt,
+                     ty: ty::t,
+                     can_simplify_params: bool)
+                     -> Option<SimplifiedType>
+{
+    /*!
+     * Tries to simplify a type by dropping type parameters, deref'ing
+     * away any reference types, etc. The idea is to get something
+     * simple that we can use to quickly decide if two types could
+     * unify during method lookup.
+     *
+     * If `can_simplify_params` is false, then we will fail to
+     * simplify type parameters entirely. This is useful when those
+     * type parameters would be instantiated with fresh type
+     * variables, since then we can't say much about whether two types
+     * would unify. Put another way, `can_simplify_params` should be
+     * true if type parameters appear free in `ty` and `false` if they
+     * are to be considered bound.
+     */
+
+    match ty::get(ty).sty {
+        ty::ty_bool => Some(BoolSimplifiedType),
+        ty::ty_char => Some(CharSimplifiedType),
+        ty::ty_int(int_type) => Some(IntSimplifiedType(int_type)),
+        ty::ty_uint(uint_type) => Some(UintSimplifiedType(uint_type)),
+        ty::ty_float(float_type) => Some(FloatSimplifiedType(float_type)),
+        ty::ty_enum(def_id, _) => Some(EnumSimplifiedType(def_id)),
+        ty::ty_str => Some(StrSimplifiedType),
+        ty::ty_vec(..) => Some(VecSimplifiedType),
+        ty::ty_ptr(_) => Some(PtrSimplifiedType),
+        ty::ty_trait(ref trait_info) => {
+            Some(TraitSimplifiedType(trait_info.principal.def_id))
+        }
+        ty::ty_struct(def_id, _) => {
+            Some(StructSimplifiedType(def_id))
+        }
+        ty::ty_rptr(_, mt) => {
+            // since we introduce auto-refs during method lookup, we
+            // just treat &T and T as equivalent from the point of
+            // view of possibly unifying
+            simplify_type(tcx, mt.ty, can_simplify_params)
+        }
+        ty::ty_uniq(_) => {
+            // treat like we would treat `Box`
+            let def_id = tcx.lang_items.owned_box().unwrap();
+            Some(StructSimplifiedType(def_id))
+        }
+        ty::ty_unboxed_closure(def_id, _, _) => {
+            Some(UnboxedClosureSimplifiedType(def_id))
+        }
+        ty::ty_tup(ref tys) => {
+            Some(TupleSimplifiedType(tys.len()))
+        }
+        ty::ty_closure(ref f) => {
+            Some(FunctionSimplifiedType(f.sig.inputs.len()))
+        }
+        ty::ty_bare_fn(ref f) => {
+            Some(FunctionSimplifiedType(f.sig.inputs.len()))
+        }
+        ty::ty_param(_) => {
+            if can_simplify_params {
+                Some(ParameterSimplifiedType)
+            } else {
+                None
+            }
+        }
+        ty::ty_open(_) | ty::ty_infer(_) | ty::ty_err => None,
+    }
+}
+
index d28402b05305d52d4b60e3d72c8857dd8ebd77e5..bc46b975cdb915d0b720153e9fb13556647d0915 100644 (file)
@@ -16,6 +16,7 @@
 use super::NoMatch;
 use super::TraitSource;
 
+use middle::fast_reject;
 use middle::subst;
 use middle::subst::Subst;
 use middle::traits;
@@ -36,6 +37,7 @@ struct ProbeContext<'a, 'tcx:'a> {
     span: Span,
     method_name: ast::Name,
     steps: Rc<Vec<CandidateStep>>,
+    opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate>,
     extension_candidates: Vec<Candidate>,
     impl_dups: HashSet<ast::DefId>,
@@ -44,7 +46,7 @@ struct ProbeContext<'a, 'tcx:'a> {
 
 struct CandidateStep {
     self_ty: ty::t,
-    adjustment: PickAdjustment
+    adjustment: PickAdjustment,
 }
 
 struct Candidate {
@@ -123,16 +125,31 @@ pub fn probe(fcx: &FnCtxt,
     // take place in the `fcx.infcx().probe` below.
     let steps = create_steps(fcx, span, self_ty);
 
+    // Create a list of simplified self types, if we can.
+    let mut simplified_steps = Vec::new();
+    for step in steps.iter() {
+        match fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) {
+            None => { break; }
+            Some(simplified_type) => { simplified_steps.push(simplified_type); }
+        }
+    }
+    let opt_simplified_steps =
+        if simplified_steps.len() < steps.len() {
+            None // failed to convert at least one of the steps
+        } else {
+            Some(simplified_steps)
+        };
+
     debug!("ProbeContext: steps for self_ty={} are {}",
            self_ty.repr(fcx.tcx()),
            steps.repr(fcx.tcx()));
 
     // this creates one big transaction so that all type variables etc
     // that we create during the probe process are removed later
-    let mut steps = Some(steps); // FIXME(#18101) need once closures
+    let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures
     fcx.infcx().probe(|| {
-        let steps = steps.take().unwrap();
-        let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps);
+        let (steps, opt_simplified_steps) = dummy.take().unwrap();
+        let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps);
         probe_cx.assemble_inherent_candidates();
         probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id);
         probe_cx.pick()
@@ -177,7 +194,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn new(fcx: &'a FnCtxt<'a,'tcx>,
            span: Span,
            method_name: ast::Name,
-           steps: Vec<CandidateStep>)
+           steps: Vec<CandidateStep>,
+           opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
            -> ProbeContext<'a,'tcx>
     {
         ProbeContext {
@@ -188,6 +206,7 @@ fn new(fcx: &'a FnCtxt<'a,'tcx>,
             extension_candidates: Vec::new(),
             impl_dups: HashSet::new(),
             steps: Rc::new(steps),
+            opt_simplified_steps: opt_simplified_steps,
             static_candidates: Vec::new(),
         }
     }
@@ -473,6 +492,10 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
                    trait_def_id.repr(self.tcx()),
                    impl_def_id.repr(self.tcx()));
 
+            if !self.impl_can_possibly_match(impl_def_id) {
+                continue;
+            }
+
             let impl_pty = check::impl_self_ty(self.fcx, self.span, impl_def_id);
             let impl_substs = impl_pty.substs;
 
@@ -499,6 +522,22 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
         }
     }
 
+    fn impl_can_possibly_match(&self, impl_def_id: ast::DefId) -> bool {
+        let simplified_steps = match self.opt_simplified_steps {
+            Some(ref simplified_steps) => simplified_steps,
+            None => { return true; }
+        };
+
+        let impl_type = ty::lookup_item_type(self.tcx(), impl_def_id);
+        let impl_simplified_type =
+            match fast_reject::simplify_type(self.tcx(), impl_type.ty, false) {
+                Some(simplified_type) => simplified_type,
+                None => { return true; }
+            };
+
+        simplified_steps.contains(&impl_simplified_type)
+    }
+
     fn assemble_unboxed_closure_candidates(&mut self,
                                            trait_def_id: ast::DefId,
                                            method_ty: Rc<ty::Method>,