Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 940adda

Browse files
committedMar 14, 2016
Move specialization graph walks to iterators; make associated type
projection sensitive to "mode" (most importantly, trans vs middle). This commit introduces several pieces of iteration infrastructure in the specialization graph data structure, as well as various helpers for finding the definition of a given item, given its kind and name. In addition, associated type projection is now *mode-sensitive*, with three possible modes: - **Topmost**. This means that projection is only possible if there is a non-`default` definition of the associated type directly on the selected impl. This mode is a bit of a hack: it's used during early coherence checking before we have built the specialization graph (and therefore before we can walk up the specialization parents to find other definitions). Eventually, this should be replaced with a less "staged" construction of the specialization graph. - **AnyFinal**. Projection succeeds for any non-`default` associated type definition, even if it is defined by a parent impl. Used throughout typechecking. - **Any**. Projection always succeeds. Used by trans. The lasting distinction here is between `AnyFinal` and `Any` -- we wish to treat `default` associated types opaquely for typechecking purposes. In addition to the above, the commit includes a few other minor review fixes.
1 parent 462c83e commit 940adda

File tree

16 files changed

+989
-650
lines changed

16 files changed

+989
-650
lines changed
 

‎src/librustc/middle/traits/coherence.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
//! See `README.md` for high-level documentation
1212
13+
use super::build_selcx;
1314
use super::{SelectionContext, Obligation, ObligationCause};
1415
use super::util;
1516

@@ -36,7 +37,7 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
3637
impl1_def_id,
3738
impl2_def_id);
3839

39-
let selcx = &mut SelectionContext::intercrate(infcx);
40+
let selcx = &mut build_selcx(infcx).project_topmost().intercrate().build();
4041
overlap(selcx, impl1_def_id, impl2_def_id)
4142
}
4243

‎src/librustc/middle/traits/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,11 @@ pub use self::object_safety::object_safety_violations;
4545
pub use self::object_safety::ObjectSafetyViolation;
4646
pub use self::object_safety::MethodViolationCode;
4747
pub use self::object_safety::is_vtable_safe_method;
48-
pub use self::select::EvaluationCache;
49-
pub use self::select::SelectionContext;
50-
pub use self::select::SelectionCache;
48+
pub use self::select::{EvaluationCache, SelectionContextBuilder, build_selcx};
49+
pub use self::select::{ProjectionMode, SelectionContext, SelectionCache};
5150
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
5251
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
53-
pub use self::specialize::{Overlap, SpecializationGraph, specializes};
54-
pub use self::specialize::{ItemSource, get_impl_item_or_default, get_parent_impl_item};
52+
pub use self::specialize::{Overlap, specialization_graph, specializes, translate_substs};
5553
pub use self::util::elaborate_predicates;
5654
pub use self::util::get_vtable_index_of_object_method;
5755
pub use self::util::trait_ref_for_builtin_bound;

‎src/librustc/middle/traits/project.rs

+100-45
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
//! Code for projecting associated types out of trait references.
1212
1313
use super::elaborate_predicates;
14-
use super::get_impl_item_or_default;
1514
use super::report_overflow_error;
15+
use super::specialization_graph;
16+
use super::translate_substs;
1617
use super::Obligation;
1718
use super::ObligationCause;
1819
use super::PredicateObligation;
@@ -22,14 +23,18 @@ use super::VtableClosureData;
2223
use super::VtableImplData;
2324
use super::util;
2425

26+
use middle::def_id::DefId;
2527
use middle::infer::{self, TypeOrigin};
2628
use middle::subst::Subst;
2729
use middle::ty::{self, ToPredicate, RegionEscape, HasTypeFlags, ToPolyTraitRef, Ty, TyCtxt};
2830
use middle::ty::fold::{TypeFoldable, TypeFolder};
2931
use rustc_front::hir;
3032
use syntax::parse::token;
33+
use syntax::ast;
3134
use util::common::FN_OUTPUT_NAME;
3235

36+
use std::rc::Rc;
37+
3338
pub type PolyProjectionObligation<'tcx> =
3439
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
3540

