Auto merge of #30652 - aturon:specialization, r=nikomatsakis

Implement RFC 1210: impl specialization

This PR implements [impl specialization](https://github.com/rust-lang/rfcs/pull/1210),
carefully following the proposal laid out in the RFC.

The implementation covers the bulk of the RFC. The remaining gaps I know of are:

- no checking for lifetime-dependent specialization (a soundness hole);
- no `default impl` yet;
- no support for `default` with associated consts;

I plan to cover these gaps in follow-up PRs, as per @nikomatsakis's preference.

The basic strategy is to build up a *specialization graph* during
coherence checking. Insertion into the graph locates the right place
to put an impl in the specialization hierarchy; if there is no right
place (due to partial overlap but no containment), you get an overlap
error. Specialization is consulted when selecting an impl (of course),
and the graph is consulted when propagating defaults down the
specialization hierarchy.

You might expect that the specialization graph would be used during
selection -- i.e., when actually performing specialization. This is
not done for two reasons:

- It's merely an optimization: given a set of candidates that apply,
  we can determine the most specialized one by comparing them directly
  for specialization, rather than consulting the graph. Given that we
  also cache the results of selection, the benefit of this
  optimization is questionable.

- To build the specialization graph in the first place, we need to use
  selection (because we need to determine whether one impl specializes
  another). Dealing with this reentrancy would require some additional
  mode switch for selection. Given that there seems to be no strong
  reason to use the graph anyway, we stick with a simpler approach in
  selection, and use the graph only for propagating default
  implementations.

Trait impl selection can succeed even when multiple impls can apply,
as long as they are part of the same specialization family. In that
case, it returns a *single* impl on success -- this is the most
specialized impl *known* to apply. However, if there are any inference
variables in play, the returned impl may not be the actual impl we
will use at trans time. Thus, we take special care to avoid projecting
associated types unless either (1) the associated type does not use
`default` and thus cannot be overridden or (2) all input types are
known concretely.

r? @nikomatsakis
This commit is contained in:
bors 2016-03-14 17:55:41 -07:00
commit 9ca75619dc
115 changed files with 3033 additions and 624 deletions

View file

@ -51,7 +51,7 @@ could invalidate work done for other items. So, for example:
not shared state, because if it changes it does not itself
invalidate other functions (though it may be that it causes new
monomorphizations to occur, but that's handled independently).
Put another way: if the HIR for an item changes, we are going to
recompile that item for sure. But we need the dep tracking map to tell
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:
| ^
| |
+---------------------------------+ // added by `visit_all_items_in_krate`
In particular, the edge from `Hir(X)` to `ItemSignature(X)` is only
present because we called `read` ourselves when entering the `ItemSignature(X)`
task.
@ -273,8 +273,8 @@ should not exist. In contrast, using the memoized helper, you get:
... -> MapVariant(key) -> A
|
+----------> B
which is much cleaner.
which is much cleaner.
**Be aware though that the closure is executed with `MapVariant(key)`
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'
This will dump out all the nodes that lead from `Hir(foo)` to
`TypeckItemBody(bar)`, from which you can (hopefully) see the source
of the erroneous edge.

View file

@ -25,6 +25,7 @@ use middle::expr_use_visitor as euv;
use middle::infer;
use middle::mem_categorization::{cmt};
use middle::pat_util::*;
use middle::traits::ProjectionMode;
use middle::ty::*;
use middle::ty;
use std::cmp::Ordering;
@ -1101,7 +1102,8 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
//FIXME: (@jroesch) this code should be floated up as well
let infcx = infer::new_infer_ctxt(cx.tcx,
&cx.tcx.tables,
Some(cx.param_env.clone()));
Some(cx.param_env.clone()),
ProjectionMode::AnyFinal);
if infcx.type_moves_by_default(pat_ty, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
}
@ -1133,7 +1135,8 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
let infcx = infer::new_infer_ctxt(cx.tcx,
&cx.tcx.tables,
Some(checker.cx.param_env.clone()));
Some(checker.cx.param_env.clone()),
ProjectionMode::AnyFinal);
let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
visitor.walk_expr(guard);

View file

