Skip to content

Commit 336349c

Browse files
committed
auto merge of #18694 : nikomatsakis/rust/issue-18208-method-dispatch-2, r=nrc
This is a pretty major refactoring of the method dispatch infrastructure. It is intended to avoid gross inefficiencies and enable caching and other optimizations (e.g. #17995), though it itself doesn't seem to execute particularly faster yet. It also solves some cases where we were failing to resolve methods that we theoretically should have succeeded with. Fixes #18674. cc #18208
2 parents f092793 + 99fbd34 commit 336349c

25 files changed

+2643
-2074
lines changed

Diff for: src/librustc/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ This API is completely unstable and subject to change.
2929
html_root_url = "http://doc.rust-lang.org/nightly/")]
3030

3131
#![feature(default_type_params, globs, if_let, import_shadowing, macro_rules, phase, quote)]
32-
#![feature(slicing_syntax, struct_variant, unsafe_destructor)]
32+
#![feature(slicing_syntax, struct_variant, tuple_indexing, unsafe_destructor)]
3333
#![feature(rustc_diagnostic_macros)]
3434

3535
extern crate arena;
@@ -87,6 +87,7 @@ pub mod middle {
8787
pub mod effect;
8888
pub mod entry;
8989
pub mod expr_use_visitor;
90+
pub mod fast_reject;
9091
pub mod graph;
9192
pub mod intrinsicck;
9293
pub mod lang_items;

Diff for: 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+
use self::SimplifiedType::*;
15+
16+
/** See `simplify_type */
17+
#[deriving(Clone, PartialEq, Eq, Hash)]
18+
pub enum SimplifiedType {
19+
BoolSimplifiedType,
20+
CharSimplifiedType,
21+
IntSimplifiedType(ast::IntTy),
22+
UintSimplifiedType(ast::UintTy),
23+
FloatSimplifiedType(ast::FloatTy),
24+
EnumSimplifiedType(ast::DefId),
25+
StrSimplifiedType,
26+
VecSimplifiedType,
27+
PtrSimplifiedType,
28+
TupleSimplifiedType(uint),
29+
TraitSimplifiedType(ast::DefId),
30+
StructSimplifiedType(ast::DefId),
31+
UnboxedClosureSimplifiedType(ast::DefId),
32+
FunctionSimplifiedType(uint),
33+
ParameterSimplifiedType,
34+
}
35+
36+
pub fn simplify_type(tcx: &ty::ctxt,
37+
ty: ty::t,
38+
can_simplify_params: bool)
39+
-> Option<SimplifiedType>
40+
{
41+
/*!
42+
* Tries to simplify a type by dropping type parameters, deref'ing
43+
* away any reference types, etc. The idea is to get something
44+
* simple that we can use to quickly decide if two types could
45+
* unify during method lookup.
46+
*
47+
* If `can_simplify_params` is false, then we will fail to
48+
* simplify type parameters entirely. This is useful when those
49+
* type parameters would be instantiated with fresh type
50+
* variables, since then we can't say much about whether two types
51+
* would unify. Put another way, `can_simplify_params` should be
52+
* true if type parameters appear free in `ty` and `false` if they
53+
* are to be considered bound.
54+
*/
55+
56+
match ty::get(ty).sty {
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+

Diff for: src/librustc/middle/traits/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ pub fn overlapping_impls(infcx: &InferCtxt,
281281
coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id)
282282
}
283283

284+
pub fn impl_obligations(tcx: &ty::ctxt,
285+
cause: ObligationCause,
286+
impl_def_id: ast::DefId,
287+
impl_substs: &subst::Substs)
288+
-> subst::VecPerParamSpace<Obligation>
289+
{
290+
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
291+
obligations_for_generics(tcx, cause, &impl_generics, impl_substs)
292+
}
293+
284294
pub fn obligations_for_generics(tcx: &ty::ctxt,
285295
cause: ObligationCause,
286296
generics: &ty::Generics,

Diff for: src/librustc/middle/traits/select.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure};
2727
use super::{VtableImplData, VtableParamData, VtableBuiltinData};
2828
use super::{util};
2929

30+
use middle::fast_reject;
3031
use middle::mem_categorization::Typer;
3132
use middle::subst::{Subst, Substs, VecPerParamSpace};
3233
use middle::ty;
3334
use middle::typeck::check::regionmanip;
3435
use middle::typeck::infer;
36+
use middle::typeck::infer::LateBoundRegionConversionTime::*;
3537
use middle::typeck::infer::{InferCtxt, TypeSkolemizer};
3638
use middle::ty_fold::TypeFoldable;
3739
use std::cell::RefCell;
@@ -1714,7 +1716,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17141716
closure_type.sig.binder_id,
17151717
&closure_type.sig,
17161718
|br| self.infcx.next_region_var(
1717-
infer::LateBoundRegion(obligation.cause.span, br)));
1719+
infer::LateBoundRegion(obligation.cause.span, br,
1720+
infer::FnCall)));
17181721

