Skip to content

Commit 336349c

Browse files
committed
auto merge of rust-lang#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. rust-lang#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 rust-lang#18674. cc rust-lang#18208
2 parents f092793 + 99fbd34 commit 336349c

25 files changed

+2643
-2074
lines changed

src/librustc/lib.rs

Lines changed: 2 additions & 1 deletion
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;

src/librustc/middle/fast_reject.rs

Lines changed: 105 additions & 0 deletions
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+

src/librustc/middle/traits/mod.rs

Lines changed: 10 additions & 0 deletions
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,

src/librustc/middle/traits/select.rs

Lines changed: 37 additions & 3 deletions
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>)

src/librustc/middle/ty.rs

Lines changed: 30 additions & 28 deletions
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)