@ -24,6 +24,7 @@ use middle::def_id::DefId;
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::util::IntTypeExt;
use middle::traits::ProjectionMode;
use middle::astconv_util::ast_ty_to_prim_ty;
use util::nodemap::NodeMap;
@ -1049,7 +1050,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
trait_ref);
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
@ -1067,6 +1068,11 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
}
};
// NOTE: this code does not currently account for specialization, but when
// it does so, it should hook into the ProjectionMode to determine when the
// constant should resolve; this will also require plumbing through to this
// function whether we are in "trans mode" to pick the right ProjectionMode
// when constructing the inference context above.
match selection {
traits::VtableImpl(ref impl_data) => {
match tcx.associated_consts(impl_data.impl_def_id)

View file

@ -176,6 +176,7 @@ pub trait CrateStore<'tcx> : Any {
-> Option<ty::adjustment::CustomCoerceUnsized>;
fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>>;
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
// trait/impl-item info
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
@ -346,6 +347,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
{ unimplemented!() }
fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> { unimplemented!() }
fn impl_parent(&self, def: DefId) -> Option<DefId> { unimplemented!() }
// trait/impl-item info
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)

View file

@ -27,7 +27,7 @@ use middle::region::CodeExtent;
use middle::subst;
use middle::subst::Substs;
use middle::subst::Subst;
use middle::traits;
use middle::traits::{self, ProjectionMode};
use middle::ty::adjustment;
use middle::ty::{TyVid, IntVid, FloatVid};
use middle::ty::{self, Ty, TyCtxt};
@ -99,6 +99,11 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
// directly.
normalize: bool,
// Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the
// documentation for `ProjectionMode`.
projection_mode: ProjectionMode,
err_count_on_creation: usize,
}
@ -354,7 +359,8 @@ pub fn fixup_err_to_string(f: FixupError) -> String {
pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>,
param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>)
param_env: Option<ty::ParameterEnvironment<'a, 'tcx>>,
projection_mode: ProjectionMode)
-> InferCtxt<'a, 'tcx> {
InferCtxt {
tcx: tcx,
@ -366,14 +372,16 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: false,
projection_mode: projection_mode,
err_count_on_creation: tcx.sess.err_count()
}
}
pub fn normalizing_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>,
tables: &'a RefCell<ty::Tables<'tcx>>)
tables: &'a RefCell<ty::Tables<'tcx>>,
projection_mode: ProjectionMode)
-> InferCtxt<'a, 'tcx> {
let mut infcx = new_infer_ctxt(tcx, tables, None);
let mut infcx = new_infer_ctxt(tcx, tables, None, projection_mode);
infcx.normalize = true;
infcx
}
@ -514,6 +522,7 @@ pub struct CombinedSnapshot {
region_vars_snapshot: RegionSnapshot,
}
// NOTE: Callable from trans only!
pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T
where T : TypeFoldable<'tcx>
{
@ -525,7 +534,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &TyCtxt<'tcx>, value: &T) -> T
return value;
}
let infcx = new_infer_ctxt(tcx, &tcx.tables, None);
let infcx = new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Any);
let mut selcx = traits::SelectionContext::new(&infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
@ -593,6 +602,10 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn projection_mode(&self) -> ProjectionMode {
self.projection_mode
}
pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
}
@ -1025,8 +1038,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
substs: &mut Substs<'tcx>,
defs: &[ty::TypeParameterDef<'tcx>]) {
let mut vars = Vec::with_capacity(defs.len());
for def in defs.iter() {
let default = def.default.map(|default| {
type_variable::Default {
@ -1038,7 +1049,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let ty_var = self.next_ty_var_with_default(default);
substs.types.push(space, ty_var);
vars.push(ty_var)
}
}

View file

@ -160,6 +160,15 @@ impl<'tcx> Substs<'tcx> {
Substs { types: types, regions: regions }
}
pub fn with_method_from_subst(self, other: &Substs<'tcx>) -> Substs<'tcx> {
let Substs { types, regions } = self;
let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace));
let regions = regions.map(|r| {
r.with_slice(FnSpace, other.regions().get_slice(FnSpace))
});
Substs { types: types, regions: regions }
}
/// Creates a trait-ref out of this substs, ignoring the FnSpace substs
pub fn to_trait_ref(&self, tcx: &TyCtxt<'tcx>, trait_id: DefId)
-> ty::TraitRef<'tcx> {

View file

@ -428,3 +428,43 @@ We used to try and draw finer-grained distinctions, but that led to a
serious of annoying and weird bugs like #22019 and #18290. This simple
rule seems to be pretty clearly safe and also still retains a very
high hit rate (~95% when compiling rustc).
# Specialization
Defined in the `specialize` module.
The basic strategy is to build up a *specialization graph* during
coherence checking. Insertion into the graph locates the right place
to put an impl in the specialization hierarchy; if there is no right
place (due to partial overlap but no containment), you get an overlap
error. Specialization is consulted when selecting an impl (of course),
and the graph is consulted when propagating defaults down the
specialization hierarchy.
You might expect that the specialization graph would be used during
selection -- i.e., when actually performing specialization. This is
not done for two reasons:
- It's merely an optimization: given a set of candidates that apply,
we can determine the most specialized one by comparing them directly
for specialization, rather than consulting the graph. Given that we
also cache the results of selection, the benefit of this
optimization is questionable.
- To build the specialization graph in the first place, we need to use
selection (because we need to determine whether one impl specializes
another). Dealing with this reentrancy would require some additional
mode switch for selection. Given that there seems to be no strong
reason to use the graph anyway, we stick with a simpler approach in
selection, and use the graph only for propagating default
implementations.
Trait impl selection can succeed even when multiple impls can apply,
as long as they are part of the same specialization family. In that
case, it returns a *single* impl on success -- this is the most
specialized impl *known* to apply. However, if there are any inference
variables in play, the returned impl may not be the actual impl we
will use at trans time. Thus, we take special care to avoid projecting
associated types unless either (1) the associated type does not use
`default` and thus cannot be overridden or (2) all input types are
known concretely.

View file

@ -10,8 +10,7 @@
//! See `README.md` for high-level documentation
use super::{SelectionContext};
use super::{Obligation, ObligationCause};
use super::{SelectionContext, Obligation, ObligationCause};
use middle::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
@ -23,8 +22,8 @@ use syntax::codemap::DUMMY_SP;
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
/// If there are types that satisfy both impls, returns an `ImplTy`
/// with those types substituted (by updating the given `infcx`)
/// If there are types that satisfy both impls, returns a suitably-freshened
/// `ImplHeader` with those types substituted
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
impl1_def_id: DefId,
impl2_def_id: DefId)

View file

@ -36,20 +36,18 @@ pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls;
pub use self::coherence::OrphanCheckErr;
pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
pub use self::project::MismatchedProjectionTypes;
pub use self::project::normalize;
pub use self::project::Normalized;
pub use self::project::{MismatchedProjectionTypes, ProjectionMode};
pub use self::project::{normalize, Normalized};
pub use self::object_safety::is_object_safe;
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::object_safety_violations;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::is_vtable_safe_method;
pub use self::select::EvaluationCache;
pub use self::select::SelectionContext;
pub use self::select::SelectionCache;
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
pub use self::specialize::{Overlap, specialization_graph, specializes, translate_substs};
pub use self::util::elaborate_predicates;
pub use self::util::get_vtable_index_of_object_method;
pub use self::util::trait_ref_for_builtin_bound;
@ -67,6 +65,7 @@ mod fulfill;
mod project;
mod object_safety;
mod select;
mod specialize;
mod structural_impls;
mod util;
@ -434,7 +433,10 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env));
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(elaborated_env),
ProjectionMode::AnyFinal);
let predicates = match fully_normalize(&infcx,
cause,
&infcx.parameter_environment.caller_bounds) {

View file

@ -12,6 +12,8 @@
use super::elaborate_predicates;
use super::report_overflow_error;
use super::specialization_graph;
use super::translate_substs;
use super::Obligation;
use super::ObligationCause;
use super::PredicateObligation;
@ -21,13 +23,103 @@ use super::VtableClosureData;
use super::VtableImplData;
use super::util;
use middle::def_id::DefId;
use middle::infer::{self, TypeOrigin};
use middle::subst::Subst;
use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
use middle::ty::fold::{TypeFoldable, TypeFolder};
use syntax::parse::token;
use syntax::ast;
use util::common::FN_OUTPUT_NAME;
use std::rc::Rc;
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ProjectionMode {
/// FIXME (#32205)
/// At coherence-checking time, we're still constructing the
/// specialization graph, and thus we only project project
/// non-`default` associated types that are defined directly in
/// the applicable impl. (This behavior should be improved over
/// time, to allow for successful projections modulo cycles
/// between different impls).
///
/// Here's an example that will fail due to the restriction:
///
/// ```
/// trait Assoc {
/// type Output;
/// }
///
/// impl<T> Assoc for T {
/// type Output = bool;
/// }
///
/// impl Assoc for u8 {} // <- inherits the non-default type from above
///
/// trait Foo {}
/// impl Foo for u32 {}
/// impl Foo for <u8 as Assoc>::Output {} // <- this projection will fail
/// ```
///
/// The projection would succeed if `Output` had been defined
/// directly in the impl for `u8`.
Topmost,
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for
/// soundness of specialization. However, we *could* allow
/// projections in fully-monomorphic cases. We choose not to,
/// because we prefer for `default type` to force the type
/// definition to be treated abstractly by any consumers of the
/// impl. Concretely, that means that the following example will
/// fail to compile:
///
/// ```
/// trait Assoc {
/// type Output;
/// }
///
/// impl<T> Assoc for T {
/// default type Output = bool;
/// }
///
/// fn main() {
/// let <() as Assoc>::Output = true;
/// }
AnyFinal,
/// At trans time, all projections will succeed.
Any,
}
impl ProjectionMode {
pub fn is_topmost(&self) -> bool {
match *self {
ProjectionMode::Topmost => true,
_ => false,
}
}
pub fn is_any_final(&self) -> bool {
match *self {
ProjectionMode::AnyFinal => true,
_ => false,
}
}
pub fn is_any(&self) -> bool {
match *self {
ProjectionMode::Any => true,
_ => false,
}
}
}
pub type PolyProjectionObligation<'tcx> =
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
@ -566,7 +658,76 @@ fn project_type<'cx,'tcx>(
assert!(candidates.vec.len() <= 1);
match candidates.vec.pop() {
let possible_candidate = candidates.vec.pop().and_then(|candidate| {
// In Any (i.e. trans) mode, all projections succeed;
// otherwise, we need to be sensitive to `default` and
// specialization.
if !selcx.projection_mode().is_any() {
if let ProjectionTyCandidate::Impl(ref impl_data) = candidate {
if let Some(node_item) = assoc_ty_def(selcx,
impl_data.impl_def_id,
obligation.predicate.item_name) {
if node_item.node.is_from_trait() {
if node_item.item.ty.is_some() {
// If the associated type has a default from the
// trait, that should be considered `default` and
// hence not projected.
//
// Note, however, that we allow a projection from
// the trait specifically in the case that the trait
// does *not* give a default. This is purely to
// avoid spurious errors: the situation can only
// arise when *no* impl in the specialization chain
// has provided a definition for the type. When we
// confirm the candidate, we'll turn the projection
// into a TyError, since the actual error will be
// reported in `check_impl_items_against_trait`.
return None;
}
} else if node_item.item.defaultness.is_default() {
return None;
}
} else {
// Normally this situation could only arise througha
// compiler bug, but at coherence-checking time we only look
// at the topmost impl (we don't even consider the trait
// itself) for the definition -- so we can fail to find a
// definition of the type even if it exists.
// For now, we just unconditionally ICE, because otherwise,
// examples like the following will succeed:
//
// ```
// trait Assoc {
// type Output;
// }
//
// impl<T> Assoc for T {
// default type Output = bool;
// }
//
// impl Assoc for u8 {}
// impl Assoc for u16 {}
//
// trait Foo {}
// impl Foo for <u8 as Assoc>::Output {}
// impl Foo for <u16 as Assoc>::Output {}
// return None;
// }
// ```
//
// The essential problem here is that the projection fails,
// leaving two unnormalized types, which appear not to unify
// -- so the overlap check succeeds, when it should fail.
selcx.tcx().sess.bug("Tried to project an inherited associated type during \
coherence checking, which is currently not supported.");
}
}
}
Some(candidate)
});
match possible_candidate {
Some(candidate) => {
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
Ok(ProjectedTy::Progress(ty, obligations))
@ -941,43 +1102,63 @@ fn confirm_impl_candidate<'cx,'tcx>(
impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
// there don't seem to be nicer accessors to these:
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
// Look for the associated type in the impl
for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
if assoc_ty.name == obligation.predicate.item_name {
return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs),
impl_vtable.nested);
}
let tcx = selcx.tcx();
let trait_ref = obligation.predicate.trait_ref;
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name);
match assoc_ty {
Some(node_item) => {
let ty = node_item.item.ty.unwrap_or_else(|| {
// This means that the impl is missing a definition for the
// associated type. This error will be reported by the type
// checker method `check_impl_items_against_trait`, so here we
// just return TyError.
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
node_item.item.name,
obligation.predicate.trait_ref);
tcx.types.err
});
let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node);
(ty.subst(tcx, substs), nested)
}
None => {
tcx.sess.span_bug(obligation.cause.span,
&format!("No associated type for {:?}", trait_ref));
}
}
}
// It is not in the impl - get the default from the trait.
let trait_ref = obligation.predicate.trait_ref;
for trait_item in selcx.tcx().trait_items(trait_ref.def_id).iter() {
if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {
if assoc_ty.name == obligation.predicate.item_name {
if let Some(ty) = assoc_ty.ty {
return (ty.subst(selcx.tcx(), trait_ref.substs),
impl_vtable.nested);
} else {
// This means that the impl is missing a
// definition for the associated type. This error
// ought to be reported by the type checker method
// `check_impl_items_against_trait`, so here we
// just return TyError.
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.name,
trait_ref);
return (selcx.tcx().types.err, vec!());
/// Locate the definition of an associated type in the specialization hierarchy,
/// starting from the given impl.
///
/// Based on the "projection mode", this lookup may in fact only examine the
/// topmost impl. See the comments for `ProjectionMode` for more details.
fn assoc_ty_def<'cx, 'tcx>(selcx: &SelectionContext<'cx, 'tcx>,
impl_def_id: DefId,
assoc_ty_name: ast::Name)
-> Option<specialization_graph::NodeItem<Rc<ty::AssociatedType<'tcx>>>>
{
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
if selcx.projection_mode().is_topmost() {
let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(selcx.tcx()) {
if let ty::TypeTraitItem(assoc_ty) = item {
if assoc_ty.name == assoc_ty_name {
return Some(specialization_graph::NodeItem {
node: specialization_graph::Node::Impl(impl_def_id),
item: assoc_ty,
});
}
}
}
None
} else {
selcx.tcx().lookup_trait_def(trait_def_id)
.ancestors(impl_def_id)
.type_defs(selcx.tcx(), assoc_ty_name)
.next()
}
selcx.tcx().sess.span_bug(obligation.cause.span,
&format!("No associated type for {:?}",
trait_ref));
}

View file

@ -25,6 +25,7 @@ use super::report_overflow_error;
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
use super::{ObjectCastObligation, Obligation};
use super::ProjectionMode;
use super::TraitNotObjectSafe;
use super::Selection;
use super::SelectionResult;
@ -40,6 +41,7 @@ use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin};
use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use middle::traits;
use middle::ty::fast_reject;
use middle::ty::relate::TypeRelation;
@ -75,7 +77,6 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
/// other words, we consider `$0 : Bar` to be unimplemented if
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
intercrate: bool,
}
@ -224,6 +225,12 @@ struct SelectionCandidateSet<'tcx> {
ambiguous: bool,
}
#[derive(PartialEq,Eq,Debug,Clone)]
struct EvaluatedCandidate<'tcx> {
candidate: SelectionCandidate<'tcx>,
evaluation: EvaluationResult,
}
enum BuiltinBoundConditions<'tcx> {
If(ty::Binder<Vec<Ty<'tcx>>>),
ParameterBuiltin,
@ -251,8 +258,7 @@ pub struct EvaluationCache<'tcx> {
}
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>)
-> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx: infcx,
freshener: infcx.freshener(),
@ -260,8 +266,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>)
-> SelectionContext<'cx, 'tcx> {
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx: infcx,
freshener: infcx.freshener(),
@ -285,6 +290,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx
}
pub fn projection_mode(&self) -> ProjectionMode {
self.infcx.projection_mode()
}
///////////////////////////////////////////////////////////////////////////
// Selection
//
@ -558,7 +567,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// this crate, perhaps the type would be unified with
// something from another crate that does provide an impl.
//
// In intracrate mode, we must still be conservative. The reason is
// In intra mode, we must still be conservative. The reason is
// that we want to avoid cycles. Imagine an impl like:
//
// impl<T:Eq> Eq for Vec<T>
@ -746,6 +755,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidate
}
// Treat negative impls as unimplemented
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
if let ImplCandidate(def_id) = candidate {
if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) {
return Err(Unimplemented)
}
}
Ok(Some(candidate))
}
fn candidate_from_obligation_no_cache<'o>(&mut self,
stack: &TraitObligationStack<'o, 'tcx>)
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
@ -762,7 +782,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if !self.is_knowable(stack) {
debug!("intercrate not knowable");
debug!("coherence stage: not knowable");
return Ok(None);
}
@ -803,12 +823,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// we were to winnow, we'd wind up with zero candidates.
// Instead, we select the right impl now but report `Bar does
// not implement Clone`.
if candidates.len() > 1 {
candidates.retain(|c| self.evaluate_candidate(stack, c).may_apply())
if candidates.len() == 1 {
return self.filter_negative_impls(candidates.pop().unwrap());
}
// If there are STILL multiple candidate, we can further reduce
// the list by dropping duplicates.
// Winnow, but record the exact outcome of evaluation, which
// is needed for specialization.
let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
let eval = self.evaluate_candidate(stack, &c);
if eval.may_apply() {
Some(EvaluatedCandidate {
candidate: c,
evaluation: eval,
})
} else {
None
}
}).collect();
// If there are STILL multiple candidate, we can further
// reduce the list by dropping duplicates -- including
// resolving specializations.
if candidates.len() > 1 {
let mut i = 0;
while i < candidates.len() {
@ -836,8 +871,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Ok(None);
}
// If there are *NO* candidates, that there are no impls --
// If there are *NO* candidates, then there are no impls --
// that we know of, anyway. Note that in the case where there
// are unbound type variables within the obligation, it might
// be the case that you could still satisfy the obligation
@ -851,19 +885,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// Just one candidate left.
let candidate = candidates.pop().unwrap();
match candidate {
ImplCandidate(def_id) => {
match self.tcx().trait_impl_polarity(def_id) {
Some(hir::ImplPolarity::Negative) => return Err(Unimplemented),
_ => {}
}
}
_ => {}
}
Ok(Some(candidate))
self.filter_negative_impls(candidates.pop().unwrap().candidate)
}
fn is_knowable<'o>(&mut self,
@ -1565,41 +1587,54 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// candidates and prefer where-clause candidates.
///
/// See the comment for "SelectionCandidate" for more details.
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
victim: &SelectionCandidate<'tcx>,
other: &SelectionCandidate<'tcx>)
-> bool
fn candidate_should_be_dropped_in_favor_of<'o>(
&mut self,
victim: &EvaluatedCandidate<'tcx>,
other: &EvaluatedCandidate<'tcx>)
-> bool
{
if victim == other {
if victim.candidate == other.candidate {
return true;
}
match other {
&ObjectCandidate |
&ParamCandidate(_) | &ProjectionCandidate => match victim {
&DefaultImplCandidate(..) => {
match other.candidate {
ObjectCandidate |
ParamCandidate(_) | ProjectionCandidate => match victim.candidate {
DefaultImplCandidate(..) => {
self.tcx().sess.bug(
"default implementations shouldn't be recorded \
when there are other valid candidates");
}
&ImplCandidate(..) |
&ClosureCandidate(..) |
&FnPointerCandidate |
&BuiltinObjectCandidate |
&BuiltinUnsizeCandidate |
&DefaultImplObjectCandidate(..) |
&BuiltinCandidate(..) => {
ImplCandidate(..) |
ClosureCandidate(..) |
FnPointerCandidate |
BuiltinObjectCandidate |
BuiltinUnsizeCandidate |
DefaultImplObjectCandidate(..) |
BuiltinCandidate(..) => {
// We have a where-clause so don't go around looking
// for impls.
true
}
&ObjectCandidate |
&ProjectionCandidate => {
ObjectCandidate |
ProjectionCandidate => {
// Arbitrarily give param candidates priority
// over projection and object candidates.
true
},
&ParamCandidate(..) => false,
ParamCandidate(..) => false,
},
ImplCandidate(other_def) => {
// See if we can toss out `victim` based on specialization.
// This requires us to know *for sure* that the `other` impl applies
// i.e. EvaluatedToOk:
if other.evaluation == EvaluatedToOk {
if let ImplCandidate(victim_def) = victim.candidate {
return traits::specializes(self.tcx(), other_def, victim_def);
}
}
false
},
_ => false
}

View file

@ -0,0 +1,229 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Logic and data structures related to impl specialization, explained in
// greater detail below.
//
// At the moment, this implementation support only the simple "chain" rule:
// If any two impls overlap, one must be a strict subset of the other.
//
// See traits/README.md for a bit more detail on how specialization
// fits together with the rest of the trait machinery.
use super::{SelectionContext, FulfillmentContext};
use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig};
use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::infer::{self, InferCtxt, TypeOrigin};
use middle::region;
use middle::subst::{Subst, Substs};
use middle::traits::{self, ProjectionMode, ObligationCause, Normalized};
use middle::ty::{self, TyCtxt};
use syntax::codemap::DUMMY_SP;
pub mod specialization_graph;
/// Information pertinent to an overlapping impl error.
pub struct Overlap<'a, 'tcx: 'a> {
pub in_context: InferCtxt<'a, 'tcx>,
pub with_impl: DefId,
pub on_trait_ref: ty::TraitRef<'tcx>,
}
/// Given a subst for the requested impl, translate it to a subst
/// appropriate for the actual item definition (whether it be in that impl,
/// a parent impl, or the trait).
/// When we have selected one impl, but are actually using item definitions from
/// a parent impl providing a default, we need a way to translate between the
/// type parameters of the two impls. Here the `source_impl` is the one we've
/// selected, and `source_substs` is a substitution of its generics (and
/// possibly some relevant `FnSpace` variables as well). And `target_node` is
/// the impl/trait we're actually going to get the definition from. The resulting
/// substitution will map from `target_node`'s generics to `source_impl`'s
/// generics as instantiated by `source_subst`.
///
/// For example, consider the following scenario:
///
/// ```rust
/// trait Foo { ... }
/// impl<T, U> Foo for (T, U) { ... } // target impl
/// impl<V> Foo for (V, V) { ... } // source impl
/// ```
///
/// Suppose we have selected "source impl" with `V` instantiated with `u32`.
/// This function will produce a substitution with `T` and `U` both mapping to `u32`.
///
/// Where clauses add some trickiness here, because they can be used to "define"
/// an argument indirectly:
///
/// ```rust
/// impl<'a, I, T: 'a> Iterator for Cloned<I>
/// where I: Iterator<Item=&'a T>, T: Clone
/// ```
///
/// In a case like this, the substitution for `T` is determined indirectly,
/// through associated type projection. We deal with such cases by using
/// *fulfillment* to relate the two impls, requiring that all projections are
/// resolved.
pub fn translate_substs<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
source_impl: DefId,
source_substs: &'tcx Substs<'tcx>,
target_node: specialization_graph::Node)
-> &'tcx Substs<'tcx> {
let source_trait_ref = infcx.tcx
.impl_trait_ref(source_impl)
.unwrap()
.subst(infcx.tcx, &source_substs);
// translate the Self and TyParam parts of the substitution, since those
// vary across impls
let target_substs = match target_node {
specialization_graph::Node::Impl(target_impl) => {
// no need to translate if we're targetting the impl we started with
if source_impl == target_impl {
return source_substs;
}
fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| {
infcx.tcx
.sess
.bug("When translating substitutions for specialization, the expected \
specializaiton failed to hold")
})
}
specialization_graph::Node::Trait(..) => source_trait_ref.substs.clone(),
};
// retain erasure mode
// NB: this must happen before inheriting method generics below
let target_substs = if source_substs.regions.is_erased() {
target_substs.erase_regions()
} else {
target_substs
};
// directly inherent the method generics, since those do not vary across impls
infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs))
}
/// Is impl1 a specialization of impl2?
///
/// Specialization is determined by the sets of types to which the impls apply;
/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
/// to.
pub fn specializes(tcx: &TyCtxt, impl1_def_id: DefId, impl2_def_id: DefId) -> bool {
// The feature gate should prevent introducing new specializations, but not
// taking advantage of upstream ones.
if !tcx.sess.features.borrow().specialization &&
(impl1_def_id.is_local() || impl2_def_id.is_local()) {
return false;
}
// We determine whether there's a subset relationship by:
//
// - skolemizing impl1,
// - assuming the where clauses for impl1,
// - instantiating impl2 with fresh inference variables,
// - unifying,
// - attempting to prove the where clauses for impl2
//
// The last three steps are encapsulated in `fulfill_implication`.
//
// See RFC 1210 for more details and justification.
// Currently we do not allow e.g. a negative impl to specialize a positive one
if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) {
return false;
}
let mut infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Topmost);
// create a parameter environment corresponding to a (skolemized) instantiation of impl1
let scheme = tcx.lookup_item_type(impl1_def_id);
let predicates = tcx.lookup_predicates(impl1_def_id);
let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
&scheme.generics,
&predicates,
region::DUMMY_CODE_EXTENT);
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
.unwrap()
.subst(tcx, &penv.free_substs);
// Normalize the trait reference, adding any obligations that arise into the impl1 assumptions
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
let selcx = &mut SelectionContext::new(&infcx);
traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
};
penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
// Install the parameter environment, taking the predicates of impl1 as assumptions:
infcx.parameter_environment = penv;
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
}
/// Attempt to fulfill all obligations of `target_impl` after unification with
/// `source_trait_ref`. If successful, returns a substitution for *all* the
/// generics of `target_impl`, including both those needed to unify with
/// `source_trait_ref` and those whose identity is determined via a where
/// clause in the impl.
fn fulfill_implication<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
source_trait_ref: ty::TraitRef<'tcx>,
target_impl: DefId)
-> Result<Substs<'tcx>, ()> {
infcx.commit_if_ok(|_| {
let selcx = &mut SelectionContext::new(&infcx);
let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl);
let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx,
target_impl,
&target_substs);
// do the impls unify? If not, no specialization.
if let Err(_) = infer::mk_eq_trait_refs(&infcx,
true,
TypeOrigin::Misc(DUMMY_SP),
source_trait_ref,
target_trait_ref) {
debug!("fulfill_implication: {:?} does not unify with {:?}",
source_trait_ref,
target_trait_ref);
return Err(());
}
// attempt to prove all of the predicates for impl2 given those for impl1
// (which are packed up in penv)
let mut fulfill_cx = FulfillmentContext::new();
for oblig in obligations.into_iter() {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
if let Err(errors) = infer::drain_fulfillment_cx(&infcx, &mut fulfill_cx, &()) {
// no dice!
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
{:?}",
source_trait_ref,
target_trait_ref,
errors,
infcx.parameter_environment.caller_bounds);
Err(())
} else {
debug!("fulfill_implication: an impl for {:?} specializes {:?}",
source_trait_ref,
target_trait_ref);
// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_type_vars_if_possible(&target_substs))
}
})
}

