From aa393b0cde881c612379d90ca300396cd7ce2e96 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Apr 2019 23:58:57 +0300 Subject: [PATCH] Some cleanup to `maybe_parse_struct_expr` --- src/libsyntax/parse/parser.rs | 31 ++++++------- ...truct-literal-in-match-discriminant.stderr | 1 + src/test/ui/struct-literal-variant-in-if.rs | 4 +- .../ui/struct-literal-variant-in-if.stderr | 44 +++++-------------- 4 files changed, 26 insertions(+), 54 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2a2c4637c571..8feab373e7102 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2910,27 +2910,22 @@ impl<'a> Parser<'a> { path: &ast::Path, attrs: &ThinVec, ) -> Option>> { - // We don't want to assume it's a struct when encountering `{ : }` because - // it could be type ascription, like in `{ ident: u32 }`. - let isnt_ascription = self.look_ahead(1, |t| t.is_ident()) && - self.look_ahead(2, |t| *t == token::Colon) && ( - (self.look_ahead(3, |t| t.is_ident()) && - self.look_ahead(4, |t| *t == token::Comma)) || - self.look_ahead(3, |t| t.is_lit()) || - self.look_ahead(3, |t| *t == token::BinOp(token::Minus)) && - self.look_ahead(4, |t| t.is_lit()) - ); - let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && ( - self.look_ahead(2, |t| *t == token::Colon) && isnt_ascription - || self.look_ahead(2, |t| *t == token::Comma) - // We could also check for `token::CloseDelim(token::Brace)`, but that would - // have false positives in the case of `if x == y { z } { a }`. + let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); + let certainly_not_a_block = || self.look_ahead(1, |t| t.is_ident()) && ( + // `{ ident, ` cannot start a block + self.look_ahead(2, |t| t == &token::Comma) || + self.look_ahead(2, |t| t == &token::Colon) && ( + // `{ ident: token, ` cannot start a block + self.look_ahead(4, |t| t == &token::Comma) || + // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type` + self.look_ahead(3, |t| !t.can_begin_type()) + ) ); - let bad_struct = self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - if !bad_struct || could_be_struct { + + if struct_allowed || certainly_not_a_block() { // This is a struct literal, but we don't can't accept them here let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); - if let (Ok(expr), true) = (&expr, bad_struct) { + if let (Ok(expr), false) = (&expr, struct_allowed) { let mut err = self.diagnostic().struct_span_err( expr.span, "struct literals are not allowed here", diff --git a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr index b8818ccba3955..0058e8981cd25 100644 --- a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr +++ b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr @@ -14,3 +14,4 @@ LL | }) { | error: aborting due to previous error + diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs index 8f2d50586c055..4ef8effaf1f5f 100644 --- a/src/test/ui/struct-literal-variant-in-if.rs +++ b/src/test/ui/struct-literal-variant-in-if.rs @@ -13,9 +13,7 @@ fn test_E(x: E) { if x == E::I { field1: true, field2: 42 } {} //~^ ERROR struct literals are not allowed here if x == E::V { field: false } {} - //~^ ERROR expected identifier, found keyword `false` - //~| ERROR expected type, found keyword `false` - //~| ERROR expected value, found struct variant `E::V` + //~^ ERROR struct literals are not allowed here if x == E::J { field: -42 } {} //~^ ERROR struct literals are not allowed here if x == E::K { field: "" } {} diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr index 0af0c6aefaf40..55f23baea7aa8 100644 --- a/src/test/ui/struct-literal-variant-in-if.stderr +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -8,32 +8,18 @@ help: surround the struct literal with parenthesis LL | if x == (E::I { field1: true, field2: 42 }) {} | ^ ^ -error: expected identifier, found keyword `false` - --> $DIR/struct-literal-variant-in-if.rs:15:27 - | -LL | if x == E::V { field: false } {} - | ^^^^^ expected identifier, found keyword -help: you can escape reserved keywords to use them as identifiers - | -LL | if x == E::V { field: r#false } {} - | ^^^^^^^ - -error: expected type, found keyword `false` - --> $DIR/struct-literal-variant-in-if.rs:15:27 +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:15:13 | LL | if x == E::V { field: false } {} - | ^^^^^ expecting a type here because of type ascription - | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/struct-literal-variant-in-if.rs:15:20 + | ^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis | -LL | if x == E::V { field: false } {} - | ^^^^^ - = help: this might be indicative of a syntax error elsewhere +LL | if x == (E::V { field: false }) {} + | ^ ^ error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:19:13 + --> $DIR/struct-literal-variant-in-if.rs:17:13 | LL | if x == E::J { field: -42 } {} | ^^^^^^^^^^^^^^^^^^^ @@ -43,7 +29,7 @@ LL | if x == (E::J { field: -42 }) {} | ^ ^ error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:21:13 + --> $DIR/struct-literal-variant-in-if.rs:19:13 | LL | if x == E::K { field: "" } {} | ^^^^^^^^^^^^^^^^^^ @@ -60,14 +46,6 @@ LL | if x == E::V { field } {} | | | help: surround the struct literal with parenthesis: `(E::V { field })` -error[E0423]: expected value, found struct variant `E::V` - --> $DIR/struct-literal-variant-in-if.rs:15:13 - | -LL | if x == E::V { field: false } {} - | ^^^^----------------- - | | - | help: surround the struct literal with parenthesis: `(E::V { field: false })` - error[E0308]: mismatched types --> $DIR/struct-literal-variant-in-if.rs:10:20 | @@ -81,7 +59,7 @@ LL | if x == E::V { field } {} found type `bool` error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:23:20 + --> $DIR/struct-literal-variant-in-if.rs:21:20 | LL | let y: usize = (); | ^^ expected usize, found () @@ -89,7 +67,7 @@ LL | let y: usize = (); = note: expected type `usize` found type `()` -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0308, E0423. +Some errors have detailed explanations: E0308, E0423. For more information about an error, try `rustc --explain E0308`.