Port a simplified versions of pcwalton's "quick reject" mechanism for quickly throwing out method candidates. Yields a 40%-50% improvement in typechecking time as well as lowering peak memory use from 2.2GB to 1.8GB (due to creating fewer types).
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
This commit is contained in:
parent
0ed0a4633b
commit
d93921b348
3 changed files with 148 additions and 5 deletions
|
|
@ -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;
|
||||
|
|
|
|||
103
src/librustc/middle/fast_reject.rs
Normal file
103
src/librustc/middle/fast_reject.rs
Normal file
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ use super::MethodIndex;
|
|||
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 @@ impl<'a,'tcx> ProbeContext<'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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue