Skip to content

Commit 73f39a0

Browse files
Ariel Ben-Yehudaarielb1
authored andcommitted
Short-cut Sized matching on ADTs
Put a constraint type on every ADT def, such that the ADT def is sized iff the constraint type is, and use that in selection. This ignores types that are obviously sized. This improves typeck performance by ~15%.
1 parent 3157691 commit 73f39a0

File tree

3 files changed

+225
-83
lines changed

3 files changed

+225
-83
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub enum DepNode<D: Clone + Debug> {
8888
ImplOrTraitItems(D),
8989
ItemSignature(D),
9090
FieldTy(D),
91+
SizedConstraint(D),
9192
TraitItemDefIds(D),
9293
InherentImpls(D),
9394
ImplItems(D),
@@ -193,6 +194,7 @@ impl<D: Clone + Debug> DepNode<D> {
193194
ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
194195
ItemSignature(ref d) => op(d).map(ItemSignature),
195196
FieldTy(ref d) => op(d).map(FieldTy),
197+
SizedConstraint(ref d) => op(d).map(SizedConstraint),
196198
TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
197199
InherentImpls(ref d) => op(d).map(InherentImpls),
198200
ImplItems(ref d) => op(d).map(ImplItems),

src/librustc/traits/select.rs

Lines changed: 73 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
pub use self::MethodMatchResult::*;
1414
pub use self::MethodMatchedData::*;
1515
use self::SelectionCandidate::*;
16-
use self::BuiltinBoundConditions::*;
1716
use self::EvaluationResult::*;
1817

1918
use super::coherence;
@@ -232,10 +231,18 @@ struct EvaluatedCandidate<'tcx> {
232231
evaluation: EvaluationResult,
233232
}
234233

235-
enum BuiltinBoundConditions<'tcx> {
236-
If(ty::Binder<Vec<Ty<'tcx>>>),
237-
ParameterBuiltin,
238-
AmbiguousBuiltin
234+
/// When does the builtin impl for `T: Trait` apply?
235+
enum BuiltinImplConditions<'tcx> {
236+
/// The impl is conditional on T1,T2,.. : Trait
237+
Where(ty::Binder<Vec<Ty<'tcx>>>),
238+
/// There is no built-in impl. There may be some other
239+
/// candidate (a where-clause or user-defined impl).
240+
None,
241+
/// There is *no* impl for this, builtin or not. Ignore
242+
/// all where-clauses.
243+
Never(SelectionError<'tcx>),
244+
/// It is unknown whether there is an impl.
245+
Ambiguous
239246
}
240247

241248
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
@@ -1608,39 +1615,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16081615
// those will hopefully change to library-defined traits in the
16091616
// future.
16101617

1618+
// HACK: if this returns an error, selection exits without considering
1619+
// other impls.
16111620
fn assemble_builtin_bound_candidates<'o>(&mut self,
16121621
bound: ty::BuiltinBound,
16131622
obligation: &TraitObligation<'tcx>,
16141623
candidates: &mut SelectionCandidateSet<'tcx>)
16151624
-> Result<(),SelectionError<'tcx>>
16161625
{
16171626
match self.builtin_bound(bound, obligation) {
1618-
Ok(If(..)) => {
1627+
BuiltinImplConditions::Where(..) => {
16191628
debug!("builtin_bound: bound={:?}",
16201629
bound);
16211630
candidates.vec.push(BuiltinCandidate(bound));
16221631
Ok(())
16231632
}
1624-
Ok(ParameterBuiltin) => { Ok(()) }
1625-
Ok(AmbiguousBuiltin) => {
1633+
BuiltinImplConditions::None => { Ok(()) }
1634+
BuiltinImplConditions::Ambiguous => {
16261635
debug!("assemble_builtin_bound_candidates: ambiguous builtin");
16271636
Ok(candidates.ambiguous = true)
16281637
}
1629-
Err(e) => { Err(e) }
1638+
BuiltinImplConditions::Never(e) => { Err(e) }
16301639
}
16311640
}
16321641

16331642
fn builtin_bound(&mut self,
16341643
bound: ty::BuiltinBound,
16351644
obligation: &TraitObligation<'tcx>)
1636-
-> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
1645+
-> BuiltinImplConditions<'tcx>
16371646
{
16381647
// Note: these tests operate on types that may contain bound
16391648
// regions. To be proper, we ought to skolemize here, but we
16401649
// forego the skolemization and defer it until the
16411650
// confirmation step.
16421651

16431652
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
1653+
1654+
let always = BuiltinImplConditions::Where(ty::Binder(Vec::new()));
1655+
let never = BuiltinImplConditions::Never(Unimplemented);
1656+
16441657
return match self_ty.sty {
16451658
ty::TyInfer(ty::IntVar(_)) |
16461659
ty::TyInfer(ty::FloatVar(_)) |
@@ -1652,14 +1665,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16521665
ty::TyFnPtr(_) |
16531666
ty::TyChar => {
16541667
// safe for everything
1655-
ok_if(Vec::new())
1668+
always
16561669
}
16571670

16581671
ty::TyBox(_) => { // Box<T>
16591672
match bound {
1660-
ty::BoundCopy => Err(Unimplemented),
1661-
1662-
ty::BoundSized => ok_if(Vec::new()),
1673+
ty::BoundCopy => never,
1674+
ty::BoundSized => always,
16631675

16641676
ty::BoundSync | ty::BoundSend => {
16651677
bug!("Send/Sync shouldn't occur in builtin_bounds()");
@@ -1669,7 +1681,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16691681

16701682
ty::TyRawPtr(..) => { // *const T, *mut T
16711683
match bound {
1672-
ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()),
1684+
ty::BoundCopy | ty::BoundSized => always,
16731685

16741686
ty::BoundSync | ty::BoundSend => {
16751687
bug!("Send/Sync shouldn't occur in builtin_bounds()");
@@ -1679,10 +1691,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16791691

16801692
ty::TyTrait(ref data) => {
16811693
match bound {
1682-
ty::BoundSized => Err(Unimplemented),
1694+
ty::BoundSized => never,
16831695
ty::BoundCopy => {
1696+
// FIXME(#32963): bit-rot fungus infestation
16841697
if data.bounds.builtin_bounds.contains(&bound) {
1685-
ok_if(Vec::new())
1698+
always
16861699
} else {
16871700
// Recursively check all supertraits to find out if any further
16881701
// bounds are required and thus we must fulfill.
@@ -1692,11 +1705,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16921705
let copy_def_id = obligation.predicate.def_id();
16931706
for tr in util::supertraits(self.tcx(), principal) {
16941707
if tr.def_id() == copy_def_id {
1695-
return ok_if(Vec::new())
1708+
return always
16961709
}
16971710
}
16981711

1699-
Err(Unimplemented)
1712+
never
17001713
}
17011714
}
17021715
ty::BoundSync | ty::BoundSend => {
@@ -1711,14 +1724,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17111724
ty::BoundCopy => {
17121725
match mutbl {
17131726
// &mut T is affine and hence never `Copy`
1714-
hir::MutMutable => Err(Unimplemented),
1727+
hir::MutMutable => never,
17151728

17161729
// &T is always copyable
1717-
hir::MutImmutable => ok_if(Vec::new()),
1730+
hir::MutImmutable => always
17181731
}
17191732
}
17201733

1721-
ty::BoundSized => ok_if(Vec::new()),
1734+
ty::BoundSized => always,
17221735

17231736
ty::BoundSync | ty::BoundSend => {
17241737
bug!("Send/Sync shouldn't occur in builtin_bounds()");
@@ -1730,7 +1743,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17301743
// [T; n]
17311744
match bound {
17321745
ty::BoundCopy => ok_if(vec![element_ty]),
1733-
ty::BoundSized => ok_if(Vec::new()),
1746+
ty::BoundSized => always,
17341747
ty::BoundSync | ty::BoundSend => {
17351748
bug!("Send/Sync shouldn't occur in builtin_bounds()");
17361749
}
@@ -1743,65 +1756,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17431756
bug!("Send/Sync shouldn't occur in builtin_bounds()");
17441757
}
17451758

1746-
ty::BoundCopy | ty::BoundSized => Err(Unimplemented),
1759+
ty::BoundCopy | ty::BoundSized => never
17471760
}
17481761
}
17491762

17501763
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
17511764
ty::TyTuple(ref tys) => ok_if(tys.clone()),
17521765

1753-
ty::TyClosure(_, ref substs) => {
1754-
// FIXME -- This case is tricky. In the case of by-ref
1755-
// closures particularly, we need the results of
1756-
// inference to decide how to reflect the type of each
1757-
// upvar (the upvar may have type `T`, but the runtime
1758-
// type could be `&mut`, `&`, or just `T`). For now,
1759-
// though, we'll do this unsoundly and assume that all
1760-
// captures are by value. Really what we ought to do
1761-
// is reserve judgement and then intertwine this
1762-
// analysis with closure inference.
1763-
1764-
// Unboxed closures shouldn't be
1765-
// implicitly copyable
1766-
if bound == ty::BoundCopy {
1767-
return Ok(ParameterBuiltin);
1768-
}
1766+
ty::TyClosure(..) => {
1767+
match bound {
1768+
ty::BoundSync | ty::BoundSend => {
1769+
bug!("Send/Sync shouldn't occur in builtin_bounds()");
1770+
}
17691771

1770-
// Upvars are always local variables or references to
1771-
// local variables, and local variables cannot be
1772-
// unsized, so the closure struct as a whole must be
1773-
// Sized.
1774-
if bound == ty::BoundSized {
1775-
return ok_if(Vec::new());
1772+
ty::BoundCopy => never,
1773+
ty::BoundSized => always
17761774
}
1777-
1778-
ok_if(substs.upvar_tys.clone())
17791775
}
17801776

17811777
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
1782-
let types: Vec<Ty> = def.all_fields().map(|f| {
1783-
f.ty(self.tcx(), substs)
1784-
}).collect();
1785-
nominal(bound, types)
1778+
match bound {
1779+
// Fallback to whatever user-defined impls exist in this case.
1780+
ty::BoundCopy => BuiltinImplConditions::None,
1781+
1782+
// Sized if all the component types are sized.
1783+
ty::BoundSized => {
1784+
let sized_crit = def.sized_constraint(self.tcx());
1785+
if sized_crit == self.tcx().types.bool {
1786+
always
1787+
} else {
1788+
ok_if(vec![sized_crit.subst(self.tcx(), substs)])
1789+
}
1790+
}
1791+
1792+
// Shouldn't be coming through here.
1793+
ty::BoundSend | ty::BoundSync => bug!(),
1794+
}
17861795
}
17871796

17881797
ty::TyProjection(_) | ty::TyParam(_) => {
17891798
// Note: A type parameter is only considered to meet a
17901799
// particular bound if there is a where clause telling
17911800
// us that it does, and that case is handled by
17921801
// `assemble_candidates_from_caller_bounds()`.
1793-
Ok(ParameterBuiltin)
1802+
BuiltinImplConditions::None
17941803
}
17951804

17961805
ty::TyInfer(ty::TyVar(_)) => {
17971806
// Unbound type variable. Might or might not have
17981807
// applicable impls and so forth, depending on what
17991808
// those type variables wind up being bound to.
18001809
debug!("assemble_builtin_bound_candidates: ambiguous builtin");
1801-
Ok(AmbiguousBuiltin)
1810+
BuiltinImplConditions::Ambiguous
18021811
}
18031812

1804-
ty::TyError => ok_if(Vec::new()),
1813+
ty::TyError => always,
18051814

18061815
ty::TyInfer(ty::FreshTy(_))
18071816
| ty::TyInfer(ty::FreshIntTy(_))
@@ -1811,26 +1820,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
18111820
}
18121821
};
18131822

1814-
fn ok_if<'tcx>(v: Vec<Ty<'tcx>>)
1815-
-> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>> {
1816-
Ok(If(ty::Binder(v)))
1817-
}
1818-
1819-
fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
1820-
types: Vec<Ty<'tcx>>)
1821-
-> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>>
1822-
{
1823-
// First check for markers and other nonsense.
1824-
match bound {
1825-
// Fallback to whatever user-defined impls exist in this case.
1826-
ty::BoundCopy => Ok(ParameterBuiltin),
1827-
1828-
// Sized if all the component types are sized.
1829-
ty::BoundSized => ok_if(types),
1830-
1831-
// Shouldn't be coming through here.
1832-
ty::BoundSend | ty::BoundSync => bug!(),
1833-
}
1823+
fn ok_if<'tcx>(v: Vec<Ty<'tcx>>) -> BuiltinImplConditions<'tcx> {
1824+
BuiltinImplConditions::Where(ty::Binder(v))
18341825
}
18351826
}
18361827

@@ -1999,7 +1990,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19991990
match candidate {
20001991
BuiltinCandidate(builtin_bound) => {
20011992
Ok(VtableBuiltin(
2002-
self.confirm_builtin_candidate(obligation, builtin_bound)?))
1993+
self.confirm_builtin_candidate(obligation, builtin_bound)))
20031994
}
20041995

20051996
ParamCandidate(param) => {
@@ -2100,18 +2091,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21002091
fn confirm_builtin_candidate(&mut self,
21012092
obligation: &TraitObligation<'tcx>,
21022093
bound: ty::BuiltinBound)
2103-
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
2104-
SelectionError<'tcx>>
2094+
-> VtableBuiltinData<PredicateObligation<'tcx>>
21052095
{
21062096
debug!("confirm_builtin_candidate({:?})",
21072097
obligation);
21082098

2109-
match self.builtin_bound(bound, obligation)? {
2110-
If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
2111-
AmbiguousBuiltin | ParameterBuiltin => {
2099+
match self.builtin_bound(bound, obligation) {
2100+
BuiltinImplConditions::Where(nested) =>
2101+
self.vtable_builtin_data(obligation, bound, nested),
2102+
_ => {
21122103
span_bug!(
21132104
obligation.cause.span,
2114-
"builtin bound for {:?} was ambig",
2105+
"confiriming builtin impl for {:?} where none exists",
21152106
obligation);
21162107
}
21172108
}

0 commit comments

Comments
 (0)