Skip to content

Commit b7c33e2

Browse files
Rollup merge of rust-lang#130725 - GrigorenkoPV:@-in-struct-patterns, r=Nadrieril
Parser: better error messages for `@` in struct patterns
2 parents 44f6275 + 9cd668b commit b7c33e2

File tree

5 files changed

+150
-13
lines changed

5 files changed

+150
-13
lines changed

compiler/rustc_parse/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20
2626
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
2727
.suggestion = try switching the order
2828
29+
parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns
30+
.suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @`
31+
32+
parse_at_in_struct_pattern = Unexpected `@` in struct pattern
33+
.note = struct patterns use `field: pattern` syntax to bind to fields
34+
.help = consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
35+
2936
parse_attr_after_generic = trailing attribute after generic parameter
3037
.label = attributes must go before parameters
3138

compiler/rustc_parse/src/errors.rs

+19
Original file line numberDiff line numberDiff line change
@@ -2571,6 +2571,25 @@ pub(crate) struct EnumPatternInsteadOfIdentifier {
25712571
pub span: Span,
25722572
}
25732573

2574+
#[derive(Diagnostic)]
2575+
#[diag(parse_at_dot_dot_in_struct_pattern)]
2576+
pub(crate) struct AtDotDotInStructPattern {
2577+
#[primary_span]
2578+
pub span: Span,
2579+
#[suggestion(code = "", style = "verbose", applicability = "machine-applicable")]
2580+
pub remove: Span,
2581+
pub ident: Ident,
2582+
}
2583+
2584+
#[derive(Diagnostic)]
2585+
#[diag(parse_at_in_struct_pattern)]
2586+
#[note]
2587+
#[help]
2588+
pub(crate) struct AtInStructPattern {
2589+
#[primary_span]
2590+
pub span: Span,
2591+
}
2592+
25742593
#[derive(Diagnostic)]
25752594
#[diag(parse_dot_dot_dot_for_remaining_fields)]
25762595
pub(crate) struct DotDotDotForRemainingFields {

compiler/rustc_parse/src/parser/pat.rs

+41-13
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ use thin_vec::{ThinVec, thin_vec};
1717

1818
use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos};
1919
use crate::errors::{
20-
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
21-
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
22-
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
23-
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
24-
ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
25-
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
26-
TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg,
27-
UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
28-
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
20+
self, AmbiguousRangePattern, AtDotDotInStructPattern, AtInStructPattern,
21+
DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern,
22+
EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField,
23+
GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
24+
InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt,
25+
RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
26+
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern,
27+
UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
28+
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
29+
UnexpectedVertVertInPattern, WrapInParens,
2930
};
3031
use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal};
3132
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -1433,7 +1434,7 @@ impl<'a> Parser<'a> {
14331434

14341435
/// Parses the fields of a struct-like pattern.
14351436
fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)> {
1436-
let mut fields = ThinVec::new();
1437+
let mut fields: ThinVec<PatField> = ThinVec::new();
14371438
let mut etc = PatFieldsRest::None;
14381439
let mut ate_comma = true;
14391440
let mut delayed_err: Option<Diag<'a>> = None;
@@ -1454,12 +1455,22 @@ impl<'a> Parser<'a> {
14541455

14551456
// check that a comma comes after every field
14561457
if !ate_comma {
1457-
let mut err =
1458-
self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span });
1458+
let err = if self.token == token::At {
1459+
let prev_field = fields
1460+
.last()
1461+
.expect("Unreachable on first iteration, not empty otherwise")
1462+
.ident;
1463+
self.report_misplaced_at_in_struct_pat(prev_field)
1464+
} else {
1465+
let mut err = self
1466+
.dcx()
1467+
.create_err(ExpectedCommaAfterPatternField { span: self.token.span });
1468+
self.recover_misplaced_pattern_modifiers(&fields, &mut err);
1469+
err
1470+
};
14591471
if let Some(delayed) = delayed_err {
14601472
delayed.emit();
14611473
}
1462-
self.recover_misplaced_pattern_modifiers(&fields, &mut err);
14631474
return Err(err);
14641475
}
14651476
ate_comma = false;
@@ -1594,6 +1605,23 @@ impl<'a> Parser<'a> {
15941605
Ok((fields, etc))
15951606
}
15961607

1608+
#[deny(rustc::untranslatable_diagnostic)]
1609+
fn report_misplaced_at_in_struct_pat(&self, prev_field: Ident) -> Diag<'a> {
1610+
debug_assert_eq!(self.token, token::At);
1611+
let span = prev_field.span.to(self.token.span);
1612+
if let Some(dot_dot_span) =
1613+
self.look_ahead(1, |t| if t == &token::DotDot { Some(t.span) } else { None })
1614+
{
1615+
self.dcx().create_err(AtDotDotInStructPattern {
1616+
span: span.to(dot_dot_span),
1617+
remove: span.until(dot_dot_span),
1618+
ident: prev_field,
1619+
})
1620+
} else {
1621+
self.dcx().create_err(AtInStructPattern { span: span })
1622+
}
1623+
}
1624+
15971625
/// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest
15981626
/// the correct code.
15991627
fn recover_misplaced_pattern_modifiers(&self, fields: &ThinVec<PatField>, err: &mut Diag<'a>) {
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
struct Foo {
2+
field1: u8,
3+
field2: u8,
4+
}
5+
6+
fn main() {
7+
let foo = Foo { field1: 1, field2: 2 };
8+
let Foo { var @ field1, .. } = foo; //~ ERROR Unexpected `@` in struct pattern
9+
dbg!(var); //~ ERROR cannot find value `var` in this scope
10+
let Foo { field1: _, bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
11+
let Foo { bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns
12+
let Foo { @ } = foo; //~ ERROR expected identifier, found `@`
13+
let Foo { @ .. } = foo; //~ ERROR expected identifier, found `@`
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error: Unexpected `@` in struct pattern
2+
--> $DIR/at-in-struct-patterns.rs:8:15
3+
|
4+
LL | let Foo { var @ field1, .. } = foo;
5+
| --- ^^^^^
6+
| |
7+
| while parsing the fields for this pattern
8+
|
9+
= note: struct patterns use `field: pattern` syntax to bind to fields
10+
= help: consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended
11+
12+
error: `@ ..` is not supported in struct patterns
13+
--> $DIR/at-in-struct-patterns.rs:10:26
14+
|
15+
LL | let Foo { field1: _, bar @ .. } = foo;
16+
| --- ^^^^^^^^
17+
| |
18+
| while parsing the fields for this pattern
19+
|
20+
help: bind to each field separately or, if you don't need them, just remove `bar @`
21+
|
22+
LL - let Foo { field1: _, bar @ .. } = foo;
23+
LL + let Foo { field1: _, .. } = foo;
24+
|
25+
26+
error: `@ ..` is not supported in struct patterns
27+
--> $DIR/at-in-struct-patterns.rs:11:15
28+
|
29+
LL | let Foo { bar @ .. } = foo;
30+
| --- ^^^^^^^^
31+
| |
32+
| while parsing the fields for this pattern
33+
|
34+
help: bind to each field separately or, if you don't need them, just remove `bar @`
35+
|
36+
LL - let Foo { bar @ .. } = foo;
37+
LL + let Foo { .. } = foo;
38+
|
39+
40+
error: expected identifier, found `@`
41+
--> $DIR/at-in-struct-patterns.rs:12:15
42+
|
43+
LL | let Foo { @ } = foo;
44+
| --- ^ expected identifier
45+
| |
46+
| while parsing the fields for this pattern
47+
48+
error: expected identifier, found `@`
49+
--> $DIR/at-in-struct-patterns.rs:13:15
50+
|
51+
LL | let Foo { @ .. } = foo;
52+
| --- ^ expected identifier
53+
| |
54+
| while parsing the fields for this pattern
55+
56+
error[E0425]: cannot find value `var` in this scope
57+
--> $DIR/at-in-struct-patterns.rs:9:10
58+
|
59+
LL | dbg!(var);
60+
| ^^^ not found in this scope
61+
|
62+
help: consider importing this function
63+
|
64+
LL + use std::env::var;
65+
|
66+
67+
error: aborting due to 6 previous errors
68+
69+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)