Skip to content

Commit 1f34086

Browse files
committed
Initial incorporation of specialization:
- Rewrites the overlap checker to instead build up a specialization graph, checking for overlap errors in the process. - Use the specialization order during impl selection. This commit does not yet handle associated types correctly, and assumes that all items are `default` and are overridden.
1 parent c5849e4 commit 1f34086

File tree

17 files changed

+254
-219
lines changed

17 files changed

+254
-219
lines changed

src/librustc/dep_graph/README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ could invalidate work done for other items. So, for example:
5151
not shared state, because if it changes it does not itself
5252
invalidate other functions (though it may be that it causes new
5353
monomorphizations to occur, but that's handled independently).
54-
54+
5555
Put another way: if the HIR for an item changes, we are going to
5656
recompile that item for sure. But we need the dep tracking map to tell
5757
us what *else* we have to recompile. Shared state is anything that is
@@ -177,7 +177,7 @@ reads from `item`, there would be missing edges in the graph:
177177
| ^
178178
| |
179179
+---------------------------------+ // added by `visit_all_items_in_krate`
180-
180+
181181
In particular, the edge from `Hir(X)` to `ItemSignature(X)` is only
182182
present because we called `read` ourselves when entering the `ItemSignature(X)`
183183
task.
@@ -273,8 +273,8 @@ should not exist. In contrast, using the memoized helper, you get:
273273
... -> MapVariant(key) -> A
274274
|
275275
+----------> B
276-
277-
which is much cleaner.
276+
277+
which is much cleaner.
278278

279279
**Be aware though that the closure is executed with `MapVariant(key)`
280280
pushed onto the stack as the current task!** That means that you must
@@ -387,4 +387,3 @@ RUST_DEP_GRAPH_FILTER='Hir&foo -> TypeckItemBody & bar'
387387
This will dump out all the nodes that lead from `Hir(foo)` to
388388
`TypeckItemBody(bar)`, from which you can (hopefully) see the source
389389
of the erroneous edge.
390-

src/librustc/middle/cstore.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ pub trait CrateStore<'tcx> : Any {
176176
-> Option<ty::adjustment::CustomCoerceUnsized>;
177177
fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
178178
-> Vec<Rc<ty::AssociatedConst<'tcx>>>;
179+
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
179180

180181
// trait/impl-item info
181182
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
@@ -346,6 +347,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
346347
{ unimplemented!() }
347348
fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
348349
-> Vec<Rc<ty::AssociatedConst<'tcx>>> { unimplemented!() }
350+
fn impl_parent(&self, def: DefId) -> Option<DefId> { unimplemented!() }
349351

350352
// trait/impl-item info
351353
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)

src/librustc/middle/traits/coherence.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use syntax::codemap::DUMMY_SP;
2323
#[derive(Copy, Clone)]
2424
struct InferIsLocal(bool);
2525

26-
/// If there are types that satisfy both impls, returns an `ImplTy`
27-
/// with those types substituted (by updating the given `infcx`)
26+
/// If there are types that satisfy both impls, returns a suitably-freshened
27+
/// `ImplHeader` with those types substituted
2828
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
2929
impl1_def_id: DefId,
3030
impl2_def_id: DefId)
@@ -85,7 +85,10 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
8585
return None
8686
}
8787

88-
Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
88+
let substituted = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
89+
let freshened = selcx.infcx().freshen(substituted);
90+
91+
Some(freshened)
8992
}
9093

9194
pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool

src/librustc/middle/traits/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub use self::select::SelectionContext;
5050
pub use self::select::SelectionCache;
5151
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
5252
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
53+
pub use self::specialize::{Overlap, SpecializationGraph, specializes};
5354
pub use self::util::elaborate_predicates;
5455
pub use self::util::get_vtable_index_of_object_method;
5556
pub use self::util::trait_ref_for_builtin_bound;
@@ -67,6 +68,7 @@ mod fulfill;
6768
mod project;
6869
mod object_safety;
6970
mod select;
71+
mod specialize;
7072
mod structural_impls;
7173
mod util;
7274