View file

@ -0,0 +1,393 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cell;
use std::rc::Rc;
use super::{Overlap, specializes};
use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::infer;
use middle::traits::{self, ProjectionMode};
use middle::ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
use syntax::ast::Name;
use util::nodemap::DefIdMap;
/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction, which implicitly checks for overlapping impls (i.e., impls
/// that overlap but where neither specializes the other -- an artifact of the
/// simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
/// parents of a given specializing impl, which is needed for extracting
/// default items amongst other thigns. In the simple "chain" rule, every impl
/// has at most one parent.
pub struct Graph {
// all impls have a parent; the "root" impls have as their parent the def_id
// of the trait
parent: DefIdMap<DefId>,
// the "root" impls are found by looking up the trait's def_id.
children: DefIdMap<Vec<DefId>>,
}
impl Graph {
pub fn new() -> Graph {
Graph {
parent: Default::default(),
children: Default::default(),
}
}
/// Insert a local impl into the specialization graph. If an existing impl
/// conflicts with it (has overlap, but neither specializes the other),
/// information about the area of overlap is returned in the `Err`.
pub fn insert<'a, 'tcx>(&mut self,
tcx: &'a TyCtxt<'tcx>,
impl_def_id: DefId)
-> Result<(), Overlap<'a, 'tcx>> {
assert!(impl_def_id.is_local());
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_def_id = trait_ref.def_id;
debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
impl_def_id, trait_ref);
// if the reference itself contains an earlier error (e.g., due to a
// resolution failure), then we just insert the impl at the top level of
// the graph and claim that there's no overlap (in order to supress
// bogus errors).
if trait_ref.references_error() {
debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \
impl_def_id={:?}, trait_def_id={:?}",
trait_ref, impl_def_id, trait_def_id);
self.parent.insert(impl_def_id, trait_def_id);
self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id);
return Ok(());
}
let mut parent = trait_def_id;
// Ugly hack around borrowck limitations. Assigned only in the case
// where we bump downward an existing node in the graph.
let child_to_insert;
'descend: loop {
let mut possible_siblings = self.children.entry(parent).or_insert(vec![]);
for slot in possible_siblings.iter_mut() {
let possible_sibling = *slot;
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Topmost);
let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id);
if let Some(impl_header) = overlap {
let le = specializes(tcx, impl_def_id, possible_sibling);
let ge = specializes(tcx, possible_sibling, impl_def_id);
if le && !ge {
debug!("descending as child of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
// the impl specializes possible_sibling
parent = possible_sibling;
continue 'descend;
} else if ge && !le {
debug!("placing as parent of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
// possible_sibling specializes the impl
*slot = impl_def_id;
self.parent.insert(impl_def_id, parent);
self.parent.insert(possible_sibling, impl_def_id);
// we have to defer the insertion, because we can't
// relinquish the borrow of `self.children`
child_to_insert = possible_sibling;
break 'descend;
} else {
// overlap, but no specialization; error out
return Err(Overlap {
with_impl: possible_sibling,
on_trait_ref: impl_header.trait_ref.unwrap(),
in_context: infcx,
});
}
}
}
// no overlap with any potential siblings, so add as a new sibling
debug!("placing as new sibling");
self.parent.insert(impl_def_id, parent);
possible_siblings.push(impl_def_id);
return Ok(());
}
self.children.insert(impl_def_id, vec![child_to_insert]);
Ok(())
}
/// Insert cached metadata mapping from a child impl back to its parent.
pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) {
if self.parent.insert(child, parent).is_some() {
panic!("When recording an impl from the crate store, information about its parent \
was already present.");
}
self.children.entry(parent).or_insert(vec![]).push(child);
}
/// The parent of a given impl, which is the def id of the trait when the
/// impl is a "specialization root".
pub fn parent(&self, child: DefId) -> DefId {
*self.parent.get(&child).unwrap()
}
}
/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
#[derive(Debug, Copy, Clone)]
pub enum Node {
Impl(DefId),
Trait(DefId),
}
impl Node {
pub fn is_from_trait(&self) -> bool {
match *self {
Node::Trait(..) => true,
_ => false,
}
}
/// Iterate over the items defined directly by the given (impl or trait) node.
pub fn items<'a, 'tcx>(&self, tcx: &'a TyCtxt<'tcx>) -> NodeItems<'a, 'tcx> {
match *self {
Node::Impl(impl_def_id) => {
NodeItems::Impl {
tcx: tcx,
items: cell::Ref::map(tcx.impl_items.borrow(),
|impl_items| &impl_items[&impl_def_id]),
idx: 0,
}
}
Node::Trait(trait_def_id) => {
NodeItems::Trait {
items: tcx.trait_items(trait_def_id).clone(),
idx: 0,
}
}
}
}
pub fn def_id(&self) -> DefId {
match *self {
Node::Impl(did) => did,
Node::Trait(did) => did,
}
}
}
/// An iterator over the items defined within a trait or impl.
pub enum NodeItems<'a, 'tcx: 'a> {
Impl {
tcx: &'a TyCtxt<'tcx>,
items: cell::Ref<'a, Vec<ty::ImplOrTraitItemId>>,
idx: usize,
},
Trait {
items: Rc<Vec<ImplOrTraitItem<'tcx>>>,
idx: usize,
},
}
impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> {
type Item = ImplOrTraitItem<'tcx>;
fn next(&mut self) -> Option<ImplOrTraitItem<'tcx>> {
match *self {
NodeItems::Impl { tcx, ref items, ref mut idx } => {
let items_table = tcx.impl_or_trait_items.borrow();
if *idx < items.len() {
let item_def_id = items[*idx].def_id();
let item = items_table[&item_def_id].clone();
*idx += 1;
Some(item)
} else {
None
}
}
NodeItems::Trait { ref items, ref mut idx } => {
if *idx < items.len() {
let item = items[*idx].clone();
*idx += 1;
Some(item)
} else {
None
}
}
}
}
}
pub struct Ancestors<'a, 'tcx: 'a> {
trait_def: &'a TraitDef<'tcx>,
current_source: Option<Node>,
}
impl<'a, 'tcx> Iterator for Ancestors<'a, 'tcx> {
type Item = Node;
fn next(&mut self) -> Option<Node> {
let cur = self.current_source.take();
if let Some(Node::Impl(cur_impl)) = cur {
let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl);
if parent == self.trait_def.def_id() {
self.current_source = Some(Node::Trait(parent));
} else {
self.current_source = Some(Node::Impl(parent));
}
}
cur
}
}
pub struct NodeItem<T> {
pub node: Node,
pub item: T,
}
impl<T> NodeItem<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
NodeItem {
node: self.node,
item: f(self.item),
}
}
}
pub struct TypeDefs<'a, 'tcx: 'a> {
// generally only invoked once or twice, so the box doesn't hurt
iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>> + 'a>,
}
impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> {
type Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
pub struct FnDefs<'a, 'tcx: 'a> {
// generally only invoked once or twice, so the box doesn't hurt
iter: Box<Iterator<Item = NodeItem<Rc<ty::Method<'tcx>>>> + 'a>,
}
impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> {
type Item = NodeItem<Rc<ty::Method<'tcx>>>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
pub struct ConstDefs<'a, 'tcx: 'a> {
// generally only invoked once or twice, so the box doesn't hurt
iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>> + 'a>,
}
impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> {
type Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
impl<'a, 'tcx> Ancestors<'a, 'tcx> {
/// Search the items from the given ancestors, returning each type definition
/// with the given name.
pub fn type_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> TypeDefs<'a, 'tcx> {
let iter = self.flat_map(move |node| {
node.items(tcx)
.filter_map(move |item| {
if let ty::TypeTraitItem(assoc_ty) = item {
if assoc_ty.name == name {
return Some(NodeItem {
node: node,
item: assoc_ty,
});
}
}
None
})
});
TypeDefs { iter: Box::new(iter) }
}
/// Search the items from the given ancestors, returning each fn definition
/// with the given name.
pub fn fn_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> FnDefs<'a, 'tcx> {
let iter = self.flat_map(move |node| {
node.items(tcx)
.filter_map(move |item| {
if let ty::MethodTraitItem(method) = item {
if method.name == name {
return Some(NodeItem {
node: node,
item: method,
});
}
}
None
})
});
FnDefs { iter: Box::new(iter) }
}
/// Search the items from the given ancestors, returning each const
/// definition with the given name.
pub fn const_defs(self, tcx: &'a TyCtxt<'tcx>, name: Name) -> ConstDefs<'a, 'tcx> {
let iter = self.flat_map(move |node| {
node.items(tcx)
.filter_map(move |item| {
if let ty::ConstTraitItem(konst) = item {
if konst.name == name {
return Some(NodeItem {
node: node,
item: konst,
});
}
}
None
})
});
ConstDefs { iter: Box::new(iter) }
}
}
/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors<'a, 'tcx>(trait_def: &'a TraitDef<'tcx>,
start_from_impl: DefId)
-> Ancestors<'a, 'tcx> {
Ancestors {
trait_def: trait_def,
current_source: Some(Node::Impl(start_from_impl)),
}
}

View file

@ -10,13 +10,13 @@
use middle::def_id::DefId;
use middle::infer::InferCtxt;
use middle::subst::Substs;
use middle::subst::{Subst, Substs};
use middle::ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
use syntax::codemap::Span;
use util::common::ErrorReported;
use util::nodemap::FnvHashSet;
use super::{Obligation, ObligationCause, PredicateObligation};
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
struct PredicateSet<'a,'tcx:'a> {
tcx: &'a TyCtxt<'tcx>,
@ -299,6 +299,38 @@ impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
// Other
///////////////////////////////////////////////////////////////////////////
/// Instantiate all bound parameters of the impl with the given substs,
/// returning the resulting trait ref and all obligations that arise.
/// The obligations are closed under normalization.
pub fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
impl_def_id: DefId,
impl_substs: &Substs<'tcx>)
-> (ty::TraitRef<'tcx>,
Vec<PredicateObligation<'tcx>>)
{
let impl_trait_ref =
selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
let impl_trait_ref =
impl_trait_ref.subst(selcx.tcx(), impl_substs);
let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref);
let predicates = selcx.tcx().lookup_predicates(impl_def_id);
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
let Normalized { value: predicates, obligations: normalization_obligations2 } =
super::normalize(selcx, ObligationCause::dummy(), &predicates);
let impl_obligations =
predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
let impl_obligations: Vec<_> =
impl_obligations.into_iter()
.chain(normalization_obligations1)
.chain(normalization_obligations2)
.collect();
(impl_trait_ref, impl_obligations)
}
// determine the `self` type, using fresh variables for all variables
// declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
@ -349,7 +381,6 @@ pub fn trait_ref_for_builtin_bound<'tcx>(
}
}
pub fn predicate_for_trait_ref<'tcx>(
cause: ObligationCause<'tcx>,
trait_ref: ty::TraitRef<'tcx>,

View file

@ -281,6 +281,7 @@ pub struct Method<'tcx> {
pub fty: BareFnTy<'tcx>,
pub explicit_self: ExplicitSelfCategory,
pub vis: hir::Visibility,
pub defaultness: hir::Defaultness,
pub def_id: DefId,
pub container: ImplOrTraitItemContainer,
}
@ -292,16 +293,18 @@ impl<'tcx> Method<'tcx> {
fty: BareFnTy<'tcx>,
explicit_self: ExplicitSelfCategory,
vis: hir::Visibility,
defaultness: hir::Defaultness,
def_id: DefId,
container: ImplOrTraitItemContainer)
-> Method<'tcx> {
Method {
Method {
name: name,
generics: generics,
predicates: predicates,
fty: fty,
explicit_self: explicit_self,
vis: vis,
defaultness: defaultness,
def_id: def_id,
container: container,
}
@ -334,6 +337,7 @@ pub struct AssociatedConst<'tcx> {
pub name: Name,
pub ty: Ty<'tcx>,
pub vis: hir::Visibility,
pub defaultness: hir::Defaultness,
pub def_id: DefId,
pub container: ImplOrTraitItemContainer,
pub has_value: bool
@ -344,6 +348,7 @@ pub struct AssociatedType<'tcx> {
pub name: Name,
pub ty: Option<Ty<'tcx>>,
pub vis: hir::Visibility,
pub defaultness: hir::Defaultness,
pub def_id: DefId,
pub container: ImplOrTraitItemContainer,
}
@ -2451,8 +2456,13 @@ impl<'tcx> TyCtxt<'tcx> {
for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) {
let impl_items = self.sess.cstore.impl_items(impl_def_id);
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
// Record the trait->implementation mapping.
def.record_impl(self, impl_def_id, trait_ref);
if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) {
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
} else {
def.record_remote_impl(self, impl_def_id, trait_ref, trait_id);
}
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
@ -2660,7 +2670,6 @@ impl<'tcx> TyCtxt<'tcx> {
Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
}
pub fn visit_all_items_in_krate<V,F>(&self,
dep_node_fn: F,
visitor: &mut V)
@ -2668,6 +2677,16 @@ impl<'tcx> TyCtxt<'tcx> {
{
dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor);
}
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
/// with the name of the crate containing the impl.
pub fn span_of_impl(&self, impl_did: DefId) -> Result<Span, String> {
if impl_did.is_local() {
let node_id = self.map.as_local_node_id(impl_did).unwrap();
Ok(self.map.span(node_id))
} else {
Err(self.sess.cstore.crate_name(impl_did.krate))
}
}
}
/// The category of explicit self.
@ -2709,28 +2728,4 @@ impl<'tcx> TyCtxt<'tcx> {
Some(d) => f(&d[..])
}
}
pub fn make_substs_for_receiver_types(&self,
trait_ref: &ty::TraitRef<'tcx>,
method: &ty::Method<'tcx>)
-> subst::Substs<'tcx>
{
/*!
* Substitutes the values for the receiver's type parameters
* that are found in method, leaving the method's type parameters
* intact.
*/
let meth_tps: Vec<Ty> =
method.generics.types.get_slice(subst::FnSpace)
.iter()
.map(|def| self.mk_param_from_def(def))
.collect();
let meth_regions: Vec<ty::Region> =
method.generics.regions.get_slice(subst::FnSpace)
.iter()
.map(|def| def.to_early_bound_region())
.collect();
trait_ref.substs.clone().with_method(meth_tps, meth_regions)
}
}

View file

@ -1106,6 +1106,13 @@ impl<'tcx> TyS<'tcx> {
}
}
pub fn has_concrete_skeleton(&self) -> bool {
match self.sty {
TyParam(_) | TyInfer(_) | TyError => false,
_ => true,
}
}
// Returns the type and mutability of *ty.
//
// The parameter `explicit` indicates if this is an *explicit* dereference.

View file

