Skip to content

Commit 7c2c232

Browse files
committed
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
1 parent 5a31b6e commit 7c2c232

File tree

3 files changed

+150
-5
lines changed

3 files changed

+150
-5
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub mod middle {
8888
pub mod effect;
8989
pub mod entry;
9090
pub mod expr_use_visitor;
91+
pub mod fast_reject;
9192
pub mod graph;
9293
pub mod intrinsicck;
9394
pub mod lang_items;

src/librustc/middle/fast_reject.rs

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use middle::ty;
12+
use syntax::ast;
13+
14+
/** See `simplify_type */
15+
#[deriving(Clone, PartialEq, Eq, Hash)]
16+
pub enum SimplifiedType {
17+
NilSimplifiedType,
18+
BoolSimplifiedType,
19+
CharSimplifiedType,
20+
IntSimplifiedType(ast::IntTy),
21+
UintSimplifiedType(ast::UintTy),
22+
FloatSimplifiedType(ast::FloatTy),
23+
EnumSimplifiedType(ast::DefId),
24+
StrSimplifiedType,
25+
VecSimplifiedType,
26+
PtrSimplifiedType,
27+
TupleSimplifiedType(uint),
28+
TraitSimplifiedType(ast::DefId),
29+
StructSimplifiedType(ast::DefId),
30+
UnboxedClosureSimplifiedType(ast::DefId),
31+
FunctionSimplifiedType(uint),
32+
ParameterSimplifiedType,
33+
}
34+
35+
pub fn simplify_type(tcx: &ty::ctxt,
36+
ty: ty::t,
37+
can_simplify_params: bool)
38+
-> Option<SimplifiedType>
39+
{
40+
/*!
41+
* Tries to simplify a type by dropping type parameters, deref'ing
42+
* away any reference types, etc. The idea is to get something
43+
* simple that we can use to quickly decide if two types could
44+
* unify during method lookup.
45+
*
46+
* If `can_simplify_params` is false, then we will fail to
47+
* simplify type parameters entirely. This is useful when those
48+
* type parameters would be instantiated with fresh type
49+
* variables, since then we can't say much about whether two types
50+
* would unify. Put another way, `can_simplify_params` should be
51+
* true if type parameters appear free in `ty` and `false` if they
52+
* are to be considered bound.
53+
*/
54+
55+
match ty::get(ty).sty {
56+
ty::ty_nil => Some(NilSimplifiedType),
57+
ty::ty_bool => Some(BoolSimplifiedType),
58+
ty::ty_char => Some(CharSimplifiedType),
59+
ty::ty_int(int_type) => Some(IntSimplifiedType(int_type)),
60+
ty::ty_uint(uint_type) => Some(UintSimplifiedType(uint_type)),
61+
ty::ty_float(float_type) => Some(FloatSimplifiedType(float_type)),
62+
ty::ty_enum(def_id, _) => Some(EnumSimplifiedType(def_id)),
63+
ty::ty_str => Some(StrSimplifiedType),
64+
ty::ty_vec(..) => Some(VecSimplifiedType),
65+
ty::ty_ptr(_) => Some(PtrSimplifiedType),
66+
ty::ty_trait(ref trait_info) => {
67+
Some(TraitSimplifiedType(trait_info.principal.def_id))
68+
}
69+
ty::ty_struct(def_id, _) => {
70+
Some(StructSimplifiedType(def_id))
71+
}
72+
ty::ty_rptr(_, mt) => {
73+
// since we introduce auto-refs during method lookup, we
74+
// just treat &T and T as equivalent from the point of
75+
// view of possibly unifying
76+
simplify_type(tcx, mt.ty, can_simplify_params)
77+
}
78+
ty::ty_uniq(_) => {
79+
// treat like we would treat `Box`
80+
let def_id = tcx.lang_items.owned_box().unwrap();
81+
Some(StructSimplifiedType(def_id))
82+
}
83+
ty::ty_unboxed_closure(def_id, _, _) => {
84+
Some(UnboxedClosureSimplifiedType(def_id))
85+
}
86+
ty::ty_tup(ref tys) => {
87+
Some(TupleSimplifiedType(tys.len()))
88+
}
89+
ty::ty_closure(ref f) => {
90+
Some(FunctionSimplifiedType(f.sig.inputs.len()))
91+
}
92+
ty::ty_bare_fn(ref f) => {
93+
Some(FunctionSimplifiedType(f.sig.inputs.len()))
94+
}
95+
ty::ty_param(_) => {
96+
if can_simplify_params {
97+
Some(ParameterSimplifiedType)
98+
} else {
99+
None
100+
}
101+
}
102+
ty::ty_open(_) | ty::ty_infer(_) | ty::ty_err => None,
103+
}
104+
}
105+

src/librustc/middle/typeck/check/method/probe.rs

+44-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use super::MethodIndex;
1616
use super::NoMatch;
1717
use super::TraitSource;
1818

19+
use middle::fast_reject;
1920
use middle::subst;
2021
use middle::subst::Subst;
2122
use middle::traits;
@@ -36,6 +37,7 @@ struct ProbeContext<'a, 'tcx:'a> {
3637
span: Span,
3738
method_name: ast::Name,
3839
steps: Rc<Vec<CandidateStep>>,
40+
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
3941
inherent_candidates: Vec<Candidate>,
4042
extension_candidates: Vec<Candidate>,
4143
impl_dups: HashSet<ast::DefId>,
@@ -44,7 +46,7 @@ struct ProbeContext<'a, 'tcx:'a> {
4446

4547
struct CandidateStep {
4648
self_ty: ty::t,
47-
adjustment: PickAdjustment
49+
adjustment: PickAdjustment,
4850
}
4951

5052
struct Candidate {
@@ -123,16 +125,31 @@ pub fn probe(fcx: &FnCtxt,
123125
// take place in the `fcx.infcx().probe` below.
124126
let steps = create_steps(fcx, span, self_ty);
125127

128+
// Create a list of simplified self types, if we can.
129+
let mut simplified_steps = Vec::new();
130+
for step in steps.iter() {
131+
match fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) {
132+
None => { break; }
133+
Some(simplified_type) => { simplified_steps.push(simplified_type); }
134+
}
135+
}
136+
let opt_simplified_steps =
137+
if simplified_steps.len() < steps.len() {
138+
None // failed to convert at least one of the steps
139+
} else {
140+
Some(simplified_steps)
141+
};
142+
126143
debug!("ProbeContext: steps for self_ty={} are {}",
127144
self_ty.repr(fcx.tcx()),
128145
steps.repr(fcx.tcx()));
129146

130147
// this creates one big transaction so that all type variables etc
131148
// that we create during the probe process are removed later
132-
let mut steps = Some(steps); // FIXME(#18101) need once closures
149+
let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures
133150
fcx.infcx().probe(|| {
134-
let steps = steps.take().unwrap();
135-
let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps);
151+
let (steps, opt_simplified_steps) = dummy.take().unwrap();
152+
let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps);
136153
probe_cx.assemble_inherent_candidates();
137154
probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id);
138155
probe_cx.pick()
@@ -177,7 +194,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
177194
fn new(fcx: &'a FnCtxt<'a,'tcx>,
178195
span: Span,
179196
method_name: ast::Name,
180-
steps: Vec<CandidateStep>)
197+
steps: Vec<CandidateStep>,
198+
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
181199
-> ProbeContext<'a,'tcx>
182200
{
183201
ProbeContext {
@@ -188,6 +206,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
188206
extension_candidates: Vec::new(),
189207
impl_dups: HashSet::new(),
190208
steps: Rc::new(steps),
209+
opt_simplified_steps: opt_simplified_steps,
191210
static_candidates: Vec::new(),
192211
}
193212
}
@@ -473,6 +492,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
473492
trait_def_id.repr(self.tcx()),
474493
impl_def_id.repr(self.tcx()));
475494

495+
if !self.impl_can_possibly_match(impl_def_id) {
496+
continue;
497+
}
498+
476499
let impl_pty = check::impl_self_ty(self.fcx, self.span, impl_def_id);
477500
let impl_substs = impl_pty.substs;
478501

@@ -499,6 +522,22 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
499522
}
500523
}
501524

525+
fn impl_can_possibly_match(&self, impl_def_id: ast::DefId) -> bool {
526+
let simplified_steps = match self.opt_simplified_steps {
527+
Some(ref simplified_steps) => simplified_steps,
528+
None => { return true; }
529+
};
530+
531+
let impl_type = ty::lookup_item_type(self.tcx(), impl_def_id);
532+
let impl_simplified_type =
533+
match fast_reject::simplify_type(self.tcx(), impl_type.ty, false) {
534+
Some(simplified_type) => simplified_type,
535+
None => { return true; }
536+
};
537+
538+
simplified_steps.contains(&impl_simplified_type)
539+
}
540+
502541
fn assemble_unboxed_closure_candidates(&mut self,
503542
trait_def_id: ast::DefId,
504543
method_ty: Rc<ty::Method>,

0 commit comments

Comments
 (0)