diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 3aa76d168df07..c9fcdf7647b9c 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -89,6 +89,7 @@ extern char *yytext; %token TRAIT %token TYPE %token UNSAFE +%token DEFAULT %token USE %token WHILE %token CONTINUE @@ -534,6 +535,12 @@ maybe_unsafe | %empty { $$ = mk_none(); } ; +maybe_default_maybe_unsafe +: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); } +| DEFAULT { $$ = mk_atom("Default"); } +| UNSAFE { $$ = mk_atom("Unsafe"); } +| %empty { $$ = mk_none(); } + trait_method : type_method { $$ = mk_node("Required", 1, $1); } | method { $$ = mk_node("Provided", 1, $1); } @@ -588,27 +595,27 @@ impl_method // they are ambiguous with traits. We do the same here, regrettably, // by splitting ty into ty and ty_prim. item_impl -: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); } -| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); } -| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); } -| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' +| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' +| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); } @@ -1935,4 +1942,4 @@ brackets_delimited_token_trees $2, mk_node("TTTok", 1, mk_atom("]"))); } -; +; \ No newline at end of file diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b7aafa0a9ab0b..8f4dce5a78303 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1326,7 +1326,13 @@ impl<'a> LoweringContext<'a> { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), 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() .map(|item| self.lower_impl_item_ref(item)) .collect(); @@ -1340,6 +1346,7 @@ impl<'a> LoweringContext<'a> { hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), + self.lower_defaultness(defaultness, true /* [1] */), self.lower_generics(generics), ifce, self.lower_ty(ty), @@ -1355,6 +1362,9 @@ impl<'a> LoweringContext<'a> { } ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } + + // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to + // not cause an assertion failure inside the `lower_defaultness` function } fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 562b58844409d..cb7f530b9952f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1712,6 +1712,7 @@ pub enum Item_ { /// An implementation, eg `impl Trait for Foo { .. }` ItemImpl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5144f75b1a363..a78d5ce1c16d0 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -678,12 +678,14 @@ impl<'a> State<'a> { } hir::ItemImpl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -820,6 +822,14 @@ impl<'a> State<'a> { } } + pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { + match defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &hir::VariantData, generics: &hir::Generics, @@ -931,11 +941,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - - match ii.defaultness { - hir::Defaultness::Default { .. } => self.word_nbsp("default")?, - hir::Defaultness::Final => (), - } + self.print_defaultness(ii.defaultness)?; match ii.node { hir::ImplItemKind::Const(ref ty, expr) => { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 82e03a9fddc35..3aeee1c1b981f 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -933,7 +933,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemUnion(variant_data, generics), ItemTrait(unsafety, generics, bounds, item_refs), ItemDefaultImpl(unsafety, trait_ref), - ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) + ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); impl_stable_hash_for!(struct hir::TraitItemRef { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 3251addcb3283..60171f1a4289a 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -195,6 +195,7 @@ pub trait CrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -329,6 +330,7 @@ impl CrateStore for DummyCrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 431760b6fcd65..939d7364d9e06 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -49,7 +49,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool { } match item.node { - hir::ItemImpl(_, _, ref generics, ..) | + hir::ItemImpl(_, _, _, ref generics, ..) | hir::ItemFn(.., ref generics, _) => { generics_require_inlining(generics) } @@ -185,7 +185,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // does too. let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); match self.tcx.hir.expect_item(impl_node_id).node { - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { generics_require_inlining(generics) } _ => false diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a1aabc775a31a..a8ba708cc2cd4 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { 1 // Self comes before lifetimes @@ -834,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } match parent.node { hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 7e0954c92a660..e01f97eb1f3a0 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -923,7 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - node_item.item.defaultness.is_default() + node_item.item.defaultness.is_default() || + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 396c7dbd1a874..1d10c3a969509 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,6 +13,8 @@ use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; +use hir::{self}; +use traits::specialize::specialization_graph::NodeItem; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -504,6 +506,30 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; ty::Binder((trait_ref, sig.skip_binder().output())) } + + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { + match self.hir.as_local_node_id(node_item_def_id) { + Some(node_id) => { + let item = self.hir.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + self.global_tcx() + .sess + .cstore + .impl_defaultness(node_item_def_id) + .is_default() + } + } + } + + pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool { + node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id()) + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f310279ea3c3a..ddb3332be3731 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -178,6 +178,12 @@ impl CrateStore for cstore::CStore { result } + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness + { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).get_impl_defaultness(def.index) + } + fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1656d489269d0..37913dad7eeb5 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -629,6 +629,10 @@ impl<'a, 'tcx> CrateMetadata { 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, id: DefIndex) -> Option { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 783e7604cdaf1..3676e5a7f0f72 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -706,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { hir::ItemDefaultImpl(..) => { let data = ImplData { polarity: hir::ImplPolarity::Positive, + defaultness: hir::Defaultness::Final, parent_impl: None, coerce_unsized_info: None, 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)) } - hir::ItemImpl(_, polarity, ..) => { + hir::ItemImpl(_, polarity, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = tcx.trait_def(trait_ref.def_id); @@ -740,6 +741,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = ImplData { polarity: polarity, + defaultness: defaultness, parent_impl: parent, coerce_unsized_info: coerce_unsized_info, trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2f2e0e125aea5..5870903e7718f 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -406,6 +406,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub parent_impl: Option, /// This is `Some` only for impls of `CoerceUnsized`. @@ -415,6 +416,7 @@ pub struct ImplData<'tcx> { impl_stable_hash_for!(struct ImplData<'tcx> { polarity, + defaultness, parent_impl, coerce_unsized_info, trait_ref diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9e3e727d4bdcd..4639847651c74 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -430,7 +430,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } None => { if let Some(NodeItem(item)) = self.tcx.hir.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); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 93ec7e11606df..77155a474aed4 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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 is_impl_generic = match hir_map.expect_item(parent_node_id) { &hir::Item { - node: hir::ItemImpl(_, _, ref generics, ..), + node: hir::ItemImpl(_, _, _, ref generics, ..), .. } => { generics.is_type_parameterized() @@ -911,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, + _, _, ref generics, .., diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1c0c68ae7d7cb..fe003f3f24230 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1141,7 +1141,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|node_item| node_item.map(|parent| parent.defaultness)); if let Some(parent) = parent { - if parent.item.is_final() { + if tcx.impl_item_is_final(&parent) { report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 5bb45cbb1ae8a..503212f2c970e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -105,11 +105,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { /// /// won't be allowed unless there's an *explicit* implementation of `Send` /// for `T` - hir::ItemImpl(_, hir::ImplPolarity::Positive, _, + hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _, ref trait_ref, ref self_ty, _) => { 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? let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap(); diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 4463cff9c503f..4672975d056b8 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -87,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { hir::ItemDefaultImpl(unsafety, _) => { 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); } _ => {} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 099586e6bcc2a..3cd8b8bd48914 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -309,7 +309,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -825,7 +825,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) => generics, + ItemImpl(_, _, _, ref generics, ..) => generics, ItemTy(_, ref generics) | ItemEnum(_, ref generics) | @@ -1236,7 +1236,7 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d819268240bad..71594825cdb01 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -214,6 +214,7 @@ pub struct Trait { pub struct Impl { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub generics: hir::Generics, pub trait_: Option, pub for_: P, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4252f2981ed61..d463e41c58a2a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,7 +502,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { 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 // regardless of where they're located. if !self.inlining { @@ -512,6 +518,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let i = Impl { unsafety: unsafety, polarity: polarity, + defaultness: defaultness, generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 131adfe47afda..e5bb02fe08230 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1852,6 +1852,7 @@ pub enum ItemKind { /// E.g. `impl Foo { .. }` or `impl Trait for Foo { .. }` Impl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b55a860b3595..b6a2c983fd4d7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1215,7 +1215,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { and possibly buggy"); } - ast::ItemKind::Impl(_, polarity, _, _, _, _) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { match polarity { ast::ImplPolarity::Negative => { gate_feature_post!(&self, optin_builtin_traits, @@ -1225,6 +1225,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { }, _ => {} } + + if let ast::Defaultness::Default = defaultness { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } } _ => {} diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index f39399a62e856..58cf50cdc000c 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -897,9 +897,16 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::DefaultImpl(unsafety, ref trait_ref) => { 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, polarity, + defaultness, folder.fold_generics(generics), ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), folder.fold_ty(ty), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index afdb0cc4fdb79..cba7733514371 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4865,7 +4865,9 @@ impl<'a> Parser<'a> { /// impl Foo { ... } /// impl ToString for &'static T { ... } /// 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; // First, parse type parameters if necessary. @@ -4918,6 +4920,11 @@ impl<'a> Parser<'a> { allowed to have generics"); } + if let ast::Defaultness::Default = defaultness { + self.span_err(impl_span, "`default impl` is not allowed for \ + default trait implementations"); + } + self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::CloseDelim(token::Brace))?; Ok((keywords::Invalid.ident(), @@ -4946,7 +4953,7 @@ impl<'a> Parser<'a> { } 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))) } } @@ -5759,13 +5766,19 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) + if (self.check_keyword(keywords::Unsafe) && + 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 + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; 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 item = self.mk_item(lo.to(prev_span), ident, @@ -5859,9 +5872,16 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); 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 - 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 item = self.mk_item(lo.to(prev_span), ident, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index be1d26f8fe487..a911c21ed98d0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1317,12 +1317,14 @@ impl<'a> State<'a> { } ast::ItemKind::Impl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; 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, struct_def: &ast::VariantData, generics: &ast::Generics, @@ -1602,9 +1611,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - if let ast::Defaultness::Default = ii.defaultness { - self.word_nbsp("default")?; - } + self.print_defaultness(ii.defaultness)?; match ii.node { ast::ImplItemKind::Const(ref ty, ref expr) => { self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bae1c56db007c..2e42c6986e64e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -266,7 +266,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::DefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } - ItemKind::Impl(_, _, + ItemKind::Impl(_, _, _, ref type_parameters, ref opt_trait_reference, ref typ, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e96883c26f33a..be7883cad5f38 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -658,6 +658,7 @@ impl<'a> TraitDef<'a> { a, ast::ItemKind::Impl(unsafety, ast::ImplPolarity::Positive, + ast::Defaultness::Final, trait_generics, opt_trait_ref, self_type, diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs new file mode 100644 index 0000000000000..ad55f44255b48 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs @@ -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 or the MIT license +// , 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 Foo for T { + type Assoc = (); +} + +impl Foo for u8 { + type Assoc = String; +} + +fn generic() -> ::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::(); + println!("{}", s); // bad news if this all compiles +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs new file mode 100644 index 0000000000000..7353f7ac8c5c0 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs @@ -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 or the MIT license +// , 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 Example for T { + type Output = Box; + 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) -> Box { + Example::generate(t) //~ ERROR mismatched types +} + +fn weaponize() -> bool { + let b: Box = trouble(true); + *b +} + +fn main() { + weaponize(); +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs new file mode 100644 index 0000000000000..5bab4c5438e51 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs @@ -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 or the MIT license +// , 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 Foo for T { //~ ERROR specialization is unstable + fn foo(&self) {} +} + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs new file mode 100644 index 0000000000000..c1746d765dd9f --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +trait Foo {} + +default impl Foo for .. {} +//~^ ERROR `default impl` is not allowed for default trait implementations + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs new file mode 100644 index 0000000000000..2874108157d83 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs @@ -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 or the MIT license +// , 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 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 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 Baz for T { + fn baz(&self) {} +} + +impl 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 Redundant for T { + fn redundant(&self) {} +} + +impl Redundant for T { + fn redundant(&self) {} +} + +default impl Redundant for i32 { + fn redundant(&self) {} //~ ERROR E0520 +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs new file mode 100644 index 0000000000000..dd060f8ef40dc --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs @@ -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 or the MIT license +// , 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(this: &G, arg: isize) { + this.go(arg) +} + +pub trait GoMut { + fn go_mut(&mut self, arg: isize); +} + +pub fn go_mut(this: &mut G, arg: isize) { + this.go_mut(arg) +} + +pub trait GoOnce { + fn go_once(self, arg: isize); +} + +pub fn go_once(this: G, arg: isize) { + this.go_once(arg) +} + +default impl GoMut for G + where G : Go +{ + fn go_mut(&mut self, arg: isize) { + go(&*self, arg) + } +} + +default impl GoOnce for G + where G : GoMut +{ + fn go_once(mut self, arg: isize) { + go_mut(&mut self, arg) + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs new file mode 100644 index 0000000000000..71dd7c99009ea --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl 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 Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +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 Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs new file mode 100644 index 0000000000000..9d0ea64fed428 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs @@ -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 or the MIT license +// , 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 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 Bar for T {} // use the provided method + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs new file mode 100644 index 0000000000000..6b999f3835835 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs @@ -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 or the MIT license +// , 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() { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs new file mode 100644 index 0000000000000..b99ba3d0f1c93 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn mk() -> T { + T::default() + } +} + +impl Foo for Vec { + fn mk() -> Vec { + vec![0] + } +} + +fn main() { + let v1: Vec = Foo::mk(); + let v2: Vec = Foo::mk(); + + assert!(v1.len() == 0); + assert!(v2.len() == 1); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs new file mode 100644 index 0000000000000..7daecc842f3f9 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs @@ -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 or the MIT license +// , 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. + +unsafe trait Foo { + fn foo(&self) -> &'static str; +} + +default unsafe impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default unsafe impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default unsafe impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default unsafe impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default unsafe impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default unsafe impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +default unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +default unsafe impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +default unsafe impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +unsafe trait MyMarker {} +default unsafe impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +unsafe 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"); + 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"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs new file mode 100644 index 0000000000000..594f1e4fcdfc2 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl 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 Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +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 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"); + 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"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs new file mode 100644 index 0000000000000..62c7e3e2e4431 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs new file mode 100644 index 0000000000000..b9548539e1649 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs @@ -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 or the MIT license +// , 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"); + 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)"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs new file mode 100644 index 0000000000000..7517824b62bba --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs @@ -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 or the MIT license +// , 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); +default impl Foo for MyType { + fn foo(&self) -> &'static str { + "generic MyType" + } +} + +impl Foo for MyType { + fn foo(&self) -> &'static str { + "MyType" + } +} + +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"); + 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"); + assert!(MyOtherType.foo() == "generic"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs new file mode 100644 index 0000000000000..4ac9afc1c897f --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs @@ -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 or the MIT license +// , 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 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 +// /\ +// / \ +// Vec $Vec + +// use the provided method +impl Bar for T {} + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + 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(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs new file mode 100644 index 0000000000000..f77b88e2f850a --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs @@ -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 or the MIT license +// , 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 Foo for T { + type Out = bool; +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs new file mode 100644 index 0000000000000..500cded38c1ad --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs @@ -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 or the MIT license +// , 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 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 ::Output {} +impl Foo for ::Output {} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs new file mode 100644 index 0000000000000..2397c3e2bff5d --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs @@ -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 or the MIT license +// , 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 = ::Out; + +default impl Id_ for T { + type Out = T; +} + +fn test_proection() { + let x: Id = panic!(); +} + +fn main() { + +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs new file mode 100644 index 0000000000000..6a833ba6760f6 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs @@ -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 or the MIT license +// , 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 Foo for T { + type Assoc = (); +} + +fn generic_foo() -> ::Assoc { + () +} + +// Next, allow for one layer of specialization + +trait Bar { + type Assoc; +} + +default impl Bar for T { + type Assoc = (); +} + +impl Bar for T { + type Assoc = u8; +} + +fn generic_bar_clone() -> ::Assoc { + 0u8 +} + +fn main() { +}