@ -10,9 +10,10 @@
use dep_graph::DepNode;
use middle::def_id::DefId;
use middle::traits::{self, specialization_graph};
use middle::ty;
use middle::ty::fast_reject;
use middle::ty::{Ty, TyCtxt};
use middle::ty::{Ty, TyCtxt, TraitRef};
use std::borrow::{Borrow};
use std::cell::{Cell, Ref, RefCell};
use syntax::ast::Name;
@ -59,6 +60,9 @@ pub struct TraitDef<'tcx> {
/// Blanket impls associated with the trait.
blanket_impls: RefCell<Vec<DefId>>,
/// The specialization order for impls of this trait.
pub specialization_graph: RefCell<traits::specialization_graph::Graph>,
/// Various flags
pub flags: Cell<TraitFlags>
}
@ -78,7 +82,8 @@ impl<'tcx> TraitDef<'tcx> {
associated_type_names: associated_type_names,
nonblanket_impls: RefCell::new(FnvHashMap()),
blanket_impls: RefCell::new(vec![]),
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
}
}
@ -114,11 +119,14 @@ impl<'tcx> TraitDef<'tcx> {
tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id));
}
/// Records a trait-to-implementation mapping.
pub fn record_impl(&self,
tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: ty::TraitRef<'tcx>) {
/// Records a basic trait-to-implementation mapping.
///
/// Returns `true` iff the impl has not previously been recorded.
fn record_impl(&self,
tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>)
-> bool {
debug!("TraitDef::record_impl for {:?}, from {:?}",
self, impl_trait_ref);
@ -134,22 +142,71 @@ impl<'tcx> TraitDef<'tcx> {
impl_trait_ref.self_ty(), false) {
if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
if is.contains(&impl_def_id) {
return // duplicate - skip
return false; // duplicate - skip
}
}
self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
} else {
if self.blanket_impls.borrow().contains(&impl_def_id) {
return // duplicate - skip
return false; // duplicate - skip
}
self.blanket_impls.borrow_mut().push(impl_def_id)
}
true
}
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &TyCtxt<'tcx>, mut f: F) {
self.read_trait_impls(tcx);
/// Records a trait-to-implementation mapping for a crate-local impl.
pub fn record_local_impl(&self,
tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>) {
assert!(impl_def_id.is_local());
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
assert!(was_new);
}
/// Records a trait-to-implementation mapping for a non-local impl.
///
/// The `parent_impl` is the immediately-less-specialized impl, or the
/// trait's def ID if the impl is is not a specialization -- information that
/// should be pulled from the metadata.
pub fn record_remote_impl(&self,
tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>,
parent_impl: DefId) {
assert!(!impl_def_id.is_local());
// if the impl has not previously been recorded
if self.record_impl(tcx, impl_def_id, impl_trait_ref) {
// if the impl is non-local, it's placed directly into the
// specialization graph using parent information drawn from metadata.
self.specialization_graph.borrow_mut()
.record_impl_from_cstore(parent_impl, impl_def_id)
}
}
/// Adds a local impl into the specialization graph, returning an error with
/// overlap information if the impl overlaps but does not specialize an
/// existing impl.
pub fn add_impl_for_specialization<'a>(&self,
tcx: &'a TyCtxt<'tcx>,
impl_def_id: DefId)
-> Result<(), traits::Overlap<'a, 'tcx>> {
assert!(impl_def_id.is_local());
self.specialization_graph.borrow_mut()
.insert(tcx, impl_def_id)
}
pub fn ancestors<'a>(&'a self, of_impl: DefId) -> specialization_graph::Ancestors<'a, 'tcx> {
specialization_graph::ancestors(self, of_impl)
}
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &TyCtxt<'tcx>, mut f: F) {
self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
for &impl_def_id in self.blanket_impls.borrow().iter() {
@ -223,4 +280,3 @@ bitflags! {
const IMPLS_VALID = 1 << 3,
}
}

View file

@ -14,10 +14,10 @@ use back::svh::Svh;
use middle::const_eval::{self, ConstVal, ErrKind};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def_id::DefId;
use middle::subst::{self, Subst, Substs};
use middle::subst;
use middle::infer;
use middle::pat_util;
use middle::traits;
use middle::traits::{self, ProjectionMode};
use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use middle::ty::{Disr, ParameterEnvironment};
use middle::ty::TypeVariants::*;
@ -26,7 +26,6 @@ use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
use std::cmp;
use std::hash::{Hash, SipHasher, Hasher};
use std::rc::Rc;
use syntax::ast::{self, Name};
use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
use syntax::codemap::Span;
@ -131,7 +130,10 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
let tcx = self.tcx;
// FIXME: (@jroesch) float this code up
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()));
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(self.clone()),
ProjectionMode::AnyFinal);
let adt = match self_type.sty {
ty::TyStruct(struct_def, substs) => {
@ -536,58 +538,6 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
#[derive(Debug)]
pub struct ImplMethod<'tcx> {
pub method: Rc<ty::Method<'tcx>>,
pub substs: &'tcx Substs<'tcx>,
pub is_provided: bool
}
impl<'tcx> TyCtxt<'tcx> {
pub fn get_impl_method(&self,
impl_def_id: DefId,
substs: &'tcx Substs<'tcx>,
name: Name)
-> ImplMethod<'tcx>
{
// there don't seem to be nicer accessors to these:
let impl_or_trait_items_map = self.impl_or_trait_items.borrow();
for impl_item in &self.impl_items.borrow()[&impl_def_id] {
if let ty::MethodTraitItem(ref meth) =
impl_or_trait_items_map[&impl_item.def_id()] {
if meth.name == name {
return ImplMethod {
method: meth.clone(),
substs: substs,
is_provided: false
}
}
}
}
// It is not in the impl - get the default from the trait.
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
for trait_item in self.trait_items(trait_ref.def_id).iter() {
if let &ty::MethodTraitItem(ref meth) = trait_item {
if meth.name == name {
let impl_to_trait_substs = self
.make_substs_for_receiver_types(&trait_ref, meth);
let substs = impl_to_trait_substs.subst(self, substs);
return ImplMethod {
method: meth.clone(),
substs: self.mk_substs(substs),
is_provided: true
}
}
}
}
self.sess.bug(&format!("method {:?} not found in {:?}",
name, impl_def_id))
}
}
impl<'tcx> ty::TyS<'tcx> {
fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
bound: ty::BuiltinBound,
@ -595,7 +545,10 @@ impl<'tcx> ty::TyS<'tcx> {
-> bool
{
let tcx = param_env.tcx;
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env.clone()));
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(param_env.clone()),
ProjectionMode::AnyFinal);
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx,
self, bound, span);

View file

@ -27,6 +27,7 @@ use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::region;
use rustc::middle::ty::{self, TyCtxt};
use rustc::middle::traits::ProjectionMode;
use syntax::ast;
use syntax::codemap::Span;
use rustc_front::hir;
@ -202,7 +203,10 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
debug!("check_loans(body id={})", body.id);
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = infer::new_infer_ctxt(bccx.tcx, &bccx.tcx.tables, Some(param_env));
let infcx = infer::new_infer_ctxt(bccx.tcx,
&bccx.tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
let mut clcx = CheckLoanCtxt {
bccx: bccx,

View file

@ -24,6 +24,7 @@ use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::region;
use rustc::middle::ty::{self, TyCtxt};
use rustc::middle::traits::ProjectionMode;
use syntax::ast;
use syntax::codemap::Span;
@ -55,7 +56,10 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
};
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = infer::new_infer_ctxt(bccx.tcx, &bccx.tcx.tables, Some(param_env));
let infcx = infer::new_infer_ctxt(bccx.tcx,
&bccx.tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
{
let mut euv = euv::ExprUseVisitor::new(&mut glcx, &infcx);
euv.walk_fn(decl, body);
@ -525,7 +529,10 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> {
impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
fn visit_expr(&mut self, ex: &Expr) {
if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
let infcx = infer::new_infer_ctxt(self.bccx.tcx, &self.bccx.tcx.tables, None);
let infcx = infer::new_infer_ctxt(self.bccx.tcx,
&self.bccx.tcx.tables,
None,
ProjectionMode::AnyFinal);
let mc = mc::MemCategorizationContext::new(&infcx);
let base_cmt = mc.cat_expr(&base).unwrap();
let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);

View file

@ -60,7 +60,7 @@ which includes three bits of information:
`process_obligations` would simply yield back further ambiguous
results. This is used by the `FulfillmentContext` to decide when it
has reached a steady state.
#### Snapshots
The `ObligationForest` supports a limited form of snapshots; see
@ -79,5 +79,3 @@ parent and (for convenience) its root (which may be itself). It also
has a current state, described by `NodeState`. After each
processing step, we compress the vector to remove completed and error
nodes, which aren't needed anymore.

View file

@ -22,6 +22,7 @@ use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
use rustc_typeck::middle::subst;
use rustc_typeck::middle::subst::Subst;
use rustc_typeck::middle::traits::ProjectionMode;
use rustc_typeck::middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_typeck::middle::ty::relate::TypeRelation;
use rustc_typeck::middle::infer::{self, TypeOrigin};
@ -146,7 +147,10 @@ fn test_env<F>(source_string: &str,
lang_items,
index,
|tcx| {
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
None,
ProjectionMode::AnyFinal);
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions,

View file

@ -839,6 +839,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> ImplItem {
name: folder.fold_name(i.name),
attrs: fold_attrs(i.attrs, folder),
vis: i.vis,
defaultness: i.defaultness,
node: match i.node {
ImplItemKind::Const(ty, expr) => {
ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))

View file

@ -864,10 +864,10 @@ pub struct MethodSig {
pub explicit_self: ExplicitSelf,
}
/// Represents a method declaration in a trait declaration, possibly including
/// a default implementation A trait method is either required (meaning it
/// doesn't have an implementation, just a signature) or provided (meaning it
/// has a default implementation).
/// Represents an item declaration within a trait declaration,
/// possibly including a default implementation. A trait item is
/// either required (meaning it doesn't have an implementation, just a
/// signature) or provided (meaning it has a default implementation).
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TraitItem {
pub id: NodeId,
@ -889,6 +889,7 @@ pub struct ImplItem {
pub id: NodeId,
pub name: Name,
pub vis: Visibility,
pub defaultness: Defaultness,
pub attrs: HirVec<Attribute>,
pub node: ImplItemKind,
pub span: Span,
@ -1046,6 +1047,22 @@ pub enum Constness {
NotConst,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Defaultness {
Default,
Final,
}
impl Defaultness {
pub fn is_final(&self) -> bool {
*self == Defaultness::Final
}
pub fn is_default(&self) -> bool {
*self == Defaultness::Default
}
}
impl fmt::Display for Unsafety {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(match *self {

View file

@ -756,6 +756,7 @@ pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem {
name: i.ident.name,
attrs: lower_attrs(lctx, &i.attrs),
vis: lower_visibility(lctx, i.vis),
defaultness: lower_defaultness(lctx, i.defaultness),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
@ -1707,6 +1708,13 @@ pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibili
}
}
pub fn lower_defaultness(_lctx: &LoweringContext, d: Defaultness) -> hir::Defaultness {
match d {
Defaultness::Default => hir::Defaultness::Default,
Defaultness::Final => hir::Defaultness::Final,
}
}
pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
match *b {
BlockCheckMode::Default => hir::DefaultBlock,

View file

@ -1014,6 +1014,11 @@ impl<'a> State<'a> {
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ii.span.lo));
try!(self.print_outer_attributes(&ii.attrs));
if let hir::Defaultness::Default = ii.defaultness {
try!(self.word_nbsp("default"));
}
match ii.node {
hir::ImplItemKind::Const(ref ty, ref expr) => {
try!(self.print_associated_const(ii.name, &ty, Some(&expr), ii.vis));

View file

@ -35,6 +35,7 @@ use middle::def_id::DefId;
use middle::subst::Substs;
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::adjustment;
use middle::traits::ProjectionMode;
use rustc::front::map as hir_map;
use util::nodemap::{NodeSet};
use lint::{Level, LateContext, LintContext, LintArray, Lint};
@ -868,7 +869,10 @@ impl LateLintPass for UnconditionalRecursion {
let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound.

View file

@ -241,6 +241,10 @@ pub const tag_items_data_item_constness: usize = 0xa6;
pub const tag_items_data_item_deprecation: usize = 0xa7;
pub const tag_items_data_item_defaultness: usize = 0xa8;
pub const tag_items_data_parent_impl: usize = 0xa9;
pub const tag_rustc_version: usize = 0x10f;
pub fn rustc_version() -> String {
format!(

View file

@ -225,6 +225,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx)
}
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
let cdata = self.get_crate_data(impl_def.krate);
decoder::get_parent_impl(&*cdata, impl_def.index)
}
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> Option<DefId>
{
let cdata = self.get_crate_data(def_id.krate);

View file

@ -165,6 +165,19 @@ fn fn_constness(item: rbml::Doc) -> hir::Constness {
}
}
fn item_defaultness(item: rbml::Doc) -> hir::Defaultness {
match reader::maybe_get_doc(item, tag_items_data_item_defaultness) {
None => hir::Defaultness::Default, // should occur only for default impls on traits
Some(defaultness_doc) => {
match reader::doc_as_u8(defaultness_doc) as char {
'd' => hir::Defaultness::Default,
'f' => hir::Defaultness::Final,
_ => panic!("unknown defaultness character")
}
}
}
}
fn item_sort(item: rbml::Doc) -> Option<char> {
reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
doc.as_str_slice().as_bytes()[0] as char
@ -551,6 +564,13 @@ pub fn get_visibility(cdata: Cmd, id: DefIndex) -> hir::Visibility {
item_visibility(cdata.lookup_item(id))
}
pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option<DefId> {
let item = cdata.lookup_item(id);
reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| {
translated_def_id(cdata, doc)
})
}
pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
let item = cdata.lookup_item(id);
match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
@ -976,6 +996,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
let name = item_name(&intr, item_doc);
let vis = item_visibility(item_doc);
let defaultness = item_defaultness(item_doc);
match item_sort(item_doc) {
sort @ Some('C') | sort @ Some('c') => {
@ -984,6 +1005,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
name: name,
ty: ty,
vis: vis,
defaultness: defaultness,
def_id: def_id,
container: container,
has_value: sort == Some('C')
@ -1007,6 +1029,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
fty,
explicit_self,
vis,
defaultness,
def_id,
container)))
}
@ -1016,6 +1039,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
name: name,
ty: ty,
vis: vis,
defaultness: defaultness,
def_id: def_id,
container: container,
}))

View file

@ -25,6 +25,7 @@ use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::dependency_format::Linkage;
use middle::stability;
use middle::subst;
use middle::traits::specialization_graph;
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::util::IntTypeExt;
@ -451,6 +452,14 @@ fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) {
rbml_w.end_tag();
}
fn encode_defaultness(rbml_w: &mut Encoder, defaultness: hir::Defaultness) {
let ch = match defaultness {
hir::Defaultness::Default => 'd',
hir::Defaultness::Final => 'f',
};
rbml_w.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8);
}
fn encode_explicit_self(rbml_w: &mut Encoder,
explicit_self: &ty::ExplicitSelfCategory) {
let tag = tag_item_trait_method_explicit_self;
@ -674,6 +683,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
encode_defaultness(rbml_w, ii.defaultness);
encode_inlined_item(ecx,
rbml_w,
InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
@ -725,6 +735,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
impl_item));
}
encode_constness(rbml_w, sig.constness);
encode_defaultness(rbml_w, impl_item.defaultness);
if !any_types {
let m_id = ecx.local_id(m.def_id);
encode_symbol(ecx, rbml_w, m_id);
@ -767,6 +778,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
encode_defaultness(rbml_w, ii.defaultness);
} else {
encode_predicates(rbml_w, ecx, index,
&ecx.tcx.lookup_predicates(associated_type.def_id),
@ -873,6 +885,12 @@ fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option<attr::Deprecation>)
});
}
fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option<DefId>) {
parent_opt.map(|parent| {
rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
});
}
fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
xrefs: FnvHashMap<XRef<'tcx>, u32>)
@ -1150,8 +1168,19 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
}
rbml_w.end_tag();
}
if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) {
let did = ecx.tcx.map.local_def_id(item.id);
if let Some(trait_ref) = tcx.impl_trait_ref(did) {
encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
let parent = trait_def.ancestors(did)
.skip(1)
.next()
.and_then(|node| match node {
specialization_graph::Node::Impl(parent) => Some(parent),
_ => None,
});
encode_parent_impl(rbml_w, parent);
}
encode_path(rbml_w, path.clone());
encode_stability(rbml_w, stab);

View file

@ -27,6 +27,7 @@ use hair::cx::Cx;
use rustc::mir::mir_map::MirMap;
use rustc::middle::infer;
use rustc::middle::region::CodeExtentData;
use rustc::middle::traits::ProjectionMode;
use rustc::middle::ty::{self, Ty, TyCtxt};
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
@ -137,7 +138,11 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
};
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
Err(ErrorReported) => {}

