From 8fe63e23421f66b730afdbd14c3ec90e39950288 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 18 Dec 2015 14:38:28 -0800 Subject: [PATCH] Add `default` as contextual keyword, and parse it for impl items. --- src/librustc_front/fold.rs | 1 + src/librustc_front/hir.rs | 15 +++- src/librustc_front/lowering.rs | 8 ++ src/libsyntax/ast.rs | 15 +++- src/libsyntax/ext/expand.rs | 1 + src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 33 +++++++- src/libsyntax/parse/token.rs | 97 ++++++++++++----------- src/libsyntax_ext/deriving/generic/mod.rs | 2 + src/test/parse-fail/default.rs | 35 ++++++++ 10 files changed, 150 insertions(+), 58 deletions(-) create mode 100644 src/test/parse-fail/default.rs diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs index beedb3d70b6..6ae59122f71 100644 --- a/src/librustc_front/fold.rs +++ b/src/librustc_front/fold.rs @@ -839,6 +839,7 @@ pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) -> ImplItem { name: folder.fold_name(i.name), attrs: fold_attrs(i.attrs, folder), vis: i.vis, + defaultness: i.defaultness, node: match i.node { ImplItemKind::Const(ty, expr) => { ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr)) diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs index cc7c0f7865e..939b527fad3 100644 --- a/src/librustc_front/hir.rs +++ b/src/librustc_front/hir.rs @@ -864,10 +864,10 @@ pub struct MethodSig { pub explicit_self: ExplicitSelf, } -/// Represents a method declaration in a trait declaration, possibly including -/// a default implementation A trait method is either required (meaning it -/// doesn't have an implementation, just a signature) or provided (meaning it -/// has a default implementation). +/// Represents an item declaration within a trait declaration, +/// possibly including a default implementation. A trait item is +/// either required (meaning it doesn't have an implementation, just a +/// signature) or provided (meaning it has a default implementation). #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TraitItem { pub id: NodeId, @@ -889,6 +889,7 @@ pub struct ImplItem { pub id: NodeId, pub name: Name, pub vis: Visibility, + pub defaultness: Defaultness, pub attrs: HirVec, pub node: ImplItemKind, pub span: Span, @@ -1046,6 +1047,12 @@ pub enum Constness { NotConst, } +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Defaultness { + Default, + Final, +} + impl fmt::Display for Unsafety { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(match *self { diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index 291df66755e..825ab3fbd4c 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -756,6 +756,7 @@ pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem { name: i.ident.name, attrs: lower_attrs(lctx, &i.attrs), vis: lower_visibility(lctx, i.vis), + defaultness: lower_defaultness(lctx, i.defaultness), node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr)) @@ -1707,6 +1708,13 @@ pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibili } } +pub fn lower_defaultness(_lctx: &LoweringContext, d: Defaultness) -> hir::Defaultness { + match d { + Defaultness::Default => hir::Defaultness::Default, + Defaultness::Final => hir::Defaultness::Final, + } +} + pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode { match *b { BlockCheckMode::Default => hir::DefaultBlock, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f7621b0131a..c830fed5db9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1328,10 +1328,10 @@ pub struct MethodSig { pub explicit_self: ExplicitSelf, } -/// Represents a method declaration in a trait declaration, possibly including -/// a default implementation. A trait method is either required (meaning it -/// doesn't have an implementation, just a signature) or provided (meaning it -/// has a default implementation). +/// Represents an item declaration within a trait declaration, +/// possibly including a default implementation. A trait item is +/// either required (meaning it doesn't have an implementation, just a +/// signature) or provided (meaning it has a default implementation). #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TraitItem { pub id: NodeId, @@ -1353,6 +1353,7 @@ pub struct ImplItem { pub id: NodeId, pub ident: Ident, pub vis: Visibility, + pub defaultness: Defaultness, pub attrs: Vec, pub node: ImplItemKind, pub span: Span, @@ -1654,6 +1655,12 @@ pub enum Constness { NotConst, } +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Defaultness { + Default, + Final, +} + impl fmt::Display for Unsafety { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(match *self { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f5794f7219b..5bfdab791d6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1061,6 +1061,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) ident: ii.ident, attrs: ii.attrs, vis: ii.vis, + defaultness: ii.defaultness, node: match ii.node { ast::ImplItemKind::Method(sig, body) => { let (sig, body) = expand_and_rename_method(sig, body, fld); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9056103d300..cd8998a211a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -993,6 +993,7 @@ pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) ident: folder.fold_ident(i.ident), attrs: fold_attrs(i.attrs, folder), vis: i.vis, + defaultness: i.defaultness, node: match i.node { ast::ImplItemKind::Const(ty, expr) => { ast::ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5884be40150..969d39056aa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -18,7 +18,7 @@ use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind}; use ast::Block; use ast::{BlockCheckMode, CaptureBy}; use ast::{Constness, Crate, CrateConfig}; -use ast::{Decl, DeclKind}; +use ast::{Decl, DeclKind, Defaultness}; use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; @@ -644,6 +644,25 @@ impl<'a> Parser<'a> { } } + pub fn check_contextual_keyword(&mut self, ident: Ident) -> bool { + let tok = token::Ident(ident, token::Plain); + self.expected_tokens.push(TokenType::Token(tok)); + if let token::Ident(ref cur_ident, _) = self.token { + cur_ident.name == ident.name + } else { + false + } + } + + pub fn eat_contextual_keyword(&mut self, ident: Ident) -> PResult { + if self.check_contextual_keyword(ident) { + try!(self.bump()); + Ok(true) + } else { + Ok(false) + } + } + /// If the given word is not a keyword, signal an error. /// If the next token is not the given word, signal an error. /// Otherwise, eat it. @@ -705,7 +724,6 @@ impl<'a> Parser<'a> { } } - /// Attempt to consume a `<`. If `<<` is seen, replace it with a single /// `<` and continue. If a `<` is not seen, return false. /// @@ -4846,6 +4864,7 @@ impl<'a> Parser<'a> { let mut attrs = try!(self.parse_outer_attributes()); let lo = self.span.lo; let vis = try!(self.parse_visibility()); + let defaultness = try!(self.parse_defaultness()); let (name, node) = if self.eat_keyword(keywords::Type) { let name = try!(self.parse_ident()); try!(self.expect(&token::Eq)); @@ -4872,6 +4891,7 @@ impl<'a> Parser<'a> { span: mk_sp(lo, self.last_span.hi), ident: name, vis: vis, + defaultness: defaultness, attrs: attrs, node: node }) @@ -5208,6 +5228,15 @@ impl<'a> Parser<'a> { else { Ok(Visibility::Inherited) } } + /// Parse defaultness: DEFAULT or nothing + fn parse_defaultness(&mut self) -> PResult { + if try!(self.eat_contextual_keyword(special_idents::DEFAULT)) { + Ok(Defaultness::Default) + } else { + Ok(Defaultness::Final) + } + } + /// Given a termination token, parse all of the items in a module fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> { let mut items = vec![]; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 294cbf35895..033ac9440bc 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -545,66 +545,67 @@ declare_special_idents_and_keywords! { (9, __unused1, "<__unused1>"); (super::SELF_TYPE_KEYWORD_NAME_NUM, type_self, "Self"); (11, prelude_import, "prelude_import"); + (12, DEFAULT, "default"); } pub mod keywords { // These ones are variants of the Keyword enum 'strict: - (12, As, "as"); - (13, Break, "break"); - (14, Crate, "crate"); - (15, Else, "else"); - (16, Enum, "enum"); - (17, Extern, "extern"); - (18, False, "false"); - (19, Fn, "fn"); - (20, For, "for"); - (21, If, "if"); - (22, Impl, "impl"); - (23, In, "in"); - (24, Let, "let"); - (25, Loop, "loop"); - (26, Match, "match"); - (27, Mod, "mod"); - (28, Move, "move"); - (29, Mut, "mut"); - (30, Pub, "pub"); - (31, Ref, "ref"); - (32, Return, "return"); + (13, As, "as"); + (14, Break, "break"); + (15, Crate, "crate"); + (16, Else, "else"); + (17, Enum, "enum"); + (18, Extern, "extern"); + (19, False, "false"); + (20, Fn, "fn"); + (21, For, "for"); + (22, If, "if"); + (23, Impl, "impl"); + (24, In, "in"); + (25, Let, "let"); + (26, Loop, "loop"); + (27, Match, "match"); + (28, Mod, "mod"); + (29, Move, "move"); + (30, Mut, "mut"); + (31, Pub, "pub"); + (32, Ref, "ref"); + (33, Return, "return"); // Static and Self are also special idents (prefill de-dupes) (super::STATIC_KEYWORD_NAME_NUM, Static, "static"); (super::SELF_KEYWORD_NAME_NUM, SelfValue, "self"); (super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self"); - (33, Struct, "struct"); + (34, Struct, "struct"); (super::SUPER_KEYWORD_NAME_NUM, Super, "super"); - (34, True, "true"); - (35, Trait, "trait"); - (36, Type, "type"); - (37, Unsafe, "unsafe"); - (38, Use, "use"); - (39, While, "while"); - (40, Continue, "continue"); - (41, Box, "box"); - (42, Const, "const"); - (43, Where, "where"); + (35, True, "true"); + (36, Trait, "trait"); + (37, Type, "type"); + (38, Unsafe, "unsafe"); + (39, Use, "use"); + (40, While, "while"); + (41, Continue, "continue"); + (42, Box, "box"); + (43, Const, "const"); + (44, Where, "where"); 'reserved: - (44, Virtual, "virtual"); - (45, Proc, "proc"); - (46, Alignof, "alignof"); - (47, Become, "become"); - (48, Offsetof, "offsetof"); - (49, Priv, "priv"); - (50, Pure, "pure"); - (51, Sizeof, "sizeof"); - (52, Typeof, "typeof"); - (53, Unsized, "unsized"); - (54, Yield, "yield"); - (55, Do, "do"); - (56, Abstract, "abstract"); - (57, Final, "final"); - (58, Override, "override"); - (59, Macro, "macro"); + (45, Virtual, "virtual"); + (46, Proc, "proc"); + (47, Alignof, "alignof"); + (48, Become, "become"); + (49, Offsetof, "offsetof"); + (50, Priv, "priv"); + (51, Pure, "pure"); + (52, Sizeof, "sizeof"); + (53, Typeof, "typeof"); + (54, Unsized, "unsized"); + (55, Yield, "yield"); + (56, Do, "do"); + (57, Abstract, "abstract"); + (58, Final, "final"); + (59, Override, "override"); + (60, Macro, "macro"); } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index c0237a5d29a..937055fcfa6 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -476,6 +476,7 @@ impl<'a> TraitDef<'a> { span: self.span, ident: ident, vis: ast::Visibility::Inherited, + defaultness: ast::Defaultness::Final, attrs: Vec::new(), node: ast::ImplItemKind::Type(type_def.to_ty(cx, self.span, @@ -893,6 +894,7 @@ impl<'a> MethodDef<'a> { attrs: self.attributes.clone(), span: trait_.span, vis: ast::Visibility::Inherited, + defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { generics: fn_generics, diff --git a/src/test/parse-fail/default.rs b/src/test/parse-fail/default.rs new file mode 100644 index 00000000000..d18401e6764 --- /dev/null +++ b/src/test/parse-fail/default.rs @@ -0,0 +1,35 @@ +// 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. + +// compile-flags: -Z parse-only + +// Test successful and unsucessful parsing of the `default` contextual keyword + +trait Foo { + fn foo() -> T; +} + +impl Foo for u8 { + default fn foo() -> T { + T::default() + } +} + +impl Foo for u16 { + pub default fn foo() -> T { + T::default() + } +} + +impl Foo for u32 { + default pub fn foo() -> T { T::default() } //~ ERROR expected one of +} + +fn main() {}