src/librustc/middle/traits/select.rs

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use middle::infer;
4040
use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin};
4141
use middle::subst::{Subst, Substs, TypeSpace};
4242
use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
43+
use middle::traits;
4344
use middle::ty::fast_reject;
4445
use middle::ty::relate::TypeRelation;
4546

@@ -224,6 +225,12 @@ struct SelectionCandidateSet<'tcx> {
224225
ambiguous: bool,
225226
}
226227

228+
#[derive(PartialEq,Eq,Debug,Clone)]
229+
struct EvaluatedCandidate<'tcx> {
230+
candidate: SelectionCandidate<'tcx>,
231+
evaluation: EvaluationResult,
232+
}
233+
227234
enum BuiltinBoundConditions<'tcx> {
228235
If(ty::Binder<Vec<Ty<'tcx>>>),
229236
ParameterBuiltin,
@@ -746,6 +753,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
746753
candidate
747754
}
748755

756+
// Treat negative impls as unimplemented
757+
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
758+
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
759+
if let ImplCandidate(def_id) = candidate {
760+
if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) {
761+
return Err(Unimplemented)
762+
}
763+
}
764+
Ok(Some(candidate))
765+
}
766+
749767
fn candidate_from_obligation_no_cache<'o>(&mut self,
750768
stack: &TraitObligationStack<'o, 'tcx>)
751769
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
@@ -803,12 +821,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
803821
// we were to winnow, we'd wind up with zero candidates.
804822
// Instead, we select the right impl now but report `Bar does
805823
// not implement Clone`.
806-
if candidates.len() > 1 {
807-
candidates.retain(|c| self.evaluate_candidate(stack, c).may_apply())
808-
}
824+
if candidates.len() == 1 {
825+
return self.filter_negative_impls(candidates.pop().unwrap());
826+
}
827+
828+
// Winnow, but record the exact outcome of evaluation, which
829+
// is needed for specialization.
830+
let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
831+
let eval = self.evaluate_candidate(stack, &c);
832+
if eval.may_apply() {
833+
Some(EvaluatedCandidate {
834+
candidate: c,
835+
evaluation: eval,
836+
})
837+
} else {
838+
None
839+
}
840+
}).collect();
809841

810-
// If there are STILL multiple candidate, we can further reduce
811-
// the list by dropping duplicates.
842+
// If there are STILL multiple candidate, we can further
843+
// reduce the list by dropping duplicates -- including
844+
// resolving specializations.
812845
if candidates.len() > 1 {
813846
let mut i = 0;
814847
while i < candidates.len() {
@@ -850,19 +883,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
850883
}
851884

852885
// Just one candidate left.
853-
let candidate = candidates.pop().unwrap();
854-
855-
match candidate {
856-
ImplCandidate(def_id) => {
857-
match self.tcx().trait_impl_polarity(def_id) {
858-
Some(hir::ImplPolarity::Negative) => return Err(Unimplemented),
859-
_ => {}
860-
}
861-
}
862-
_ => {}
863-
}
864-
865-
Ok(Some(candidate))
886+
self.filter_negative_impls(candidates.pop().unwrap().candidate)
866887
}
867888

