1
Fork 0

support default impl for specialization

this commit implements the first step of the `default impl` feature:
all items in a `default impl` are (implicitly) `default` and hence
specializable.
In order to test this feature I've copied all the tests provided for the
`default` method implementation (in run-pass/specialization and
compile-fail/specialization directories) and moved the `default` keyword
from the item to the impl.
See referenced issue for further info
This commit is contained in:
Gianni Ciccarelli 2016-11-18 17:14:42 +01:00
parent 15ce54096a
commit 116e9831a5
50 changed files with 1078 additions and 41 deletions

2
cargo

@ -1 +1 @@
Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28

2
rls

@ -1 +1 @@
Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373

@ -1 +1 @@
Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178

@ -1 +1 @@
Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5

@ -1 +1 @@
Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d

@ -1 +1 @@
Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968

@ -1 +1 @@
Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f

View file

@ -1326,7 +1326,13 @@ impl<'a> LoweringContext<'a> {
hir::ItemDefaultImpl(self.lower_unsafety(unsafety), hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
trait_ref) trait_ref)
} }
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { ItemKind::Impl(unsafety,
polarity,
defaultness,
ref generics,
ref ifce,
ref ty,
ref impl_items) => {
let new_impl_items = impl_items.iter() let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item_ref(item)) .map(|item| self.lower_impl_item_ref(item))
.collect(); .collect();
@ -1340,6 +1346,7 @@ impl<'a> LoweringContext<'a> {
hir::ItemImpl(self.lower_unsafety(unsafety), hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity), self.lower_impl_polarity(polarity),
self.lower_defaultness(defaultness),
self.lower_generics(generics), self.lower_generics(generics),
ifce, ifce,
self.lower_ty(ty), self.lower_ty(ty),

View file

@ -1712,6 +1712,7 @@ pub enum Item_ {
/// An implementation, eg `impl<A> Trait for Foo { .. }` /// An implementation, eg `impl<A> Trait for Foo { .. }`
ItemImpl(Unsafety, ItemImpl(Unsafety,
ImplPolarity, ImplPolarity,
Defaultness,
Generics, Generics,
Option<TraitRef>, // (optional) trait this impl implements Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self P<Ty>, // self

View file

@ -678,12 +678,14 @@ impl<'a> State<'a> {
} }
hir::ItemImpl(unsafety, hir::ItemImpl(unsafety,
polarity, polarity,
defaultness,
ref generics, ref generics,
ref opt_trait, ref opt_trait,
ref ty, ref ty,
ref impl_items) => { ref impl_items) => {
self.head("")?; self.head("")?;
self.print_visibility(&item.vis)?; self.print_visibility(&item.vis)?;
self.print_defaultness(defaultness)?;
self.print_unsafety(unsafety)?; self.print_unsafety(unsafety)?;
self.word_nbsp("impl")?; self.word_nbsp("impl")?;
@ -820,6 +822,13 @@ impl<'a> State<'a> {
} }
} }
pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> {
if let hir::Defaultness::Default = defaultness {
self.word_nbsp("default")?;
}
Ok(())
}
pub fn print_struct(&mut self, pub fn print_struct(&mut self,
struct_def: &hir::VariantData, struct_def: &hir::VariantData,
generics: &hir::Generics, generics: &hir::Generics,
@ -931,11 +940,7 @@ impl<'a> State<'a> {
self.hardbreak_if_not_bol()?; self.hardbreak_if_not_bol()?;
self.maybe_print_comment(ii.span.lo)?; self.maybe_print_comment(ii.span.lo)?;
self.print_outer_attributes(&ii.attrs)?; self.print_outer_attributes(&ii.attrs)?;
self.print_defaultness(ii.defaultness)?;
match ii.defaultness {
hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
hir::Defaultness::Final => (),
}
match ii.node { match ii.node {
hir::ImplItemKind::Const(ref ty, expr) => { hir::ImplItemKind::Const(ref ty, expr) => {

View file

@ -50,7 +50,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
} }
match item.node { match item.node {
hir::ItemImpl(_, _, ref generics, ..) | hir::ItemImpl(_, _, _, ref generics, ..) |
hir::ItemFn(.., ref generics, _) => { hir::ItemFn(.., ref generics, _) => {
generics_require_inlining(generics) generics_require_inlining(generics)
} }
@ -186,7 +186,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
// does too. // does too.
let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap();
match self.tcx.hir.expect_item(impl_node_id).node { match self.tcx.hir.expect_item(impl_node_id).node {
hir::ItemImpl(_, _, ref generics, ..) => { hir::ItemImpl(_, _, _, ref generics, ..) => {
generics_require_inlining(generics) generics_require_inlining(generics)
} }
_ => false _ => false

View file

@ -331,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir::ItemStruct(_, ref generics) | hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) | hir::ItemUnion(_, ref generics) |
hir::ItemTrait(_, ref generics, ..) | hir::ItemTrait(_, ref generics, ..) |
hir::ItemImpl(_, _, ref generics, ..) => { hir::ItemImpl(_, _, _, ref generics, ..) => {
// These kinds of items have only early bound lifetime parameters. // These kinds of items have only early bound lifetime parameters.
let mut index = if let hir::ItemTrait(..) = item.node { let mut index = if let hir::ItemTrait(..) = item.node {
1 // Self comes before lifetimes 1 // Self comes before lifetimes
@ -834,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
match parent.node { match parent.node {
hir::ItemTrait(_, ref generics, ..) | hir::ItemTrait(_, ref generics, ..) |
hir::ItemImpl(_, _, ref generics, ..) => { hir::ItemImpl(_, _, _, ref generics, ..) => {
index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; index += (generics.lifetimes.len() + generics.ty_params.len()) as u32;
} }
_ => {} _ => {}

View file

@ -33,6 +33,7 @@ use ty::subst::Subst;
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder}; use ty::fold::{TypeFoldable, TypeFolder};
use util::common::FN_OUTPUT_NAME; use util::common::FN_OUTPUT_NAME;
use hir::{self};
/// Depending on the stage of compilation, we want projection to be /// Depending on the stage of compilation, we want projection to be
/// more or less conservative. /// more or less conservative.
@ -923,7 +924,28 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
// being invoked). // being invoked).
node_item.item.defaultness.has_value() node_item.item.defaultness.has_value()
} else { } else {
node_item.item.defaultness.is_default() let is_default = match selcx.tcx()
.map
.as_local_node_id(node_item.node.def_id()) {
Some(node_id) => {
let item = selcx.tcx().map.expect_item(node_id);
if let hir::ItemImpl(_, _, defaultness, ..) = item.node {
defaultness.is_default()
} else {
false
}
}
None => {
selcx.tcx()
.global_tcx()
.sess
.cstore
.impl_defaultness(node_item.node.def_id())
.is_default()
}
};
node_item.item.defaultness.is_default() || is_default
}; };
// Only reveal a specializable default if we're past type-checking // Only reveal a specializable default if we're past type-checking

View file

@ -90,6 +90,7 @@ provide! { <'tcx> tcx, def_id, cdata
associated_item => { cdata.get_associated_item(def_id.index) } associated_item => { cdata.get_associated_item(def_id.index) }
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
impl_polarity => { cdata.get_impl_polarity(def_id.index) } impl_polarity => { cdata.get_impl_polarity(def_id.index) }
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
coerce_unsized_info => { coerce_unsized_info => {
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);

View file

@ -629,6 +629,10 @@ impl<'a, 'tcx> CrateMetadata {
self.get_impl_data(id).polarity self.get_impl_data(id).polarity
} }
pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
self.get_impl_data(id).defaultness
}
pub fn get_coerce_unsized_info(&self, pub fn get_coerce_unsized_info(&self,
id: DefIndex) id: DefIndex)
-> Option<ty::adjustment::CoerceUnsizedInfo> { -> Option<ty::adjustment::CoerceUnsizedInfo> {

View file

@ -706,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
hir::ItemDefaultImpl(..) => { hir::ItemDefaultImpl(..) => {
let data = ImplData { let data = ImplData {
polarity: hir::ImplPolarity::Positive, polarity: hir::ImplPolarity::Positive,
defaultness: hir::Defaultness::Final,
parent_impl: None, parent_impl: None,
coerce_unsized_info: None, coerce_unsized_info: None,
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
@ -713,7 +714,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
EntryKind::DefaultImpl(self.lazy(&data)) EntryKind::DefaultImpl(self.lazy(&data))
} }
hir::ItemImpl(_, polarity, ..) => { hir::ItemImpl(_, polarity, defaultness, ..) => {
let trait_ref = tcx.impl_trait_ref(def_id); let trait_ref = tcx.impl_trait_ref(def_id);
let parent = if let Some(trait_ref) = trait_ref { let parent = if let Some(trait_ref) = trait_ref {
let trait_def = tcx.lookup_trait_def(trait_ref.def_id); let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
@ -740,6 +741,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
let data = ImplData { let data = ImplData {
polarity: polarity, polarity: polarity,
defaultness: defaultness,
parent_impl: parent, parent_impl: parent,
coerce_unsized_info: coerce_unsized_info, coerce_unsized_info: coerce_unsized_info,
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),

View file

@ -406,6 +406,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> {
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct ImplData<'tcx> { pub struct ImplData<'tcx> {
pub polarity: hir::ImplPolarity, pub polarity: hir::ImplPolarity,
pub defaultness: hir::Defaultness,
pub parent_impl: Option<DefId>, pub parent_impl: Option<DefId>,
/// This is `Some` only for impls of `CoerceUnsized`. /// This is `Some` only for impls of `CoerceUnsized`.

View file

@ -429,8 +429,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
} }
} }
None => { None => {
if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) {
if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
trait_id = self.lookup_def_id(ty.id); trait_id = self.lookup_def_id(ty.id);
} }
} }

View file

@ -880,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
let parent_node_id = hir_map.get_parent_node(ii.id); let parent_node_id = hir_map.get_parent_node(ii.id);
let is_impl_generic = match hir_map.expect_item(parent_node_id) { let is_impl_generic = match hir_map.expect_item(parent_node_id) {
&hir::Item { &hir::Item {
node: hir::ItemImpl(_, _, ref generics, ..), node: hir::ItemImpl(_, _, _, ref generics, ..),
.. ..
} => { } => {
generics.is_type_parameterized() generics.is_type_parameterized()
@ -911,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
let tcx = scx.tcx(); let tcx = scx.tcx();
match item.node { match item.node {
hir::ItemImpl(_, hir::ItemImpl(_,
_,
_, _,
ref generics, ref generics,
.., ..,

View file

@ -1142,7 +1142,23 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if let Some(parent) = parent { if let Some(parent) = parent {
if parent.item.is_final() { if parent.item.is_final() {
report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); let is_final = match tcx.map.as_local_node_id(parent.node.def_id()) {
Some(node_id) => {
let item = tcx.map.expect_item(node_id);
if let hir::ItemImpl(_, _, defaultness, ..) = item.node {
defaultness.is_final()
} else {
true
}
}
None => {
tcx.global_tcx().sess.cstore.impl_defaultness(parent.node.def_id()).is_final()
}
};
if is_final {
report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
}
} }
} }

View file

@ -105,11 +105,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
/// ///
/// won't be allowed unless there's an *explicit* implementation of `Send` /// won't be allowed unless there's an *explicit* implementation of `Send`
/// for `T` /// for `T`
hir::ItemImpl(_, hir::ImplPolarity::Positive, _, hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _,
ref trait_ref, ref self_ty, _) => { ref trait_ref, ref self_ty, _) => {
self.check_impl(item, self_ty, trait_ref); self.check_impl(item, self_ty, trait_ref);
} }
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => { hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => {
// FIXME(#27579) what amount of WF checking do we need for neg impls? // FIXME(#27579) what amount of WF checking do we need for neg impls?
let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap(); let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();

View file

@ -87,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
hir::ItemDefaultImpl(unsafety, _) => { hir::ItemDefaultImpl(unsafety, _) => {
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
} }
hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => { hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => {
self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
} }
_ => {} _ => {}

View file

@ -214,6 +214,7 @@ pub struct Trait {
pub struct Impl { pub struct Impl {
pub unsafety: hir::Unsafety, pub unsafety: hir::Unsafety,
pub polarity: hir::ImplPolarity, pub polarity: hir::ImplPolarity,
pub defaultness: hir::Defaultness,
pub generics: hir::Generics, pub generics: hir::Generics,
pub trait_: Option<hir::TraitRef>, pub trait_: Option<hir::TraitRef>,
pub for_: P<hir::Ty>, pub for_: P<hir::Ty>,

View file

@ -502,7 +502,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
om.traits.push(t); om.traits.push(t);
}, },
hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { hir::ItemImpl(unsafety, polarity, defaultness, ref gen, ref tr, ref ty, ref item_ids) => {
// Don't duplicate impls when inlining, we'll pick them up // Don't duplicate impls when inlining, we'll pick them up
// regardless of where they're located. // regardless of where they're located.
if !self.inlining { if !self.inlining {
@ -512,6 +512,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
let i = Impl { let i = Impl {
unsafety: unsafety, unsafety: unsafety,
polarity: polarity, polarity: polarity,
defaultness: defaultness,
generics: gen.clone(), generics: gen.clone(),
trait_: tr.clone(), trait_: tr.clone(),
for_: ty.clone(), for_: ty.clone(),

View file

@ -1852,6 +1852,7 @@ pub enum ItemKind {
/// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }` /// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`
Impl(Unsafety, Impl(Unsafety,
ImplPolarity, ImplPolarity,
Defaultness,
Generics, Generics,
Option<TraitRef>, // (optional) trait this impl implements Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self P<Ty>, // self

View file

@ -1215,7 +1215,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
and possibly buggy"); and possibly buggy");
} }
ast::ItemKind::Impl(_, polarity, _, _, _, _) => { ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
match polarity { match polarity {
ast::ImplPolarity::Negative => { ast::ImplPolarity::Negative => {
gate_feature_post!(&self, optin_builtin_traits, gate_feature_post!(&self, optin_builtin_traits,
@ -1225,6 +1225,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}, },
_ => {} _ => {}
} }
match defaultness {
ast::Defaultness::Default => {
gate_feature_post!(&self, specialization,
i.span,
"specialization is unstable");
}
_ => {}
}
} }
_ => {} _ => {}

View file

@ -897,9 +897,16 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
} }
ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl( ItemKind::Impl(unsafety,
polarity,
defaultness,
generics,
ifce,
ty,
impl_items) => ItemKind::Impl(
unsafety, unsafety,
polarity, polarity,
defaultness,
folder.fold_generics(generics), folder.fold_generics(generics),
ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())),
folder.fold_ty(ty), folder.fold_ty(ty),

View file

@ -4863,7 +4863,9 @@ impl<'a> Parser<'a> {
/// impl<T> Foo { ... } /// impl<T> Foo { ... }
/// impl<T> ToString for &'static T { ... } /// impl<T> ToString for &'static T { ... }
/// impl Send for .. {} /// impl Send for .. {}
fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> { fn parse_item_impl(&mut self,
unsafety: ast::Unsafety,
defaultness: Defaultness) -> PResult<'a, ItemInfo> {
let impl_span = self.span; let impl_span = self.span;
// First, parse type parameters if necessary. // First, parse type parameters if necessary.
@ -4944,7 +4946,7 @@ impl<'a> Parser<'a> {
} }
Ok((keywords::Invalid.ident(), Ok((keywords::Invalid.ident(),
ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items), ItemKind::Impl(unsafety, polarity, defaultness, generics, opt_trait, ty, impl_items),
Some(attrs))) Some(attrs)))
} }
} }
@ -5756,13 +5758,19 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs)); maybe_append(attrs, extra_attrs));
return Ok(Some(item)); return Ok(Some(item));
} }
if self.check_keyword(keywords::Unsafe) && if (self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) ||
(self.check_keyword(keywords::Default) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) &&
self.look_ahead(2, |t| t.is_keyword(keywords::Impl)))
{ {
// IMPL ITEM // IMPL ITEM
let defaultness = self.parse_defaultness()?;
self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Unsafe)?;
self.expect_keyword(keywords::Impl)?; self.expect_keyword(keywords::Impl)?;
let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; let (ident,
item_,
extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe, defaultness)?;
let prev_span = self.prev_span; let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span), let item = self.mk_item(lo.to(prev_span),
ident, ident,
@ -5856,9 +5864,16 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs)); maybe_append(attrs, extra_attrs));
return Ok(Some(item)); return Ok(Some(item));
} }
if self.eat_keyword(keywords::Impl) { if (self.check_keyword(keywords::Impl)) ||
(self.check_keyword(keywords::Default) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Impl)))
{
// IMPL ITEM // IMPL ITEM
let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; let defaultness = self.parse_defaultness()?;
self.expect_keyword(keywords::Impl)?;
let (ident,
item_,
extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal, defaultness)?;
let prev_span = self.prev_span; let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span), let item = self.mk_item(lo.to(prev_span),
ident, ident,

View file

@ -1317,12 +1317,14 @@ impl<'a> State<'a> {
} }
ast::ItemKind::Impl(unsafety, ast::ItemKind::Impl(unsafety,
polarity, polarity,
defaultness,
ref generics, ref generics,
ref opt_trait, ref opt_trait,
ref ty, ref ty,
ref impl_items) => { ref impl_items) => {
self.head("")?; self.head("")?;
self.print_visibility(&item.vis)?; self.print_visibility(&item.vis)?;
self.print_defaultness(defaultness)?;
self.print_unsafety(unsafety)?; self.print_unsafety(unsafety)?;
self.word_nbsp("impl")?; self.word_nbsp("impl")?;
@ -1477,6 +1479,13 @@ impl<'a> State<'a> {
} }
} }
pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> {
if let ast::Defaultness::Default = defatulness {
try!(self.word_nbsp("default"));
}
Ok(())
}
pub fn print_struct(&mut self, pub fn print_struct(&mut self,
struct_def: &ast::VariantData, struct_def: &ast::VariantData,
generics: &ast::Generics, generics: &ast::Generics,
@ -1602,9 +1611,7 @@ impl<'a> State<'a> {
self.hardbreak_if_not_bol()?; self.hardbreak_if_not_bol()?;
self.maybe_print_comment(ii.span.lo)?; self.maybe_print_comment(ii.span.lo)?;
self.print_outer_attributes(&ii.attrs)?; self.print_outer_attributes(&ii.attrs)?;
if let ast::Defaultness::Default = ii.defaultness { self.print_defaultness(ii.defaultness)?;
self.word_nbsp("default")?;
}
match ii.node { match ii.node {
ast::ImplItemKind::Const(ref ty, ref expr) => { ast::ImplItemKind::Const(ref ty, ref expr) => {
self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?; self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?;

View file

@ -266,7 +266,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
ItemKind::DefaultImpl(_, ref trait_ref) => { ItemKind::DefaultImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref) visitor.visit_trait_ref(trait_ref)
} }
ItemKind::Impl(_, _, ItemKind::Impl(_, _, _,
ref type_parameters, ref type_parameters,
ref opt_trait_reference, ref opt_trait_reference,
ref typ, ref typ,

View file

@ -658,6 +658,7 @@ impl<'a> TraitDef<'a> {
a, a,
ast::ItemKind::Impl(unsafety, ast::ItemKind::Impl(unsafety,
ast::ImplPolarity::Positive, ast::ImplPolarity::Positive,
ast::Defaultness::Final,
trait_generics, trait_generics,
opt_trait_ref, opt_trait_ref,
self_type, self_type,

@ -1 +0,0 @@
Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92

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;
}
default impl<T> Foo for T {
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;
}
default impl<T> Example for T {
type Output = Box<T>;
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);
}
default impl<T> Foo for T { //~ ERROR specialization is unstable
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);
}
default impl<T> Baz for T {
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);
}
default impl<T> Redundant for T {
fn redundant(&self) {}
}
impl<T: Clone> Redundant for T {
fn redundant(&self) {}
}
default impl Redundant for i32 {
fn redundant(&self) {} //~ ERROR E0520
}
fn main() {}

View file

@ -0,0 +1,53 @@
// 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)]
// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
pub trait Go {
fn go(&self, arg: isize);
}
pub fn go<G:Go>(this: &G, arg: isize) {
this.go(arg)
}
pub trait GoMut {
fn go_mut(&mut self, arg: isize);
}
pub fn go_mut<G:GoMut>(this: &mut G, arg: isize) {
this.go_mut(arg)
}
pub trait GoOnce {
fn go_once(self, arg: isize);
}
pub fn go_once<G:GoOnce>(this: G, arg: isize) {
this.go_once(arg)
}
default impl<G> GoMut for G
where G : Go
{
fn go_mut(&mut self, arg: isize) {
go(&*self, arg)
}
}
default impl<G> GoOnce for G
where G : GoMut
{
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;
}
default impl<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default impl<T: Clone> Foo for (T, T) {
fn foo(&self) -> &'static str {
"generic uniform pair"
}
}
default impl Foo for (u8, u32) {
fn foo(&self) -> &'static str {
"(u8, u32)"
}
}
default impl Foo for (u8, u8) {
fn foo(&self) -> &'static str {
"(u8, u8)"
}
}
default impl<T: Clone> Foo for Vec<T> {
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 {}
default impl<T: Clone + MyMarker> Foo for T {
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;
}
default impl<T> Foo for T {
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 {}
default impl<T> Bar for Vec<T> {
fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
fn bar(&self) -> i32 { 3 }
}

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() { }

View file

@ -0,0 +1,37 @@
// 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 non-method associated functions can be specialized
#![feature(specialization)]
trait Foo {
fn mk() -> Self;
}
default impl<T: Default> Foo for T {
fn mk() -> T {
T::default()
}
}
impl Foo for Vec<u8> {
fn mk() -> Vec<u8> {
vec![0]
}
}
fn main() {
let v1: Vec<i32> = Foo::mk();
let v2: Vec<u8> = Foo::mk();
assert!(v1.len() == 0);
assert!(v2.len() == 1);
}

View file

@ -0,0 +1,106 @@
// 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)]
// Tests a variety of basic specialization scenarios and method
// dispatch for them.
trait Foo {
fn foo(&self) -> &'static str;
}
default impl<T> Foo for T {
fn foo(&self) -> &'static str {
"generic"
}
}
default impl<T: Clone> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone"
}
}
default impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
fn foo(&self) -> &'static str {
"generic pair"
}
}
default impl<T: Clone> Foo for (T, T) {
fn foo(&self) -> &'static str {
"generic uniform pair"
}
}
default impl Foo for (u8, u32) {
fn foo(&self) -> &'static str {
"(u8, u32)"
}
}
default impl Foo for (u8, u8) {
fn foo(&self) -> &'static str {
"(u8, u8)"
}
}
default impl<T: Clone> Foo for Vec<T> {
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"
}
}
struct NotClone;
trait MyMarker {}
default impl<T: Clone + MyMarker> Foo for T {
fn foo(&self) -> &'static str {
"generic Clone + MyMarker"
}
}
#[derive(Clone)]
struct MarkedAndClone;
impl MyMarker for MarkedAndClone {}
fn main() {
assert!(NotClone.foo() == "generic");
assert!(0u8.foo() == "generic Clone");
assert!(vec![NotClone].foo() == "generic");
assert!(vec![0u8].foo() == "generic Vec");
assert!(vec![0i32].foo() == "Vec<i32>");
assert!(0i32.foo() == "i32");
assert!(String::new().foo() == "String");
assert!(((), 0).foo() == "generic pair");
assert!(((), ()).foo() == "generic uniform pair");
assert!((0u8, 0u32).foo() == "(u8, u32)");
assert!((0u8, 0u8).foo() == "(u8, u8)");
assert!(MarkedAndClone.foo() == "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.
// aux-build:specialization_cross_crate_defaults.rs
#![feature(specialization)]
extern crate specialization_cross_crate_defaults;
use specialization_cross_crate_defaults::*;
struct LocalDefault;
struct LocalOverride;
impl Foo for LocalDefault {}
impl Foo for LocalOverride {
fn foo(&self) -> bool { true }
}
fn test_foo() {
assert!(!0i8.foo());
assert!(!0i32.foo());
assert!(0i64.foo());
assert!(!LocalDefault.foo());
assert!(LocalOverride.foo());
}
fn test_bar() {
assert!(0u8.bar() == 0);
assert!(0i32.bar() == 1);
assert!("hello".bar() == 0);
assert!(vec![()].bar() == 2);
assert!(vec![0i32].bar() == 2);
assert!(vec![0i64].bar() == 3);
}
fn main() {
test_foo();
test_bar();
}

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.
// Test that specialization works even if only the upstream crate enables it
// aux-build:specialization_cross_crate.rs
extern crate specialization_cross_crate;
use specialization_cross_crate::*;
fn main() {
assert!(0u8.foo() == "generic Clone");
assert!(vec![0u8].foo() == "generic Vec");
assert!(vec![0i32].foo() == "Vec<i32>");
assert!(0i32.foo() == "i32");
assert!(String::new().foo() == "String");
assert!(((), 0).foo() == "generic pair");
assert!(((), ()).foo() == "generic uniform pair");
assert!((0u8, 0u32).foo() == "(u8, u32)");
assert!((0u8, 0u8).foo() == "(u8, u8)");
}

View file

@ -0,0 +1,58 @@
// 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.
// aux-build:specialization_cross_crate.rs
#![feature(specialization)]
extern crate specialization_cross_crate;
use specialization_cross_crate::*;
struct NotClone;
#[derive(Clone)]
struct MarkedAndClone;
impl MyMarker for MarkedAndClone {}
struct MyType<T>(T);
default impl<T> Foo for MyType<T> {
fn foo(&self) -> &'static str {
"generic MyType"
}
}
impl Foo for MyType<u8> {
fn foo(&self) -> &'static str {
"MyType<u8>"
}
}
struct MyOtherType;
impl Foo for MyOtherType {}
fn main() {
assert!(NotClone.foo() == "generic");
assert!(0u8.foo() == "generic Clone");
assert!(vec![NotClone].foo() == "generic");
assert!(vec![0u8].foo() == "generic Vec");
assert!(vec![0i32].foo() == "Vec<i32>");
assert!(0i32.foo() == "i32");
assert!(String::new().foo() == "String");
assert!(((), 0).foo() == "generic pair");
assert!(((), ()).foo() == "generic uniform pair");
assert!((0u8, 0u32).foo() == "(u8, u32)");
assert!((0u8, 0u8).foo() == "(u8, u8)");
assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
assert!(MyType(()).foo() == "generic MyType");
assert!(MyType(0u8).foo() == "MyType<u8>");
assert!(MyOtherType.foo() == "generic");
}

View file

@ -0,0 +1,94 @@
// 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)]
// Test that default methods are cascaded correctly
// First, test only use of explicit `default` items:
trait Foo {
fn foo(&self) -> bool;
}
// Specialization tree for Foo:
//
// T
// / \
// i32 i64
default impl<T> Foo for T {
fn foo(&self) -> bool { false }
}
impl Foo for i32 {}
impl Foo for i64 {
fn foo(&self) -> bool { true }
}
fn test_foo() {
assert!(!0i8.foo());
assert!(!0i32.foo());
assert!(0i64.foo());
}
// Next, test mixture of explicit `default` and provided methods:
trait Bar {
fn bar(&self) -> i32 { 0 }
}
// Specialization tree for Bar.
// Uses of $ designate that method is provided
//
// $Bar (the trait)
// |
// T
// /|\
// / | \
// / | \
// / | \
// / | \
// / | \
// $i32 &str $Vec<T>
// /\
// / \
// Vec<i32> $Vec<i64>
// use the provided method
impl<T> Bar for T {}
impl Bar for i32 {
fn bar(&self) -> i32 { 1 }
}
impl<'a> Bar for &'a str {}
default impl<T> Bar for Vec<T> {
fn bar(&self) -> i32 { 2 }
}
impl Bar for Vec<i32> {}
impl Bar for Vec<i64> {
fn bar(&self) -> i32 { 3 }
}
fn test_bar() {
assert!(0u8.bar() == 0);
assert!(0i32.bar() == 1);
assert!("hello".bar() == 0);
assert!(vec![()].bar() == 2);
assert!(vec![0i32].bar() == 2);
assert!(vec![0i64].bar() == 3);
}
fn main() {
test_foo();
test_bar();
}

View file

@ -0,0 +1,27 @@
// 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.
// Test that you can list the more specific impl before the more general one.
#![feature(specialization)]
trait Foo {
type Out;
}
impl Foo for bool {
type Out = ();
}
default impl<T> Foo for T {
type Out = bool;
}
fn main() {}

View file

@ -0,0 +1,33 @@
// 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.
// Test that impls on projected self types can resolve overlap, even when the
// projections involve specialization, so long as the associated type is
// provided by the most specialized impl.
#![feature(specialization)]
trait Assoc {
type Output;
}
default impl<T> Assoc for T {
type Output = bool;
}
impl Assoc for u8 { type Output = u8; }
impl Assoc for u16 { type Output = u16; }
trait Foo {}
impl Foo for u32 {}
impl Foo for <u8 as Assoc>::Output {}
impl Foo for <u16 as Assoc>::Output {}
fn main() {}

View file

@ -0,0 +1,32 @@
// 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.
#![feature(specialization)]
// Regression test for ICE when combining specialized associated types and type
// aliases
trait Id_ {
type Out;
}
type Id<T> = <T as Id_>::Out;
default impl<T> Id_ for T {
type Out = T;
}
fn test_proection() {
let x: Id<bool> = panic!();
}
fn main() {
}

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)]
// Make sure we *can* project non-defaulted associated types
// cf compile-fail/specialization-default-projection.rs
// First, do so without any use of specialization
trait Foo {
type Assoc;
}
impl<T> Foo for T {
type Assoc = ();
}
fn generic_foo<T>() -> <T as Foo>::Assoc {
()
}
// Next, allow for one layer of specialization
trait Bar {
type Assoc;
}
default impl<T> Bar for T {
type Assoc = ();
}
impl<T: Clone> Bar for T {
type Assoc = u8;
}
fn generic_bar_clone<T: Clone>() -> <T as Bar>::Assoc {
0u8
}
fn main() {
}