From 116e9831a57dd09b4c580c2f480064299137b0b0 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Fri, 18 Nov 2016 17:14:42 +0100 Subject: [PATCH 1/5] 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 --- cargo | 2 +- rls | 2 +- src/compiler-rt | 2 +- src/doc/book | 2 +- src/doc/reference | 2 +- src/jemalloc | 2 +- src/liblibc | 2 +- src/librustc/hir/lowering.rs | 9 +- src/librustc/hir/mod.rs | 1 + src/librustc/hir/print.rs | 15 ++- src/librustc/middle/reachable.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 4 +- src/librustc/traits/project.rs | 24 +++- src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 4 + src/librustc_metadata/encoder.rs | 4 +- src/librustc_metadata/schema.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 4 +- src/librustc_trans/collector.rs | 3 +- src/librustc_typeck/check/mod.rs | 18 ++- src/librustc_typeck/check/wfcheck.rs | 4 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustdoc/doctree.rs | 1 + src/librustdoc/visit_ast.rs | 3 +- src/libsyntax/ast.rs | 1 + src/libsyntax/feature_gate.rs | 11 +- src/libsyntax/fold.rs | 9 +- src/libsyntax/parse/parser.rs | 29 +++-- src/libsyntax/print/pprust.rs | 13 ++- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 1 + src/rt/hoedown | 1 - .../specialization-default-projection.rs | 46 ++++++++ .../specialization-default-types.rs | 45 ++++++++ .../specialization-feature-gate-default.rs | 21 ++++ .../defaultimpl/specialization-no-default.rs | 95 ++++++++++++++++ .../defaultimpl/auxiliary/go_trait.rs | 53 +++++++++ .../auxiliary/specialization_cross_crate.rs | 82 ++++++++++++++ .../specialization_cross_crate_defaults.rs | 49 ++++++++ .../specialization-allowed-cross-crate.rs | 31 +++++ .../defaultimpl/specialization-assoc-fns.rs | 37 ++++++ .../defaultimpl/specialization-basics.rs | 106 ++++++++++++++++++ .../specialization-cross-crate-defaults.rs | 49 ++++++++ .../specialization-cross-crate-no-gate.rs | 29 +++++ .../defaultimpl/specialization-cross-crate.rs | 58 ++++++++++ .../specialization-default-methods.rs | 94 ++++++++++++++++ .../specialization-out-of-order.rs | 27 +++++ .../specialization-overlap-projection.rs | 33 ++++++ .../specialization-projection-alias.rs | 32 ++++++ .../defaultimpl/specialization-projection.rs | 49 ++++++++ 50 files changed, 1078 insertions(+), 41 deletions(-) delete mode 160000 src/rt/hoedown create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-basics.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-projection.rs diff --git a/cargo b/cargo index 8326a3683a904..c416fb60b11ec 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 +Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 diff --git a/rls b/rls index 6ecff95fdc3ee..016cbc514cf44 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce +Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 diff --git a/src/compiler-rt b/src/compiler-rt index d30da544a8afc..a8fc4c169fac4 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 +Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 diff --git a/src/doc/book b/src/doc/book index ad7de198561b3..beea82b9230cd 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 +Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 diff --git a/src/doc/reference b/src/doc/reference index 6b0de90d87dda..b060f732145f2 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 +Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d diff --git a/src/jemalloc b/src/jemalloc index 11bfb0dcf85f7..e058ca661692a 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 +Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 diff --git a/src/liblibc b/src/liblibc index c34a802d1eb03..05a2d197356ef 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 +Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b7aafa0a9ab0b..5fb8170cd6c36 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), self.lower_generics(generics), ifce, self.lower_ty(ty), 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..dec0753be064c 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,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, struct_def: &hir::VariantData, generics: &hir::Generics, @@ -931,11 +940,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/middle/reachable.rs b/src/librustc/middle/reachable.rs index be4ec16cd63aa..12280acfac21a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -50,7 +50,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) } @@ -186,7 +186,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 3d8f9e41c675b..f417ad5b3d9d5 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,6 +33,7 @@ use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; +use hir::{self}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -923,7 +924,28 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } 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 diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 9e6a45e7f8b7c..618c1711dad40 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -90,6 +90,7 @@ provide! { <'tcx> tcx, def_id, cdata associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } + impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a9eae5281b241..ff643c17cfa65 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 ce9f0a73fe2b8..d55f489107d7f 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.lookup_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..933c3482474b5 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`. diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3e8f7e11b6b43..36e59b4774ad2 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -429,8 +429,8 @@ 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 Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + 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 13bb0d371250f..991470ebe6405 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 098e8c53a52c1..74886e503a85e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1142,7 +1142,23 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(parent) = parent { 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()); + } } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 85c87adf9be68..8b8a765dd60a5 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 22247d2531aec..323700f9eafb9 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/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..4ffc8c97c5002 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,7 +502,7 @@ 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 +512,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..152a4e7ee1add 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,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { }, _ => {} } + + match defaultness { + ast::Defaultness::Default => { + 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 1baf0d1b54ce1..58f81c8b3d751 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4863,7 +4863,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. @@ -4944,7 +4946,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))) } } @@ -5756,13 +5758,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, @@ -5856,9 +5864,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/rt/hoedown b/src/rt/hoedown deleted file mode 160000 index da282f1bb7277..0000000000000 --- a/src/rt/hoedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 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.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.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() { +} From 6427fdce7a4c7b9d98bdffd396021046c8f8347f Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 21 Nov 2016 11:59:52 +0100 Subject: [PATCH 2/5] support `default impl` for specialization fix tidy --- src/librustdoc/visit_ast.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4ffc8c97c5002..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, defaultness, 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 { From b0fca5f790e86a4235c64095f4ac55d325253b92 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 21 Nov 2016 18:39:25 +0000 Subject: [PATCH 3/5] support `default impl` for specialization rebase after support for llvm-3.7 --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/print.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5fb8170cd6c36..d072340d8c880 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1346,7 +1346,7 @@ impl<'a> LoweringContext<'a> { hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), - self.lower_defaultness(defaultness), + self.lower_defaultness(defaultness, true /* [1] */), self.lower_generics(generics), ifce, self.lower_ty(ty), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index dec0753be064c..a78d5ce1c16d0 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -823,8 +823,9 @@ 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")?; + match defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), } Ok(()) } From 715811d0be05dcdc55b44f97d9fd2cd1eb7eee05 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 24 Apr 2017 09:56:54 +0000 Subject: [PATCH 4/5] support `default impl` for specialization pr review --- cargo | 2 +- rls | 2 +- src/compiler-rt | 2 +- src/doc/book | 2 +- src/doc/reference | 2 +- src/grammar/parser-lalr.y | 28 +++-- src/jemalloc | 2 +- src/liblibc | 2 +- src/librustc/hir/lowering.rs | 3 + src/librustc/ich/impls_hir.rs | 2 +- src/librustc/middle/cstore.rs | 2 + src/librustc/traits/project.rs | 25 +---- src/librustc/traits/util.rs | 21 ++++ src/librustc_metadata/cstore_impl.rs | 7 +- src/librustc_metadata/schema.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_typeck/check/mod.rs | 16 +-- src/librustc_typeck/collect.rs | 6 +- src/libsyntax/parse/parser.rs | 14 ++- src/rt/hoedown | 1 + ...zation-no-default-trait-implementations.rs | 19 ++++ .../specialization-basics-unsafe.rs | 106 ++++++++++++++++++ 22 files changed, 202 insertions(+), 65 deletions(-) create mode 160000 src/rt/hoedown create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs diff --git a/cargo b/cargo index c416fb60b11ec..8326a3683a904 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 diff --git a/rls b/rls index 016cbc514cf44..6ecff95fdc3ee 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 +Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce diff --git a/src/compiler-rt b/src/compiler-rt index a8fc4c169fac4..d30da544a8afc 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 +Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 diff --git a/src/doc/book b/src/doc/book index beea82b9230cd..ad7de198561b3 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 +Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 diff --git a/src/doc/reference b/src/doc/reference index b060f732145f2..6b0de90d87dda 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d +Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 3aa76d168df07..69ba0c9098be3 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,11 @@ maybe_unsafe | %empty { $$ = mk_none(); } ; +maybe_default_impl +: IMPL { $$ = mk_none(); } +| DEFAULT IMPL { $$ = $1 } +; + trait_method : type_method { $$ = mk_node("Required", 1, $1); } | method { $$ = mk_node("Provided", 1, $1); } @@ -588,27 +594,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_unsafe maybe_default_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); + $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8, $2); } -| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); + $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10, $2); } -| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_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); + $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10, $2); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_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); + $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11, $2); } -| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' +| maybe_unsafe maybe_default_impl generic_params trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' +| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); } @@ -1935,4 +1941,4 @@ brackets_delimited_token_trees $2, mk_node("TTTok", 1, mk_atom("]"))); } -; +; \ No newline at end of file diff --git a/src/jemalloc b/src/jemalloc index e058ca661692a..11bfb0dcf85f7 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 +Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 diff --git a/src/liblibc b/src/liblibc index 05a2d197356ef..c34a802d1eb03 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f +Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d072340d8c880..8dda297e897b2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1362,6 +1362,9 @@ impl<'a> LoweringContext<'a> { } ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } + + // [1] `defaultness.has_value()` is necer 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/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/traits/project.rs b/src/librustc/traits/project.rs index f417ad5b3d9d5..7675b2d00ebb2 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,7 +33,6 @@ use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use hir::{self}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -924,28 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - 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 + 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 d4245ec9b2475..4aa7950de8f1e 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,6 +13,7 @@ use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; +use hir::{self}; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -504,6 +505,26 @@ 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 enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 618c1711dad40..767114a37be4e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -90,7 +90,6 @@ provide! { <'tcx> tcx, def_id, cdata associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } - impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); @@ -179,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/schema.rs b/src/librustc_metadata/schema.rs index 933c3482474b5..5870903e7718f 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -416,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 36e59b4774ad2..507ac1efc2c66 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } None => { - if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { trait_id = self.lookup_def_id(ty.id); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 74886e503a85e..a00d1ad0eae65 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1142,21 +1142,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(parent) = parent { if parent.item.is_final() { - 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 { + if !tcx.impl_is_default(parent.node.def_id()) { report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 660ce837043c1..0203c3b6299fe 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<'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<'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/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 58f81c8b3d751..2c10fff03dbe8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4918,6 +4918,14 @@ impl<'a> Parser<'a> { allowed to have generics"); } + match defaultness { + ast::Defaultness::Default => { + 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(), @@ -5760,13 +5768,13 @@ impl<'a> Parser<'a> { } 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.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Default)) && self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM - let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Impl)?; let (ident, item_, diff --git a/src/rt/hoedown b/src/rt/hoedown new file mode 160000 index 0000000000000..da282f1bb7277 --- /dev/null +++ b/src/rt/hoedown @@ -0,0 +1 @@ +Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 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/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..9376d0db2df63 --- /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; +} + +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +unsafe default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +unsafe default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +unsafe default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +unsafe default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +unsafe default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +unsafe impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +unsafe impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +unsafe trait MyMarker {} +unsafe default 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"); +} From b48eb5e0be2a6e06d9629f770288c46f7bcb326c Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 26 Apr 2017 03:17:48 +0000 Subject: [PATCH 5/5] support `default impl` for specialization `[default] [unsafe] impl` and typecheck --- src/grammar/parser-lalr.y | 29 ++++++++++--------- src/librustc/hir/lowering.rs | 2 +- src/librustc/traits/util.rs | 5 ++++ src/librustc_typeck/check/mod.rs | 6 ++-- src/libsyntax/feature_gate.rs | 11 +++---- src/libsyntax/parse/parser.rs | 15 ++++------ .../specialization-basics-unsafe.rs | 22 +++++++------- 7 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 69ba0c9098be3..c9fcdf7647b9c 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -535,10 +535,11 @@ maybe_unsafe | %empty { $$ = mk_none(); } ; -maybe_default_impl -: IMPL { $$ = mk_none(); } -| DEFAULT IMPL { $$ = $1 } -; +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); } @@ -594,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 maybe_default_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, $2); + $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); } -| maybe_unsafe maybe_default_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, $2); + $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); } -| maybe_unsafe maybe_default_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, $2); + $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); } -| maybe_unsafe maybe_default_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, $2); + $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); } -| maybe_unsafe maybe_default_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 maybe_default_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); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8dda297e897b2..8f4dce5a78303 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1363,7 +1363,7 @@ impl<'a> LoweringContext<'a> { ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } - // [1] `defaultness.has_value()` is necer called for an `impl`, always `true` in order to + // [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 } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 4aa7950de8f1e..e7c61dde768c0 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -14,6 +14,7 @@ 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}; @@ -525,6 +526,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } + + 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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a00d1ad0eae65..631e09d831d5c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1141,10 +1141,8 @@ 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_is_default(parent.node.def_id()) { - report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); - } + if tcx.impl_item_is_final(&parent) { + report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 152a4e7ee1add..b6a2c983fd4d7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1226,13 +1226,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { _ => {} } - match defaultness { - ast::Defaultness::Default => { - gate_feature_post!(&self, specialization, - i.span, - "specialization is unstable"); - } - _ => {} + if let ast::Defaultness::Default = defaultness { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2c10fff03dbe8..f806e1e3bde62 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4918,12 +4918,9 @@ impl<'a> Parser<'a> { allowed to have generics"); } - match defaultness { - ast::Defaultness::Default => { - self.span_err(impl_span, "`default impl` is not allowed for \ - default trait implementations"); - } - _ => {} + 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))?; @@ -5768,13 +5765,13 @@ impl<'a> Parser<'a> { } if (self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || - (self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Default)) && + (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 - self.expect_keyword(keywords::Unsafe)?; let defaultness = self.parse_defaultness()?; + self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Impl)?; let (ident, item_, diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs index 9376d0db2df63..7daecc842f3f9 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs @@ -17,61 +17,61 @@ unsafe trait Foo { fn foo(&self) -> &'static str; } -unsafe default impl Foo for T { +default unsafe impl Foo for T { fn foo(&self) -> &'static str { "generic" } } -unsafe default impl Foo for T { +default unsafe impl Foo for T { fn foo(&self) -> &'static str { "generic Clone" } } -unsafe default impl Foo for (T, U) where T: Clone, U: Clone { +default unsafe impl Foo for (T, U) where T: Clone, U: Clone { fn foo(&self) -> &'static str { "generic pair" } } -unsafe default impl Foo for (T, T) { +default unsafe impl Foo for (T, T) { fn foo(&self) -> &'static str { "generic uniform pair" } } -unsafe default impl Foo for (u8, u32) { +default unsafe impl Foo for (u8, u32) { fn foo(&self) -> &'static str { "(u8, u32)" } } -unsafe default impl Foo for (u8, u8) { +default unsafe impl Foo for (u8, u8) { fn foo(&self) -> &'static str { "(u8, u8)" } } -unsafe default impl Foo for Vec { +default unsafe impl Foo for Vec { fn foo(&self) -> &'static str { "generic Vec" } } -unsafe impl Foo for Vec { +default unsafe impl Foo for Vec { fn foo(&self) -> &'static str { "Vec" } } -unsafe impl Foo for String { +default unsafe impl Foo for String { fn foo(&self) -> &'static str { "String" } } -unsafe impl Foo for i32 { +default unsafe impl Foo for i32 { fn foo(&self) -> &'static str { "i32" } @@ -80,7 +80,7 @@ unsafe impl Foo for i32 { struct NotClone; unsafe trait MyMarker {} -unsafe default impl Foo for T { +default unsafe impl Foo for T { fn foo(&self) -> &'static str { "generic Clone + MyMarker" }