View file

@ -13,7 +13,7 @@
use rustc::dep_graph::DepNode;
use rustc::middle::infer::{self, InferCtxt};
use rustc::middle::traits;
use rustc::middle::traits::{self, ProjectionMode};
use rustc::middle::ty::fold::TypeFoldable;
use rustc::middle::ty::{self, Ty, TyCtxt};
use rustc::mir::repr::*;
@ -582,7 +582,10 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
}
let _task = tcx.dep_graph.in_task(DepNode::MirTypeck(id));
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
let mut checker = TypeChecker::new(&infcx);
{
let mut verifier = TypeVerifier::new(&mut checker, mir);

View file

@ -35,8 +35,8 @@ use rustc::middle::expr_use_visitor as euv;
use rustc::middle::infer;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::traits;
use rustc::middle::ty::{self, Ty, TyCtxt};
use rustc::middle::traits::{self, ProjectionMode};
use rustc::util::nodemap::NodeMap;
use rustc::middle::const_qualif::ConstQualif;
use rustc::lint::builtin::CONST_ERR;
@ -92,7 +92,10 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
None => self.tcx.empty_parameter_environment()
};
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
Some(param_env),
ProjectionMode::AnyFinal);
f(&mut euv::ExprUseVisitor::new(self, &infcx))
}
@ -247,7 +250,10 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
fn check_static_type(&self, e: &hir::Expr) {
let ty = self.tcx.node_id_to_type(e.id);
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
None,
ProjectionMode::AnyFinal);
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);

View file

@ -16,6 +16,7 @@ use rustc::middle::expr_use_visitor as euv;
use rustc::middle::infer;
use rustc::middle::mem_categorization as mc;
use rustc::middle::ty::{self, TyCtxt, ParameterEnvironment};
use rustc::middle::traits::ProjectionMode;
use rustc_front::hir;
use rustc_front::intravisit;
@ -43,7 +44,8 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
Some(param_env.clone()));
Some(param_env.clone()),
ProjectionMode::AnyFinal);
let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: &param_env };
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
euv.walk_fn(fd, b);

View file

@ -217,6 +217,7 @@ use trans::tvec;
use trans::type_of;
use trans::Disr;
use middle::ty::{self, Ty, TyCtxt};
use middle::traits::ProjectionMode;
use session::config::NoDebugInfo;
use util::common::indenter;
use util::nodemap::FnvHashMap;
@ -1475,7 +1476,9 @@ fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool
reassigned: false
};
{
let infcx = infer::normalizing_infer_ctxt(bcx.tcx(), &bcx.tcx().tables);
let infcx = infer::normalizing_infer_ctxt(bcx.tcx(),
&bcx.tcx().tables,
ProjectionMode::Any);
let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
visitor.walk_expr(body);
}

View file

@ -13,6 +13,7 @@ use libc::{c_uint, c_ulonglong};
use llvm::{self, ValueRef, AttrHelper};
use middle::ty;
use middle::infer;
use middle::traits::ProjectionMode;
use session::config::NoDebugInfo;
use syntax::abi::Abi;
pub use syntax::attr::InlineAttr;
@ -133,7 +134,9 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
let (fn_sig, abi, env_ty) = match fn_type.sty {
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None),
ty::TyClosure(closure_did, ref substs) => {
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
&ccx.tcx().tables,
ProjectionMode::Any);
function_type = infcx.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
(&function_type.sig, Abi::RustCall, Some(self_type))

View file

@ -13,6 +13,7 @@ use back::link::{self, mangle_internal_name_by_path_and_seq};
use llvm::{ValueRef, get_params};
use middle::def_id::DefId;
use middle::infer;
use middle::traits::ProjectionMode;
use trans::adt;
use trans::attributes;
use trans::base::*;
@ -206,7 +207,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
// this function (`trans_closure`) is invoked at the point
// of the closure expression.
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
let function_type = infcx.closure_type(closure_def_id, closure_substs);
let freevars: Vec<ty::Freevar> =
@ -329,7 +330,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
ccx.tn().val_to_string(llreffn));
let tcx = ccx.tcx();
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
// Find a version of the closure type. Substitute static for the
// region since it doesn't really matter.

View file

@ -819,10 +819,11 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
nested: _ }) =>
{
let callee_substs = impl_substs.with_method_from(&rcvr_substs);
let impl_method = tcx.get_impl_method(impl_did,
tcx.mk_substs(callee_substs),
trait_method.name);
Some((impl_method.method.def_id, impl_method.substs))
let impl_method = meth::get_impl_method(tcx,
impl_did,
tcx.mk_substs(callee_substs),
trait_method.name);
Some((impl_method.method.def_id, &impl_method.substs))
}
// If we have a closure or a function pointer, we will also encounter
// the concrete closure/function somewhere else (during closure or fn
@ -982,7 +983,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if can_have_local_instance(ccx, impl_method.method.def_id) {
Some(create_fn_trans_item(ccx,
impl_method.method.def_id,
impl_method.substs,
&impl_method.substs,
&Substs::trans_empty()))
} else {
None
@ -1160,13 +1161,14 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
let mth = tcx.get_impl_method(impl_def_id,
callee_substs,
default_impl.name);
let mth = meth::get_impl_method(tcx,
impl_def_id,
callee_substs,
default_impl.name);
assert!(mth.is_provided);
let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
continue;
}

View file

@ -37,8 +37,8 @@ use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
use middle::traits;
use middle::ty::{self, Ty, TyCtxt};
use middle::traits::{self, SelectionContext, ProjectionMode};
use middle::ty::fold::{TypeFolder, TypeFoldable};
use rustc_front::hir;
use rustc::mir::repr::Mir;
@ -1137,8 +1137,8 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
let mut selcx = traits::SelectionContext::new(&infcx);
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
let mut selcx = SelectionContext::new(&infcx);
let obligation =
traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
@ -1198,8 +1198,8 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
predicates);
let tcx = ccx.tcx();
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables);
let mut selcx = traits::SelectionContext::new(&infcx);
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = traits::FulfillmentContext::new();
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: predicates, obligations } =

View file

@ -22,6 +22,7 @@
use llvm::{self, ValueRef};
use middle::ty;
use middle::infer;
use middle::traits::ProjectionMode;
use syntax::abi::Abi;
use trans::attributes;
use trans::base;
@ -111,7 +112,9 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
(&f.sig, f.abi, None)
}
ty::TyClosure(closure_did, ref substs) => {
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
&ccx.tcx().tables,
ProjectionMode::Any);
function_type = infcx.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::rc::Rc;
use arena::TypedArena;
use back::link;
use llvm::{ValueRef, get_params};
@ -15,7 +17,7 @@ use middle::def_id::DefId;
use middle::infer;
use middle::subst::{Subst, Substs};
use middle::subst;
use middle::traits;
use middle::traits::{self, ProjectionMode};
use trans::base::*;
use trans::build::*;
use trans::callee::{Callee, Virtual, ArgVals,
@ -31,9 +33,9 @@ use trans::glue;
use trans::machine;
use trans::type_::Type;
use trans::type_of::*;
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use syntax::ast;
use syntax::ast::{self, Name};
use syntax::attr;
use syntax::codemap::DUMMY_SP;
@ -107,7 +109,7 @@ pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// those from the impl and those from the method:
let impl_substs = vtable_impl.substs.with_method_from(&substs);
let substs = ccx.tcx().mk_substs(impl_substs);
let mth = ccx.tcx().get_impl_method(impl_did, substs, mname);
let mth = get_impl_method(ccx.tcx(), impl_did, substs, mname);
// Translate the function, bypassing Callee::def.
// That is because default methods have the same ID as the
@ -315,7 +317,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
trans_fn_ref_with_substs(ccx,
mth.method.def_id,
None,
mth.substs).val
&mth.substs).val
}
None => nullptr
}
@ -378,7 +380,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
impl_id: DefId,
substs: &'tcx subst::Substs<'tcx>)
-> Vec<Option<ty::util::ImplMethod<'tcx>>>
-> Vec<Option<ImplMethod<'tcx>>>
{
let tcx = ccx.tcx();
@ -428,7 +430,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
let mth = tcx.get_impl_method(impl_id, substs, name);
let mth = get_impl_method(tcx, impl_id, substs, name);
debug!("get_vtable_methods: mth={:?}", mth);
@ -438,7 +440,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// method could then never be called, so we do not want to
// try and trans it, in that case. Issue #23435.
if mth.is_provided {
let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
debug!("get_vtable_methods: predicates do not hold");
return None;
@ -466,3 +468,37 @@ fn opaque_method_ty<'tcx>(tcx: &TyCtxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
}),
})
}
#[derive(Debug)]
pub struct ImplMethod<'tcx> {
pub method: Rc<ty::Method<'tcx>>,
pub substs: &'tcx Substs<'tcx>,
pub is_provided: bool
}
/// Locates the applicable definition of a method, given its name.
pub fn get_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
substs: &'tcx Substs<'tcx>,
name: Name)
-> ImplMethod<'tcx>
{
assert!(!substs.types.needs_infer());
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let trait_def = tcx.lookup_trait_def(trait_def_id);
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
Some(node_item) => {
ImplMethod {
method: node_item.item,
substs: traits::translate_substs(&infcx, impl_def_id, substs, node_item.node),
is_provided: node_item.node.is_from_trait(),
}
}
None => {
tcx.sess.bug(&format!("method {:?} not found in {:?}", name, impl_def_id))
}
}
}

View file

@ -10,8 +10,8 @@
use middle::free_region::FreeRegionMap;
use middle::infer::{self, TypeOrigin};
use middle::traits;
use middle::ty::{self, TyCtxt};
use middle::traits::{self, ProjectionMode};
use middle::subst::{self, Subst, Substs, VecPerParamSpace};
use syntax::ast;
@ -42,7 +42,7 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>,
debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
impl_trait_ref);
let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
let mut fulfillment_cx = traits::FulfillmentContext::new();
let trait_to_impl_substs = &impl_trait_ref.substs;
@ -416,7 +416,7 @@ pub fn compare_const_impl<'tcx>(tcx: &TyCtxt<'tcx>,
debug!("compare_const_impl(impl_trait_ref={:?})",
impl_trait_ref);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
let mut fulfillment_cx = traits::FulfillmentContext::new();
// The below is for the most part highly similar to the procedure

View file

@ -15,8 +15,8 @@ use middle::free_region::FreeRegionMap;
use middle::infer;
use middle::region;
use middle::subst::{self, Subst};
use middle::traits;
use middle::ty::{self, Ty, TyCtxt};
use middle::traits::{self, ProjectionMode};
use util::nodemap::FnvHashSet;
use syntax::ast;
@ -82,7 +82,10 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
// check that the impl type can be made to match the trait type.
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env));
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,
Some(impl_param_env),
ProjectionMode::AnyFinal);
let mut fulfillment_cx = traits::FulfillmentContext::new();
let named_type = tcx.lookup_item_type(self_type_did).ty;

View file