17191722
let arguments_tuple = new_signature.inputs[0];
17201723
let trait_ref = Rc::new(ty::TraitRef {
@@ -1766,12 +1769,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17661769
obligation: &Obligation)
17671770
-> Result<Substs, ()>
17681771
{
1772+
let impl_trait_ref = ty::impl_trait_ref(self.tcx(),
1773+
impl_def_id).unwrap();
1774+
1775+
// Before we create the substitutions and everything, first
1776+
// consider a "quick reject". This avoids creating more types
1777+
// and so forth that we need to.
1778+
if self.fast_reject_trait_refs(obligation, &*impl_trait_ref) {
1779+
return Err(());
1780+
}
1781+
17691782
let impl_substs = util::fresh_substs_for_impl(self.infcx,
17701783
obligation.cause.span,
17711784
impl_def_id);
17721785

1773-
let impl_trait_ref = ty::impl_trait_ref(self.tcx(),
1774-
impl_def_id).unwrap();
17751786
let impl_trait_ref = impl_trait_ref.subst(self.tcx(),
17761787
&impl_substs);
17771788

@@ -1781,6 +1792,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17811792
}
17821793
}
17831794

1795+
fn fast_reject_trait_refs(&mut self,
1796+
obligation: &Obligation,
1797+
impl_trait_ref: &ty::TraitRef)
1798+
-> bool
1799+
{
1800+
// We can avoid creating type variables and doing the full
1801+
// substitution if we find that any of the input types, when
1802+
// simplified, do not match.
1803+
1804+
obligation.trait_ref.input_types().iter()
1805+
.zip(impl_trait_ref.input_types().iter())
1806+
.any(|(&obligation_ty, &impl_ty)| {
1807+
let simplified_obligation_ty =
1808+
fast_reject::simplify_type(self.tcx(), obligation_ty, true);
1809+
let simplified_impl_ty =
1810+
fast_reject::simplify_type(self.tcx(), impl_ty, false);
1811+
1812+
simplified_obligation_ty.is_some() &&
1813+
simplified_impl_ty.is_some() &&
1814+
simplified_obligation_ty != simplified_impl_ty
1815+
})
1816+
}
1817+
17841818
fn match_trait_refs(&mut self,
17851819
obligation: &Obligation,
17861820
trait_ref: Rc<ty::TraitRef>)

Diff for: src/librustc/middle/ty.rs

+30-28
Original file line numberDiff line numberDiff line change
@@ -3491,43 +3491,45 @@ pub fn adjust_ty(cx: &ctxt,
34913491
}
34923492
}
34933493

3494-
match adj.autoref {
3495-
None => adjusted_ty,
3496-
Some(ref autoref) => adjust_for_autoref(cx, span, adjusted_ty, autoref)
3497-
}
3494+
adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref())
34983495
}
34993496
}
35003497
}
35013498
None => unadjusted_ty
35023499
};
3500+
}
35033501

3504-
fn adjust_for_autoref(cx: &ctxt,
3505-
span: Span,
3506-
ty: ty::t,
3507-
autoref: &AutoRef) -> ty::t{
3508-
match *autoref {
3509-
AutoPtr(r, m, ref a) => {
3510-
let adjusted_ty = match a {
3511-
&Some(box ref a) => adjust_for_autoref(cx, span, ty, a),
3512-
&None => ty
3513-
};
3514-
mk_rptr(cx, r, mt {
3515-
ty: adjusted_ty,
3516-
mutbl: m
3517-
})
3518-
}
3502+
pub fn adjust_ty_for_autoref(cx: &ctxt,
3503+
span: Span,
3504+
ty: ty::t,
3505+
autoref: Option<&AutoRef>)
3506+
-> ty::t
3507+
{
3508+
match autoref {
3509+
None => ty,
35193510

3520-
AutoUnsafe(m, ref a) => {
3521-
let adjusted_ty = match a {
3522-
&Some(box ref a) => adjust_for_autoref(cx, span, ty, a),
3523-
&None => ty
3524-
};
3525-
mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
3526-
}
3511+
Some(&AutoPtr(r, m, ref a)) => {
3512+
let adjusted_ty = match a {
3513+
&Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
3514+
&None => ty
3515+
};
3516+
mk_rptr(cx, r, mt {
3517+
ty: adjusted_ty,
3518+
mutbl: m
3519+
})
3520+
}
35273521

3528-
AutoUnsize(ref k) => unsize_ty(cx, ty, k, span),
3529-
AutoUnsizeUniq(ref k) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)),
3522+
Some(&AutoUnsafe(m, ref a)) => {
3523+
let adjusted_ty = match a {
3524+
&Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
3525+
&None => ty
3526+
};
3527+
mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
35303528
}
3529+
3530+
Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span),
3531+
3532+
Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)),
35313533
}
35323534
}
35333535

0 commit comments

Comments
 (0)