868889
fn is_knowable<'o>(&mut self,
@@ -1564,41 +1585,55 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15641585
/// candidates and prefer where-clause candidates.
15651586
///
15661587
/// See the comment for "SelectionCandidate" for more details.
1567-
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
1568-
victim: &SelectionCandidate<'tcx>,
1569-
other: &SelectionCandidate<'tcx>)
1570-
-> bool
1588+
fn candidate_should_be_dropped_in_favor_of<'o>(
1589+
&mut self,
1590+
victim: &EvaluatedCandidate<'tcx>,
1591+
other: &EvaluatedCandidate<'tcx>)
1592+
-> bool
15711593
{
1572-
if victim == other {
1594+
if victim.candidate == other.candidate {
15731595
return true;
15741596
}
15751597

1576-
match other {
1577-
&ObjectCandidate |
1578-
&ParamCandidate(_) | &ProjectionCandidate => match victim {
1579-
&DefaultImplCandidate(..) => {
1598+
match other.candidate {
1599+
ObjectCandidate |
1600+
ParamCandidate(_) | ProjectionCandidate => match victim.candidate {
1601+
DefaultImplCandidate(..) => {
15801602
self.tcx().sess.bug(
15811603
"default implementations shouldn't be recorded \
15821604
when there are other valid candidates");
15831605
}
1584-
&ImplCandidate(..) |
1585-
&ClosureCandidate(..) |
1586-
&FnPointerCandidate |
1587-
&BuiltinObjectCandidate |
1588-
&BuiltinUnsizeCandidate |
1589-
&DefaultImplObjectCandidate(..) |
1590-
&BuiltinCandidate(..) => {
1606+
ImplCandidate(..) |
1607+
ClosureCandidate(..) |
1608+
FnPointerCandidate |
1609+
BuiltinObjectCandidate |
1610+
BuiltinUnsizeCandidate |
1611+
DefaultImplObjectCandidate(..) |
1612+
BuiltinCandidate(..) => {
15911613
// We have a where-clause so don't go around looking
15921614
// for impls.
15931615
true
15941616
}
1595-
&ObjectCandidate |
1596-
&ProjectionCandidate => {
1617+
ObjectCandidate |
1618+
ProjectionCandidate => {
15971619
// Arbitrarily give param candidates priority
15981620
// over projection and object candidates.
15991621
true
16001622
},
1601-
&ParamCandidate(..) => false,
1623+
ParamCandidate(..) => false,
1624+
ErrorCandidate => false // propagate errors
1625+
},
1626+
ImplCandidate(other_def) => {
1627+
// See if we can toss out `victim` based on specialization.
1628+
// This requires us to know *for sure* that the `other` impl applies
1629+
// i.e. EvaluatedToOk:
1630+
if other.evaluation == EvaluatedToOk {
1631+
if let ImplCandidate(victim_def) = victim.candidate {
1632+
return traits::specializes(self.infcx(), other_def, victim_def);
1633+
}
1634+
}
1635+
1636+
false
16021637
},
16031638
_ => false
16041639
}

src/librustc/middle/traits/util.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,6 @@ pub fn trait_ref_for_builtin_bound<'tcx>(
381381
}
382382
}
383383

384-
385384
pub fn predicate_for_trait_ref<'tcx>(
386385
cause: ObligationCause<'tcx>,
387386
trait_ref: ty::TraitRef<'tcx>,

src/librustc/middle/ty/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2456,8 +2456,13 @@ impl<'tcx> TyCtxt<'tcx> {
24562456
for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) {
24572457
let impl_items = self.sess.cstore.impl_items(impl_def_id);
24582458
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
2459+
24592460
// Record the trait->implementation mapping.
2460-
def.record_impl(self, impl_def_id, trait_ref);
2461+
if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) {
2462+
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
2463+
} else {
2464+
def.record_remote_impl(self, impl_def_id, trait_ref, trait_id);
2465+
}
24612466

24622467
// For any methods that use a default implementation, add them to
24632468
// the map. This is a bit unfortunate.

src/librustc/middle/ty/sty.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,13 @@ impl<'tcx> TyS<'tcx> {
11061106
}
11071107
}
11081108

1109+
pub fn has_concrete_skeleton(&self) -> bool {
1110+
match self.sty {
1111+
TyParam(_) | TyInfer(_) | TyError => false,
1112+
_ => true,
1113+
}
1114+
}
1115+
11091116
// Returns the type and mutability of *ty.
11101117
//
11111118
// The parameter `explicit` indicates if this is an *explicit* dereference.

0 commit comments

Comments
 (0)