From 1e25882944aabcf0c871182b887cd4ffe9c7b330 Mon Sep 17 00:00:00 2001 From: yukang Date: Thu, 13 Oct 2022 23:27:17 +0800 Subject: [PATCH 1/3] fix #102806, suggest use .. to fill in the rest of the fields of Struct --- .../locales/en-US/parser.ftl | 3 ++ compiler/rustc_parse/src/errors.rs | 9 ++++ compiler/rustc_parse/src/parser/expr.rs | 21 ++++++-- src/test/ui/parser/issue-102806.rs | 22 ++++++++ src/test/ui/parser/issue-102806.stderr | 51 +++++++++++++++++++ 5 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/parser/issue-102806.rs create mode 100644 src/test/ui/parser/issue-102806.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 13c368d1c5850..455ff34f7247f 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -112,6 +112,9 @@ parser_missing_semicolon_before_array = expected `;`, found `[` parser_invalid_block_macro_segment = cannot use a `block` macro fragment here .label = the `block` fragment is within this context +parser_expect_dotdot_not_dotdotdot = expected `..`, found `...` + .suggestion = use `..` to fill in the rest of the fields + parser_if_expression_missing_then_block = this `if` expression is missing a block after the condition .add_then_block = add a block here .condition_possibly_unfinished = this binary operation is possibly unfinished diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dc20490284293..b02bd66453373 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -368,6 +368,15 @@ pub(crate) struct MissingSemicolonBeforeArray { pub semicolon: Span, } +#[derive(Diagnostic)] +#[diag(parser_expect_dotdot_not_dotdotdot)] +pub(crate) struct MissingDotDot { + #[primary_span] + pub token_span: Span, + #[suggestion_verbose(applicability = "maybe-incorrect", code = "..")] + pub sugg_span: Span, +} + #[derive(Diagnostic)] #[diag(parser_invalid_block_macro_segment)] pub(crate) struct InvalidBlockMacroSegment { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0eb633f641687..7de025e7860dd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -20,9 +20,9 @@ use crate::errors::{ InvalidNumLiteralSuffix, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm, - MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, NoFieldsForFnCall, - NotAsNegationOperator, NotAsNegationOperatorSub, OctalFloatLiteralNotSupported, - OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, + MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, + NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub, + OctalFloatLiteralNotSupported, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere, StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses, @@ -2897,6 +2897,21 @@ impl<'a> Parser<'a> { } self.recover_struct_comma_after_dotdot(exp_span); break; + } else if self.token == token::DotDotDot { + // suggest `..v` instead of `...v` + let snapshot = self.create_snapshot_for_diagnostic(); + let span = self.token.span; + self.bump(); + match self.parse_expr() { + Ok(_p) => { + self.sess.emit_err(MissingDotDot { token_span: span, sugg_span: span }); + break; + } + Err(inner_err) => { + inner_err.cancel(); + self.restore_snapshot(snapshot); + } + } } let recovery_field = self.find_struct_error_after_field_looking_code(); diff --git a/src/test/ui/parser/issue-102806.rs b/src/test/ui/parser/issue-102806.rs new file mode 100644 index 0000000000000..f5513c87a92e8 --- /dev/null +++ b/src/test/ui/parser/issue-102806.rs @@ -0,0 +1,22 @@ +#![allow(dead_code)] + +struct V3 { + x: f32, + y: f32, + z: f32, +} + +fn pz(v: V3) { + let _ = V3 { z: 0.0, ...v}; + //~^ ERROR expected `..` + //~| ERROR missing fields `x` and `y` in initializer of `V3` + let _ = V3 { z: 0.0, ... }; + //~^ expected identifier + //~| ERROR missing fields `x` and `y` in initializer of `V3` + + let _ = V3 { z: 0.0, ...Default::default() }; + //~^ ERROR expected `..` + //~| ERROR missing fields `x` and `y` in initializer of `V3` +} + +fn main() {} diff --git a/src/test/ui/parser/issue-102806.stderr b/src/test/ui/parser/issue-102806.stderr new file mode 100644 index 0000000000000..53a43b5396141 --- /dev/null +++ b/src/test/ui/parser/issue-102806.stderr @@ -0,0 +1,51 @@ +error: expected `..`, found `...` + --> $DIR/issue-102806.rs:10:26 + | +LL | let _ = V3 { z: 0.0, ...v}; + | ^^^ + | +help: use `..` to fill in the rest of the fields + | +LL | let _ = V3 { z: 0.0, ..v}; + | ~~ + +error: expected identifier, found `...` + --> $DIR/issue-102806.rs:13:26 + | +LL | let _ = V3 { z: 0.0, ... }; + | -- ^^^ expected identifier + | | + | while parsing this struct + +error: expected `..`, found `...` + --> $DIR/issue-102806.rs:17:26 + | +LL | let _ = V3 { z: 0.0, ...Default::default() }; + | ^^^ + | +help: use `..` to fill in the rest of the fields + | +LL | let _ = V3 { z: 0.0, ..Default::default() }; + | ~~ + +error[E0063]: missing fields `x` and `y` in initializer of `V3` + --> $DIR/issue-102806.rs:10:13 + | +LL | let _ = V3 { z: 0.0, ...v}; + | ^^ missing `x` and `y` + +error[E0063]: missing fields `x` and `y` in initializer of `V3` + --> $DIR/issue-102806.rs:13:13 + | +LL | let _ = V3 { z: 0.0, ... }; + | ^^ missing `x` and `y` + +error[E0063]: missing fields `x` and `y` in initializer of `V3` + --> $DIR/issue-102806.rs:17:13 + | +LL | let _ = V3 { z: 0.0, ...Default::default() }; + | ^^ missing `x` and `y` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0063`. From 4b77e730b5c9e5126abf12ccca5e36f2a2c66868 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 14 Oct 2022 06:52:23 +0800 Subject: [PATCH 2/3] fake a base to suppress later extra error message --- compiler/rustc_parse/src/errors.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 29 ++++++++++----------- src/test/ui/parser/issue-102806.rs | 11 +++++--- src/test/ui/parser/issue-102806.stderr | 34 ++++++++++--------------- 4 files changed, 35 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index b02bd66453373..0924c8537159c 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -373,7 +373,7 @@ pub(crate) struct MissingSemicolonBeforeArray { pub(crate) struct MissingDotDot { #[primary_span] pub token_span: Span, - #[suggestion_verbose(applicability = "maybe-incorrect", code = "..")] + #[suggestion(applicability = "maybe-incorrect", code = "..", style = "verbose")] pub sugg_span: Span, } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7de025e7860dd..338e6a8e28955 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2880,7 +2880,7 @@ impl<'a> Parser<'a> { }; while self.token != token::CloseDelim(close_delim) { - if self.eat(&token::DotDot) { + if self.eat(&token::DotDot) || self.recover_struct_fileds_dots(close_delim) { let exp_span = self.prev_token.span; // We permit `.. }` on the left-hand side of a destructuring assignment. if self.check(&token::CloseDelim(close_delim)) { @@ -2897,21 +2897,6 @@ impl<'a> Parser<'a> { } self.recover_struct_comma_after_dotdot(exp_span); break; - } else if self.token == token::DotDotDot { - // suggest `..v` instead of `...v` - let snapshot = self.create_snapshot_for_diagnostic(); - let span = self.token.span; - self.bump(); - match self.parse_expr() { - Ok(_p) => { - self.sess.emit_err(MissingDotDot { token_span: span, sugg_span: span }); - break; - } - Err(inner_err) => { - inner_err.cancel(); - self.restore_snapshot(snapshot); - } - } } let recovery_field = self.find_struct_error_after_field_looking_code(); @@ -3042,6 +3027,18 @@ impl<'a> Parser<'a> { self.recover_stmt(); } + fn recover_struct_fileds_dots(&mut self, close_delim: Delimiter) -> bool { + if !self.look_ahead(1, |t| *t == token::CloseDelim(close_delim)) + && self.eat(&token::DotDotDot) + { + // recover from typo of `...`, suggest `..` + let span = self.prev_token.span; + self.sess.emit_err(MissingDotDot { token_span: span, sugg_span: span }); + return true; + } + false + } + /// Parses `ident (COLON expr)?`. fn parse_expr_field(&mut self) -> PResult<'a, ExprField> { let attrs = self.parse_outer_attributes()?; diff --git a/src/test/ui/parser/issue-102806.rs b/src/test/ui/parser/issue-102806.rs index f5513c87a92e8..ba297bdc9677b 100644 --- a/src/test/ui/parser/issue-102806.rs +++ b/src/test/ui/parser/issue-102806.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] +#[derive(Default)] struct V3 { x: f32, y: f32, @@ -9,14 +10,16 @@ struct V3 { fn pz(v: V3) { let _ = V3 { z: 0.0, ...v}; //~^ ERROR expected `..` - //~| ERROR missing fields `x` and `y` in initializer of `V3` - let _ = V3 { z: 0.0, ... }; - //~^ expected identifier - //~| ERROR missing fields `x` and `y` in initializer of `V3` let _ = V3 { z: 0.0, ...Default::default() }; //~^ ERROR expected `..` + + let _ = V3 { z: 0.0, ... }; + //~^ expected identifier //~| ERROR missing fields `x` and `y` in initializer of `V3` + + let V3 { z: val, ... } = v; + //~^ ERROR expected field pattern } fn main() {} diff --git a/src/test/ui/parser/issue-102806.stderr b/src/test/ui/parser/issue-102806.stderr index 53a43b5396141..6872b8bc0afec 100644 --- a/src/test/ui/parser/issue-102806.stderr +++ b/src/test/ui/parser/issue-102806.stderr @@ -1,5 +1,5 @@ error: expected `..`, found `...` - --> $DIR/issue-102806.rs:10:26 + --> $DIR/issue-102806.rs:11:26 | LL | let _ = V3 { z: 0.0, ...v}; | ^^^ @@ -9,16 +9,8 @@ help: use `..` to fill in the rest of the fields LL | let _ = V3 { z: 0.0, ..v}; | ~~ -error: expected identifier, found `...` - --> $DIR/issue-102806.rs:13:26 - | -LL | let _ = V3 { z: 0.0, ... }; - | -- ^^^ expected identifier - | | - | while parsing this struct - error: expected `..`, found `...` - --> $DIR/issue-102806.rs:17:26 + --> $DIR/issue-102806.rs:14:26 | LL | let _ = V3 { z: 0.0, ...Default::default() }; | ^^^ @@ -28,24 +20,26 @@ help: use `..` to fill in the rest of the fields LL | let _ = V3 { z: 0.0, ..Default::default() }; | ~~ -error[E0063]: missing fields `x` and `y` in initializer of `V3` - --> $DIR/issue-102806.rs:10:13 +error: expected identifier, found `...` + --> $DIR/issue-102806.rs:17:26 | -LL | let _ = V3 { z: 0.0, ...v}; - | ^^ missing `x` and `y` +LL | let _ = V3 { z: 0.0, ... }; + | -- ^^^ expected identifier + | | + | while parsing this struct -error[E0063]: missing fields `x` and `y` in initializer of `V3` - --> $DIR/issue-102806.rs:13:13 +error: expected field pattern, found `...` + --> $DIR/issue-102806.rs:21:22 | -LL | let _ = V3 { z: 0.0, ... }; - | ^^ missing `x` and `y` +LL | let V3 { z: val, ... } = v; + | ^^^ help: to omit remaining fields, use one fewer `.`: `..` error[E0063]: missing fields `x` and `y` in initializer of `V3` --> $DIR/issue-102806.rs:17:13 | -LL | let _ = V3 { z: 0.0, ...Default::default() }; +LL | let _ = V3 { z: 0.0, ... }; | ^^ missing `x` and `y` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0063`. From 28d82ddfc22bcbcef2ade0a3c75e6711475a9098 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 5 Nov 2022 19:33:12 -0700 Subject: [PATCH 3/3] Fix typo --- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 338e6a8e28955..4a1162b959983 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2880,7 +2880,7 @@ impl<'a> Parser<'a> { }; while self.token != token::CloseDelim(close_delim) { - if self.eat(&token::DotDot) || self.recover_struct_fileds_dots(close_delim) { + if self.eat(&token::DotDot) || self.recover_struct_field_dots(close_delim) { let exp_span = self.prev_token.span; // We permit `.. }` on the left-hand side of a destructuring assignment. if self.check(&token::CloseDelim(close_delim)) { @@ -3027,7 +3027,7 @@ impl<'a> Parser<'a> { self.recover_stmt(); } - fn recover_struct_fileds_dots(&mut self, close_delim: Delimiter) -> bool { + fn recover_struct_field_dots(&mut self, close_delim: Delimiter) -> bool { if !self.look_ahead(1, |t| *t == token::CloseDelim(close_delim)) && self.eat(&token::DotDotDot) {