@ -92,7 +92,7 @@ use middle::infer;
use middle::infer::{TypeOrigin, TypeTrace, type_variable};
use middle::pat_util::{self, pat_id_map};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
use middle::traits::{self, report_fulfillment_errors};
use middle::traits::{self, report_fulfillment_errors, ProjectionMode};
use middle::ty::{GenericPredicates, TypeScheme};
use middle::ty::{ParamTy, ParameterEnvironment};
use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
@ -307,7 +307,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
-> Inherited<'a, 'tcx> {
Inherited {
infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env)),
infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), ProjectionMode::AnyFinal),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
locals: RefCell::new(NodeMap()),
tables: tables,
@ -672,10 +672,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
hir::ItemFn(..) => {} // entirely within check_item_body
hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
debug!("ItemImpl {} with id {}", it.name, it.id);
match ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(it.id)) {
let impl_def_id = ccx.tcx.map.local_def_id(it.id);
match ccx.tcx.impl_trait_ref(impl_def_id) {
Some(impl_trait_ref) => {
check_impl_items_against_trait(ccx,
it.span,
impl_def_id,
&impl_trait_ref,
impl_items);
}
@ -862,12 +864,71 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
}
fn report_forbidden_specialization(tcx: &TyCtxt,
impl_item: &hir::ImplItem,
parent_impl: DefId)
{
let mut err = struct_span_err!(
tcx.sess, impl_item.span, E0520,
"item `{}` is provided by an `impl` that specializes \
another, but the item in the parent `impl` is not \
marked `default` and so it cannot be specialized.",
impl_item.name);
match tcx.span_of_impl(parent_impl) {
Ok(span) => {
err.span_note(span, "parent implementation is here:");
}
Err(cname) => {
err.note(&format!("parent implementation is in crate `{}`", cname));
}
}
err.emit();
}
fn check_specialization_validity<'tcx>(tcx: &TyCtxt<'tcx>, trait_def: &ty::TraitDef<'tcx>,
impl_id: DefId, impl_item: &hir::ImplItem)
{
let ancestors = trait_def.ancestors(impl_id);
let parent = match impl_item.node {
hir::ImplItemKind::Const(..) => {
ancestors.const_defs(tcx, impl_item.name).skip(1).next()
.map(|node_item| node_item.map(|parent| parent.defaultness))
}
hir::ImplItemKind::Method(..) => {
ancestors.fn_defs(tcx, impl_item.name).skip(1).next()
.map(|node_item| node_item.map(|parent| parent.defaultness))
}
hir::ImplItemKind::Type(_) => {
ancestors.type_defs(tcx, impl_item.name).skip(1).next()
.map(|node_item| node_item.map(|parent| parent.defaultness))
}
};
if let Some(parent) = parent {
if parent.item.is_final() {
report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
}
}
}
fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_span: Span,
impl_id: DefId,
impl_trait_ref: &ty::TraitRef<'tcx>,
impl_items: &[hir::ImplItem]) {
// Locate trait methods
// If the trait reference itself is erroneous (so the compilation is going
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
// isn't populated for such impls.
if impl_trait_ref.references_error() { return; }
// Locate trait definition and items
let tcx = ccx.tcx;
let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
let trait_items = tcx.trait_items(impl_trait_ref.def_id);
let mut overridden_associated_type = None;
@ -878,6 +939,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let ty_trait_item = trait_items.iter()
.find(|ac| ac.name() == ty_impl_item.name());
// Check that impl definition matches trait definition
if let Some(ty_trait_item) = ty_trait_item {
match impl_item.node {
hir::ImplItemKind::Const(..) => {
@ -944,6 +1006,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
}
}
check_specialization_validity(tcx, trait_def, impl_id, impl_item);
}
// Check for missing items from trait
@ -952,9 +1016,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let mut invalidated_items = Vec::new();
let associated_type_overridden = overridden_associated_type.is_some();
for trait_item in trait_items.iter() {
let is_implemented;
let is_provided;
match *trait_item {
ty::ConstTraitItem(ref associated_const) => {
let is_implemented = impl_items.iter().any(|ii| {
is_provided = associated_const.has_value;
is_implemented = impl_items.iter().any(|ii| {
match ii.node {
hir::ImplItemKind::Const(..) => {
ii.name == associated_const.name
@ -962,53 +1030,30 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
_ => false,
}
});
let is_provided = associated_const.has_value;
if !is_implemented {
if !is_provided {
missing_items.push(associated_const.name);
} else if associated_type_overridden {
invalidated_items.push(associated_const.name);
}
}
}
ty::MethodTraitItem(ref trait_method) => {
let is_implemented =
impl_items.iter().any(|ii| {
match ii.node {
hir::ImplItemKind::Method(..) => {
ii.name == trait_method.name
}
_ => false,
}
});
let is_provided =
provided_methods.iter().any(|m| m.name == trait_method.name);
if !is_implemented {
if !is_provided {
missing_items.push(trait_method.name);
} else if associated_type_overridden {
invalidated_items.push(trait_method.name);
}
}
is_provided = provided_methods.iter().any(|m| m.name == trait_method.name);
is_implemented = trait_def.ancestors(impl_id)
.fn_defs(tcx, trait_method.name)
.next()
.map(|node_item| !node_item.node.is_from_trait())
.unwrap_or(false);
}
ty::TypeTraitItem(ref associated_type) => {
let is_implemented = impl_items.iter().any(|ii| {
match ii.node {
hir::ImplItemKind::Type(_) => {
ii.name == associated_type.name
}
_ => false,
}
});
let is_provided = associated_type.ty.is_some();
if !is_implemented {
if !is_provided {
missing_items.push(associated_type.name);
} else if associated_type_overridden {
invalidated_items.push(associated_type.name);
}
}
ty::TypeTraitItem(ref trait_assoc_ty) => {
is_provided = trait_assoc_ty.ty.is_some();
is_implemented = trait_def.ancestors(impl_id)
.type_defs(tcx, trait_assoc_ty.name)
.next()
.map(|node_item| !node_item.node.is_from_trait())
.unwrap_or(false);
}
}
if !is_implemented {
if !is_provided {
missing_items.push(trait_item.name());
} else if associated_type_overridden {
invalidated_items.push(trait_item.name());
}
}
}

View file

@ -15,12 +15,11 @@
// done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here.
use middle::def_id::DefId;
use middle::lang_items::UnsizeTraitLangItem;
use middle::subst::{self, Subst};
use middle::traits;
use middle::ty::{self, TyCtxt, TypeFoldable};
use middle::traits::{self, ProjectionMode};
use middle::ty::{ImplOrTraitItemId, ConstTraitItemId};
use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
@ -197,7 +196,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
impl_trait_ref, impl_def_id);
let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
}
// Converts an implementation in the AST to a vector of items.
@ -385,7 +384,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
source, target);
let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env), ProjectionMode::Topmost);
let origin = TypeOrigin::Misc(span);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
@ -530,7 +529,10 @@ pub fn report_duplicate_item<'tcx>(tcx: &TyCtxt<'tcx>, sp: Span, name: ast::Name
pub fn check_coherence(crate_context: &CrateCtxt) {
let _task = crate_context.tcx.dep_graph.in_task(DepNode::Coherence);
let infcx = new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None);
let infcx = new_infer_ctxt(crate_context.tcx,
&crate_context.tcx.tables,
None,
ProjectionMode::Topmost);
CoherenceChecker {
crate_context: crate_context,
inference_context: infcx,

View file

@ -12,21 +12,20 @@
//! same type. Likewise, no two inherent impls for a given type
//! constructor provide a method with the same name.
use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::traits;
use middle::ty::{self, TyCtxt};
use middle::traits::{self, ProjectionMode};
use middle::infer;
use middle::ty::{self, TyCtxt};
use syntax::ast;
use syntax::codemap::Span;
use rustc::dep_graph::DepNode;
use rustc_front::hir;
use rustc_front::intravisit;
use util::nodemap::{DefIdMap, DefIdSet};
use util::nodemap::DefIdMap;
pub fn check(tcx: &TyCtxt) {
let mut overlap = OverlapChecker { tcx: tcx,
traits_checked: DefIdSet(),
default_impls: DefIdMap() };
// this secondary walk specifically checks for some other cases,
@ -37,134 +36,11 @@ pub fn check(tcx: &TyCtxt) {
struct OverlapChecker<'cx, 'tcx:'cx> {
tcx: &'cx TyCtxt<'tcx>,
// The set of traits where we have checked for overlap. This is
// used to avoid checking the same trait twice.
//
// NB. It's ok to skip tracking this set because we fully
// encapsulate it, and we always create a task
// (`CoherenceOverlapCheck`) corresponding to each entry.
traits_checked: DefIdSet,
// maps from a trait def-id to an impl id
default_impls: DefIdMap<ast::NodeId>,
}
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
fn check_for_overlapping_impls_of_trait(&mut self, trait_def_id: DefId) {
debug!("check_for_overlapping_impls_of_trait(trait_def_id={:?})",
trait_def_id);
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
if !self.traits_checked.insert(trait_def_id) {
return;
}
let trait_def = self.tcx.lookup_trait_def(trait_def_id);
self.tcx.populate_implementations_for_trait_if_necessary(
trait_def.trait_ref.def_id);
// We should already know all impls of this trait, so these
// borrows are safe.
let (blanket_impls, nonblanket_impls) = trait_def.borrow_impl_lists(self.tcx);
// Conflicts can only occur between a blanket impl and another impl,
// or between 2 non-blanket impls of the same kind.
for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
for &impl2_def_id in &blanket_impls[(i+1)..] {
self.check_if_impls_overlap(impl1_def_id,
impl2_def_id);
}
for v in nonblanket_impls.values() {
for &impl2_def_id in v {
self.check_if_impls_overlap(impl1_def_id,
impl2_def_id);
}
}
}
for impl_group in nonblanket_impls.values() {
for (i, &impl1_def_id) in impl_group.iter().enumerate() {
for &impl2_def_id in &impl_group[(i+1)..] {
self.check_if_impls_overlap(impl1_def_id,
impl2_def_id);
}
}
}
}
// We need to coherently pick which impl will be displayed
// as causing the error message, and it must be the in the current
// crate. Just pick the smaller impl in the file.
fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
-> Option<(DefId, DefId)> {
if impl1_def_id.krate != LOCAL_CRATE {
if impl2_def_id.krate != LOCAL_CRATE {
// we don't need to check impls if both are external;
// that's the other crate's job.
None
} else {
Some((impl2_def_id, impl1_def_id))
}
} else if impl2_def_id.krate != LOCAL_CRATE {
Some((impl1_def_id, impl2_def_id))
} else if impl1_def_id < impl2_def_id {
Some((impl1_def_id, impl2_def_id))
} else {
Some((impl2_def_id, impl1_def_id))
}
}
fn check_if_impls_overlap(&self,
impl1_def_id: DefId,
impl2_def_id: DefId)
{
if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
impl1_def_id, impl2_def_id)
{
debug!("check_if_impls_overlap({:?}, {:?})",
impl1_def_id,
impl2_def_id);
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
if let Some(header) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
self.report_overlap_error(impl1_def_id, impl2_def_id, header.trait_ref.unwrap());
}
}
}
fn report_overlap_error(&self,
impl1: DefId,
impl2: DefId,
trait_ref: ty::TraitRef)
{
// only print the Self type if it's concrete; otherwise, it's not adding much information.
let self_type = {
trait_ref.substs.self_ty().and_then(|ty| {
if let ty::TyInfer(_) = ty.sty {
None
} else {
Some(format!(" for type `{}`", ty))
}
}).unwrap_or(String::new())
};
let mut err = struct_span_err!(self.tcx.sess, self.span_of_def_id(impl1), E0119,
"conflicting implementations of trait `{}`{}:",
trait_ref,
self_type);
if impl2.is_local() {
span_note!(&mut err, self.span_of_def_id(impl2),
"conflicting implementation is here:");
} else {
let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
err.note(&format!("conflicting implementation in crate `{}`", cname));
}
err.emit();
}
fn span_of_def_id(&self, did: DefId) -> Span {
let node_id = self.tcx.map.as_local_node_id(did).unwrap();
self.tcx.map.span(node_id)
@ -213,7 +89,10 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i+1)..] {
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
let infcx = infer::new_infer_ctxt(self.tcx,
&self.tcx.tables,
None,
ProjectionMode::Topmost);
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
}
@ -222,15 +101,9 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
}
}
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
hir::ItemTrait(..) => {
let trait_def_id = self.tcx.map.local_def_id(item.id);
self.check_for_overlapping_impls_of_trait(trait_def_id);
}
hir::ItemEnum(..) | hir::ItemStruct(..) => {
let type_def_id = self.tcx.map.local_def_id(item.id);
self.check_for_overlapping_inherent_impls(type_def_id);
@ -243,50 +116,90 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
let impl_def_id = self.tcx.map.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
self.check_for_overlapping_impls_of_trait(trait_ref.def_id);
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
match prev_default_impl {
Some(prev_id) => {
self.report_overlap_error(impl_def_id,
self.tcx.map.local_def_id(prev_id),
trait_ref);
}
None => { }
if let Some(prev_id) = prev_default_impl {
let mut err = struct_span_err!(
self.tcx.sess,
self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
"redundant default implementations of trait `{}`:",
trait_ref);
err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
.unwrap(),
"redundant implementation is here:");
err.emit();
}
}
hir::ItemImpl(_, _, _, Some(_), _, _) => {
let impl_def_id = self.tcx.map.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_def_id = trait_ref.def_id;
self.check_for_overlapping_impls_of_trait(trait_def_id);
match trait_ref.self_ty().sty {
ty::TyTrait(ref data) => {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
// This is an error, but it will be
// reported by wfcheck. Ignore it
// here. This is tested by
// `coherence-impl-trait-for-trait-object-safe.rs`.
} else {
let mut supertrait_def_ids =
traits::supertrait_def_ids(self.tcx, data.principal_def_id());
if supertrait_def_ids.any(|d| d == trait_def_id) {
span_err!(self.tcx.sess, item.span, E0371,
"the object type `{}` automatically \
implements the trait `{}`",
trait_ref.self_ty(),
self.tcx.item_path_str(trait_def_id));
let _task = self.tcx.dep_graph.in_task(
DepNode::CoherenceOverlapCheck(trait_def_id));
let def = self.tcx.lookup_trait_def(trait_def_id);
// attempt to insert into the specialization graph
let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
// insertion failed due to overlap
if let Err(overlap) = insert_result {
// only print the Self type if it has at least some outer
// concrete shell; otherwise, it's not adding much
// information.
let self_type = {
overlap.on_trait_ref.substs.self_ty().and_then(|ty| {
if ty.has_concrete_skeleton() {
Some(format!(" for type `{}`", ty))
} else {
None
}
}).unwrap_or(String::new())
};
let mut err = struct_span_err!(
self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
"conflicting implementations of trait `{}`{}:",
overlap.on_trait_ref,
self_type);
match self.tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_note(span, "conflicting implementation is here:");
}
Err(cname) => {
err.note(&format!("conflicting implementation in crate `{}`",
cname));
}
}
err.emit();
}
// check for overlap with the automatic `impl Trait for Trait`
if let ty::TyTrait(ref data) = trait_ref.self_ty().sty {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
// This is an error, but it will be
// reported by wfcheck. Ignore it
// here. This is tested by
// `coherence-impl-trait-for-trait-object-safe.rs`.
} else {
let mut supertrait_def_ids =
traits::supertrait_def_ids(self.tcx, data.principal_def_id());
if supertrait_def_ids.any(|d| d == trait_def_id) {
span_err!(self.tcx.sess, item.span, E0371,
"the object type `{}` automatically \
implements the trait `{}`",
trait_ref.self_ty(),
self.tcx.item_path_str(trait_def_id));
}
}
_ => { }
}
}
_ => {
}
_ => {}
}
}
}

View file

@ -533,6 +533,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
id: ast::NodeId,
vis: hir::Visibility,
sig: &hir::MethodSig,
defaultness: hir::Defaultness,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
@ -554,6 +555,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fty,
explicit_self_category,
vis,
defaultness,
def_id,
container);
@ -600,6 +602,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
name: ast::Name,
id: ast::NodeId,
vis: hir::Visibility,
defaultness: hir::Defaultness,
ty: ty::Ty<'tcx>,
has_value: bool)
{
@ -611,6 +614,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let associated_const = Rc::new(ty::AssociatedConst {
name: name,
vis: vis,
defaultness: defaultness,
def_id: ccx.tcx.map.local_def_id(id),
container: container,
ty: ty,
@ -625,11 +629,13 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
name: ast::Name,
id: ast::NodeId,
vis: hir::Visibility,
defaultness: hir::Defaultness,
ty: Option<Ty<'tcx>>)
{
let associated_type = Rc::new(ty::AssociatedType {
name: name,
vis: vis,
defaultness: defaultness,
ty: ty,
def_id: ccx.tcx.map.local_def_id(id),
container: container
@ -767,6 +773,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
convert_associated_const(ccx, ImplContainer(def_id),
impl_item.name, impl_item.id,
impl_item.vis.inherit_from(parent_visibility),
impl_item.defaultness,
ty, true /* has_value */);
}
}
@ -783,7 +790,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
convert_associated_type(ccx, ImplContainer(def_id),
impl_item.name, impl_item.id, impl_item.vis,
Some(typ));
impl_item.defaultness, Some(typ));
}
}
@ -797,7 +804,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
convert_method(ccx, ImplContainer(def_id),
impl_item.name, impl_item.id, method_vis,
sig, selfty, &ty_generics, &ty_predicates);
sig, impl_item.defaultness, selfty, &ty_generics,
&ty_predicates);
}
}
@ -831,6 +839,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
trait_item.name,
trait_item.id,
hir::Public,
hir::Defaultness::Default,
ty,
default.is_some())
}
@ -848,6 +857,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
trait_item.name,
trait_item.id,
hir::Public,
hir::Defaultness::Default,
typ);
}
}
@ -861,6 +871,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
trait_item.id,
hir::Inherited,
sig,
hir::Defaultness::Default,
tcx.mk_self_type(),
&trait_def.generics,
&trait_predicates);

View file

@ -3695,5 +3695,7 @@ register_diagnostics! {
E0399, // trait items need to be implemented because the associated
// type `{}` was overridden
E0436, // functional record update requires a struct
E0513 // no type for local variable ..
E0513, // no type for local variable ..
E0520, // cannot specialize non-default item
E0521 // redundant default implementations of trait
}

View file

