support default impl
for specialization
a `default impl` need not include all items from the trait a `default impl` alone does not mean that a type implements the trait
This commit is contained in:
parent
29c8276cee
commit
f5c55ff379
30 changed files with 870 additions and 33 deletions
|
@ -218,7 +218,8 @@ impl_stable_hash_for!(enum ty::Visibility {
|
|||
});
|
||||
|
||||
impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
|
||||
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
|
||||
impl_stable_hash_for!(enum ty::DefaultImplCheck { Yes, No });
|
||||
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref, default_impl_check });
|
||||
impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
|
||||
impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });
|
||||
|
||||
|
|
|
@ -1083,12 +1083,39 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Treat negative impls as unimplemented
|
||||
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
|
||||
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||
fn filter_negative_and_default_impls<'o>(&self,
|
||||
candidate: SelectionCandidate<'tcx>,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||
|
||||
if let ImplCandidate(def_id) = candidate {
|
||||
if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative {
|
||||
return Err(Unimplemented)
|
||||
}
|
||||
|
||||
// if def_id is a default impl and it doesn't implement all the trait items,
|
||||
// the impl doesn't implement the trait.
|
||||
// An `Unimplemented` error is returned only if the default_impl_check is
|
||||
// applicable to the trait predicate or the cause of the predicate is an
|
||||
// `ObjectCastObligation`
|
||||
if self.tcx().impl_is_default(def_id) &&
|
||||
!self.tcx().default_impl_implement_all_methods(def_id){
|
||||
match stack.obligation.cause.code {
|
||||
ObligationCauseCode::ObjectCastObligation(_) => {
|
||||
return Err(Unimplemented)
|
||||
},
|
||||
ObligationCauseCode::ItemObligation(..) |
|
||||
ObligationCauseCode::MiscObligation => {
|
||||
if let ty::DefaultImplCheck::Yes = stack.obligation
|
||||
.predicate
|
||||
.skip_binder()
|
||||
.default_impl_check {
|
||||
return Err(Unimplemented)
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(candidate))
|
||||
}
|
||||
|
@ -1178,9 +1205,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
// Instead, we select the right impl now but report `Bar does
|
||||
// not implement Clone`.
|
||||
if candidates.len() == 1 {
|
||||
return self.filter_negative_impls(candidates.pop().unwrap());
|
||||
return self.filter_negative_and_default_impls(candidates.pop().unwrap(), stack);
|
||||
}
|
||||
|
||||
// Winnow, but record the exact outcome of evaluation, which
|
||||
// is needed for specialization.
|
||||
let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
|
||||
|
@ -1239,7 +1265,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Just one candidate left.
|
||||
self.filter_negative_impls(candidates.pop().unwrap().candidate)
|
||||
self.filter_negative_and_default_impls(candidates.pop().unwrap().candidate, stack)
|
||||
}
|
||||
|
||||
fn is_knowable<'o>(&mut self,
|
||||
|
|
|
@ -22,8 +22,11 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|||
pred: &ty::Predicate<'tcx>)
|
||||
-> ty::Predicate<'tcx> {
|
||||
match *pred {
|
||||
ty::Predicate::Trait(ref data) =>
|
||||
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)),
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let anonymized_pred = ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data));
|
||||
anonymized_pred.change_default_impl_check(ty::DefaultImplCheck::No)
|
||||
.unwrap_or(anonymized_pred)
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(ref data) =>
|
||||
ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)),
|
||||
|
@ -554,6 +557,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn impl_item_is_final(self, node_item: &NodeItem<hir::Defaultness>) -> bool {
|
||||
node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id())
|
||||
}
|
||||
|
||||
pub fn default_impl_implement_all_methods(self, node_item_def_id: DefId) -> bool {
|
||||
if let Some(impl_trait_ref) = self.impl_trait_ref(node_item_def_id) {
|
||||
let trait_def = self.trait_def(impl_trait_ref.def_id);
|
||||
for trait_item in self.associated_items(impl_trait_ref.def_id) {
|
||||
let is_implemented = trait_def.ancestors(self, node_item_def_id)
|
||||
.defs(self, trait_item.name, trait_item.kind, impl_trait_ref.def_id)
|
||||
.next()
|
||||
.map(|node_item| !node_item.node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TupleArgumentsFlag { Yes, No }
|
||||
|
|
|
@ -9,14 +9,19 @@
|
|||
// except according to those terms.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
|
||||
use ty::subst::Kind;
|
||||
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt, AssociatedKind, AssociatedItemContainer};
|
||||
use ty::subst::{Kind, Subst};
|
||||
use traits;
|
||||
use syntax::abi::Abi;
|
||||
use util::ppaux;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use syntax_pos::{BytePos, Span};
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use hir::map::Node::NodeTraitItem;
|
||||
use hir;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Instance<'tcx> {
|
||||
pub def: InstanceDef<'tcx>,
|
||||
|
@ -260,6 +265,13 @@ fn resolve_associated_item<'a, 'tcx>(
|
|||
traits::VtableImpl(impl_data) => {
|
||||
let (def_id, substs) = traits::find_associated_item(
|
||||
tcx, trait_item, rcvr_substs, &impl_data);
|
||||
|
||||
check_unimplemented_trait_item(tcx,
|
||||
impl_data.impl_def_id,
|
||||
def_id,
|
||||
trait_id,
|
||||
trait_item);
|
||||
|
||||
let substs = tcx.erase_regions(&substs);
|
||||
Some(ty::Instance::new(def_id, substs))
|
||||
}
|
||||
|
@ -363,3 +375,108 @@ fn fn_once_adapter_instance<'a, 'tcx>(
|
|||
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
|
||||
Instance { def, substs }
|
||||
}
|
||||
|
||||
fn check_unimplemented_trait_item<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
impl_def_id: DefId,
|
||||
trait_item_def_id: DefId,
|
||||
trait_id: DefId,
|
||||
trait_item: &ty::AssociatedItem)
|
||||
{
|
||||
// if trait_item_def_id is a trait item and it doesn't have a default trait implementation
|
||||
// the resolution has found an unimplemented trait item inside a default impl
|
||||
if tcx.impl_is_default(impl_def_id) {
|
||||
let is_unimplemented_trait_item = match tcx.hir.as_local_node_id(trait_item_def_id) {
|
||||
Some(node_id) =>
|
||||
match tcx.hir.find(node_id) {
|
||||
Some(NodeTraitItem(item)) => {
|
||||
if let hir::TraitItemKind::Method(_,
|
||||
hir::TraitMethod::Provided(_))
|
||||
= item.node {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
None => {
|
||||
let item = tcx.global_tcx().associated_item(trait_item_def_id);
|
||||
match item.kind {
|
||||
AssociatedKind::Method => match item.container {
|
||||
AssociatedItemContainer::TraitContainer(_) => {
|
||||
!item.defaultness.has_value()
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if is_unimplemented_trait_item {
|
||||
let mut err = tcx.sess.struct_err(&format!("the trait method `{}` \
|
||||
is not implemented",
|
||||
trait_item.name));
|
||||
|
||||
let mut help_messages = Vec::new();
|
||||
help_messages.push(
|
||||
if impl_def_id.is_local() {
|
||||
let item = tcx.hir
|
||||
.expect_item(
|
||||
tcx.hir
|
||||
.as_local_node_id(impl_def_id).unwrap()
|
||||
);
|
||||
(item.span, format!("implement it inside this `default impl`"))
|
||||
} else {
|
||||
(Span::new (
|
||||
BytePos(0),
|
||||
BytePos(0),
|
||||
SyntaxContext::empty()
|
||||
),
|
||||
format!("implement it inside the {} `default impl`",
|
||||
tcx.item_path_str(impl_def_id)))
|
||||
}
|
||||
);
|
||||
|
||||
help_messages.push(
|
||||
if trait_id.is_local() {
|
||||
let trait_item = tcx.hir
|
||||
.expect_item(
|
||||
tcx.hir
|
||||
.as_local_node_id(trait_id).unwrap()
|
||||
);
|
||||
(trait_item.span, format!("provide a default method implementation \
|
||||
inside this `trait`"))
|
||||
} else {
|
||||
(Span::new (
|
||||
BytePos(0),
|
||||
BytePos(0),
|
||||
SyntaxContext::empty()
|
||||
),
|
||||
format!("provide a default method implementation \
|
||||
inside the {} `trait`",
|
||||
tcx.item_path_str(trait_id)))
|
||||
}
|
||||
);
|
||||
|
||||
help_messages.sort_by(|&(a,_), &(b,_)| a.partial_cmp(&b).unwrap());
|
||||
|
||||
let mut cnjs = vec!["or ", "either "];
|
||||
help_messages.iter().for_each(|&(span, ref msg)| {
|
||||
let mut help_msg = String::from(cnjs.pop().unwrap_or(""));
|
||||
help_msg.push_str(&msg);
|
||||
|
||||
if span.data().lo == BytePos(0) && span.data().hi == BytePos(0) {
|
||||
err.help(&help_msg);
|
||||
} else {
|
||||
err.span_help(span, &help_msg);
|
||||
}
|
||||
});
|
||||
|
||||
err.note(&format!("a `default impl` doesn't need to include all \
|
||||
items from the trait"));
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1070,9 +1070,13 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum DefaultImplCheck { Yes, No, }
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct TraitPredicate<'tcx> {
|
||||
pub trait_ref: TraitRef<'tcx>
|
||||
pub trait_ref: TraitRef<'tcx>,
|
||||
pub default_impl_check: DefaultImplCheck
|
||||
}
|
||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>;
|
||||
|
||||
|
@ -1180,7 +1184,8 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
|
|||
assert!(!self.has_escaping_regions());
|
||||
|
||||
ty::Predicate::Trait(ty::Binder(ty::TraitPredicate {
|
||||
trait_ref: self.clone()
|
||||
trait_ref: self.clone(),
|
||||
default_impl_check: DefaultImplCheck::No
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -1298,6 +1303,36 @@ impl<'tcx> Predicate<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck)
|
||||
-> Option<Predicate<'tcx>> {
|
||||
match *self {
|
||||
Predicate::Trait(ref t) => {
|
||||
if t.skip_binder().default_impl_check != default_impl_check {
|
||||
Some(
|
||||
Predicate::Trait(ty::Binder(ty::TraitPredicate {
|
||||
trait_ref: t.skip_binder().trait_ref,
|
||||
default_impl_check: default_impl_check
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Predicate::Trait(..) |
|
||||
Predicate::Projection(..) |
|
||||
Predicate::Equate(..) |
|
||||
Predicate::Subtype(..) |
|
||||
Predicate::RegionOutlives(..) |
|
||||
Predicate::WellFormed(..) |
|
||||
Predicate::ObjectSafe(..) |
|
||||
Predicate::ClosureKind(..) |
|
||||
Predicate::TypeOutlives(..) |
|
||||
Predicate::ConstEvaluatable(..) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the bounds declared on a particular set of type
|
||||
|
|
|
@ -278,7 +278,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
|
|||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
|
||||
-> Option<ty::TraitPredicate<'tcx>> {
|
||||
tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate {
|
||||
trait_ref,
|
||||
trait_ref: trait_ref,
|
||||
default_impl_check: self.default_impl_check
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1127,7 +1128,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
|
|||
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
ty::TraitPredicate {
|
||||
trait_ref: self.trait_ref.fold_with(folder)
|
||||
trait_ref: self.trait_ref.fold_with(folder),
|
||||
default_impl_check: self.default_impl_check
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -582,7 +582,10 @@ impl<'tcx> PolyTraitRef<'tcx> {
|
|||
|
||||
pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
|
||||
// Note that we preserve binding levels
|
||||
Binder(ty::TraitPredicate { trait_ref: self.0.clone() })
|
||||
Binder(ty::TraitPredicate {
|
||||
trait_ref: self.0.clone(),
|
||||
default_impl_check: ty::DefaultImplCheck::No
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1230,8 +1230,12 @@ define_print! {
|
|||
define_print! {
|
||||
('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) {
|
||||
debug {
|
||||
write!(f, "TraitPredicate({:?})",
|
||||
self.trait_ref)
|
||||
let default_impl_check_value = match self.default_impl_check {
|
||||
ty::DefaultImplCheck::Yes => "default_impl_check: yes",
|
||||
ty::DefaultImplCheck::No => "default_impl_check: no",
|
||||
};
|
||||
write!(f, "TraitPredicate({:?}, {})",
|
||||
self.trait_ref, default_impl_check_value)
|
||||
}
|
||||
display {
|
||||
print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))
|
||||
|
|
|
@ -618,6 +618,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
self.output);
|
||||
} else {
|
||||
visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
|
||||
|
||||
if tcx.sess.has_errors() {
|
||||
match func {
|
||||
&mir::Operand::Consume(_) => {}
|
||||
&mir::Operand::Constant(ref cst) => {
|
||||
tcx.sess
|
||||
.span_note_without_error(cst.span,
|
||||
"the function call is here");
|
||||
}
|
||||
}
|
||||
tcx.sess.abort_if_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
mir::TerminatorKind::Drop { ref location, .. } |
|
||||
|
@ -678,7 +690,10 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
ty::ParamEnv::empty(traits::Reveal::All),
|
||||
def_id,
|
||||
substs).unwrap();
|
||||
visit_instance_use(tcx, instance, is_direct_call, output);
|
||||
if !tcx.sess.has_errors() {
|
||||
// continue only if no errors are encountered during monomorphization
|
||||
visit_instance_use(tcx, instance, is_direct_call, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1378,7 +1378,10 @@ pub struct Bounds<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
|
||||
pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
|
||||
pub fn predicates(&self,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_ty: Ty<'tcx>,
|
||||
default_impl_check: ty::DefaultImplCheck)
|
||||
-> Vec<ty::Predicate<'tcx>>
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
|
@ -1402,7 +1405,16 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
|
|||
}
|
||||
|
||||
for bound_trait_ref in &self.trait_bounds {
|
||||
vec.push(bound_trait_ref.to_predicate());
|
||||
vec.push(
|
||||
if bound_trait_ref.skip_binder().def_id !=
|
||||
tcx.lang_items().sized_trait().unwrap() {
|
||||
bound_trait_ref.to_predicate()
|
||||
.change_default_impl_check(default_impl_check)
|
||||
.unwrap_or(bound_trait_ref.to_predicate())
|
||||
} else {
|
||||
bound_trait_ref.to_predicate()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for projection in &self.projection_bounds {
|
||||
|
|
|
@ -189,7 +189,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
|||
let generic_assumptions = tcx.predicates_of(self_type_did);
|
||||
|
||||
let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
|
||||
let assumptions_in_impl_context = assumptions_in_impl_context.predicates;
|
||||
let assumptions_in_impl_context: Vec<ty::Predicate> =
|
||||
assumptions_in_impl_context.predicates
|
||||
.iter()
|
||||
.map(|predicate| {
|
||||
predicate.change_default_impl_check(ty::DefaultImplCheck::No)
|
||||
.unwrap_or(predicate.clone())
|
||||
}).collect();
|
||||
|
||||
// An earlier version of this code attempted to do this checking
|
||||
// via the traits::fulfill machinery. However, it ran into trouble
|
||||
|
@ -211,7 +217,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
|||
// the analysis together via the fulfill , rather than the
|
||||
// repeated `contains` calls.
|
||||
|
||||
if !assumptions_in_impl_context.contains(&predicate) {
|
||||
if !assumptions_in_impl_context.contains(
|
||||
&predicate.change_default_impl_check(ty::DefaultImplCheck::No)
|
||||
.unwrap_or(predicate.clone())) {
|
||||
let item_span = tcx.hir.span(self_type_node_id);
|
||||
struct_span_err!(tcx.sess, drop_impl_span, E0367,
|
||||
"The requirement `{}` is added only by the Drop impl.", predicate)
|
||||
|
|
|
@ -1395,7 +1395,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
.map(|node_item| !node_item.node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
if !is_implemented && !tcx.impl_is_default(impl_id) {
|
||||
if !trait_item.defaultness.has_value() {
|
||||
missing_items.push(trait_item);
|
||||
} else if associated_type_overridden {
|
||||
|
|
|
@ -25,6 +25,7 @@ use errors::{DiagnosticBuilder, DiagnosticId};
|
|||
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::hir;
|
||||
use rustc::ty::TypeFoldable;
|
||||
|
||||
pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
@ -343,8 +344,36 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
|||
fcx.body_id,
|
||||
&trait_ref,
|
||||
ast_trait_ref.path.span);
|
||||
|
||||
// not registering predicates associcated with a `default impl`
|
||||
// that doesn't implement all the trait items.
|
||||
// it's left to the trait selection to select those trait predicates
|
||||
// and trigger an `Unimplemented` error in case the defaul_impl_check
|
||||
// is applicable
|
||||
let impl_not_implement_trait =
|
||||
if fcx.tcx.impl_is_default(item_def_id) &&
|
||||
!fcx.tcx.default_impl_implement_all_methods(item_def_id) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
for obligation in obligations {
|
||||
fcx.register_predicate(obligation);
|
||||
let register = match obligation.predicate {
|
||||
ty::Predicate::Trait(..) => {
|
||||
if impl_not_implement_trait &&
|
||||
!obligation.predicate.has_param_types() {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
_ => true
|
||||
};
|
||||
|
||||
if register {
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
|
|
@ -677,7 +677,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
SizedByDefault::No,
|
||||
item.span);
|
||||
|
||||
let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
|
||||
let superbounds1 = superbounds1.predicates(tcx, self_param_ty, ty::DefaultImplCheck::No);
|
||||
|
||||
// Convert any explicit superbounds in the where clause,
|
||||
// e.g. `trait Foo where Self : Bar`:
|
||||
|
@ -694,7 +694,11 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: superbounds
|
||||
predicates: superbounds.iter()
|
||||
.map(|predicate| {
|
||||
predicate.change_default_impl_check(ty::DefaultImplCheck::Yes)
|
||||
.unwrap_or(predicate.clone())
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1364,17 +1368,39 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let node = tcx.hir.get(node_id);
|
||||
|
||||
let mut is_trait = None;
|
||||
let mut default_impl_check = ty::DefaultImplCheck::No;
|
||||
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let no_generics = hir::Generics::empty();
|
||||
let ast_generics = match node {
|
||||
NodeTraitItem(item) => &item.generics,
|
||||
NodeImplItem(item) => &item.generics,
|
||||
NodeTraitItem(item) => {
|
||||
match item.node {
|
||||
TraitItemKind::Method(ref sig, _) => {
|
||||
default_impl_check = ty::DefaultImplCheck::Yes;
|
||||
&item.generics
|
||||
},
|
||||
_ => &item.generics
|
||||
}
|
||||
}
|
||||
NodeImplItem(item) => {
|
||||
match item.node {
|
||||
ImplItemKind::Method(ref sig, _) => {
|
||||
default_impl_check = ty::DefaultImplCheck::Yes;
|
||||
&item.generics
|
||||
},
|
||||
_ => &item.generics
|
||||
}
|
||||
}
|
||||
|
||||
NodeItem(item) => {
|
||||
match item.node {
|
||||
ItemFn(.., ref generics, _) |
|
||||
ItemImpl(_, _, _, ref generics, ..) |
|
||||
ItemStruct(_, ref generics) => {
|
||||
default_impl_check = ty::DefaultImplCheck::Yes;
|
||||
generics
|
||||
}
|
||||
|
||||
ItemTy(_, ref generics) |
|
||||
ItemEnum(_, ref generics) |
|
||||
ItemStruct(_, ref generics) |
|
||||
|
@ -1415,7 +1441,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
|
||||
debug!("explicit_predicates_of: bounds={:?}", bounds);
|
||||
|
||||
let predicates = bounds.predicates(tcx, anon_ty);
|
||||
let predicates = bounds.predicates(tcx, anon_ty, ty::DefaultImplCheck::No);
|
||||
|
||||
debug!("explicit_predicates_of: predicates={:?}", predicates);
|
||||
|
||||
|
@ -1476,7 +1502,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
¶m.bounds,
|
||||
SizedByDefault::Yes,
|
||||
param.span);
|
||||
predicates.extend(bounds.predicates(tcx, param_ty));
|
||||
predicates.extend(bounds.predicates(tcx, param_ty, default_impl_check));
|
||||
}
|
||||
|
||||
// Add in the bounds that appear in the where-clause
|
||||
|
@ -1496,8 +1522,16 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
poly_trait_ref,
|
||||
ty,
|
||||
&mut projections);
|
||||
|
||||
predicates.push(trait_ref.to_predicate());
|
||||
predicates.push(
|
||||
if trait_ref.skip_binder().def_id !=
|
||||
tcx.lang_items().sized_trait().unwrap() {
|
||||
trait_ref.to_predicate()
|
||||
.change_default_impl_check(default_impl_check)
|
||||
.unwrap_or(trait_ref.to_predicate())
|
||||
} else {
|
||||
trait_ref.to_predicate()
|
||||
}
|
||||
);
|
||||
|
||||
for projection in &projections {
|
||||
predicates.push(projection.to_predicate());
|
||||
|
@ -1552,7 +1586,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
SizedByDefault::Yes,
|
||||
trait_item.span);
|
||||
|
||||
bounds.predicates(tcx, assoc_ty).into_iter()
|
||||
bounds.predicates(tcx, assoc_ty, ty::DefaultImplCheck::No).into_iter()
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// 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:foo_trait_default_impl.rs
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
extern crate foo_trait_default_impl;
|
||||
|
||||
use foo_trait_default_impl::*;
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
MyStruct.foo_two(); //~ NOTE the function call is here
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// 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:foo_trait.rs
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
extern crate foo_trait;
|
||||
|
||||
use foo_trait::{Foo};
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
default impl Foo for MyStruct {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
//~^^^^^ HELP implement it inside this `default impl`
|
||||
|
||||
fn main() {
|
||||
MyStruct.foo_two(); //~ NOTE the function call is here
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
||||
//~^^^^ HELP provide a default method implementation inside this `trait`
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
//~^^^^^ HELP implement it inside this `default impl`
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
MyStruct.foo_two(); //~ NOTE the function call is here
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
|
||||
// error-pattern: the trait bound `MyStruct: Draw` is not satisfied
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Draw {
|
||||
fn draw(&self);
|
||||
fn draw2(&self);
|
||||
}
|
||||
|
||||
struct Screen {
|
||||
pub components: Vec<Box<Draw>>,
|
||||
}
|
||||
|
||||
impl Screen {
|
||||
pub fn run(&self) {
|
||||
for component in self.components.iter() {
|
||||
component.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default impl<T> Draw for T {
|
||||
fn draw(&self) {
|
||||
println!("draw");
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
let screen = Screen {
|
||||
components: vec![
|
||||
Box::new(MyStruct)
|
||||
]
|
||||
};
|
||||
screen.run();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// 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.
|
||||
|
||||
// error-pattern: the trait bound `MyStruct: Foo` is not satisfied
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
fn foo<T: Foo>(x: T) -> &'static str {
|
||||
x.foo_one()
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", foo(MyStruct));
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
|
||||
// error-pattern: the trait bound `MyStruct: Foo` is not satisfied
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
struct FooS;
|
||||
|
||||
impl FooS{
|
||||
fn foo<T: Foo>(&self, x: T) -> &'static str{
|
||||
x.foo_one()
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", FooS.foo(MyStruct));
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// 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.
|
||||
|
||||
// error-pattern: the trait bound `MyStruct: SuperFoo` is not satisfied
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait SuperFoo {
|
||||
fn super_foo_one(&self) -> &'static str;
|
||||
fn super_foo_two(&self) -> &'static str;
|
||||
}
|
||||
|
||||
trait Foo: SuperFoo {
|
||||
fn foo(&self) -> &'static str;
|
||||
}
|
||||
|
||||
default impl<T> SuperFoo for T {
|
||||
fn super_foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
impl Foo for MyStruct {
|
||||
fn foo(&self) -> &'static str {
|
||||
"foo"
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", MyStruct.foo());
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo<T> {
|
||||
fn dummy(&self, t: T);
|
||||
}
|
||||
|
||||
trait Bar<A> {
|
||||
fn method<B>(&self) where A: Foo<B>;
|
||||
}
|
||||
|
||||
struct S;
|
||||
struct X;
|
||||
|
||||
default impl Foo<X> for X {}
|
||||
|
||||
impl Bar<X> for isize {
|
||||
fn method<U>(&self) where X: Foo<U> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
1.method::<X>();
|
||||
//~^ ERROR the trait bound `X: Foo<X>` is not satisfied
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// 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.
|
||||
|
||||
// error-pattern: the trait bound `MyStruct: Draw` is not satisfied
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Draw {
|
||||
fn draw(&self);
|
||||
fn draw2(&self);
|
||||
}
|
||||
|
||||
struct Screen<T: Draw> {
|
||||
pub components: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Screen<T>
|
||||
where T: Draw {
|
||||
pub fn run(&self) {
|
||||
for component in self.components.iter() {
|
||||
component.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default impl Draw for MyStruct {
|
||||
fn draw(&self) {
|
||||
println!("draw");
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
let screen = Screen {
|
||||
components: vec![
|
||||
MyStruct
|
||||
]
|
||||
};
|
||||
screen.run();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str {
|
||||
"generic Trait"
|
||||
}
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
default impl<T: Clone> Foo for T {
|
||||
fn foo_two(&self) -> &'static str {
|
||||
"generic Clone"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic one"
|
||||
}
|
||||
fn foo_two(&self) -> &'static str {
|
||||
"generic two"
|
||||
}
|
||||
}
|
||||
|
||||
fn foo_one<T: Foo>(x: T) -> &'static str {
|
||||
x.foo_one()
|
||||
}
|
||||
|
||||
fn foo_two<T: Foo>(x: T) -> &'static str {
|
||||
x.foo_two()
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
assert!(foo_one(MyStruct) == "generic one");
|
||||
assert!(foo_two(MyStruct) == "generic two");
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// 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:foo_trait.rs
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
extern crate foo_trait;
|
||||
|
||||
use foo_trait::*;
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
assert!(MyStruct.foo_one() == "generic");
|
||||
assert!(0u8.foo_two() == "generic Clone");
|
||||
assert!(MyStruct.foo_two() == "generic Trait");
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str {
|
||||
"generic Trait"
|
||||
}
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
default impl<T: Clone> Foo for T {
|
||||
fn foo_two(&self) -> &'static str {
|
||||
"generic Clone"
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
assert!(MyStruct.foo_one() == "generic");
|
||||
assert!(0u8.foo_two() == "generic Clone");
|
||||
assert!(MyStruct.foo_two() == "generic Trait");
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
#![feature(specialization)]
|
||||
|
||||
trait Foo {
|
||||
fn foo_one(&self) -> &'static str;
|
||||
fn foo_two(&self) -> &'static str;
|
||||
}
|
||||
|
||||
default impl<T> Foo for T {
|
||||
fn foo_one(&self) -> &'static str {
|
||||
"generic"
|
||||
}
|
||||
}
|
||||
|
||||
default impl<T: Clone> Foo for T {
|
||||
fn foo_two(&self) -> &'static str {
|
||||
"generic Clone"
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
fn main() {
|
||||
assert!(MyStruct.foo_one() == "generic");
|
||||
assert!(0u8.foo_two() == "generic Clone");
|
||||
}
|
Loading…
Reference in a new issue