From c4bbe9cbbe9921646cdedb856e34dc951641ed96 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 30 Nov 2019 18:25:44 +0100 Subject: [PATCH] Alias `TraitItem` & `ImplItem`. Allow defaultness on trait items syntactically. --- src/librustc_parse/parser/item.rs | 6 ++- src/librustc_passes/ast_validation.rs | 9 +++++ src/libsyntax/ast.rs | 22 +++-------- src/libsyntax/mut_visit.rs | 3 +- src/libsyntax/print/pprust.rs | 1 + src/libsyntax_expand/placeholders.rs | 1 + src/test/ui/issues/issue-60075.stderr | 2 +- src/test/ui/parser/issue-32446.stderr | 4 +- .../parser/macro/trait-non-item-macros.stderr | 4 +- .../missing-close-brace-in-trait.stderr | 4 +- ...ait-item-with-defaultness-fail-semantic.rs | 10 +++++ ...item-with-defaultness-fail-semantic.stderr | 38 +++++++++++++++++++ .../trait-item-with-defaultness-pass.rs | 13 +++++++ 13 files changed, 90 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs create mode 100644 src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr create mode 100644 src/test/ui/parser/trait-item-with-defaultness-pass.rs diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 34ef12e818c..c159fb66d50 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -714,9 +714,9 @@ impl<'a> Parser<'a> { id: DUMMY_NODE_ID, span: lo.to(self.prev_span), ident: name, + attrs, vis, defaultness, - attrs, generics, kind, tokens: None, @@ -882,6 +882,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, TraitItem> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; + let defaultness = self.parse_defaultness(); let (name, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_trait_item_assoc_ty()? } else if self.is_const_item() { @@ -895,12 +896,13 @@ impl<'a> Parser<'a> { Ok(TraitItem { id: DUMMY_NODE_ID, + span: lo.to(self.prev_span), ident: name, attrs, vis, + defaultness, generics, kind, - span: lo.to(self.prev_span), tokens: None, }) } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 202b6ae2f94..a078a36db7a 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -271,6 +271,14 @@ impl<'a> AstValidator<'a> { forbid, and warn are the only allowed built-in attributes in function parameters") }); } + + fn check_defaultness(&self, span: Span, defaultness: Defaultness) { + if let Defaultness::Default = defaultness { + self.err_handler() + .struct_span_err(span, "`default` is only allowed on items in `impl` definitions") + .emit(); + } + } } enum GenericPosition { @@ -746,6 +754,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_trait_item(&mut self, ti: &'a TraitItem) { self.invalid_visibility(&ti.vis, None); + self.check_defaultness(ti.span, ti.defaultness); visit::walk_trait_item(self, ti); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 92ba071a03d..964acfa92b9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1603,24 +1603,12 @@ pub struct FnSig { pub decl: P, } -/// Represents an item declaration within a trait declaration, +pub type TraitItem = ImplItem; + +/// Represents the kind of 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, RustcEncodable, RustcDecodable, Debug)] -pub struct TraitItem { - pub attrs: Vec, - pub id: NodeId, - pub span: Span, - pub vis: Visibility, - pub ident: Ident, - - pub generics: Generics, - pub kind: TraitItemKind, - /// See `Item::tokens` for what this is. - pub tokens: Option, -} - #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum TraitItemKind { Const(P, Option>), @@ -1631,7 +1619,7 @@ pub enum TraitItemKind { /// Represents anything within an `impl` block. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct ImplItem { +pub struct ImplItem { pub attrs: Vec, pub id: NodeId, pub span: Span, @@ -1640,7 +1628,7 @@ pub struct ImplItem { pub defaultness: Defaultness, pub generics: Generics, - pub kind: ImplItemKind, + pub kind: K, /// See `Item::tokens` for what this is. pub tokens: Option, } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f8795d885d2..9d0a29f2951 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -939,7 +939,8 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { pub fn noop_flat_map_trait_item(mut item: TraitItem, visitor: &mut T) -> SmallVec<[TraitItem; 1]> { - let TraitItem { id, ident, vis, attrs, generics, kind, span, tokens: _ } = &mut item; + let TraitItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } = + &mut item; visitor.visit_id(id); visitor.visit_ident(ident); visitor.visit_vis(vis); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f0c5fb32fb1..2e3ea5e2444 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1550,6 +1550,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); self.print_outer_attributes(&ti.attrs); + self.print_defaultness(ti.defaultness); match ti.kind { ast::TraitItemKind::Const(ref ty, ref default) => { self.print_associated_const( diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs index faea04e691b..6057be9826a 100644 --- a/src/libsyntax_expand/placeholders.rs +++ b/src/libsyntax_expand/placeholders.rs @@ -53,6 +53,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option AstFragment::TraitItems(smallvec![ast::TraitItem { id, span, ident, vis, attrs, generics, kind: ast::TraitItemKind::Macro(mac_placeholder()), + defaultness: ast::Defaultness::Final, tokens: None, }]), AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![ast::ImplItem { diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr index e0b15130c33..e8ef981f515 100644 --- a/src/test/ui/issues/issue-60075.stderr +++ b/src/test/ui/issues/issue-60075.stderr @@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` LL | }); | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;` --> $DIR/issue-60075.rs:6:11 | LL | fn qux() -> Option { diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr index 70256a59231..1a97f54160b 100644 --- a/src/test/ui/parser/issue-32446.stderr +++ b/src/test/ui/parser/issue-32446.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...` --> $DIR/issue-32446.rs:4:11 | LL | trait T { ... } - | ^^^ expected one of 9 possible tokens + | ^^^ expected one of 10 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr index 0a433ab278e..7647ba500e0 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.stderr +++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2` --> $DIR/trait-non-item-macros.rs:2:19 | LL | ($a:expr) => ($a) - | ^^ expected one of 8 possible tokens + | ^^ expected one of 9 possible tokens ... LL | bah!(2); | -------- in this macro invocation diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr index cbaf9315e85..7e8abf22d55 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -7,11 +7,11 @@ LL | trait T { LL | fn main() {} | ^ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct` +error: expected one of `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct` --> $DIR/missing-close-brace-in-trait.rs:5:12 | LL | pub(crate) struct Bar(); - | ^^^^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` + | ^^^^^^ expected one of 7 possible tokens error[E0601]: `main` function not found in crate `missing_close_brace_in_trait` --> $DIR/missing-close-brace-in-trait.rs:1:1 diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs new file mode 100644 index 00000000000..b67e30637aa --- /dev/null +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs @@ -0,0 +1,10 @@ +fn main() {} + +trait X { + default const A: u8; //~ ERROR `default` is only allowed on items in `impl` definitions + default const B: u8 = 0; //~ ERROR `default` is only allowed on items in `impl` definitions + default type D; //~ ERROR `default` is only allowed on items in `impl` definitions + default type C: Ord; //~ ERROR `default` is only allowed on items in `impl` definitions + default fn f1(); //~ ERROR `default` is only allowed on items in `impl` definitions + default fn f2() {} //~ ERROR `default` is only allowed on items in `impl` definitions +} diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr new file mode 100644 index 00000000000..48b502a1506 --- /dev/null +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -0,0 +1,38 @@ +error: `default` is only allowed on items in `impl` definitions + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:4:5 + | +LL | default const A: u8; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:5:5 + | +LL | default const B: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:6:5 + | +LL | default type D; + | ^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:7:5 + | +LL | default type C: Ord; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:8:5 + | +LL | default fn f1(); + | ^^^^^^^^^^^^^^^^ + +error: `default` is only allowed on items in `impl` definitions + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:9:5 + | +LL | default fn f2() {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/trait-item-with-defaultness-pass.rs b/src/test/ui/parser/trait-item-with-defaultness-pass.rs new file mode 100644 index 00000000000..a6318bd99e2 --- /dev/null +++ b/src/test/ui/parser/trait-item-with-defaultness-pass.rs @@ -0,0 +1,13 @@ +// check-pass + +fn main() {} + +#[cfg(FALSE)] +trait X { + default const A: u8; + default const B: u8 = 0; + default type D; + default type C: Ord; + default fn f1(); + default fn f2() {} +}