@ -106,6 +106,7 @@ use middle::def::Def;
use middle::infer::{self, TypeOrigin};
use middle::subst::Substs;
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use middle::traits::ProjectionMode;
use session::{config, CompileResult};
use util::common::time;
use rustc_front::hir;
@ -196,7 +197,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &TyCtxt<'tcx>,
{
let result = match maybe_infcx {
None => {
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::AnyFinal);
infer::mk_eqty(&infcx, t1_is_expected, TypeOrigin::Misc(span), t1, t2)
}
Some(infcx) => {

View file

@ -1328,10 +1328,10 @@ pub struct MethodSig {
pub explicit_self: ExplicitSelf,
}
/// Represents a method declaration in a trait declaration, possibly including
/// a default implementation. A trait method is either required (meaning it
/// doesn't have an implementation, just a signature) or provided (meaning it
/// has a default implementation).
/// Represents an item declaration within a trait declaration,
/// possibly including a default implementation. A trait item is
/// either required (meaning it doesn't have an implementation, just a
/// signature) or provided (meaning it has a default implementation).
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TraitItem {
pub id: NodeId,
@ -1353,6 +1353,7 @@ pub struct ImplItem {
pub id: NodeId,
pub ident: Ident,
pub vis: Visibility,
pub defaultness: Defaultness,
pub attrs: Vec<Attribute>,
pub node: ImplItemKind,
pub span: Span,
@ -1654,6 +1655,12 @@ pub enum Constness {
NotConst,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Defaultness {
Default,
Final,
}
impl fmt::Display for Unsafety {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(match *self {

View file

@ -1061,6 +1061,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
ident: ii.ident,
attrs: ii.attrs,
vis: ii.vis,
defaultness: ii.defaultness,
node: match ii.node {
ast::ImplItemKind::Method(sig, body) => {
let (sig, body) = expand_and_rename_method(sig, body, fld);

View file

@ -247,7 +247,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
("inclusive_range_syntax", "1.7.0", Some(28237), Active),
// `expr?`
("question_mark", "1.9.0", Some(31436), Active)
("question_mark", "1.9.0", Some(31436), Active),
// impl specialization (RFC 1210)
("specialization", "1.7.0", Some(31844), Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
@ -574,6 +577,7 @@ pub struct Features {
pub stmt_expr_attributes: bool,
pub deprecated: bool,
pub question_mark: bool,
pub specialization: bool,
}
impl Features {
@ -608,6 +612,7 @@ impl Features {
stmt_expr_attributes: false,
deprecated: false,
question_mark: false,
specialization: false,
}
}
}
@ -1102,6 +1107,12 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
}
fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
if ii.defaultness == ast::Defaultness::Default {
self.gate_feature("specialization",
ii.span,
"specialization is unstable");
}
match ii.node {
ast::ImplItemKind::Const(..) => {
self.gate_feature("associated_consts",
@ -1212,6 +1223,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
deprecated: cx.has_feature("deprecated"),
question_mark: cx.has_feature("question_mark"),
specialization: cx.has_feature("specialization"),
}
}

View file

@ -993,6 +993,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
ident: folder.fold_ident(i.ident),
attrs: fold_attrs(i.attrs, folder),
vis: i.vis,
defaultness: i.defaultness,
node: match i.node {
ast::ImplItemKind::Const(ty, expr) => {
ast::ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))

View file

@ -18,7 +18,7 @@ use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind};
use ast::Block;
use ast::{BlockCheckMode, CaptureBy};
use ast::{Constness, Crate, CrateConfig};
use ast::{Decl, DeclKind};
use ast::{Decl, DeclKind, Defaultness};
use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, ExprKind, RangeLimits};
use ast::{Field, FnDecl};
@ -644,6 +644,25 @@ impl<'a> Parser<'a> {
}
}
pub fn check_contextual_keyword(&mut self, ident: Ident) -> bool {
let tok = token::Ident(ident, token::Plain);
self.expected_tokens.push(TokenType::Token(tok));
if let token::Ident(ref cur_ident, _) = self.token {
cur_ident.name == ident.name
} else {
false
}
}
pub fn eat_contextual_keyword(&mut self, ident: Ident) -> bool {
if self.check_contextual_keyword(ident) {
self.bump();
true
} else {
false
}
}
/// If the given word is not a keyword, signal an error.
/// If the next token is not the given word, signal an error.
/// Otherwise, eat it.
@ -705,7 +724,6 @@ impl<'a> Parser<'a> {
}
}
/// Attempt to consume a `<`. If `<<` is seen, replace it with a single
/// `<` and continue. If a `<` is not seen, return false.
///
@ -4846,6 +4864,7 @@ impl<'a> Parser<'a> {
let mut attrs = try!(self.parse_outer_attributes());
let lo = self.span.lo;
let vis = try!(self.parse_visibility());
let defaultness = try!(self.parse_defaultness());
let (name, node) = if self.eat_keyword(keywords::Type) {
let name = try!(self.parse_ident());
try!(self.expect(&token::Eq));
@ -4872,6 +4891,7 @@ impl<'a> Parser<'a> {
span: mk_sp(lo, self.last_span.hi),
ident: name,
vis: vis,
defaultness: defaultness,
attrs: attrs,
node: node
})
@ -5208,6 +5228,15 @@ impl<'a> Parser<'a> {
else { Ok(Visibility::Inherited) }
}
/// Parse defaultness: DEFAULT or nothing
fn parse_defaultness(&mut self) -> PResult<'a, Defaultness> {
if self.eat_contextual_keyword(special_idents::DEFAULT) {
Ok(Defaultness::Default)
} else {
Ok(Defaultness::Final)
}
}
/// Given a termination token, parse all of the items in a module
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> {
let mut items = vec![];

View file

@ -545,66 +545,67 @@ declare_special_idents_and_keywords! {
(9, __unused1, "<__unused1>");
(super::SELF_TYPE_KEYWORD_NAME_NUM, type_self, "Self");
(11, prelude_import, "prelude_import");
(12, DEFAULT, "default");
}
pub mod keywords {
// These ones are variants of the Keyword enum
'strict:
(12, As, "as");
(13, Break, "break");
(14, Crate, "crate");
(15, Else, "else");
(16, Enum, "enum");
(17, Extern, "extern");
(18, False, "false");
(19, Fn, "fn");
(20, For, "for");
(21, If, "if");
(22, Impl, "impl");
(23, In, "in");
(24, Let, "let");
(25, Loop, "loop");
(26, Match, "match");
(27, Mod, "mod");
(28, Move, "move");
(29, Mut, "mut");
(30, Pub, "pub");
(31, Ref, "ref");
(32, Return, "return");
(13, As, "as");
(14, Break, "break");
(15, Crate, "crate");
(16, Else, "else");
(17, Enum, "enum");
(18, Extern, "extern");
(19, False, "false");
(20, Fn, "fn");
(21, For, "for");
(22, If, "if");
(23, Impl, "impl");
(24, In, "in");
(25, Let, "let");
(26, Loop, "loop");
(27, Match, "match");
(28, Mod, "mod");
(29, Move, "move");
(30, Mut, "mut");
(31, Pub, "pub");
(32, Ref, "ref");
(33, Return, "return");
// Static and Self are also special idents (prefill de-dupes)
(super::STATIC_KEYWORD_NAME_NUM, Static, "static");
(super::SELF_KEYWORD_NAME_NUM, SelfValue, "self");
(super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self");
(33, Struct, "struct");
(34, Struct, "struct");
(super::SUPER_KEYWORD_NAME_NUM, Super, "super");
(34, True, "true");
(35, Trait, "trait");
(36, Type, "type");
(37, Unsafe, "unsafe");
(38, Use, "use");
(39, While, "while");
(40, Continue, "continue");
(41, Box, "box");
(42, Const, "const");
(43, Where, "where");
(35, True, "true");
(36, Trait, "trait");
(37, Type, "type");
(38, Unsafe, "unsafe");
(39, Use, "use");
(40, While, "while");
(41, Continue, "continue");
(42, Box, "box");
(43, Const, "const");
(44, Where, "where");
'reserved:
(44, Virtual, "virtual");
(45, Proc, "proc");
(46, Alignof, "alignof");
(47, Become, "become");
(48, Offsetof, "offsetof");
(49, Priv, "priv");
(50, Pure, "pure");
(51, Sizeof, "sizeof");
(52, Typeof, "typeof");
(53, Unsized, "unsized");
(54, Yield, "yield");
(55, Do, "do");
(56, Abstract, "abstract");
(57, Final, "final");
(58, Override, "override");
(59, Macro, "macro");
(45, Virtual, "virtual");
(46, Proc, "proc");
(47, Alignof, "alignof");
(48, Become, "become");
(49, Offsetof, "offsetof");
(50, Priv, "priv");
(51, Pure, "pure");
(52, Sizeof, "sizeof");
(53, Typeof, "typeof");
(54, Unsized, "unsized");
(55, Yield, "yield");
(56, Do, "do");
(57, Abstract, "abstract");
(58, Final, "final");
(59, Override, "override");
(60, Macro, "macro");
}
}

View file

@ -1582,6 +1582,9 @@ impl<'a> State<'a> {
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ii.span.lo));
try!(self.print_outer_attributes(&ii.attrs));
if let ast::Defaultness::Default = ii.defaultness {
try!(self.word_nbsp("default"));
}
match ii.node {
ast::ImplItemKind::Const(ref ty, ref expr) => {
try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));

View file

@ -476,6 +476,7 @@ impl<'a> TraitDef<'a> {
span: self.span,
ident: ident,
vis: ast::Visibility::Inherited,
defaultness: ast::Defaultness::Final,
attrs: Vec::new(),
node: ast::ImplItemKind::Type(type_def.to_ty(cx,
self.span,
@ -893,6 +894,7 @@ impl<'a> MethodDef<'a> {
attrs: self.attributes.clone(),
span: trait_.span,
vis: ast::Visibility::Inherited,
defaultness: ast::Defaultness::Final,
ident: method_ident,
node: ast::ImplItemKind::Method(ast::MethodSig {
generics: fn_generics,

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
pub trait Go {
@ -37,7 +39,7 @@ pub fn go_once<G:GoOnce>(this: G, arg: isize) {
impl<G> GoMut for G
where G : Go
{
fn go_mut(&mut self, arg: isize) {
default fn go_mut(&mut self, arg: isize) {
go(&*self, arg)
}
}
@ -45,7 +47,7 @@ impl<G> GoMut for G
impl<G> GoOnce for G
where G : GoMut
{
fn go_once(mut self, arg: isize) {
default fn go_once(mut self, arg: isize) {
go_mut(&mut self, arg)
}
}

View file

@ -0,0 +1,82 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
pub trait Foo {
fn foo(&self) -> &'static str;
}
impl<T> Foo for T {
default fn foo(&self) -> &'static str {
"generic"
}
}
impl<T: Clone> Foo for T {
default fn foo(&self) -> &'static str {
"generic Clone"
}
}
impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
default fn foo(&self) -> &'static str {
"generic pair"
}
}
impl<T: Clone> Foo for (T, T) {
default fn foo(&self) -> &'static str {
"generic uniform pair"
}
}
impl Foo for (u8, u32) {
default fn foo(&self) -> &'static str {
"(u8, u32)"
}
}
impl Foo for (u8, u8) {
default fn foo(&self) -> &'static str {
"(u8, u8)"
}
}
impl<T: Clone> Foo for Vec<T> {
default fn foo(&self) -> &'static str {
"generic Vec"
}
}
impl Foo for Vec<i32> {
fn foo(&self) -> &'static str {
"Vec<i32>"
}
}
impl Foo for String {
fn foo(&self) -> &'static str {
"String"
}
}
impl Foo for i32 {
fn foo(&self) -> &'static str {
"i32"
}
}
pub trait MyMarker {}
impl<T: Clone + MyMarker> Foo for T {
default fn foo(&self) -> &'static str {
"generic Clone + MyMarker"
}
}

View file

@ -0,0 +1,49 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// First, test only use of explicit `default` items:
pub trait Foo {
fn foo(&self) -> bool;
}
impl<T> Foo for T {
default fn foo(&self) -> bool { false }
}
impl Foo for i32 {}
impl Foo for i64 {
fn foo(&self) -> bool { true }
}
// Next, test mixture of explicit `default` and provided methods:
pub trait Bar {
fn bar(&self) -> i32 { 0 }
}
impl<T> Bar for T {} // use the provided method
impl Bar for i32 {
fn bar(&self) -> i32 { 1 }
}
impl<'a> Bar for &'a str {}
impl<T> Bar for Vec<T> {
default fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
fn bar(&self) -> i32 { 3 }
}

View file

@ -10,9 +10,13 @@
#![feature(associated_type_defaults)]
pub trait Foo {
type Input = usize;
fn bar(&self, _: Self::Input) {}
pub trait Foo<T: Default + ToString> {
type Out: Default + ToString = T;
}
impl Foo for () {}
impl Foo<u32> for () {
}
impl Foo<u64> for () {
type Out = bool;
}

View file

@ -22,6 +22,12 @@ pub trait IntoCow<'a, B: ?Sized> {
fn into_cow(self) -> Cow<'a, B>;
}
impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
fn into_cow(self) -> Cow<'a, B> {
Cow(PhantomData)
}
}
impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
//~^ ERROR E0119
fn into_cow(self) -> Cow<'a, B> {
@ -29,14 +35,8 @@ impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
}
}
impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned {
//~^ ERROR E0119
fn into_cow(self) -> Cow<'a, B> {
Cow(PhantomData)
}
}
impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned {
//~^ ERROR E0119
fn into_cow(self) -> Cow<'a, B> {
Cow(PhantomData)
}

View file

