From b48eb5e0be2a6e06d9629f770288c46f7bcb326c Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 26 Apr 2017 03:17:48 +0000 Subject: [PATCH] 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 69ba0c9098be..c9fcdf7647b9 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 8dda297e897b..8f4dce5a7830 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 4aa7950de8f1..e7c61dde768c 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 a00d1ad0eae6..631e09d831d5 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 152a4e7ee1ad..b6a2c983fd4d 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 2c10fff03dbe..f806e1e3bde6 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 9376d0db2df6..7daecc842f3f 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" }