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:
Gianni Ciccarelli 2017-10-12 17:38:44 +00:00
parent 29c8276cee
commit f5c55ff379
30 changed files with 870 additions and 33 deletions

View file

@ -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 });

View file

@ -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,

View file

@ -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 }

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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
})
}
}

View file

@ -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))

View file

@ -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);
}
}
}

View file

@ -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 {

View file

@ -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)

View file

@ -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 {

View file

@ -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 => {

View file

@ -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>,
&param.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()
}))
}

View file

@ -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;
}

View file

@ -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"
}
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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();
}

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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());
}

View file

@ -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
}

View file

@ -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();
}

View file

@ -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"
}
}

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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");
}