@ -27,11 +27,11 @@ impl Even for isize { }
impl Odd for usize { }
impl<T:Even> MyTrait for T { //~ ERROR E0119
impl<T:Even> MyTrait for T {
fn get(&self) -> usize { 0 }
}
impl<T:Odd> MyTrait for T {
impl<T:Odd> MyTrait for T { //~ ERROR E0119
fn get(&self) -> usize { 0 }
}

View file

@ -23,11 +23,11 @@ trait Even {}
trait Odd {}
impl<T:Even> MyTrait for T { //~ ERROR E0119
impl<T:Even> MyTrait for T {
fn get(&self) -> usize { 0 }
}
impl<T:Odd> MyTrait for T {
impl<T:Odd> MyTrait for T { //~ ERROR E0119
fn get(&self) -> usize { 0 }
}

View file

@ -18,7 +18,7 @@ trait MyTrait<T> {
fn get(&self) -> T;
}
impl<T> MyTrait<T> for T { //~ ERROR E0119
impl<T> MyTrait<T> for T {
fn get(&self) -> T {
panic!()
}
@ -29,7 +29,7 @@ struct MyType {
dummy: usize
}
impl MyTrait<MyType> for MyType {
impl MyTrait<MyType> for MyType { //~ ERROR E0119
fn get(&self) -> usize { (*self).clone() }
}

View file

@ -19,7 +19,7 @@ trait MyTrait {
fn get(&self) -> usize;
}
impl<T:OtherTrait> MyTrait for T { //~ ERROR E0119
impl<T:OtherTrait> MyTrait for T {
fn get(&self) -> usize { 0 }
}
@ -27,7 +27,7 @@ struct MyType {
dummy: usize
}
impl MyTrait for MyType {
impl MyTrait for MyType { //~ ERROR E0119
fn get(&self) -> usize { self.dummy }
}

View file

@ -18,7 +18,7 @@ trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T { //~ ERROR E0119
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
@ -26,7 +26,7 @@ struct MyType {
dummy: usize
}
impl MyTrait for MyType {
impl MyTrait for MyType { //~ ERROR E0119
fn get(&self) -> usize { self.dummy }
}

View file

@ -15,8 +15,6 @@ trait MyTrait {}
struct TestType<T>(::std::marker::PhantomData<T>);
unsafe impl<T: MyTrait+'static> Send for TestType<T> {}
//~^ ERROR conflicting implementations of trait `core::marker::Send`
//~^^ ERROR conflicting implementations of trait `core::marker::Send`
impl<T: MyTrait> !Send for TestType<T> {}
//~^ ERROR conflicting implementations of trait `core::marker::Send`

View file

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Regression test for #3512 - conflicting trait impls in different crates should give a
// 'conflicting implementations' error message.
// The error here is strictly due to orphan rules; the impl here
// generalizes the one upstream
// aux-build:trait_impl_conflict.rs
extern crate trait_impl_conflict;
@ -17,7 +17,6 @@ use trait_impl_conflict::Foo;
impl<A> Foo for A {
//~^ ERROR type parameter `A` must be used as the type parameter for some local type
//~^^ ERROR E0119
}
fn main() {

View file

@ -15,7 +15,7 @@ trait MyTrait {}
impl MyTrait for .. {}
impl MyTrait for .. {}
//~^ ERROR conflicting implementations of trait `MyTrait`
//~^ ERROR redundant default implementations of trait `MyTrait`
trait MySafeTrait {}

View file

@ -0,0 +1,18 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that you cannot *directly* dispatch on lifetime requirements
trait MyTrait {}
impl<T> MyTrait for T {}
impl<T: 'static> MyTrait for T {} //~ ERROR E0119
fn main() {}

View file

@ -19,10 +19,10 @@
trait From<U> {
}
impl <T> From<T> for T { //~ ERROR E0119
impl <T> From<T> for T {
}
impl <T11, U11> From<(U11,)> for (T11,) {
impl <T11, U11> From<(U11,)> for (T11,) { //~ ERROR E0119
}
fn main() { }

View file

@ -14,6 +14,6 @@
pub trait Sugar { fn dummy(&self) { } }
pub trait Sweet { fn dummy(&self) { } }
impl<T:Sugar> Sweet for T { } //~ ERROR E0119
impl<U:Sugar> Sweet for Box<U> { }
impl<T:Sugar> Sweet for T { }
impl<U:Sugar> Sweet for Box<U> { } //~ ERROR E0119
fn main() { }

View file

@ -10,33 +10,23 @@
trait Foo {}
impl<T> Foo for T {} //~ ERROR conflicting implementations of trait `Foo`:
impl<U> Foo for U {}
impl<T> Foo for T {}
impl<U> Foo for U {} //~ ERROR conflicting implementations of trait `Foo`:
trait Bar {}
impl<T> Bar for T {} //~ ERROR conflicting implementations of trait `Bar` for type `u8`:
impl Bar for u8 {}
impl<T> Bar for (T, u8) {}
impl<T> Bar for (u8, T) {} //~ ERROR conflicting implementations of trait `Bar` for type `(u8, u8)`:
trait Baz<T> {}
impl<T, U> Baz<U> for T {} //~ ERROR conflicting implementations of trait `Baz<_>` for type `u8`:
impl<T> Baz<T> for u8 {}
impl<T> Baz<u8> for T {}
impl<T> Baz<T> for u8 {} //~ ERROR conflicting implementations of trait `Baz<u8>` for type `u8`:
trait Quux<T> {}
trait Quux<U, V> {}
impl<T, U> Quux<U> for T {} //~ ERROR conflicting implementations of trait `Quux<_>`:
impl<T> Quux<T> for T {}
trait Qaar<T> {}
impl<T, U> Qaar<U> for T {} //~ ERROR conflicting implementations of trait `Qaar<u8>`:
impl<T> Qaar<u8> for T {}
trait Qaax<T> {}
impl<T, U> Qaax<U> for T {}
//~^ ERROR conflicting implementations of trait `Qaax<u8>` for type `u32`:
impl Qaax<u8> for u32 {}
impl<T, U, V> Quux<U, V> for T {}
impl<T, U> Quux<U, U> for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`:
impl<T, V> Quux<T, V> for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`:
fn main() {}

View file

@ -21,8 +21,8 @@ pub trait Bar {
type Output: 'static;
}
impl Foo<i32> for i32 { } //~ ERROR E0119
impl Foo<i32> for i32 { }
impl<A:Iterator> Foo<A::Item> for A { }
impl<A:Iterator> Foo<A::Item> for A { } //~ ERROR E0119
fn main() {}

View file

@ -15,8 +15,8 @@ use std::marker::PhantomData;
pub trait Foo<P> {}
impl <P, T: Foo<P>> Foo<P> for Option<T> {} //~ ERROR E0119
impl <P, T: Foo<P>> Foo<P> for Option<T> {}
impl<T, U> Foo<T> for Option<U> { }
impl<T, U> Foo<T> for Option<U> { } //~ ERROR E0119
fn main() {}

View file

@ -16,9 +16,9 @@ pub trait Bar {
type Output: 'static;
}
impl Foo<i32> for i32 { } //~ ERROR E0119
impl Foo<i32> for i32 { }
impl<A:Bar> Foo<A::Output> for A { }
impl<A:Bar> Foo<A::Output> for A { } //~ ERROR E0119
impl Bar for i32 {
type Output = i32;

View file

@ -18,11 +18,11 @@ trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for (T,T) { //~ ERROR E0119
impl<T> MyTrait for (T,T) {
fn get(&self) -> usize { 0 }
}
impl<A,B> MyTrait for (A,B) {
impl<A,B> MyTrait for (A,B) { //~ ERROR E0119
fn get(&self) -> usize { self.dummy }
}

View file

@ -21,10 +21,10 @@ struct MyType { x: i32 }
trait MyTrait { }
impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
impl<T: lib::MyCopy> MyTrait for T { }
// Tuples are not fundamental.
impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { }
impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } //~ ERROR E0119
#[rustc_error]
fn main() { }

View file

@ -18,7 +18,7 @@ extern crate coherence_copy_like_lib as lib;
struct MyType { x: i32 }
trait MyTrait { }
impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
impl<T: lib::MyCopy> MyTrait for T { }
// `MyStruct` is not declared fundamental, therefore this would
// require that
@ -26,6 +26,6 @@ impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
// MyStruct<MyType>: !MyTrait
//
// which we cannot approve.
impl MyTrait for lib::MyStruct<MyType> { }
impl MyTrait for lib::MyStruct<MyType> { } //~ ERROR E0119
fn main() { }

View file

@ -18,13 +18,13 @@ extern crate coherence_copy_like_lib as lib;
struct MyType { x: i32 }
trait MyTrait { }
impl<T: lib::MyCopy> MyTrait for T { } //~ ERROR E0119
impl<T: lib::MyCopy> MyTrait for T { }
// Tuples are not fundamental, therefore this would require that
//
// (MyType,): !MyTrait
//
// which we cannot approve.
impl MyTrait for (MyType,) { }
impl MyTrait for (MyType,) { } //~ ERROR E0119
fn main() { }

View file

@ -10,14 +10,14 @@
struct MyStruct;
impl Drop for MyStruct {
//~^ ERROR conflicting implementations of trait
fn drop(&mut self) { }
}
impl Drop for MyStruct {
//~^ NOTE conflicting implementation is here
fn drop(&mut self) { }
}
impl Drop for MyStruct {
//~^ ERROR conflicting implementations of trait
fn drop(&mut self) { }
}
fn main() {}

View file

@ -198,9 +198,11 @@ mod aliases_pub {
use self::m::PubTr as PrivUseAliasTr;
type PrivAlias = m::Pub2;
trait PrivTr {
type AssocAlias;
}
impl PrivTr for Priv {
type AssocAlias = m::Pub3;
}
impl PrivTr for Priv {}
pub fn f1(arg: PrivUseAlias) {} // OK
@ -245,9 +247,11 @@ mod aliases_priv {
use self::PrivTr1 as PrivUseAliasTr;
type PrivAlias = Priv2;
trait PrivTr {
type AssocAlias;
}
impl PrivTr for Priv {
type AssocAlias = Priv3;
}
impl PrivTr for Priv {}
pub trait Tr1: PrivUseAliasTr {} //~ WARN private trait in public interface
//~^ WARNING hard error

View file

@ -0,0 +1,21 @@
This directory contains the test for incorrect usage of specialization that
should lead to compile failure. Those tests break down into a few categories:
- Feature gating
- [On use of the `default` keyword](specialization-feature-gate-default.rs)
- [On overlapping impls](specialization-feature-gate-overlap.rs)
- Overlap checking with specialization enabled
- [Basic overlap scenarios](specialization-overlap.rs)
- Includes purely structural overlap
- Includes purely trait-based overlap
- Includes mix
- [Overlap with differing polarity](specialization-overlap-negative.rs)
- [Attempt to specialize without using `default`](specialization-no-default.rs)
- [Attempt to change impl polarity in a specialization](specialization-polarity.rs)
- Attempt to rely on projection of a `default` type
- [Rely on it externally in both generic and monomorphic contexts](specialization-default-projection.rs)
- [Rely on it both within an impl and outside it](specialization-default-types.rs)

View file

@ -0,0 +1,46 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Make sure we can't project defaulted associated types
trait Foo {
type Assoc;
}
impl<T> Foo for T {
default type Assoc = ();
}
impl Foo for u8 {
type Assoc = String;
}
fn generic<T>() -> <T as Foo>::Assoc {
// `T` could be some downstream crate type that specializes (or,
// for that matter, `u8`).
() //~ ERROR mismatched types
}
fn monomorphic() -> () {
// Even though we know that `()` is not specialized in a
// downstream crate, typeck refuses to project here.
generic::<()>() //~ ERROR mismatched types
}
fn main() {
// No error here, we CAN project from `u8`, as there is no `default`
// in that impl.
let s: String = generic::<u8>();
println!("{}", s); // bad news if this all compiles
}

View file

@ -0,0 +1,45 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// It should not be possible to use the concrete value of a defaulted
// associated type in the impl defining it -- otherwise, what happens
// if it's overridden?
#![feature(specialization)]
trait Example {
type Output;
fn generate(self) -> Self::Output;
}
impl<T> Example for T {
default type Output = Box<T>;
default fn generate(self) -> Self::Output {
Box::new(self) //~ ERROR mismatched types
}
}
impl Example for bool {
type Output = bool;
fn generate(self) -> bool { self }
}
fn trouble<T>(t: T) -> Box<T> {
Example::generate(t) //~ ERROR mismatched types
}
fn weaponize() -> bool {
let b: Box<bool> = trouble(true);
*b
}
fn main() {
weaponize();
}

View file

@ -0,0 +1,21 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that specialization must be ungated to use the `default` keyword
trait Foo {
fn foo(&self);
}
impl<T> Foo for T {
default fn foo(&self) {} //~ ERROR specialization is unstable
}
fn main() {}

View file

@ -0,0 +1,25 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that writing an overlapping impl is not allow unless specialization is ungated.
trait Foo {
fn foo(&self);
}
impl<T> Foo for T {
fn foo(&self) {}
}
impl Foo for u8 { //~ ERROR E0119
fn foo(&self) {}
}
fn main() {}

View file

@ -0,0 +1,95 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
// Check a number of scenarios in which one impl tries to override another,
// without correctly using `default`.
////////////////////////////////////////////////////////////////////////////////
// Test 1: one layer of specialization, multiple methods, missing `default`
////////////////////////////////////////////////////////////////////////////////
trait Foo {
fn foo(&self);
fn bar(&self);
}
impl<T> Foo for T {
fn foo(&self) {}
fn bar(&self) {}
}
impl Foo for u8 {}
impl Foo for u16 {
fn foo(&self) {} //~ ERROR E0520
}
impl Foo for u32 {
fn bar(&self) {} //~ ERROR E0520
}
////////////////////////////////////////////////////////////////////////////////
// Test 2: one layer of specialization, missing `default` on associated type
////////////////////////////////////////////////////////////////////////////////
trait Bar {
type T;
}
impl<T> Bar for T {
type T = u8;
}
impl Bar for u8 {
type T = (); //~ ERROR E0520
}
////////////////////////////////////////////////////////////////////////////////
// Test 3a: multiple layers of specialization, missing interior `default`
////////////////////////////////////////////////////////////////////////////////
trait Baz {
fn baz(&self);
}
impl<T> Baz for T {
default fn baz(&self) {}
}
impl<T: Clone> Baz for T {
fn baz(&self) {}
}
impl Baz for i32 {
fn baz(&self) {} //~ ERROR E0520
}
////////////////////////////////////////////////////////////////////////////////
// Test 3b: multiple layers of specialization, missing interior `default`,
// redundant `default` in bottom layer.
////////////////////////////////////////////////////////////////////////////////
trait Redundant {
fn redundant(&self);
}
impl<T> Redundant for T {
default fn redundant(&self) {}
}
impl<T: Clone> Redundant for T {
fn redundant(&self) {}
}
impl Redundant for i32 {
default fn redundant(&self) {} //~ ERROR E0520
}
fn main() {}

View file

@ -0,0 +1,21 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(optin_builtin_traits)]
#![feature(specialization)]
trait MyTrait {}
struct TestType<T>(::std::marker::PhantomData<T>);
unsafe impl<T: Clone> Send for TestType<T> {}
impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR E0119
fn main() {}

View file

@ -0,0 +1,29 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(specialization)]
trait Foo {}
impl<T: Clone> Foo for T {}
impl<T> Foo for Vec<T> {} //~ ERROR E0119
trait Bar {}
impl<T> Bar for (T, u8) {}
impl<T> Bar for (u8, T) {} //~ ERROR E0119
trait Baz<U> {}
impl<T> Baz<T> for u8 {}
impl<T> Baz<u8> for T {} //~ ERROR E0119
trait Qux {}
impl<T: Clone> Qux for T {}
impl<T: Eq> Qux for T {} //~ ERROR E0119
fn main() {}

View file

@ -0,0 +1,30 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure specialization cannot change impl polarity
#![feature(optin_builtin_traits)]
#![feature(specialization)]
trait Foo {}
impl Foo for .. {}
impl<T> Foo for T {}
impl !Foo for u8 {} //~ ERROR E0119
trait Bar {}
impl Bar for .. {}
impl<T> !Bar for T {}
impl Bar for u8 {} //~ ERROR E0119
fn main() {}

View file

@ -0,0 +1,35 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
// Test successful and unsucessful parsing of the `default` contextual keyword
trait Foo {
fn foo<T: Default>() -> T;
}
impl Foo for u8 {
default fn foo<T: Default>() -> T {
T::default()
}
}
impl Foo for u16 {
pub default fn foo<T: Default>() -> T {
T::default()
}
}
impl Foo for u32 {
default pub fn foo<T: Default>() -> T { T::default() } //~ ERROR expected one of
}
fn main() {}

View file

@ -16,6 +16,6 @@ impl Foo {
fn foo() {}
#[stable(feature = "rust1", since = "1.0.0")]
} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
} //~ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
fn main() {}

View file

@ -14,6 +14,6 @@ struct Foo;
impl Foo {
#[stable(feature = "rust1", since = "1.0.0")]
} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
} //~ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
fn main() {}

View file

@ -15,4 +15,4 @@ struct S;
impl S {
static fn f() {}
}
//~^^ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
//~^^ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`

View file

@ -10,23 +10,22 @@
#![feature(associated_type_defaults)]
trait Foo<T> {
type Out = T;
fn foo(&self) -> Self::Out;
trait Foo<T: Default + ToString> {
type Out: Default + ToString = T;
}
impl Foo<u32> for () {
fn foo(&self) -> u32 {
4u32
}
}
impl Foo<u64> for bool {
type Out = ();
fn foo(&self) {}
impl Foo<u64> for () {
type Out = bool;
}
fn main() {
assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
assert_eq!(<bool as Foo<u64>>::foo(&true), ());
assert_eq!(
<() as Foo<u32>>::Out::default().to_string(),
"0");
assert_eq!(
<() as Foo<u64>>::Out::default().to_string(),
"false");
}

View file

@ -0,0 +1,37 @@
Tests that specialization is working correctly:
- Dispatch
- [On methods](specialization-basics.rs), includes:
- Specialization via adding a trait bound
- Including both remote and local traits
- Specialization via pure structure (e.g. `(T, U)` vs `(T, T)`)
- Specialization via concrete types vs unknown types
- In top level of the trait reference
- Embedded within another type (`Vec<T>` vs `Vec<i32>`)
- [Specialization based on super trait relationships](specialization-super-traits.rs)
- [On assoc fns](specialization-assoc-fns.rs)
- [Ensure that impl order doesn't matter](specialization-out-of-order.rs)
- Item inheritance
- [Correct default cascading for methods](specialization-default-methods.rs)
- Inheritance works across impls with varying generics
- [With projections](specialization-translate-projections.rs)
- [With projections that involve input types](specialization-translate-projections-with-params.rs)
- Normalization issues
- [Non-default assoc types can be projected](specialization-projection.rs)
- Including non-specialized cases
- Including specialized cases
- [Specialized Impls can happen on projections](specialization-on-projection.rs)
- [Projections and aliases play well together](specialization-projection-alias.rs)
- [Projections involving specialization allowed in the trait ref for impls, and overlap can still be determined](specialization-overlap-projection.rs)
- Only works for the simple case where the most specialized impl directly
provides a non-`default` associated type
- Across crates
- [For traits defined in upstream crate](specialization-allowed-cross-crate.rs)
- [Full method dispatch tests, drawing from upstream crate](specialization-cross-crate.rs)
- Including *additional* local specializations
- [Full method dispatch tests, *without* turning on specialization in local crate](specialization-cross-crate-no-gate.rs)
- [Test that defaults cascade correctly from upstream crates](specialization-cross-crate-defaults.rs)
- Including *additional* local use of defaults

View file

@ -0,0 +1,31 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:go_trait.rs
#![feature(specialization)]
extern crate go_trait;
use go_trait::{Go,GoMut};
use std::fmt::Debug;
use std::default::Default;
struct MyThingy;
impl Go for MyThingy {
fn go(&self, arg: isize) { }
}
impl GoMut for MyThingy {
fn go_mut(&mut self, arg: isize) { }
}
fn main() { }

Some files were not shown because too many files have changed in this diff Show more