@@ -568,7 +573,49 @@ fn project_type<'cx,'tcx>(
568573

569574
assert!(candidates.vec.len() <= 1);
570575

571-
match candidates.vec.pop() {
576+
let possible_candidate = candidates.vec.pop().and_then(|candidate| {
577+
// In Any (i.e. trans) mode, all projections succeed;
578+
// otherwise, we need to be sensitive to `default` and
579+
// specialization.
580+
if !selcx.projection_mode().any() {
581+
if let ProjectionTyCandidate::Impl(ref impl_data) = candidate {
582+
if let Some(node_item) = assoc_ty_def(selcx,
583+
impl_data.impl_def_id,
584+
obligation.predicate.item_name) {
585+
if node_item.node.is_from_trait() {
586+
if node_item.item.ty.is_some() {
587+
// If the associated type has a default from the
588+
// trait, that should be considered `default` and
589+
// hence not projected.
590+
//
591+
// Note, however, that we allow a projection from
592+
// the trait specifically in the case that the trait
593+
// does *not* give a default. This is purely to
594+
// avoid spurious errors: the situation can only
595+
// arise when *no* impl in the specialization chain
596+
// has provided a definition for the type. When we
597+
// confirm the candidate, we'll turn the projection
598+
// into a TyError, since the actual error will be
599+
// reported in `check_impl_items_against_trait`.
600+
return None;
601+
}
602+
} else if node_item.item.defaultness.is_default() {
603+
return None;
604+
}
605+
} else {
606+
// Normally this situation could only arise througha
607+
// compiler bug, but at coherence-checking time we only look
608+
// at the topmost impl (we don't even consider the trait
609+
// itself) for the definition -- so we can fail to find a
610+
// definition of the type even if it exists.
611+
return None;
612+
}
613+
}
614+
}
615+
Some(candidate)
616+
});
617+
618+
match possible_candidate {
572619
Some(candidate) => {
573620
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
574621
Ok(ProjectedTy::Progress(ty, obligations))
@@ -744,28 +791,6 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
744791

745792
match vtable {
746793
super::VtableImpl(data) => {
747-
if data.substs.types.needs_infer() {
748-
let assoc_ty_opt = get_impl_item_or_default(selcx.tcx(), data.impl_def_id, |cand| {
749-
if let &ty::TypeTraitItem(ref assoc_ty) = cand {
750-
if assoc_ty.name == obligation.predicate.item_name {
751-
return Some(assoc_ty.defaultness);
752-
}
753-
}
754-
None
755-
});
756-
757-
if let Some((defaultness, source)) = assoc_ty_opt {
758-
if !source.is_from_trait() && defaultness == hir::Defaultness::Default {
759-
// FIXME: is it OK to not mark as ambiguous?
760-
return Ok(());
761-
}
762-
} else {
763-
selcx.tcx().sess.span_bug(obligation.cause.span,
764-
&format!("No associated type for {:?}",
765-
obligation_trait_ref));
766-
}
767-
}
768-
769794
debug!("assemble_candidates_from_impls: impl candidate {:?}",
770795
data);
771796

@@ -967,29 +992,59 @@ fn confirm_impl_candidate<'cx,'tcx>(
967992
{
968993
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
969994

970-
get_impl_item_or_default(selcx.tcx(), impl_def_id, |cand| {
971-
if let &ty::TypeTraitItem(ref assoc_ty) = cand {
972-
if assoc_ty.name == obligation.predicate.item_name {
973-
if let Some(ty) = assoc_ty.ty {
974-
return Some(ty)
975-
} else {
976-
// This means that the impl is missing a definition for the
977-
// associated type. This error will be reported by the type
978-
// checker method `check_impl_items_against_trait`, so here
979-
// we just return TyError.
980-
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
981-
assoc_ty.name,
982-
obligation.predicate.trait_ref);
983-
return Some(selcx.tcx().types.err);
995+
let tcx = selcx.tcx();
996+
let trait_ref = obligation.predicate.trait_ref;
997+
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name);
998+
999+
match assoc_ty {
1000+
Some(node_item) => {
1001+
let ty = node_item.item.ty.unwrap_or_else(|| {
1002+
// This means that the impl is missing a definition for the
1003+
// associated type. This error will be reported by the type
1004+
// checker method `check_impl_items_against_trait`, so here we
1005+
// just return TyError.
1006+
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
1007+
node_item.item.name,
1008+
obligation.predicate.trait_ref);
1009+
tcx.types.err
1010+
});
1011+
let substs = translate_substs(tcx, impl_def_id, substs, node_item.node);
1012+
(ty.subst(tcx, &substs), nested)
1013+
}
1014+
None => {
1015+
tcx.sess.span_bug(obligation.cause.span,
1016+
&format!("No associated type for {:?}", trait_ref));
1017+
}
1018+
}
1019+
}
1020+
1021+
/// Locate the definition of an associated type in the specialization hierarchy,
1022+
/// starting from the given impl.
1023+
///
1024+
/// Based on the "projection mode", this lookup may in fact only examine the
1025+
/// topmost impl. See the comments for `ProjectionMode` for more details.
1026+
fn assoc_ty_def<'cx, 'tcx>(selcx: &SelectionContext<'cx, 'tcx>, impl_def_id: DefId, assoc_ty_name: ast::Name)
1027+
-> Option<specialization_graph::NodeItem<Rc<ty::AssociatedType<'tcx>>>>
1028+
{
1029+
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
1030+
1031+
if selcx.projection_mode().topmost() {
1032+
let impl_node = specialization_graph::Node::Impl(impl_def_id);
1033+
for item in impl_node.items(selcx.tcx()) {
1034+
if let ty::TypeTraitItem(assoc_ty) = item {
1035+
if assoc_ty.name == assoc_ty_name {
1036+
return Some(specialization_graph::NodeItem {
1037+
node: specialization_graph::Node::Impl(impl_def_id),
1038+
item: assoc_ty,
1039+
});
9841040
}
9851041
}
9861042
}
9871043
None
988-
}).map(|(ty, source)| {
989-
(ty.subst(selcx.tcx(), &source.translate_substs(selcx.tcx(), substs)), nested)
990-
}).unwrap_or_else(|| {
991-
selcx.tcx().sess.span_bug(obligation.cause.span,
992-
&format!("No associated type for {:?}",
993-
obligation.predicate.trait_ref));
994-
})
1044+
} else {
1045+
selcx.tcx().lookup_trait_def(trait_def_id)
1046+
.ancestors(impl_def_id)
1047+
.type_defs(selcx.tcx(), assoc_ty_name)
1048+
.next()
1049+
}
9951050
}

0 commit comments

Comments
 (0)
Please sign in to comment.