Parser: better error messages for @
in struct patterns
This commit is contained in:
parent
8ed95d1d9e
commit
9cd668beed
@ -26,6 +26,13 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
|
||||
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
|
||||
.suggestion = try switching the order
|
||||
|
||||
parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
|
||||
.suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
|
||||
|
||||
parse_at_in_struct_pattern = Unexpected `@` in struct pattern
|
||||
.note = struct patterns use `field: pattern` syntax to bind to fields
|
||||
.help = consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
|
||||
|
||||
parse_attr_after_generic = trailing attribute after generic parameter
|
||||
.label = attributes must go before parameters
|
||||
|
||||
|
@ -2583,6 +2583,25 @@ pub(crate) struct EnumPatternInsteadOfIdentifier {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_at_dot_dot_in_struct_pattern)]
|
||||
pub(crate) struct AtDotDotInStructPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = "", style = "verbose", applicability = "machine-applicable")]
|
||||
pub remove: Span,
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_at_in_struct_pattern)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub(crate) struct AtInStructPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_dot_dot_dot_for_remaining_fields)]
|
||||
pub(crate) struct DotDotDotForRemainingFields {
|
||||
|
@ -17,15 +17,16 @@
|
||||
|
||||
use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos};
|
||||
use crate::errors::{
|
||||
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
|
||||
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
||||
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
|
||||
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
|
||||
ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
|
||||
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
||||
TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg,
|
||||
UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
|
||||
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
|
||||
self, AmbiguousRangePattern, AtDotDotInStructPattern, AtInStructPattern,
|
||||
DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern,
|
||||
EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField,
|
||||
GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
|
||||
InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt,
|
||||
RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
|
||||
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern,
|
||||
UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
|
||||
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
|
||||
UnexpectedVertVertInPattern, WrapInParens,
|
||||
};
|
||||
use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat};
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
@ -1433,7 +1434,7 @@ fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
|
||||
|
||||
/// Parses the fields of a struct-like pattern.
|
||||
fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)> {
|
||||
let mut fields = ThinVec::new();
|
||||
let mut fields: ThinVec<PatField> = ThinVec::new();
|
||||
let mut etc = PatFieldsRest::None;
|
||||
let mut ate_comma = true;
|
||||
let mut delayed_err: Option<Diag<'a>> = None;
|
||||
@ -1454,12 +1455,22 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
|
||||
|
||||
// check that a comma comes after every field
|
||||
if !ate_comma {
|
||||
let mut err =
|
||||
self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span });
|
||||
let err = if self.token == token::At {
|
||||
let prev_field = fields
|
||||
.last()
|
||||
.expect("Unreachable on first iteration, not empty otherwise")
|
||||
.ident;
|
||||
self.report_misplaced_at_in_struct_pat(prev_field)
|
||||
} else {
|
||||
let mut err = self
|
||||
.dcx()
|
||||
.create_err(ExpectedCommaAfterPatternField { span: self.token.span });
|
||||
self.recover_misplaced_pattern_modifiers(&fields, &mut err);
|
||||
err
|
||||
};
|
||||
if let Some(delayed) = delayed_err {
|
||||
delayed.emit();
|
||||
}
|
||||
self.recover_misplaced_pattern_modifiers(&fields, &mut err);
|
||||
return Err(err);
|
||||
}
|
||||
ate_comma = false;
|
||||
@ -1594,6 +1605,23 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
|
||||
Ok((fields, etc))
|
||||
}
|
||||
|
||||
#[deny(rustc::untranslatable_diagnostic)]
|
||||
fn report_misplaced_at_in_struct_pat(&self, prev_field: Ident) -> Diag<'a> {
|
||||
debug_assert_eq!(self.token, token::At);
|
||||
let span = prev_field.span.to(self.token.span);
|
||||
if let Some(dot_dot_span) =
|
||||
self.look_ahead(1, |t| if t == &token::DotDot { Some(t.span) } else { None })
|
||||
{
|
||||
self.dcx().create_err(AtDotDotInStructPattern {
|
||||
span: span.to(dot_dot_span),
|
||||
remove: span.until(dot_dot_span),
|
||||
ident: prev_field,
|
||||
})
|
||||
} else {
|
||||
self.dcx().create_err(AtInStructPattern { span: span })
|
||||
}
|
||||
}
|
||||
|
||||
/// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest
|
||||
/// the correct code.
|
||||
fn recover_misplaced_pattern_modifiers(&self, fields: &ThinVec<PatField>, err: &mut Diag<'a>) {
|
||||
|
14
tests/ui/pattern/at-in-struct-patterns.rs
Normal file
14
tests/ui/pattern/at-in-struct-patterns.rs
Normal file
@ -0,0 +1,14 @@
|
||||
struct Foo {
|
||||
field1: u8,
|
||||
field2: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Foo { field1: 1, field2: 2 };
|
||||
let Foo { var @ field1, .. } = foo; //~ ERROR Unexpected `@` in struct pattern
|
||||
dbg!(var); //~ ERROR cannot find value `var` in this scope
|
||||
let Foo { field1: _, bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
|
||||
let Foo { bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
|
||||
let Foo { @ } = foo; //~ ERROR expected identifier, found `@`
|
||||
let Foo { @ .. } = foo; //~ ERROR expected identifier, found `@`
|
||||
}
|
69
tests/ui/pattern/at-in-struct-patterns.stderr
Normal file
69
tests/ui/pattern/at-in-struct-patterns.stderr
Normal file
@ -0,0 +1,69 @@
|
||||
error: Unexpected `@` in struct pattern
|
||||
--> $DIR/at-in-struct-patterns.rs:8:15
|
||||
|
|
||||
LL | let Foo { var @ field1, .. } = foo;
|
||||
| --- ^^^^^
|
||||
| |
|
||||
| while parsing the fields for this pattern
|
||||
|
|
||||
= note: struct patterns use `field: pattern` syntax to bind to fields
|
||||
= help: consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
|
||||
|
||||
error: `@ ..` is not supported in struct patterns
|
||||
--> $DIR/at-in-struct-patterns.rs:10:26
|
||||
|
|
||||
LL | let Foo { field1: _, bar @ .. } = foo;
|
||||
| --- ^^^^^^^^
|
||||
| |
|
||||
| while parsing the fields for this pattern
|
||||
|
|
||||
help: bind to each field separately or, if you don't need them, just remove `bar @`
|
||||
|
|
||||
LL - let Foo { field1: _, bar @ .. } = foo;
|
||||
LL + let Foo { field1: _, .. } = foo;
|
||||
|
|
||||
|
||||
error: `@ ..` is not supported in struct patterns
|
||||
--> $DIR/at-in-struct-patterns.rs:11:15
|
||||
|
|
||||
LL | let Foo { bar @ .. } = foo;
|
||||
| --- ^^^^^^^^
|
||||
| |
|
||||
| while parsing the fields for this pattern
|
||||
|
|
||||
help: bind to each field separately or, if you don't need them, just remove `bar @`
|
||||
|
|
||||
LL - let Foo { bar @ .. } = foo;
|
||||
LL + let Foo { .. } = foo;
|
||||
|
|
||||
|
||||
error: expected identifier, found `@`
|
||||
--> $DIR/at-in-struct-patterns.rs:12:15
|
||||
|
|
||||
LL | let Foo { @ } = foo;
|
||||
| --- ^ expected identifier
|
||||
| |
|
||||
| while parsing the fields for this pattern
|
||||
|
||||
error: expected identifier, found `@`
|
||||
--> $DIR/at-in-struct-patterns.rs:13:15
|
||||
|
|
||||
LL | let Foo { @ .. } = foo;
|
||||
| --- ^ expected identifier
|
||||
| |
|
||||
| while parsing the fields for this pattern
|
||||
|
||||
error[E0425]: cannot find value `var` in this scope
|
||||
--> $DIR/at-in-struct-patterns.rs:9:10
|
||||
|
|
||||
LL | dbg!(var);
|
||||
| ^^^ not found in this scope
|
||||
|
|
||||
help: consider importing this function
|
||||
|
|
||||
LL + use std::env::var;
|
||||
|
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
Loading…
Reference in New Issue
Block a user