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
|
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
|
||||||
.suggestion = try switching the order
|
.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
|
parse_attr_after_generic = trailing attribute after generic parameter
|
||||||
.label = attributes must go before parameters
|
.label = attributes must go before parameters
|
||||||
|
|
||||||
|
@ -2583,6 +2583,25 @@ pub(crate) struct EnumPatternInsteadOfIdentifier {
|
|||||||
pub span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_dot_dot_dot_for_remaining_fields)]
|
#[diag(parse_dot_dot_dot_for_remaining_fields)]
|
||||||
pub(crate) struct DotDotDotForRemainingFields {
|
pub(crate) struct DotDotDotForRemainingFields {
|
||||||
|
@ -17,15 +17,16 @@
|
|||||||
|
|
||||||
use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos};
|
use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
|
self, AmbiguousRangePattern, AtDotDotInStructPattern, AtInStructPattern,
|
||||||
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern,
|
||||||
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
|
EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField,
|
||||||
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
|
GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
|
||||||
ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
|
InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt,
|
||||||
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
|
||||||
TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg,
|
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern,
|
||||||
UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
|
UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
|
||||||
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
|
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
|
||||||
|
UnexpectedVertVertInPattern, WrapInParens,
|
||||||
};
|
};
|
||||||
use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat};
|
use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat};
|
||||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
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.
|
/// Parses the fields of a struct-like pattern.
|
||||||
fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)> {
|
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 etc = PatFieldsRest::None;
|
||||||
let mut ate_comma = true;
|
let mut ate_comma = true;
|
||||||
let mut delayed_err: Option<Diag<'a>> = None;
|
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
|
// check that a comma comes after every field
|
||||||
if !ate_comma {
|
if !ate_comma {
|
||||||
let mut err =
|
let err = if self.token == token::At {
|
||||||
self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span });
|
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 {
|
if let Some(delayed) = delayed_err {
|
||||||
delayed.emit();
|
delayed.emit();
|
||||||
}
|
}
|
||||||
self.recover_misplaced_pattern_modifiers(&fields, &mut err);
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
ate_comma = false;
|
ate_comma = false;
|
||||||
@ -1594,6 +1605,23 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
|
|||||||
Ok((fields, etc))
|
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
|
/// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest
|
||||||
/// the correct code.
|
/// the correct code.
|
||||||
fn recover_misplaced_pattern_modifiers(&self, fields: &ThinVec<PatField>, err: &mut Diag<'a>) {
|
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