From 715811d0be05dcdc55b44f97d9fd2cd1eb7eee05 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 24 Apr 2017 09:56:54 +0000 Subject: [PATCH] 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 c416fb60b11..8326a3683a9 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 diff --git a/rls b/rls index 016cbc514cf..6ecff95fdc3 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 +Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce diff --git a/src/compiler-rt b/src/compiler-rt index a8fc4c169fa..d30da544a8a 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 beea82b9230..ad7de198561 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 b060f732145..6b0de90d87d 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 3aa76d168df..69ba0c9098b 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 e058ca66169..11bfb0dcf85 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 +Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 diff --git a/src/liblibc b/src/liblibc index 05a2d197356..c34a802d1eb 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 d072340d8c8..8dda297e897 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 82e03a9fddc..3aeee1c1b98 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 3251addcb32..60171f1a428 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 f417ad5b3d9..7675b2d00eb 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 d4245ec9b24..4aa7950de8f 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 618c1711dad..767114a37be 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 933c3482474..5870903e771 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 36e59b4774a..507ac1efc2c 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 74886e503a8..a00d1ad0eae 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 660ce837043..0203c3b6299 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 58f81c8b3d7..2c10fff03db 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 00000000000..da282f1bb72 --- /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 00000000000..c1746d765dd --- /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 00000000000..9376d0db2df --- /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"); +}