2024-11-28 14:03:16 -08:00
use std ::ops ::Bound ;
2024-09-18 20:38:43 +02:00
use rustc_ast ::mut_visit ::{ self , MutVisitor } ;
2020-02-29 20:37:32 +03:00
use rustc_ast ::ptr ::P ;
Remove `NtPat`.
The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`.
This commit removes the complicated `Interpolated` handling in
`expected_expression_found` that results in a longer error message. But
I think the new, shorter message is actually an improvement.
The original complaint was in #71039, when the error message started
with "error: expected expression, found `1 + 1`". That was confusing
because `1 + 1` is an expression. Other than that, the reporter said
"the whole error message is not too bad if you ignore the first line".
Subsequently, extra complexity and wording was added to the error
message. But I don't think the extra wording actually helps all that
much. In particular, it still says of the `1+1` that "this is expected
to be expression". This repeats the problem from the original complaint!
This commit removes the extra complexity, reverting to a simpler error
message. This is primarily because the traversal is a pain without
`Interpolated` tokens. Nonetheless, I think the error message is
*improved*. It now starts with "expected expression, found `pat`
metavariable", which is much clearer and the real problem. It also
doesn't say anything specific about `1+1`, which is good, because the
`1+1` isn't really relevant to the error -- it's the `$e:pat` that's
important.
2024-04-18 12:44:11 +10:00
use rustc_ast ::token ::NtPatKind ::* ;
2024-12-20 07:28:16 +11:00
use rustc_ast ::token ::{ self , Delimiter , IdentIsRaw , MetaVarKind , Token } ;
2024-11-28 12:47:18 -08:00
use rustc_ast ::util ::parser ::ExprPrecedence ;
2024-09-18 20:38:43 +02:00
use rustc_ast ::visit ::{ self , Visitor } ;
2021-07-15 08:36:19 -07:00
use rustc_ast ::{
2024-11-28 12:47:18 -08:00
self as ast , Arm , AttrVec , BindingMode , ByRef , Expr , ExprKind , LocalKind , MacCall , Mutability ,
Pat , PatField , PatFieldsRest , PatKind , Path , QSelf , RangeEnd , RangeSyntax , Stmt , StmtKind ,
2021-07-15 08:36:19 -07:00
} ;
2020-01-11 17:02:46 +01:00
use rustc_ast_pretty ::pprust ;
2024-09-18 20:38:43 +02:00
use rustc_errors ::{ Applicability , Diag , DiagArgValue , PResult , StashKey } ;
2022-09-30 01:38:15 +00:00
use rustc_session ::errors ::ExprParenthesesNeeded ;
2023-11-02 14:10:12 +11:00
use rustc_span ::source_map ::{ Spanned , respan } ;
2024-12-13 10:29:23 +11:00
use rustc_span ::{ BytePos , ErrorGuaranteed , Ident , Span , kw , sym } ;
2023-01-30 14:58:23 +11:00
use thin_vec ::{ ThinVec , thin_vec } ;
2019-08-11 15:24:37 +02:00
2024-08-06 17:16:40 +10:00
use super ::{ ForceCollect , Parser , PathStyle , Restrictions , Trailing , UsePreAttrPos } ;
2023-01-28 21:16:50 +00:00
use crate ::errors ::{
2024-09-23 02:12:53 +03:00
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 ,
2024-07-29 08:13:50 +10:00
} ;
2024-07-04 14:10:17 +02:00
use crate ::parser ::expr ::{ DestructuredFloat , could_be_unclosed_char_literal } ;
Remove `NtPat`.
The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`.
This commit removes the complicated `Interpolated` handling in
`expected_expression_found` that results in a longer error message. But
I think the new, shorter message is actually an improvement.
The original complaint was in #71039, when the error message started
with "error: expected expression, found `1 + 1`". That was confusing
because `1 + 1` is an expression. Other than that, the reporter said
"the whole error message is not too bad if you ignore the first line".
Subsequently, extra complexity and wording was added to the error
message. But I don't think the extra wording actually helps all that
much. In particular, it still says of the `1+1` that "this is expected
to be expression". This repeats the problem from the original complaint!
This commit removes the extra complexity, reverting to a simpler error
message. This is primarily because the traversal is a pain without
`Interpolated` tokens. Nonetheless, I think the error message is
*improved*. It now starts with "expected expression, found `pat`
metavariable", which is much clearer and the real problem. It also
doesn't say anything specific about `1+1`, which is good, because the
`1+1` isn't really relevant to the error -- it's the `$e:pat` that's
important.
2024-04-18 12:44:11 +10:00
use crate ::{ exp , maybe_recover_from_interpolated_ty_qpath } ;
2024-07-29 08:13:50 +10:00
2022-11-08 22:03:17 +01:00
#[ derive(PartialEq, Copy, Clone) ]
pub enum Expected {
ParameterName ,
ArgumentName ,
Identifier ,
BindingPattern ,
}
2019-08-18 15:31:34 +02:00
2022-11-08 22:03:17 +01:00
impl Expected {
// FIXME(#100717): migrate users of this to proper localization
fn to_string_or_fallback ( expected : Option < Expected > ) -> & 'static str {
match expected {
Some ( Expected ::ParameterName ) = > " parameter name " ,
Some ( Expected ::ArgumentName ) = > " argument name " ,
Some ( Expected ::Identifier ) = > " identifier " ,
Some ( Expected ::BindingPattern ) = > " binding pattern " ,
None = > " pattern " ,
}
}
}
2019-08-25 04:39:28 +02:00
2019-09-29 06:21:20 +02:00
const WHILE_PARSING_OR_MSG : & str = " while parsing this or-pattern starting here " ;
2019-08-25 06:15:11 +02:00
/// Whether or not to recover a `,` when parsing or-patterns.
2019-08-24 22:12:19 +02:00
#[ derive(PartialEq, Copy, Clone) ]
2021-02-07 20:40:33 -06:00
pub enum RecoverComma {
2019-08-25 06:15:11 +02:00
Yes ,
No ,
}
2019-08-24 22:12:19 +02:00
2021-07-13 13:18:03 +02:00
/// Whether or not to recover a `:` when parsing patterns that were meant to be paths.
#[ derive(PartialEq, Copy, Clone) ]
pub enum RecoverColon {
Yes ,
No ,
}
2022-01-12 20:43:24 +00:00
/// Whether or not to recover a `a, b` when parsing patterns as `(a, b)` or that *and* `a | b`.
#[ derive(PartialEq, Copy, Clone) ]
pub enum CommaRecoveryMode {
LikelyTuple ,
EitherTupleOrPipe ,
}
2021-02-12 18:04:37 -06:00
/// The result of `eat_or_separator`. We want to distinguish which case we are in to avoid
/// emitting duplicate diagnostics.
#[ derive(Debug, Clone, Copy) ]
enum EatOrResult {
/// We recovered from a trailing vert.
TrailingVert ,
/// We ate an `|` (or `||` and recovered).
AteOr ,
/// We did not eat anything (i.e. the current token is not `|` or `||`).
None ,
}
2022-10-14 23:16:25 +02:00
/// The syntax location of a given pattern. Used for diagnostics.
2023-08-03 00:00:56 +08:00
#[ derive(Clone, Copy) ]
pub enum PatternLocation {
2022-10-14 23:16:25 +02:00
LetBinding ,
FunctionParameter ,
}
2019-08-11 15:24:37 +02:00
impl < ' a > Parser < ' a > {
/// Parses a pattern.
2019-08-18 22:35:53 +02:00
///
2024-11-24 17:36:52 +01:00
/// Corresponds to `Pattern` in RFC 3637 and admits guard patterns at the top level.
/// Used when parsing patterns in all cases where neither `PatternNoTopGuard` nor
/// `PatternNoTopAlt` (see below) are used.
pub fn parse_pat_allow_top_guard (
& mut self ,
expected : Option < Expected > ,
rc : RecoverComma ,
ra : RecoverColon ,
rt : CommaRecoveryMode ,
) -> PResult < ' a , P < Pat > > {
let pat = self . parse_pat_no_top_guard ( expected , rc , ra , rt ) ? ;
2024-12-04 15:55:06 +11:00
if self . eat_keyword ( exp! ( If ) ) {
2024-11-24 17:36:52 +01:00
let cond = self . parse_expr ( ) ? ;
// Feature-gate guard patterns
self . psess . gated_spans . gate ( sym ::guard_patterns , cond . span ) ;
let span = pat . span . to ( cond . span ) ;
Ok ( self . mk_pat ( span , PatKind ::Guard ( pat , cond ) ) )
} else {
Ok ( pat )
}
}
2019-08-11 15:24:37 +02:00
/// Parses a pattern.
2019-08-18 22:35:53 +02:00
///
2024-08-22 22:05:48 -07:00
/// Corresponds to `PatternNoTopAlt` in RFC 3637 and does not admit or-patterns
/// or guard patterns at the top level. Used when parsing the parameters of lambda
/// expressions, functions, function pointers, and `pat_param` macro fragments.
2023-08-03 00:00:56 +08:00
pub fn parse_pat_no_top_alt (
& mut self ,
expected : Option < Expected > ,
syntax_loc : Option < PatternLocation > ,
) -> PResult < ' a , P < Pat > > {
self . parse_pat_with_range_pat ( true , expected , syntax_loc )
2019-08-11 15:24:37 +02:00
}
2021-02-07 20:40:33 -06:00
/// Parses a pattern.
///
2024-08-22 22:05:48 -07:00
/// Corresponds to `PatternNoTopGuard` in RFC 3637 and allows or-patterns, but not
2024-11-24 17:36:52 +01:00
/// guard patterns, at the top level. Used for parsing patterns in `pat` fragments (until
/// the next edition) and `let`, `if let`, and `while let` expressions.
2021-02-07 20:40:33 -06:00
///
/// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
/// a leading vert is allowed in nested or-patterns, too. This allows us to
/// simplify the grammar somewhat.
2024-08-22 22:05:48 -07:00
pub fn parse_pat_no_top_guard (
2020-11-10 18:00:53 -06:00
& mut self ,
2022-11-08 22:03:17 +01:00
expected : Option < Expected > ,
2020-11-10 18:00:53 -06:00
rc : RecoverComma ,
2021-07-13 13:18:03 +02:00
ra : RecoverColon ,
2022-01-12 20:43:24 +00:00
rt : CommaRecoveryMode ,
2020-11-10 18:00:53 -06:00
) -> PResult < ' a , P < Pat > > {
2024-08-22 22:05:48 -07:00
self . parse_pat_no_top_guard_inner ( expected , rc , ra , rt , None ) . map ( | ( pat , _ ) | pat )
2021-02-12 18:04:37 -06:00
}
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
/// recovered).
2024-08-22 22:05:48 -07:00
fn parse_pat_no_top_guard_inner (
2021-02-12 18:04:37 -06:00
& mut self ,
2022-11-08 22:03:17 +01:00
expected : Option < Expected > ,
2021-02-12 18:04:37 -06:00
rc : RecoverComma ,
2021-07-13 13:18:03 +02:00
ra : RecoverColon ,
2022-01-12 20:43:24 +00:00
rt : CommaRecoveryMode ,
2023-08-03 00:00:56 +08:00
syntax_loc : Option < PatternLocation > ,
2021-02-12 18:04:37 -06:00
) -> PResult < ' a , ( P < Pat > , bool ) > {
// Keep track of whether we recovered from a trailing vert so that we can avoid duplicated
// suggestions (which bothers rustfix).
//
2019-08-18 22:04:28 +02:00
// Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
2021-02-12 18:04:37 -06:00
let ( leading_vert_span , mut trailing_vert ) = match self . eat_or_separator ( None ) {
EatOrResult ::AteOr = > ( Some ( self . prev_token . span ) , false ) ,
EatOrResult ::TrailingVert = > ( None , true ) ,
EatOrResult ::None = > ( None , false ) ,
} ;
2019-08-18 15:28:14 +02:00
2019-09-29 06:21:20 +02:00
// Parse the first pattern (`p_0`).
2023-11-06 21:06:20 +00:00
let mut first_pat = match self . parse_pat_no_top_alt ( expected , syntax_loc ) {
Ok ( pat ) = > pat ,
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
Err ( err )
2023-11-06 21:06:20 +00:00
if self . token . is_reserved_ident ( )
& & ! self . token . is_keyword ( kw ::In )
& & ! self . token . is_keyword ( kw ::If ) = >
{
err . emit ( ) ;
self . bump ( ) ;
self . mk_pat ( self . token . span , PatKind ::Wild )
}
Err ( err ) = > return Err ( err ) ,
} ;
2023-11-27 03:15:56 +01:00
if rc = = RecoverComma ::Yes & & ! first_pat . could_be_never_pattern ( ) {
2023-11-27 00:50:51 +01:00
self . maybe_recover_unexpected_comma ( first_pat . span , rt ) ? ;
2022-05-19 16:07:55 +10:00
}
2019-07-14 01:05:52 +00:00
2019-08-18 15:45:44 +02:00
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
2024-12-04 15:55:06 +11:00
if ! self . check ( exp! ( Or ) ) & & self . token ! = token ::OrOr {
2021-02-07 20:40:33 -06:00
// If we parsed a leading `|` which should be gated,
// then we should really gate the leading `|`.
// This complicated procedure is done purely for diagnostics UX.
2021-07-13 13:18:03 +02:00
2021-11-21 04:56:32 +00:00
// Check if the user wrote `foo:bar` instead of `foo::bar`.
2022-05-19 16:04:35 +10:00
if ra = = RecoverColon ::Yes {
2023-01-30 18:08:50 +00:00
first_pat = self . maybe_recover_colon_colon_in_pat_typo ( first_pat , expected ) ;
2022-05-19 16:04:35 +10:00
}
2021-07-13 13:18:03 +02:00
2021-02-07 20:40:33 -06:00
if let Some ( leading_vert_span ) = leading_vert_span {
// If there was a leading vert, treat this as an or-pattern. This improves
// diagnostics.
let span = leading_vert_span . to ( self . prev_token . span ) ;
2022-11-23 11:55:16 +11:00
return Ok ( ( self . mk_pat ( span , PatKind ::Or ( thin_vec! [ first_pat ] ) ) , trailing_vert ) ) ;
2021-02-07 20:40:33 -06:00
}
2021-02-12 18:04:37 -06:00
return Ok ( ( first_pat , trailing_vert ) ) ;
2019-07-14 01:05:52 +00:00
}
2019-09-29 06:21:20 +02:00
// Parse the patterns `p_1 | ... | p_n` where `n > 0`.
2021-02-07 20:40:33 -06:00
let lo = leading_vert_span . unwrap_or ( first_pat . span ) ;
2022-11-23 11:55:16 +11:00
let mut pats = thin_vec! [ first_pat ] ;
2021-02-12 18:04:37 -06:00
loop {
match self . eat_or_separator ( Some ( lo ) ) {
EatOrResult ::AteOr = > { }
EatOrResult ::None = > break ,
EatOrResult ::TrailingVert = > {
trailing_vert = true ;
break ;
}
}
2023-08-03 00:00:56 +08:00
let pat = self . parse_pat_no_top_alt ( expected , syntax_loc ) . map_err ( | mut err | {
2019-09-29 06:21:20 +02:00
err . span_label ( lo , WHILE_PARSING_OR_MSG ) ;
2019-08-25 01:50:21 +02:00
err
} ) ? ;
2023-11-27 03:15:56 +01:00
if rc = = RecoverComma ::Yes & & ! pat . could_be_never_pattern ( ) {
2023-11-27 00:50:51 +01:00
self . maybe_recover_unexpected_comma ( pat . span , rt ) ? ;
2022-05-19 16:07:55 +10:00
}
2019-08-18 17:44:27 +02:00
pats . push ( pat ) ;
2019-07-14 01:05:52 +00:00
}
2020-02-29 14:56:15 +03:00
let or_pattern_span = lo . to ( self . prev_token . span ) ;
2019-07-14 01:05:52 +00:00
2021-02-12 18:04:37 -06:00
Ok ( ( self . mk_pat ( or_pattern_span , PatKind ::Or ( pats ) ) , trailing_vert ) )
2019-07-14 01:05:52 +00:00
}
2021-02-12 18:04:37 -06:00
/// Parse a pattern and (maybe) a `Colon` in positions where a pattern may be followed by a
/// type annotation (e.g. for `let` bindings or `fn` params).
///
/// Generally, this corresponds to `pat_no_top_alt` followed by an optional `Colon`. It will
/// eat the `Colon` token if one is present.
///
/// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false`
/// otherwise).
pub ( super ) fn parse_pat_before_ty (
& mut self ,
2022-11-08 22:03:17 +01:00
expected : Option < Expected > ,
2021-02-12 18:04:37 -06:00
rc : RecoverComma ,
2022-10-14 23:16:25 +02:00
syntax_loc : PatternLocation ,
2021-02-12 18:04:37 -06:00
) -> PResult < ' a , ( P < Pat > , bool ) > {
// We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level
// or-patterns so that we can detect when a user tries to use it. This allows us to print a
// better error message.
2024-08-22 22:05:48 -07:00
let ( pat , trailing_vert ) = self . parse_pat_no_top_guard_inner (
2022-01-12 20:43:24 +00:00
expected ,
rc ,
RecoverColon ::No ,
CommaRecoveryMode ::LikelyTuple ,
2023-08-03 00:00:56 +08:00
Some ( syntax_loc ) ,
2022-01-12 20:43:24 +00:00
) ? ;
2024-12-04 15:55:06 +11:00
let colon = self . eat ( exp! ( Colon ) ) ;
2021-02-12 18:04:37 -06:00
if let PatKind ::Or ( pats ) = & pat . kind {
2022-10-14 23:16:25 +02:00
let span = pat . span ;
2023-07-20 09:51:47 +00:00
let sub = if pats . len ( ) = = 1 {
2024-07-06 03:07:46 +00:00
Some ( TopLevelOrPatternNotAllowedSugg ::RemoveLeadingVert {
span : span . with_hi ( span . lo ( ) + BytePos ( 1 ) ) ,
} )
2021-02-12 18:04:37 -06:00
} else {
2024-07-06 03:07:46 +00:00
Some ( TopLevelOrPatternNotAllowedSugg ::WrapInParens {
span ,
suggestion : WrapInParens { lo : span . shrink_to_lo ( ) , hi : span . shrink_to_hi ( ) } ,
} )
2023-07-20 09:51:47 +00:00
} ;
2022-10-14 23:16:25 +02:00
2024-01-05 16:38:04 +11:00
let err = self . dcx ( ) . create_err ( match syntax_loc {
2023-07-20 09:51:47 +00:00
PatternLocation ::LetBinding = > {
TopLevelOrPatternNotAllowed ::LetBinding { span , sub }
}
PatternLocation ::FunctionParameter = > {
TopLevelOrPatternNotAllowed ::FunctionParameter { span , sub }
}
} ) ;
if trailing_vert {
2024-01-05 16:38:04 +11:00
err . delay_as_bug ( ) ;
} else {
err . emit ( ) ;
2021-02-12 18:04:37 -06:00
}
}
Ok ( ( pat , colon ) )
}
/// Parse the pattern for a function or function pointer parameter, followed by a colon.
///
/// The return value represents the parsed pattern and `true` if a `Colon` was parsed (`false`
/// otherwise).
pub ( super ) fn parse_fn_param_pat_colon ( & mut self ) -> PResult < ' a , ( P < Pat > , bool ) > {
2021-02-07 20:40:33 -06:00
// In order to get good UX, we first recover in the case of a leading vert for an illegal
// top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case,
// a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
// separately.
if let token ::OrOr = self . token . kind {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( UnexpectedVertVertBeforeFunctionParam { span : self . token . span } ) ;
2021-02-07 20:40:33 -06:00
self . bump ( ) ;
}
2022-10-14 23:16:25 +02:00
self . parse_pat_before_ty (
2022-11-08 22:03:17 +01:00
Some ( Expected ::ParameterName ) ,
2022-10-14 23:16:25 +02:00
RecoverComma ::No ,
PatternLocation ::FunctionParameter ,
)
2021-02-07 20:40:33 -06:00
}
2019-08-18 18:13:19 +02:00
/// Eat the or-pattern `|` separator.
/// If instead a `||` token is encountered, recover and pretend we parsed `|`.
2021-02-12 18:04:37 -06:00
fn eat_or_separator ( & mut self , lo : Option < Span > ) -> EatOrResult {
2019-09-29 06:21:20 +02:00
if self . recover_trailing_vert ( lo ) {
2021-02-12 18:04:37 -06:00
EatOrResult ::TrailingVert
} else if matches! ( self . token . kind , token ::OrOr ) {
// Found `||`; Recover and pretend we parsed `|`.
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( UnexpectedVertVertInPattern { span : self . token . span , start : lo } ) ;
2021-02-12 18:04:37 -06:00
self . bump ( ) ;
EatOrResult ::AteOr
2024-12-04 15:55:06 +11:00
} else if self . eat ( exp! ( Or ) ) {
2021-02-12 18:04:37 -06:00
EatOrResult ::AteOr
} else {
EatOrResult ::None
2019-08-18 18:13:19 +02:00
}
}
2019-09-29 06:21:20 +02:00
/// Recover if `|` or `||` is the current token and we have one of the
/// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us.
///
/// These tokens all indicate that we reached the end of the or-pattern
/// list and can now reliably say that the `|` was an illegal trailing vert.
/// Note that there are more tokens such as `@` for which we know that the `|`
/// is an illegal parse. However, the user's intent is less clear in that case.
fn recover_trailing_vert ( & mut self , lo : Option < Span > ) -> bool {
2020-10-26 21:02:48 -04:00
let is_end_ahead = self . look_ahead ( 1 , | token | {
matches! (
& token . uninterpolate ( ) . kind ,
token ::FatArrow // e.g. `a | => 0,`.
2024-02-13 23:28:27 +00:00
| token ::Ident ( kw ::If , token ::IdentIsRaw ::No ) // e.g. `a | if expr`.
2021-02-12 18:04:37 -06:00
| token ::Eq // e.g. `let a | = 0`.
| token ::Semi // e.g. `let a |;`.
| token ::Colon // e.g. `let a | :`.
| token ::Comma // e.g. `let (a |,)`.
2022-04-26 15:40:14 +03:00
| token ::CloseDelim ( Delimiter ::Bracket ) // e.g. `let [a | ]`.
| token ::CloseDelim ( Delimiter ::Parenthesis ) // e.g. `let (a | )`.
| token ::CloseDelim ( Delimiter ::Brace ) // e.g. `let A { f: a | }`.
2020-10-26 21:02:48 -04:00
)
2019-09-29 06:21:20 +02:00
} ) ;
match ( is_end_ahead , & self . token . kind ) {
2024-12-20 07:28:16 +11:00
( true , token ::Or | token ::OrOr ) = > {
2022-10-14 23:16:25 +02:00
// A `|` or possibly `||` token shouldn't be here. Ban it.
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( TrailingVertNotAllowed {
2022-10-14 23:16:25 +02:00
span : self . token . span ,
start : lo ,
token : self . token . clone ( ) ,
2024-08-21 00:57:58 -04:00
note_double_vert : matches ! ( self . token . kind , token ::OrOr ) ,
2022-10-14 23:16:25 +02:00
} ) ;
2019-09-29 06:21:20 +02:00
self . bump ( ) ;
true
}
_ = > false ,
}
}
2024-07-04 14:10:17 +02:00
/// Ensures that the last parsed pattern (or pattern range bound) is not followed by an expression.
2024-01-28 16:12:21 +01:00
///
/// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end))
/// in order to say "expected a pattern range bound" instead of "expected a pattern";
/// ```text
/// 0..=1 + 2
/// ^^^^^
/// ```
2024-07-04 14:10:17 +02:00
/// Only the end bound is spanned in this case, and this function has no idea if there was a `..=` before `pat_span`, hence the parameter.
///
/// This function returns `Some` if a trailing expression was recovered, and said expression's span.
2024-01-28 16:12:21 +01:00
#[ must_use = " the pattern must be discarded as `PatKind::Err` if this function returns Some " ]
fn maybe_recover_trailing_expr (
& mut self ,
pat_span : Span ,
is_end_bound : bool ,
2024-07-04 14:10:17 +02:00
) -> Option < ( ErrorGuaranteed , Span ) > {
2024-01-28 16:12:21 +01:00
if self . prev_token . is_keyword ( kw ::Underscore ) | | ! self . may_recover ( ) {
// Don't recover anything after an `_` or if recovery is disabled.
return None ;
}
2024-07-04 14:10:17 +02:00
// Returns `true` iff `token` is an unsuffixed integer.
let is_one_tuple_index = | _ : & Self , token : & Token | -> bool {
use token ::{ Lit , LitKind } ;
matches! (
token . kind ,
token ::Literal ( Lit { kind : LitKind ::Integer , symbol : _ , suffix : None } )
)
} ;
// Returns `true` iff `token` is an unsuffixed `x.y` float.
let is_two_tuple_indexes = | this : & Self , token : & Token | -> bool {
use token ::{ Lit , LitKind } ;
if let token ::Literal ( Lit { kind : LitKind ::Float , symbol , suffix : None } ) = token . kind
& & let DestructuredFloat ::MiddleDot ( .. ) = this . break_up_float ( symbol , token . span )
{
true
} else {
false
}
} ;
// Check for `.hello` or `.0`.
let has_dot_expr = self . check_noexpect ( & token ::Dot ) // `.`
2024-01-28 16:12:21 +01:00
& & self . look_ahead ( 1 , | tok | {
2024-07-04 14:10:17 +02:00
tok . is_ident ( ) // `hello`
| | is_one_tuple_index ( & self , & tok ) // `0`
| | is_two_tuple_indexes ( & self , & tok ) // `0.0`
} ) ;
2024-01-28 16:12:21 +01:00
// Check for operators.
// `|` is excluded as it is used in pattern alternatives and lambdas,
// `?` is included for error propagation,
// `[` is included for indexing operations,
2024-07-04 14:10:17 +02:00
// `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`),
// `as` is included for type casts
2024-12-20 07:28:16 +11:00
let has_trailing_operator = matches! (
self . token . kind ,
token ::Plus | token ::Minus | token ::Star | token ::Slash | token ::Percent
| token ::Caret | token ::And | token ::Shl | token ::Shr // excludes `Or`
)
2024-08-09 17:44:47 +10:00
| | self . token = = token ::Question
| | ( self . token = = token ::OpenDelim ( Delimiter ::Bracket )
2024-07-04 14:10:17 +02:00
& & self . look_ahead ( 1 , | t | * t ! = token ::CloseDelim ( Delimiter ::Bracket ) ) ) // excludes `[]`
| | self . token . is_keyword ( kw ::As ) ;
2024-01-28 16:12:21 +01:00
2024-07-04 14:10:17 +02:00
if ! has_dot_expr & & ! has_trailing_operator {
2024-01-28 16:12:21 +01:00
// Nothing to recover here.
return None ;
}
// Let's try to parse an expression to emit a better diagnostic.
let mut snapshot = self . create_snapshot_for_diagnostic ( ) ;
snapshot . restrictions . insert ( Restrictions ::IS_PAT ) ;
// Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten.
2024-07-04 14:10:17 +02:00
let Ok ( expr ) = snapshot
2024-01-28 16:12:21 +01:00
. parse_expr_dot_or_call_with (
2024-07-16 15:54:34 +10:00
AttrVec ::new ( ) ,
2024-02-25 22:22:09 +01:00
self . mk_expr ( pat_span , ExprKind ::Dummy ) , // equivalent to transforming the parsed pattern into an `Expr`
2024-01-28 16:12:21 +01:00
pat_span ,
)
. map_err ( | err | err . cancel ( ) )
2024-07-04 14:10:17 +02:00
else {
// We got a trailing method/operator, but that wasn't an expression.
return None ;
} ;
2024-01-28 16:12:21 +01:00
2024-07-04 14:10:17 +02:00
// Parse an associative expression such as `+ expr`, `% expr`, ...
// Assignments, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
2024-11-28 14:03:16 -08:00
let Ok ( ( expr , _ ) ) = snapshot
. parse_expr_assoc_rest_with ( Bound ::Unbounded , false , expr )
. map_err ( | err | err . cancel ( ) )
2024-07-04 14:10:17 +02:00
else {
// We got a trailing method/operator, but that wasn't an expression.
return None ;
} ;
2024-01-28 16:12:21 +01:00
2024-07-04 14:10:17 +02:00
// We got a valid expression.
self . restore_snapshot ( snapshot ) ;
self . restrictions . remove ( Restrictions ::IS_PAT ) ;
let is_bound = is_end_bound
// is_start_bound: either `..` or `)..`
| | self . token . is_range_separator ( )
| | self . token = = token ::CloseDelim ( Delimiter ::Parenthesis )
& & self . look_ahead ( 1 , Token ::is_range_separator ) ;
2024-09-18 20:38:43 +02:00
let span = expr . span ;
2024-07-04 14:10:17 +02:00
Some ( (
2024-09-18 20:38:43 +02:00
self . dcx ( )
. create_err ( UnexpectedExpressionInPattern {
span ,
is_bound ,
2024-11-17 12:25:19 -08:00
expr_precedence : expr . precedence ( ) ,
2024-09-18 20:38:43 +02:00
} )
. stash ( span , StashKey ::ExprInPat )
. unwrap ( ) ,
span ,
2024-07-04 14:10:17 +02:00
) )
2024-01-28 16:12:21 +01:00
}
2024-09-18 20:38:43 +02:00
/// Called by [`Parser::parse_stmt_without_recovery`], used to add statement-aware subdiagnostics to the errors stashed
/// by [`Parser::maybe_recover_trailing_expr`].
pub ( super ) fn maybe_augment_stashed_expr_in_pats_with_suggestions ( & mut self , stmt : & Stmt ) {
if self . dcx ( ) . has_errors ( ) . is_none ( ) {
// No need to walk the statement if there's no stashed errors.
return ;
}
struct PatVisitor < ' a > {
/// `self`
parser : & ' a Parser < ' a > ,
/// The freshly-parsed statement.
stmt : & ' a Stmt ,
/// The current match arm (for arm guard suggestions).
arm : Option < & ' a Arm > ,
/// The current struct field (for variable name suggestions).
field : Option < & ' a PatField > ,
}
impl < ' a > PatVisitor < ' a > {
/// Looks for stashed [`StashKey::ExprInPat`] errors in `stash_span`, and emit them with suggestions.
/// `stash_span` is contained in `expr_span`, the latter being larger in borrow patterns;
/// ```txt
/// &mut x.y
/// -----^^^ `stash_span`
/// |
/// `expr_span`
/// ```
/// `is_range_bound` is used to exclude arm guard suggestions in range pattern bounds.
fn maybe_add_suggestions_then_emit (
& self ,
stash_span : Span ,
expr_span : Span ,
is_range_bound : bool ,
) {
self . parser . dcx ( ) . try_steal_modify_and_emit_err (
stash_span ,
StashKey ::ExprInPat ,
| err | {
// Includes pre-pats (e.g. `&mut <err>`) in the diagnostic.
err . span . replace ( stash_span , expr_span ) ;
let sm = self . parser . psess . source_map ( ) ;
let stmt = self . stmt ;
let line_lo = sm . span_extend_to_line ( stmt . span ) . shrink_to_lo ( ) ;
let indentation = sm . indentation_before ( stmt . span ) . unwrap_or_default ( ) ;
let Ok ( expr ) = self . parser . span_to_snippet ( expr_span ) else {
// FIXME: some suggestions don't actually need the snippet; see PR #123877's unresolved conversations.
return ;
} ;
if let StmtKind ::Let ( local ) = & stmt . kind {
match & local . kind {
LocalKind ::Decl | LocalKind ::Init ( _ ) = > {
// It's kinda hard to guess what the user intended, so don't make suggestions.
return ;
}
LocalKind ::InitElse ( _ , _ ) = > { }
}
}
// help: use an arm guard `if val == expr`
// FIXME(guard_patterns): suggest this regardless of a match arm.
if let Some ( arm ) = & self . arm
& & ! is_range_bound
{
let ( ident , ident_span ) = match self . field {
Some ( field ) = > {
( field . ident . to_string ( ) , field . ident . span . to ( expr_span ) )
}
None = > ( " val " . to_owned ( ) , expr_span ) ,
} ;
// Are parentheses required around `expr`?
// HACK: a neater way would be preferable.
let expr = match & err . args [ " expr_precedence " ] {
DiagArgValue ::Number ( expr_precedence ) = > {
2024-11-28 12:47:18 -08:00
if * expr_precedence < = ExprPrecedence ::Compare as i32 {
2024-09-18 20:38:43 +02:00
format! ( " ( {expr} ) " )
} else {
format! ( " {expr} " )
}
}
_ = > unreachable! ( ) ,
} ;
match & arm . guard {
None = > {
err . subdiagnostic (
UnexpectedExpressionInPatternSugg ::CreateGuard {
ident_span ,
pat_hi : arm . pat . span . shrink_to_hi ( ) ,
ident ,
expr ,
} ,
) ;
}
Some ( guard ) = > {
// Are parentheses required around the old guard?
2024-11-28 12:47:18 -08:00
let wrap_guard = guard . precedence ( ) < = ExprPrecedence ::LAnd ;
2024-09-18 20:38:43 +02:00
err . subdiagnostic (
UnexpectedExpressionInPatternSugg ::UpdateGuard {
ident_span ,
guard_lo : if wrap_guard {
Some ( guard . span . shrink_to_lo ( ) )
} else {
None
} ,
guard_hi : guard . span . shrink_to_hi ( ) ,
guard_hi_paren : if wrap_guard { " ) " } else { " " } ,
ident ,
expr ,
} ,
) ;
}
}
}
// help: extract the expr into a `const VAL: _ = expr`
let ident = match self . field {
Some ( field ) = > field . ident . as_str ( ) . to_uppercase ( ) ,
None = > " VAL " . to_owned ( ) ,
} ;
err . subdiagnostic ( UnexpectedExpressionInPatternSugg ::Const {
stmt_lo : line_lo ,
ident_span : expr_span ,
expr ,
ident ,
indentation ,
} ) ;
// help: wrap the expr in a `const { expr }`
// FIXME(inline_const_pat): once stabilized, remove this check and remove the `(requires #[feature(inline_const_pat)])` note from the message
if self . parser . psess . unstable_features . is_nightly_build ( ) {
err . subdiagnostic ( UnexpectedExpressionInPatternSugg ::InlineConst {
start_span : expr_span . shrink_to_lo ( ) ,
end_span : expr_span . shrink_to_hi ( ) ,
} ) ;
}
} ,
) ;
}
}
impl < ' a > Visitor < ' a > for PatVisitor < ' a > {
fn visit_arm ( & mut self , a : & ' a Arm ) -> Self ::Result {
self . arm = Some ( a ) ;
visit ::walk_arm ( self , a ) ;
self . arm = None ;
}
fn visit_pat_field ( & mut self , fp : & ' a PatField ) -> Self ::Result {
self . field = Some ( fp ) ;
visit ::walk_pat_field ( self , fp ) ;
self . field = None ;
}
fn visit_pat ( & mut self , p : & ' a Pat ) -> Self ::Result {
match & p . kind {
// Base expression
2025-01-07 08:56:23 +00:00
PatKind ::Err ( _ ) | PatKind ::Expr ( _ ) = > {
2024-09-18 20:38:43 +02:00
self . maybe_add_suggestions_then_emit ( p . span , p . span , false )
}
// Sub-patterns
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
PatKind ::Box ( subpat ) | PatKind ::Ref ( subpat , _ )
2025-01-07 08:56:23 +00:00
if matches! ( subpat . kind , PatKind ::Err ( _ ) | PatKind ::Expr ( _ ) ) = >
2024-09-18 20:38:43 +02:00
{
self . maybe_add_suggestions_then_emit ( subpat . span , p . span , false )
}
// Sub-expressions
PatKind ::Range ( start , end , _ ) = > {
if let Some ( start ) = start {
self . maybe_add_suggestions_then_emit ( start . span , start . span , true ) ;
}
if let Some ( end ) = end {
self . maybe_add_suggestions_then_emit ( end . span , end . span , true ) ;
}
}
// Walk continuation
_ = > visit ::walk_pat ( self , p ) ,
}
}
}
// Starts the visit.
PatVisitor { parser : self , stmt , arm : None , field : None } . visit_stmt ( stmt ) ;
}
Remove `NtPat`.
The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`.
This commit removes the complicated `Interpolated` handling in
`expected_expression_found` that results in a longer error message. But
I think the new, shorter message is actually an improvement.
The original complaint was in #71039, when the error message started
with "error: expected expression, found `1 + 1`". That was confusing
because `1 + 1` is an expression. Other than that, the reporter said
"the whole error message is not too bad if you ignore the first line".
Subsequently, extra complexity and wording was added to the error
message. But I don't think the extra wording actually helps all that
much. In particular, it still says of the `1+1` that "this is expected
to be expression". This repeats the problem from the original complaint!
This commit removes the extra complexity, reverting to a simpler error
message. This is primarily because the traversal is a pain without
`Interpolated` tokens. Nonetheless, I think the error message is
*improved*. It now starts with "expected expression, found `pat`
metavariable", which is much clearer and the real problem. It also
doesn't say anything specific about `1+1`, which is good, because the
`1+1` isn't really relevant to the error -- it's the `$e:pat` that's
important.
2024-04-18 12:44:11 +10:00
fn eat_metavar_pat ( & mut self ) -> Option < P < Pat > > {
// Must try both kinds of pattern nonterminals.
if let Some ( pat ) = self . eat_metavar_seq_with_matcher (
| mv_kind | matches! ( mv_kind , MetaVarKind ::Pat ( PatParam { .. } ) ) ,
| this | this . parse_pat_no_top_alt ( None , None ) ,
) {
Some ( pat )
} else if let Some ( pat ) = self . eat_metavar_seq ( MetaVarKind ::Pat ( PatWithOr ) , | this | {
this . parse_pat_no_top_guard (
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
)
} ) {
Some ( pat )
} else {
None
}
}
2019-08-11 15:24:37 +02:00
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
/// allowed).
fn parse_pat_with_range_pat (
& mut self ,
allow_range_pat : bool ,
2022-11-08 22:03:17 +01:00
expected : Option < Expected > ,
2023-08-03 00:00:56 +08:00
syntax_loc : Option < PatternLocation > ,
2019-08-11 15:24:37 +02:00
) -> PResult < ' a , P < Pat > > {
maybe_recover_from_interpolated_ty_qpath! ( self , true ) ;
Remove `NtPat`.
The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`.
This commit removes the complicated `Interpolated` handling in
`expected_expression_found` that results in a longer error message. But
I think the new, shorter message is actually an improvement.
The original complaint was in #71039, when the error message started
with "error: expected expression, found `1 + 1`". That was confusing
because `1 + 1` is an expression. Other than that, the reporter said
"the whole error message is not too bad if you ignore the first line".
Subsequently, extra complexity and wording was added to the error
message. But I don't think the extra wording actually helps all that
much. In particular, it still says of the `1+1` that "this is expected
to be expression". This repeats the problem from the original complaint!
This commit removes the extra complexity, reverting to a simpler error
message. This is primarily because the traversal is a pain without
`Interpolated` tokens. Nonetheless, I think the error message is
*improved*. It now starts with "expected expression, found `pat`
metavariable", which is much clearer and the real problem. It also
doesn't say anything specific about `1+1`, which is good, because the
`1+1` isn't really relevant to the error -- it's the `$e:pat` that's
important.
2024-04-18 12:44:11 +10:00
if let Some ( pat ) = self . eat_metavar_pat ( ) {
return Ok ( pat ) ;
}
2019-08-11 15:24:37 +02:00
2022-09-03 05:39:46 +00:00
let mut lo = self . token . span ;
2024-01-22 02:29:21 +00:00
if self . token . is_keyword ( kw ::Let )
& & self . look_ahead ( 1 , | tok | {
tok . can_begin_pattern ( token ::NtPatKind ::PatParam { inferred : false } )
} )
{
2022-09-03 05:39:46 +00:00
self . bump ( ) ;
2024-11-13 13:17:01 +00:00
// Trim extra space after the `let`
let span = lo . with_hi ( self . token . span . lo ( ) ) ;
2024-11-15 02:27:51 +00:00
self . dcx ( ) . emit_err ( RemoveLet { span : lo , suggestion : span } ) ;
2022-09-03 05:39:46 +00:00
lo = self . token . span ;
}
2019-12-11 10:04:34 +01:00
2024-12-04 15:55:06 +11:00
let pat = if self . check ( exp! ( And ) ) | | self . token = = token ::AndAnd {
2019-12-11 10:04:34 +01:00
self . parse_pat_deref ( expected ) ?
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( OpenParen ) ) {
2019-12-11 10:04:34 +01:00
self . parse_pat_tuple_or_parens ( ) ?
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( OpenBracket ) ) {
2019-12-11 10:04:34 +01:00
// Parse `[pat, pat,...]` as a slice pattern.
2024-12-04 15:55:06 +11:00
let ( pats , _ ) =
self . parse_delim_comma_seq ( exp! ( OpenBracket ) , exp! ( CloseBracket ) , | p | {
p . parse_pat_allow_top_guard (
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
)
} ) ? ;
2019-12-11 10:04:34 +01:00
PatKind ::Slice ( pats )
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( DotDot ) ) & & ! self . is_pat_range_end_start ( 1 ) {
2019-12-11 10:04:34 +01:00
// A rest pattern `..`.
self . bump ( ) ; // `..`
PatKind ::Rest
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( DotDotDot ) ) & & ! self . is_pat_range_end_start ( 1 ) {
2020-03-26 10:36:52 +05:30
self . recover_dotdotdot_rest_pat ( lo )
2019-12-11 10:04:34 +01:00
} else if let Some ( form ) = self . parse_range_end ( ) {
self . parse_pat_range_to ( form ) ? // `..=X`, `...X`, or `..X`.
2024-12-20 14:04:25 +11:00
} else if self . eat ( exp! ( Bang ) ) {
2023-11-22 02:30:43 +01:00
// Parse `!`
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::never_patterns , self . prev_token . span ) ;
2023-11-22 02:30:43 +01:00
PatKind ::Never
2024-12-04 15:55:06 +11:00
} else if self . eat_keyword ( exp! ( Underscore ) ) {
2023-11-22 02:30:43 +01:00
// Parse `_`
2019-12-11 10:04:34 +01:00
PatKind ::Wild
2024-12-04 15:55:06 +11:00
} else if self . eat_keyword ( exp! ( Mut ) ) {
2024-03-23 21:04:45 -04:00
self . parse_pat_ident_mut ( ) ?
2024-12-04 15:55:06 +11:00
} else if self . eat_keyword ( exp! ( Ref ) ) {
if self . check_keyword ( exp! ( Box ) ) {
2023-11-29 18:45:36 +00:00
// Suggest `box ref`.
2023-11-27 18:28:51 +09:00
let span = self . prev_token . span . to ( self . token . span ) ;
2023-11-29 18:45:36 +00:00
self . bump ( ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( SwitchRefBoxOrder { span } ) ;
2023-11-27 18:28:51 +09:00
}
2019-12-11 10:04:34 +01:00
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self . parse_mutability ( ) ;
2024-04-16 19:23:30 -04:00
self . parse_pat_ident ( BindingMode ( ByRef ::Yes ( mutbl ) , Mutability ::Not ) , syntax_loc ) ?
2024-12-04 15:55:06 +11:00
} else if self . eat_keyword ( exp! ( Box ) ) {
2022-06-08 04:40:55 +00:00
self . parse_pat_box ( ) ?
2020-10-19 18:44:37 -03:00
} else if self . check_inline_const ( 0 ) {
2020-09-23 18:34:44 -03:00
// Parse `const pat`
2021-11-22 16:25:28 +00:00
let const_expr = self . parse_const_block ( lo . to ( self . token . span ) , true ) ? ;
2020-10-19 16:18:47 -03:00
if let Some ( re ) = self . parse_range_end ( ) {
self . parse_pat_range_begin_with ( const_expr , re ) ?
} else {
2025-01-07 08:56:23 +00:00
PatKind ::Expr ( const_expr )
2020-10-19 16:18:47 -03:00
}
2024-03-20 16:53:50 -04:00
} else if self . is_builtin ( ) {
self . parse_pat_builtin ( ) ?
}
2023-03-17 22:27:17 +13:00
// Don't eagerly error on semantically invalid tokens when matching
// declarative macros, as the input to those doesn't have to be
// semantically valid. For attribute/derive proc macros this is not the
// case, so doing the recovery for them is fine.
2024-03-20 16:53:50 -04:00
else if self . can_be_ident_pat ( )
2023-03-17 22:27:17 +13:00
| | ( self . is_lit_bad_ident ( ) . is_some ( ) & & self . may_recover ( ) )
{
2019-12-11 10:04:34 +01:00
// Parse `ident @ pat`
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve.
2024-04-16 19:23:30 -04:00
self . parse_pat_ident ( BindingMode ::NONE , syntax_loc ) ?
2019-12-11 10:04:34 +01:00
} else if self . is_start_of_pat_with_path ( ) {
// Parse pattern starting with a path
let ( qself , path ) = if self . eat_lt ( ) {
// Parse a qualified path
2022-11-16 21:46:06 +01:00
let ( qself , path ) = self . parse_qpath ( PathStyle ::Pat ) ? ;
2019-12-11 10:04:34 +01:00
( Some ( qself ) , path )
} else {
// Parse an unqualified path
2022-11-16 21:46:06 +01:00
( None , self . parse_path ( PathStyle ::Pat ) ? )
2019-12-11 10:04:34 +01:00
} ;
2020-02-29 14:56:15 +03:00
let span = lo . to ( self . prev_token . span ) ;
2019-12-11 10:04:34 +01:00
2024-12-20 14:04:25 +11:00
if qself . is_none ( ) & & self . check ( exp! ( Bang ) ) {
2019-12-11 10:04:34 +01:00
self . parse_pat_mac_invoc ( path ) ?
} else if let Some ( form ) = self . parse_range_end ( ) {
2022-08-15 09:58:38 +10:00
let begin = self . mk_expr ( span , ExprKind ::Path ( qself , path ) ) ;
2019-12-11 10:04:34 +01:00
self . parse_pat_range_begin_with ( begin , form ) ?
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( OpenBrace ) ) {
2019-12-11 10:04:34 +01:00
self . parse_pat_struct ( qself , path ) ?
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( OpenParen ) ) {
2019-12-11 10:04:34 +01:00
self . parse_pat_tuple_struct ( qself , path ) ?
} else {
2024-01-28 16:12:21 +01:00
match self . maybe_recover_trailing_expr ( span , false ) {
2024-07-04 14:10:17 +02:00
Some ( ( guar , _ ) ) = > PatKind ::Err ( guar ) ,
2024-01-28 16:12:21 +01:00
None = > PatKind ::Path ( qself , path ) ,
}
2019-08-11 15:24:37 +02:00
}
2024-09-05 05:43:55 -04:00
} else if let Some ( ( lt , IdentIsRaw ::No ) ) = self . token . lifetime ( )
2022-09-01 18:48:09 +00:00
// In pattern position, we're totally fine with using "next token isn't colon"
// as a heuristic. We could probably just always try to recover if it's a lifetime,
// because we never have `'a: label {}` in a pattern position anyways, but it does
// keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
2024-06-20 16:36:35 -04:00
& & could_be_unclosed_char_literal ( lt )
2022-09-01 18:48:09 +00:00
& & ! self . look_ahead ( 1 , | token | matches! ( token . kind , token ::Colon ) )
{
// Recover a `'a` as a `'a'` literal
let lt = self . expect_lifetime ( ) ;
2022-12-05 14:39:56 +11:00
let ( lit , _ ) =
self . recover_unclosed_char ( lt . ident , Parser ::mk_token_lit_char , | self_ | {
2022-11-08 22:03:17 +01:00
let expected = Expected ::to_string_or_fallback ( expected ) ;
2022-12-05 14:39:56 +11:00
let msg = format! (
" expected {}, found {} " ,
expected ,
super ::token_descr ( & self_ . token )
) ;
2024-01-03 16:00:29 +11:00
self_
. dcx ( )
. struct_span_err ( self_ . token . span , msg )
2024-01-09 09:08:49 +11:00
. with_span_label ( self_ . token . span , format! ( " expected {expected} " ) )
2022-12-05 14:39:56 +11:00
} ) ;
2025-01-07 08:56:23 +00:00
PatKind ::Expr ( self . mk_expr ( lo , ExprKind ::Lit ( lit ) ) )
2019-12-11 10:04:34 +01:00
} else {
// Try to parse everything else as literal with optional minus
match self . parse_literal_maybe_minus ( ) {
2024-01-28 16:12:21 +01:00
Ok ( begin ) = > {
2024-07-04 14:10:17 +02:00
let begin = self
. maybe_recover_trailing_expr ( begin . span , false )
. map ( | ( guar , sp ) | self . mk_expr_err ( sp , guar ) )
. unwrap_or ( begin ) ;
2024-01-28 16:12:21 +01:00
match self . parse_range_end ( ) {
Some ( form ) = > self . parse_pat_range_begin_with ( begin , form ) ? ,
2025-01-07 08:56:23 +00:00
None = > PatKind ::Expr ( begin ) ,
2024-01-28 16:12:21 +01:00
}
}
2019-12-11 10:04:34 +01:00
Err ( err ) = > return self . fatal_unexpected_non_pat ( err , expected ) ,
2019-08-11 15:24:37 +02:00
}
2019-08-12 07:34:08 +02:00
} ;
2019-08-11 15:24:37 +02:00
2020-02-29 14:56:15 +03:00
let pat = self . mk_pat ( lo . to ( self . prev_token . span ) , pat ) ;
2022-05-19 15:51:49 +10:00
let pat = self . maybe_recover_from_bad_qpath ( pat ) ? ;
2019-10-14 16:47:12 +02:00
let pat = self . recover_intersection_pat ( pat ) ? ;
2019-08-11 15:24:37 +02:00
if ! allow_range_pat {
2019-12-11 10:04:34 +01:00
self . ban_pat_range_if_ambiguous ( & pat )
2019-08-11 15:24:37 +02:00
}
Ok ( pat )
}
2020-03-26 10:36:52 +05:30
/// Recover from a typoed `...` pattern that was encountered
/// Ref: Issue #70388
fn recover_dotdotdot_rest_pat ( & mut self , lo : Span ) -> PatKind {
// A typoed rest pattern `...`.
self . bump ( ) ; // `...`
// The user probably mistook `...` for a rest pattern `..`.
2024-07-06 03:07:46 +00:00
self . dcx ( ) . emit_err ( DotDotDotRestPattern {
span : lo ,
suggestion : lo . with_lo ( lo . hi ( ) - BytePos ( 1 ) ) ,
} ) ;
2020-03-26 10:36:52 +05:30
PatKind ::Rest
}
2019-10-14 16:47:12 +02:00
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
///
/// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
2023-01-14 18:23:40 +01:00
/// should already have been parsed by now at this point,
2019-10-14 16:47:12 +02:00
/// if the next token is `@` then we can try to parse the more general form.
///
/// Consult `parse_pat_ident` for the `binding` grammar.
///
/// The notion of intersection patterns are found in
/// e.g. [F#][and] where they are called AND-patterns.
///
/// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
fn recover_intersection_pat ( & mut self , lhs : P < Pat > ) -> PResult < ' a , P < Pat > > {
2024-08-09 17:44:47 +10:00
if self . token ! = token ::At {
2019-10-14 16:47:12 +02:00
// Next token is not `@` so it's not going to be an intersection pattern.
return Ok ( lhs ) ;
}
// At this point we attempt to parse `@ $pat_rhs` and emit an error.
self . bump ( ) ; // `@`
2023-08-03 00:00:56 +08:00
let mut rhs = self . parse_pat_no_top_alt ( None , None ) ? ;
2022-10-14 23:16:25 +02:00
let whole_span = lhs . span . to ( rhs . span ) ;
2019-10-14 16:47:12 +02:00
2022-11-22 09:42:01 +00:00
if let PatKind ::Ident ( _ , _ , sub @ None ) = & mut rhs . kind {
2019-10-14 16:47:12 +02:00
// The user inverted the order, so help them fix that.
let lhs_span = lhs . span ;
// Move the LHS into the RHS as a subpattern.
// The RHS is now the full pattern.
* sub = Some ( lhs ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( PatternOnWrongSideOfAt {
2022-10-14 23:16:25 +02:00
whole_span ,
whole_pat : pprust ::pat_to_string ( & rhs ) ,
pattern : lhs_span ,
binding : rhs . span ,
} ) ;
2019-10-14 17:25:50 +02:00
} else {
// The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
rhs . kind = PatKind ::Wild ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( ExpectedBindingLeftOfAt {
2022-10-14 23:16:25 +02:00
whole_span ,
lhs : lhs . span ,
rhs : rhs . span ,
} ) ;
2019-10-14 16:47:12 +02:00
}
2022-10-14 23:16:25 +02:00
rhs . span = whole_span ;
2019-10-14 17:25:50 +02:00
Ok ( rhs )
2019-10-14 16:47:12 +02:00
}
2019-08-12 08:16:04 +02:00
/// Ban a range pattern if it has an ambiguous interpretation.
2019-12-11 10:04:34 +01:00
fn ban_pat_range_if_ambiguous ( & self , pat : & Pat ) {
2019-09-26 16:18:31 +01:00
match pat . kind {
2019-08-12 08:16:04 +02:00
PatKind ::Range (
.. ,
Spanned { node : RangeEnd ::Included ( RangeSyntax ::DotDotDot ) , .. } ,
2019-12-11 10:04:34 +01:00
) = > return ,
2019-08-12 08:16:04 +02:00
PatKind ::Range ( .. ) = > { }
2019-12-11 10:04:34 +01:00
_ = > return ,
2019-08-12 08:16:04 +02:00
}
2024-07-06 03:07:46 +00:00
self . dcx ( ) . emit_err ( AmbiguousRangePattern {
span : pat . span ,
suggestion : ParenRangeSuggestion {
lo : pat . span . shrink_to_lo ( ) ,
hi : pat . span . shrink_to_hi ( ) ,
} ,
} ) ;
2019-08-12 08:16:04 +02:00
}
2019-08-12 07:37:08 +02:00
/// Parse `&pat` / `&mut pat`.
2022-11-08 22:03:17 +01:00
fn parse_pat_deref ( & mut self , expected : Option < Expected > ) -> PResult < ' a , PatKind > {
2019-08-12 07:37:08 +02:00
self . expect_and ( ) ? ;
2024-09-05 05:43:55 -04:00
if let Some ( ( lifetime , _ ) ) = self . token . lifetime ( ) {
2019-12-13 00:59:33 +01:00
self . bump ( ) ; // `'a`
2024-07-06 03:07:46 +00:00
self . dcx ( ) . emit_err ( UnexpectedLifetimeInPattern {
span : self . prev_token . span ,
2024-06-20 16:36:35 -04:00
symbol : lifetime . name ,
2024-07-06 03:07:46 +00:00
suggestion : self . prev_token . span . until ( self . token . span ) ,
} ) ;
2019-08-12 07:37:08 +02:00
}
2022-10-14 23:16:25 +02:00
let mutbl = self . parse_mutability ( ) ;
2023-08-03 00:00:56 +08:00
let subpat = self . parse_pat_with_range_pat ( false , expected , None ) ? ;
2022-10-14 23:16:25 +02:00
Ok ( PatKind ::Ref ( subpat , mutbl ) )
2019-08-12 07:37:08 +02:00
}
2019-08-12 07:41:50 +02:00
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens ( & mut self ) -> PResult < ' a , PatKind > {
2024-01-03 15:27:58 +01:00
let open_paren = self . token . span ;
2021-07-13 13:18:03 +02:00
let ( fields , trailing_comma ) = self . parse_paren_comma_seq ( | p | {
2024-11-24 17:36:52 +01:00
p . parse_pat_allow_top_guard (
2022-01-12 20:43:24 +00:00
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::LikelyTuple ,
)
2021-07-13 13:18:03 +02:00
} ) ? ;
2019-08-12 07:41:50 +02:00
// Here, `(pat,)` is a tuple pattern.
// For backward compatibility, `(..)` is a tuple pattern as well.
2024-02-13 23:48:23 +00:00
let paren_pattern =
fields . len ( ) = = 1 & & ! ( matches! ( trailing_comma , Trailing ::Yes ) | | fields [ 0 ] . is_rest ( ) ) ;
2024-07-04 14:10:17 +02:00
let pat = if paren_pattern {
2024-01-03 15:27:58 +01:00
let pat = fields . into_iter ( ) . next ( ) . unwrap ( ) ;
let close_paren = self . prev_token . span ;
match & pat . kind {
// recover ranges with parentheses around the `(start)..`
2025-01-07 08:56:23 +00:00
PatKind ::Expr ( begin )
2024-01-03 15:27:58 +01:00
if self . may_recover ( )
& & let Some ( form ) = self . parse_range_end ( ) = >
{
self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
span : vec ! [ open_paren , close_paren ] ,
sugg : UnexpectedParenInRangePatSugg {
start_span : open_paren ,
end_span : close_paren ,
} ,
} ) ;
2024-07-04 14:10:17 +02:00
self . parse_pat_range_begin_with ( begin . clone ( ) , form ) ?
2024-01-03 15:27:58 +01:00
}
2024-01-28 16:12:21 +01:00
// recover ranges with parentheses around the `(start)..`
2024-02-25 22:22:11 +01:00
PatKind ::Err ( guar )
2024-01-28 16:12:21 +01:00
if self . may_recover ( )
& & let Some ( form ) = self . parse_range_end ( ) = >
{
self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
span : vec ! [ open_paren , close_paren ] ,
sugg : UnexpectedParenInRangePatSugg {
start_span : open_paren ,
end_span : close_paren ,
} ,
} ) ;
2024-07-04 14:10:17 +02:00
self . parse_pat_range_begin_with ( self . mk_expr_err ( pat . span , * guar ) , form ) ?
2024-01-28 16:12:21 +01:00
}
2024-01-03 15:27:58 +01:00
// (pat) with optional parentheses
2024-07-04 14:10:17 +02:00
_ = > PatKind ::Paren ( pat ) ,
2024-01-03 15:27:58 +01:00
}
2019-08-12 07:41:50 +02:00
} else {
2024-07-04 14:10:17 +02:00
PatKind ::Tuple ( fields )
} ;
Ok ( match self . maybe_recover_trailing_expr ( open_paren . to ( self . prev_token . span ) , false ) {
None = > pat ,
Some ( ( guar , _ ) ) = > PatKind ::Err ( guar ) ,
} )
2019-08-12 07:41:50 +02:00
}
2019-08-27 19:51:21 +02:00
/// Parse a mutable binding with the `mut` token already eaten.
2024-03-23 21:04:45 -04:00
fn parse_pat_ident_mut ( & mut self ) -> PResult < ' a , PatKind > {
2020-02-29 14:56:15 +03:00
let mut_span = self . prev_token . span ;
2019-08-27 13:04:48 +02:00
2024-03-23 21:04:45 -04:00
self . recover_additional_muts ( ) ;
let byref = self . parse_byref ( ) ;
2019-08-27 13:04:48 +02:00
self . recover_additional_muts ( ) ;
2019-08-27 19:51:21 +02:00
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
Remove `NtPat`.
The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`.
This commit removes the complicated `Interpolated` handling in
`expected_expression_found` that results in a longer error message. But
I think the new, shorter message is actually an improvement.
The original complaint was in #71039, when the error message started
with "error: expected expression, found `1 + 1`". That was confusing
because `1 + 1` is an expression. Other than that, the reporter said
"the whole error message is not too bad if you ignore the first line".
Subsequently, extra complexity and wording was added to the error
message. But I don't think the extra wording actually helps all that
much. In particular, it still says of the `1+1` that "this is expected
to be expression". This repeats the problem from the original complaint!
This commit removes the extra complexity, reverting to a simpler error
message. This is primarily because the traversal is a pain without
`Interpolated` tokens. Nonetheless, I think the error message is
*improved*. It now starts with "expected expression, found `pat`
metavariable", which is much clearer and the real problem. It also
doesn't say anything specific about `1+1`, which is good, because the
`1+1` isn't really relevant to the error -- it's the `$e:pat` that's
important.
2024-04-18 12:44:11 +10:00
if let Some ( MetaVarKind ::Pat ( _ ) ) = self . token . is_metavar_seq ( ) {
self . expected_ident_found_err ( ) . emit ( ) ;
2019-08-27 19:51:21 +02:00
}
// Parse the pattern we hope to be an identifier.
2023-08-03 00:00:56 +08:00
let mut pat = self . parse_pat_no_top_alt ( Some ( Expected ::Identifier ) , None ) ? ;
2019-08-27 13:04:48 +02:00
2020-02-17 16:03:07 +01:00
// If we don't have `mut $ident (@ pat)?`, error.
2024-04-16 19:23:30 -04:00
if let PatKind ::Ident ( BindingMode ( br @ ByRef ::No , m @ Mutability ::Not ) , .. ) = & mut pat . kind
2022-08-30 17:34:35 -05:00
{
2020-02-17 16:03:07 +01:00
// Don't recurse into the subpattern.
// `mut` on the outer binding doesn't affect the inner bindings.
2024-03-23 21:04:45 -04:00
* br = byref ;
2020-02-17 16:03:07 +01:00
* m = Mutability ::Mut ;
} else {
// Add `mut` to any binding in the parsed pattern.
let changed_any_binding = Self ::make_all_value_bindings_mutable ( & mut pat ) ;
self . ban_mut_general_pat ( mut_span , & pat , changed_any_binding ) ;
2019-08-27 13:04:48 +02:00
}
2024-04-16 19:23:30 -04:00
if matches! ( pat . kind , PatKind ::Ident ( BindingMode ( ByRef ::Yes ( _ ) , Mutability ::Mut ) , .. ) ) {
2024-03-26 01:23:26 -04:00
self . psess . gated_spans . gate ( sym ::mut_ref , pat . span ) ;
}
2020-02-17 16:03:07 +01:00
Ok ( pat . into_inner ( ) . kind )
2019-08-27 13:04:48 +02:00
}
2019-08-27 23:44:44 +02:00
/// Turn all by-value immutable bindings in a pattern into mutable bindings.
/// Returns `true` if any change was made.
fn make_all_value_bindings_mutable ( pat : & mut P < Pat > ) -> bool {
struct AddMut ( bool ) ;
impl MutVisitor for AddMut {
fn visit_pat ( & mut self , pat : & mut P < Pat > ) {
2024-04-16 19:23:30 -04:00
if let PatKind ::Ident ( BindingMode ( ByRef ::No , m @ Mutability ::Not ) , .. ) =
2022-08-30 17:34:35 -05:00
& mut pat . kind
2020-02-17 16:03:07 +01:00
{
2019-08-27 23:44:44 +02:00
self . 0 = true ;
2020-02-17 16:03:07 +01:00
* m = Mutability ::Mut ;
2019-08-27 23:44:44 +02:00
}
2024-09-18 20:38:43 +02:00
mut_visit ::walk_pat ( self , pat ) ;
2019-08-27 23:44:44 +02:00
}
}
let mut add_mut = AddMut ( false ) ;
add_mut . visit_pat ( pat ) ;
add_mut . 0
}
2019-08-27 13:04:48 +02:00
/// Error on `mut $pat` where `$pat` is not an ident.
2019-08-27 23:44:44 +02:00
fn ban_mut_general_pat ( & self , lo : Span , pat : & Pat , changed_any_binding : bool ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( if changed_any_binding {
2023-11-06 19:47:38 +00:00
InvalidMutInPattern ::NestedIdent {
span : lo . to ( pat . span ) ,
2023-11-21 20:07:32 +01:00
pat : pprust ::pat_to_string ( pat ) ,
2023-11-06 19:47:38 +00:00
}
2019-08-12 07:45:55 +02:00
} else {
2023-11-06 19:47:38 +00:00
InvalidMutInPattern ::NonIdent { span : lo . until ( pat . span ) }
2022-10-14 23:16:25 +02:00
} ) ;
2019-08-27 13:04:48 +02:00
}
/// Eat any extraneous `mut`s and error + recover if we ate any.
fn recover_additional_muts ( & mut self ) {
let lo = self . token . span ;
2024-12-04 15:55:06 +11:00
while self . eat_keyword ( exp! ( Mut ) ) { }
2019-08-27 13:04:48 +02:00
if lo = = self . token . span {
return ;
}
2024-11-28 01:35:36 +00:00
let span = lo . to ( self . prev_token . span ) ;
let suggestion = span . with_hi ( self . token . span . lo ( ) ) ;
self . dcx ( ) . emit_err ( RepeatedMutInPattern { span , suggestion } ) ;
2019-08-12 07:45:55 +02:00
}
2019-08-12 08:27:01 +02:00
/// Parse macro invocation
2019-12-01 15:55:32 +03:00
fn parse_pat_mac_invoc ( & mut self , path : Path ) -> PResult < ' a , PatKind > {
2019-08-12 08:27:01 +02:00
self . bump ( ) ;
2022-11-18 11:24:21 +11:00
let args = self . parse_delim_args ( ) ? ;
2022-11-16 21:46:06 +01:00
let mac = P ( MacCall { path , args } ) ;
2020-02-29 19:32:20 +03:00
Ok ( PatKind ::MacCall ( mac ) )
2019-08-12 08:27:01 +02:00
}
2019-08-12 11:39:44 +02:00
fn fatal_unexpected_non_pat (
& mut self ,
2024-02-23 10:20:45 +11:00
err : Diag < ' a > ,
2022-11-08 22:03:17 +01:00
expected : Option < Expected > ,
2019-08-12 11:39:44 +02:00
) -> PResult < ' a , P < Pat > > {
2019-09-07 10:38:02 -04:00
err . cancel ( ) ;
2019-08-12 11:39:44 +02:00
2022-11-08 22:03:17 +01:00
let expected = Expected ::to_string_or_fallback ( expected ) ;
2019-12-07 03:07:35 +01:00
let msg = format! ( " expected {} , found {} " , expected , super ::token_descr ( & self . token ) ) ;
2019-08-12 11:39:44 +02:00
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( self . token . span , msg ) ;
2023-07-25 22:00:13 +02:00
err . span_label ( self . token . span , format! ( " expected {expected} " ) ) ;
2019-08-12 11:39:44 +02:00
2024-03-04 16:31:49 +11:00
let sp = self . psess . source_map ( ) . start_point ( self . token . span ) ;
if let Some ( sp ) = self . psess . ambiguous_block_expr_parse . borrow ( ) . get ( & sp ) {
2024-06-18 11:10:18 +00:00
err . subdiagnostic ( ExprParenthesesNeeded ::surrounding ( * sp ) ) ;
2019-08-12 11:39:44 +02:00
}
Err ( err )
}
2019-12-11 10:04:34 +01:00
/// Parses the range pattern end form `".." | "..." | "..=" ;`.
fn parse_range_end ( & mut self ) -> Option < Spanned < RangeEnd > > {
2024-12-04 15:55:06 +11:00
let re = if self . eat ( exp! ( DotDotDot ) ) {
2019-12-11 10:04:34 +01:00
RangeEnd ::Included ( RangeSyntax ::DotDotDot )
2024-12-04 15:55:06 +11:00
} else if self . eat ( exp! ( DotDotEq ) ) {
2019-12-11 10:04:34 +01:00
RangeEnd ::Included ( RangeSyntax ::DotDotEq )
2024-12-04 15:55:06 +11:00
} else if self . eat ( exp! ( DotDot ) ) {
2019-12-11 10:04:34 +01:00
RangeEnd ::Excluded
} else {
return None ;
} ;
2020-02-29 14:56:15 +03:00
Some ( respan ( self . prev_token . span , re ) )
2019-08-11 15:24:37 +02:00
}
2019-12-11 10:04:34 +01:00
/// Parse a range pattern `$begin $form $end?` where `$form = ".." | "..." | "..=" ;`.
/// `$begin $form` has already been parsed.
fn parse_pat_range_begin_with (
& mut self ,
begin : P < Expr > ,
re : Spanned < RangeEnd > ,
) -> PResult < ' a , PatKind > {
let end = if self . is_pat_range_end_start ( 0 ) {
2019-08-11 15:24:37 +02:00
// Parsing e.g. `X..=Y`.
2019-12-11 10:04:34 +01:00
Some ( self . parse_pat_range_end ( ) ? )
2019-08-11 15:24:37 +02:00
} else {
// Parsing e.g. `X..`.
2019-12-11 10:04:34 +01:00
if let RangeEnd ::Included ( _ ) = re . node {
// FIXME(Centril): Consider semantic errors instead in `ast_validation`.
2023-01-28 20:02:00 +00:00
self . inclusive_range_with_incorrect_end ( ) ;
2019-12-11 10:04:34 +01:00
}
None
} ;
Ok ( PatKind ::Range ( Some ( begin ) , end , re ) )
}
2019-08-11 15:24:37 +02:00
2024-02-25 22:22:11 +01:00
pub ( super ) fn inclusive_range_with_incorrect_end ( & mut self ) -> ErrorGuaranteed {
2021-06-25 19:46:41 -07:00
let tok = & self . token ;
2023-01-28 20:02:00 +00:00
let span = self . prev_token . span ;
2021-06-25 19:46:41 -07:00
// If the user typed "..==" instead of "..=", we want to give them
// a specific error message telling them to use "..=".
2023-01-28 20:02:00 +00:00
// If they typed "..=>", suggest they use ".. =>".
2021-06-25 19:46:41 -07:00
// Otherwise, we assume that they meant to type a half open exclusive
// range and give them an error telling them to do that instead.
2023-01-28 20:02:00 +00:00
let no_space = tok . span . lo ( ) = = span . hi ( ) ;
match tok . kind {
token ::Eq if no_space = > {
let span_with_eq = span . to ( tok . span ) ;
2021-06-25 19:46:41 -07:00
2023-01-28 20:02:00 +00:00
// Ensure the user doesn't receive unhelpful unexpected token errors
self . bump ( ) ;
if self . is_pat_range_end_start ( 0 ) {
let _ = self . parse_pat_range_end ( ) . map_err ( | e | e . cancel ( ) ) ;
}
2021-06-25 19:46:41 -07:00
2024-02-25 22:22:11 +01:00
self . dcx ( ) . emit_err ( InclusiveRangeExtraEquals { span : span_with_eq } )
2023-01-28 20:02:00 +00:00
}
token ::Gt if no_space = > {
2024-07-06 03:07:46 +00:00
let after_pat = span . with_hi ( span . hi ( ) - BytePos ( 1 ) ) . shrink_to_hi ( ) ;
2024-02-25 22:22:11 +01:00
self . dcx ( ) . emit_err ( InclusiveRangeMatchArrow { span , arrow : tok . span , after_pat } )
2023-01-28 20:02:00 +00:00
}
2024-07-06 03:07:46 +00:00
_ = > self . dcx ( ) . emit_err ( InclusiveRangeNoEnd {
span ,
suggestion : span . with_lo ( span . hi ( ) - BytePos ( 1 ) ) ,
} ) ,
2021-06-25 19:46:41 -07:00
}
}
2020-01-11 06:49:43 +01:00
/// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
///
/// The form `...X` is prohibited to reduce confusion with the potential
/// expression syntax `...expr` for splatting in expressions.
fn parse_pat_range_to ( & mut self , mut re : Spanned < RangeEnd > ) -> PResult < ' a , PatKind > {
2019-12-11 10:04:34 +01:00
let end = self . parse_pat_range_end ( ) ? ;
2022-11-22 09:42:01 +00:00
if let RangeEnd ::Included ( syn @ RangeSyntax ::DotDotDot ) = & mut re . node {
2020-01-11 06:49:43 +01:00
* syn = RangeSyntax ::DotDotEq ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( DotDotDotRangeToPatternNotAllowed { span : re . span } ) ;
2020-01-11 06:49:43 +01:00
}
2019-12-11 10:04:34 +01:00
Ok ( PatKind ::Range ( None , Some ( end ) , re ) )
}
/// Is the token `dist` away from the current suitable as the start of a range patterns end?
2020-10-19 18:44:37 -03:00
fn is_pat_range_end_start ( & self , dist : usize ) -> bool {
self . check_inline_const ( dist )
2020-10-19 16:18:47 -03:00
| | self . look_ahead ( dist , | t | {
t . is_path_start ( ) // e.g. `MY_CONST`;
2024-08-09 17:44:47 +10:00
| | * t = = token ::Dot // e.g. `.5` for recovery;
2024-12-20 07:28:16 +11:00
| | matches! ( t . kind , token ::Literal ( .. ) | token ::Minus )
2024-06-13 13:40:14 +10:00
| | t . is_bool_lit ( )
2019-12-11 10:04:34 +01:00
| | t . is_whole_expr ( )
2022-09-01 18:48:09 +00:00
| | t . is_lifetime ( ) // recover `'a` instead of `'a'`
2024-01-03 15:27:58 +01:00
| | ( self . may_recover ( ) // recover leading `(`
2024-08-09 17:44:47 +10:00
& & * t = = token ::OpenDelim ( Delimiter ::Parenthesis )
& & self . look_ahead ( dist + 1 , | t | * t ! = token ::OpenDelim ( Delimiter ::Parenthesis ) )
2024-01-03 15:27:58 +01:00
& & self . is_pat_range_end_start ( dist + 1 ) )
2020-10-19 16:18:47 -03:00
} )
2019-08-11 15:24:37 +02:00
}
2024-01-03 15:27:58 +01:00
/// Parse a range pattern end bound
2019-08-11 15:24:37 +02:00
fn parse_pat_range_end ( & mut self ) -> PResult < ' a , P < Expr > > {
2024-01-03 15:27:58 +01:00
// recover leading `(`
let open_paren = ( self . may_recover ( )
& & self . eat_noexpect ( & token ::OpenDelim ( Delimiter ::Parenthesis ) ) )
. then_some ( self . prev_token . span ) ;
let bound = if self . check_inline_const ( 0 ) {
2021-11-22 16:25:28 +00:00
self . parse_const_block ( self . token . span , true )
2020-10-19 16:18:47 -03:00
} else if self . check_path ( ) {
2019-08-11 15:24:37 +02:00
let lo = self . token . span ;
let ( qself , path ) = if self . eat_lt ( ) {
// Parse a qualified path
2022-11-16 21:46:06 +01:00
let ( qself , path ) = self . parse_qpath ( PathStyle ::Pat ) ? ;
2019-08-11 15:24:37 +02:00
( Some ( qself ) , path )
} else {
// Parse an unqualified path
2022-11-16 21:46:06 +01:00
( None , self . parse_path ( PathStyle ::Pat ) ? )
2019-08-11 15:24:37 +02:00
} ;
2020-02-29 14:56:15 +03:00
let hi = self . prev_token . span ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr ( lo . to ( hi ) , ExprKind ::Path ( qself , path ) ) )
2019-08-11 15:24:37 +02:00
} else {
self . parse_literal_maybe_minus ( )
2024-01-03 15:27:58 +01:00
} ? ;
2024-01-28 16:12:21 +01:00
let recovered = self . maybe_recover_trailing_expr ( bound . span , true ) ;
2024-01-03 15:27:58 +01:00
// recover trailing `)`
if let Some ( open_paren ) = open_paren {
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( CloseParen ) ) ? ;
2024-01-03 15:27:58 +01:00
self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
span : vec ! [ open_paren , self . prev_token . span ] ,
sugg : UnexpectedParenInRangePatSugg {
start_span : open_paren ,
end_span : self . prev_token . span ,
} ,
} ) ;
2019-08-11 15:24:37 +02:00
}
2024-01-03 15:27:58 +01:00
2024-01-28 16:12:21 +01:00
Ok ( match recovered {
2024-07-04 14:10:17 +02:00
Some ( ( guar , sp ) ) = > self . mk_expr_err ( sp , guar ) ,
2024-01-28 16:12:21 +01:00
None = > bound ,
} )
2019-08-11 15:24:37 +02:00
}
2019-08-27 13:04:48 +02:00
/// Is this the start of a pattern beginning with a path?
fn is_start_of_pat_with_path ( & mut self ) -> bool {
self . check_path ( )
// Just for recovery (see `can_be_ident`).
| | self . token . is_ident ( ) & & ! self . token . is_bool_lit ( ) & & ! self . token . is_keyword ( kw ::In )
}
/// Would `parse_pat_ident` be appropriate here?
fn can_be_ident_pat ( & mut self ) -> bool {
self . check_ident ( )
& & ! self . token . is_bool_lit ( ) // Avoid `true` or `false` as a binding as it is a literal.
& & ! self . token . is_path_segment_keyword ( ) // Avoid e.g. `Self` as it is a path.
// Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
& & ! self . token . is_keyword ( kw ::In )
2020-10-27 10:55:26 -04:00
// Try to do something more complex?
2022-04-26 15:40:14 +03:00
& & self . look_ahead ( 1 , | t | ! matches! ( t . kind , token ::OpenDelim ( Delimiter ::Parenthesis ) // A tuple struct pattern.
| token ::OpenDelim ( Delimiter ::Brace ) // A struct pattern.
2019-08-27 13:04:48 +02:00
| token ::DotDotDot | token ::DotDotEq | token ::DotDot // A range pattern.
2024-04-04 19:03:32 +02:00
| token ::PathSep // A tuple / struct variant pattern.
2024-12-20 14:04:25 +11:00
| token ::Bang ) ) // A macro expanding to a pattern.
2019-08-27 13:04:48 +02:00
}
2019-08-11 15:24:37 +02:00
/// Parses `ident` or `ident @ pat`.
2019-08-12 09:28:30 +02:00
/// Used by the copy foo and ref foo patterns to give a good
2019-08-11 15:24:37 +02:00
/// error message when parsing mistakes like `ref foo(a, b)`.
2023-08-03 08:56:31 +00:00
fn parse_pat_ident (
& mut self ,
2024-04-16 19:23:30 -04:00
binding_annotation : BindingMode ,
2023-08-03 08:56:31 +00:00
syntax_loc : Option < PatternLocation > ,
) -> PResult < ' a , PatKind > {
2023-11-06 21:00:13 +00:00
let ident = self . parse_ident_common ( false ) ? ;
2023-08-03 08:56:31 +00:00
2023-09-12 16:30:38 +02:00
if self . may_recover ( )
& & ! matches! ( syntax_loc , Some ( PatternLocation ::FunctionParameter ) )
2023-08-03 08:56:31 +00:00
& & self . check_noexpect ( & token ::Lt )
& & self . look_ahead ( 1 , | t | t . can_begin_type ( ) )
{
2023-12-18 21:14:02 +11:00
return Err ( self . dcx ( ) . create_err ( GenericArgsInPatRequireTurbofishSyntax {
2023-08-03 08:56:31 +00:00
span : self . token . span ,
suggest_turbofish : self . token . span . shrink_to_lo ( ) ,
} ) ) ;
}
2024-12-04 15:55:06 +11:00
let sub = if self . eat ( exp! ( At ) ) {
2023-08-03 00:00:56 +08:00
Some ( self . parse_pat_no_top_alt ( Some ( Expected ::BindingPattern ) , None ) ? )
2019-08-11 15:24:37 +02:00
} else {
None
} ;
2019-08-12 09:28:30 +02:00
// Just to be friendly, if they write something like `ref Some(i)`,
// we end up here with `(` as the current token.
// This shortly leads to a parse error. Note that if there is no explicit
2019-08-11 15:24:37 +02:00
// binding mode then we do not end up here, because the lookahead
2019-08-12 09:28:30 +02:00
// will direct us over to `parse_enum_variant()`.
2022-04-26 15:40:14 +03:00
if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2023-12-18 14:00:17 +11:00
return Err ( self
. dcx ( )
. create_err ( EnumPatternInsteadOfIdentifier { span : self . prev_token . span } ) ) ;
2019-08-11 15:24:37 +02:00
}
2024-01-28 16:12:21 +01:00
// Check for method calls after the `ident`,
// but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`.
let pat = if sub . is_none ( )
2024-07-04 14:10:17 +02:00
& & let Some ( ( guar , _ ) ) = self . maybe_recover_trailing_expr ( ident . span , false )
2024-01-28 16:12:21 +01:00
{
PatKind ::Err ( guar )
} else {
PatKind ::Ident ( binding_annotation , ident , sub )
} ;
Ok ( pat )
2019-08-11 15:24:37 +02:00
}
2019-08-12 12:27:43 +02:00
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
2022-09-08 10:52:51 +10:00
fn parse_pat_struct ( & mut self , qself : Option < P < QSelf > > , path : Path ) -> PResult < ' a , PatKind > {
2019-08-12 12:27:43 +02:00
if qself . is_some ( ) {
2020-12-10 13:20:07 +01:00
// Feature gate the use of qualified paths in patterns
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::more_qualified_paths , path . span ) ;
2019-08-12 12:27:43 +02:00
}
self . bump ( ) ;
let ( fields , etc ) = self . parse_pat_fields ( ) . unwrap_or_else ( | mut e | {
2020-10-02 00:44:16 -07:00
e . span_label ( path . span , " while parsing the fields for this pattern " ) ;
Keep track of patterns that could have introduced a binding, but didn't
When we recover from a pattern parse error, or a pattern uses `..`, we keep track of that and affect resolution error for missing bindings that could have been provided by that pattern. We differentiate between `..` and parse recovery. We silence resolution errors likely caused by the pattern parse error.
```
error[E0425]: cannot find value `title` in this scope
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:19:30
|
LL | println!("[{}]({})", title, url);
| ^^^^^ not found in this scope
|
note: `Website` has a field `title` which could have been included in this pattern, but it wasn't
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:17:12
|
LL | / struct Website {
LL | | url: String,
LL | | title: Option<String> ,
| | ----- defined here
LL | | }
| |_-
...
LL | if let Website { url, .. } = website {
| ^^^^^^^^^^^^^^^^^^^ this pattern doesn't include `title`, which is available in `Website`
```
Fix #74863.
2024-12-13 21:51:33 +00:00
let guar = e . emit ( ) ;
2019-08-12 12:27:43 +02:00
self . recover_stmt ( ) ;
2023-12-22 23:29:20 +00:00
// When recovering, pretend we had `Foo { .. }`, to avoid cascading errors.
Keep track of patterns that could have introduced a binding, but didn't
When we recover from a pattern parse error, or a pattern uses `..`, we keep track of that and affect resolution error for missing bindings that could have been provided by that pattern. We differentiate between `..` and parse recovery. We silence resolution errors likely caused by the pattern parse error.
```
error[E0425]: cannot find value `title` in this scope
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:19:30
|
LL | println!("[{}]({})", title, url);
| ^^^^^ not found in this scope
|
note: `Website` has a field `title` which could have been included in this pattern, but it wasn't
--> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:17:12
|
LL | / struct Website {
LL | | url: String,
LL | | title: Option<String> ,
| | ----- defined here
LL | | }
| |_-
...
LL | if let Website { url, .. } = website {
| ^^^^^^^^^^^^^^^^^^^ this pattern doesn't include `title`, which is available in `Website`
```
Fix #74863.
2024-12-13 21:51:33 +00:00
( ThinVec ::new ( ) , PatFieldsRest ::Recovered ( guar ) )
2019-08-12 12:27:43 +02:00
} ) ;
self . bump ( ) ;
2020-12-10 13:20:07 +01:00
Ok ( PatKind ::Struct ( qself , path , fields , etc ) )
2019-08-12 12:27:43 +02:00
}
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
2022-09-08 10:52:51 +10:00
fn parse_pat_tuple_struct (
& mut self ,
qself : Option < P < QSelf > > ,
path : Path ,
) -> PResult < ' a , PatKind > {
2021-07-13 13:18:03 +02:00
let ( fields , _ ) = self . parse_paren_comma_seq ( | p | {
2024-11-24 17:36:52 +01:00
p . parse_pat_allow_top_guard (
2022-01-12 20:43:24 +00:00
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
)
2021-07-13 13:18:03 +02:00
} ) ? ;
2020-12-10 13:20:07 +01:00
if qself . is_some ( ) {
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::more_qualified_paths , path . span ) ;
2020-12-10 13:20:07 +01:00
}
Ok ( PatKind ::TupleStruct ( qself , path , fields ) )
2019-12-31 03:36:45 +01:00
}
2022-06-08 04:40:55 +00:00
/// Are we sure this could not possibly be the start of a pattern?
///
/// Currently, this only accounts for tokens that can follow identifiers
/// in patterns, but this can be extended as necessary.
fn isnt_pattern_start ( & self ) -> bool {
[
token ::Eq ,
token ::Colon ,
token ::Comma ,
token ::Semi ,
token ::At ,
token ::OpenDelim ( Delimiter ::Brace ) ,
token ::CloseDelim ( Delimiter ::Brace ) ,
token ::CloseDelim ( Delimiter ::Parenthesis ) ,
]
. contains ( & self . token . kind )
}
2024-03-20 16:53:50 -04:00
fn parse_pat_builtin ( & mut self ) -> PResult < ' a , PatKind > {
self . parse_builtin ( | self_ , _lo , ident | {
Ok ( match ident . name {
// builtin#deref(PAT)
2024-11-24 17:36:52 +01:00
sym ::deref = > Some ( ast ::PatKind ::Deref ( self_ . parse_pat_allow_top_guard (
2024-03-20 16:53:50 -04:00
None ,
RecoverComma ::Yes ,
RecoverColon ::Yes ,
CommaRecoveryMode ::LikelyTuple ,
) ? ) ) ,
_ = > None ,
} )
} )
}
2022-06-08 04:40:55 +00:00
/// Parses `box pat`
fn parse_pat_box ( & mut self ) -> PResult < ' a , PatKind > {
let box_span = self . prev_token . span ;
if self . isnt_pattern_start ( ) {
2023-04-27 01:53:06 +01:00
let descr = super ::token_descr ( & self . token ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::BoxNotPat {
2023-04-27 01:53:06 +01:00
span : self . token . span ,
kw : box_span ,
lo : box_span . shrink_to_lo ( ) ,
descr ,
} ) ;
2022-06-08 04:40:55 +00:00
// We cannot use `parse_pat_ident()` since it will complain `box`
// is not an identifier.
2024-12-04 15:55:06 +11:00
let sub = if self . eat ( exp! ( At ) ) {
2023-08-03 00:00:56 +08:00
Some ( self . parse_pat_no_top_alt ( Some ( Expected ::BindingPattern ) , None ) ? )
2022-06-08 04:40:55 +00:00
} else {
None
} ;
2024-04-16 19:23:30 -04:00
Ok ( PatKind ::Ident ( BindingMode ::NONE , Ident ::new ( kw ::Box , box_span ) , sub ) )
2022-06-08 04:40:55 +00:00
} else {
2023-08-03 00:00:56 +08:00
let pat = self . parse_pat_with_range_pat ( false , None , None ) ? ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::box_patterns , box_span . to ( self . prev_token . span ) ) ;
2022-06-08 04:40:55 +00:00
Ok ( PatKind ::Box ( pat ) )
}
}
2019-08-11 15:24:37 +02:00
/// Parses the fields of a struct-like pattern.
2023-12-22 23:29:20 +00:00
fn parse_pat_fields ( & mut self ) -> PResult < ' a , ( ThinVec < PatField > , PatFieldsRest ) > {
2024-09-23 02:12:53 +03:00
let mut fields : ThinVec < PatField > = ThinVec ::new ( ) ;
2023-12-22 23:29:20 +00:00
let mut etc = PatFieldsRest ::None ;
2019-08-11 15:24:37 +02:00
let mut ate_comma = true ;
2024-02-23 10:20:45 +11:00
let mut delayed_err : Option < Diag < ' a > > = None ;
2023-06-02 14:40:44 +08:00
let mut first_etc_and_maybe_comma_span = None ;
let mut last_non_comma_dotdot_span = None ;
2019-08-11 15:24:37 +02:00
2022-04-26 15:40:14 +03:00
while self . token ! = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 15:24:37 +02:00
// check that a comma comes after every field
if ! ate_comma {
2024-09-23 02:12:53 +03:00
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
} ;
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
if let Some ( delayed ) = delayed_err {
2019-08-11 15:24:37 +02:00
delayed . emit ( ) ;
}
return Err ( err ) ;
}
ate_comma = false ;
2024-12-04 15:55:06 +11:00
if self . check ( exp! ( DotDot ) )
2023-01-15 21:31:04 +00:00
| | self . check_noexpect ( & token ::DotDotDot )
2024-12-04 15:55:06 +11:00
| | self . check_keyword ( exp! ( Underscore ) )
2023-01-15 21:31:04 +00:00
{
2023-12-22 23:29:20 +00:00
etc = PatFieldsRest ::Rest ;
2019-08-11 15:24:37 +02:00
let mut etc_sp = self . token . span ;
2023-06-02 14:40:44 +08:00
if first_etc_and_maybe_comma_span . is_none ( ) {
if let Some ( comma_tok ) = self
. look_ahead ( 1 , | t | if * t = = token ::Comma { Some ( t . clone ( ) ) } else { None } )
{
let nw_span = self
2024-03-04 16:31:49 +11:00
. psess
2023-06-02 14:40:44 +08:00
. source_map ( )
. span_extend_to_line ( comma_tok . span )
. trim_start ( comma_tok . span . shrink_to_lo ( ) )
2024-03-04 16:31:49 +11:00
. map ( | s | self . psess . source_map ( ) . span_until_non_whitespace ( s ) ) ;
2023-06-02 14:40:44 +08:00
first_etc_and_maybe_comma_span = nw_span . map ( | s | etc_sp . to ( s ) ) ;
} else {
first_etc_and_maybe_comma_span =
2024-03-04 16:31:49 +11:00
Some ( self . psess . source_map ( ) . span_until_non_whitespace ( etc_sp ) ) ;
2023-06-02 14:40:44 +08:00
}
}
2019-08-11 15:24:37 +02:00
2023-01-15 21:31:04 +00:00
self . recover_bad_dot_dot ( ) ;
self . bump ( ) ; // `..` || `...` || `_`
2019-08-11 15:24:37 +02:00
2022-04-26 15:40:14 +03:00
if self . token = = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 15:24:37 +02:00
break ;
}
2019-12-07 03:07:35 +01:00
let token_str = super ::token_descr ( & self . token ) ;
2023-07-25 22:00:13 +02:00
let msg = format! ( " expected ` }} `, found {token_str} " ) ;
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( self . token . span , msg ) ;
2019-08-11 15:24:37 +02:00
err . span_label ( self . token . span , " expected `}` " ) ;
let mut comma_sp = None ;
if self . token = = token ::Comma {
// Issue #49257
2024-03-04 16:31:49 +11:00
let nw_span =
self . psess . source_map ( ) . span_until_non_whitespace ( self . token . span ) ;
2019-08-11 15:24:37 +02:00
etc_sp = etc_sp . to ( nw_span ) ;
err . span_label (
etc_sp ,
" `..` must be at the end and cannot have a trailing comma " ,
) ;
comma_sp = Some ( self . token . span ) ;
self . bump ( ) ;
ate_comma = true ;
}
2022-04-26 15:40:14 +03:00
if self . token = = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 15:24:37 +02:00
// If the struct looks otherwise well formed, recover and continue.
if let Some ( sp ) = comma_sp {
err . span_suggestion_short (
sp ,
" remove this comma " ,
2022-06-13 15:48:40 +09:00
" " ,
2019-08-11 15:24:37 +02:00
Applicability ::MachineApplicable ,
) ;
}
err . emit ( ) ;
break ;
} else if self . token . is_ident ( ) & & ate_comma {
// Accept fields coming after `..,`.
// This way we avoid "pattern missing fields" errors afterwards.
// We delay this error until the end in order to have a span for a
// suggested fix.
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
if let Some ( delayed_err ) = delayed_err {
2019-08-11 15:24:37 +02:00
delayed_err . emit ( ) ;
return Err ( err ) ;
} else {
delayed_err = Some ( err ) ;
}
} else {
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
if let Some ( err ) = delayed_err {
2019-08-11 15:24:37 +02:00
err . emit ( ) ;
}
return Err ( err ) ;
}
}
2025-02-03 13:56:20 +00:00
let attrs = match self . parse_outer_attributes ( ) {
Ok ( attrs ) = > attrs ,
Err ( err ) = > {
if let Some ( delayed ) = delayed_err {
delayed . emit ( ) ;
}
return Err ( err ) ;
}
} ;
let lo = self . token . span ;
2024-08-06 17:16:40 +10:00
let field = self . collect_tokens ( None , attrs , ForceCollect ::No , | this , attrs | {
let field = match this . parse_pat_field ( lo , attrs ) {
Ok ( field ) = > Ok ( field ) ,
Err ( err ) = > {
if let Some ( delayed_err ) = delayed_err . take ( ) {
delayed_err . emit ( ) ;
2021-01-22 13:28:08 -05:00
}
2024-08-06 17:16:40 +10:00
return Err ( err ) ;
}
} ? ;
2024-12-04 15:55:06 +11:00
ate_comma = this . eat ( exp! ( Comma ) ) ;
2023-06-02 14:40:44 +08:00
2024-08-06 17:16:40 +10:00
last_non_comma_dotdot_span = Some ( this . prev_token . span ) ;
2023-06-02 14:40:44 +08:00
2024-08-06 17:16:40 +10:00
// We just ate a comma, so there's no need to capture a trailing token.
Ok ( ( field , Trailing ::No , UsePreAttrPos ::No ) )
} ) ? ;
2021-01-22 13:28:08 -05:00
fields . push ( field )
2019-08-11 15:24:37 +02:00
}
if let Some ( mut err ) = delayed_err {
2023-06-02 14:40:44 +08:00
if let Some ( first_etc_span ) = first_etc_and_maybe_comma_span {
if self . prev_token = = token ::DotDot {
// We have `.., x, ..`.
err . multipart_suggestion (
" remove the starting `..` " ,
vec! [ ( first_etc_span , String ::new ( ) ) ] ,
Applicability ::MachineApplicable ,
) ;
2024-09-11 17:23:56 -04:00
} else if let Some ( last_non_comma_dotdot_span ) = last_non_comma_dotdot_span {
// We have `.., x`.
err . multipart_suggestion (
" move the `..` to the end of the field list " ,
vec! [
( first_etc_span , String ::new ( ) ) ,
(
self . token . span . to ( last_non_comma_dotdot_span . shrink_to_hi ( ) ) ,
format! ( " {} .. }} " , if ate_comma { " " } else { " , " } ) ,
) ,
] ,
Applicability ::MachineApplicable ,
) ;
2023-06-02 14:40:44 +08:00
}
2019-08-11 15:24:37 +02:00
}
err . emit ( ) ;
}
2020-03-20 15:03:11 +01:00
Ok ( ( fields , etc ) )
2019-08-11 15:24:37 +02:00
}
2024-09-23 02:12:53 +03:00
#[ 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 {
2024-12-17 14:33:10 -08:00
self . dcx ( ) . create_err ( AtInStructPattern { span } )
2024-09-23 02:12:53 +03:00
}
}
2023-10-27 16:11:43 +00:00
/// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest
/// the correct code.
2024-02-23 10:20:45 +11:00
fn recover_misplaced_pattern_modifiers ( & self , fields : & ThinVec < PatField > , err : & mut Diag < ' a > ) {
2023-10-27 16:11:43 +00:00
if let Some ( last ) = fields . iter ( ) . last ( )
& & last . is_shorthand
& & let PatKind ::Ident ( binding , ident , None ) = last . pat . kind
2024-04-16 19:23:30 -04:00
& & binding ! = BindingMode ::NONE
2023-10-27 16:11:43 +00:00
& & self . token = = token ::Colon
// We found `ref mut? ident:`, try to parse a `name,` or `name }`.
& & let Some ( name_span ) = self . look_ahead ( 1 , | t | t . is_ident ( ) . then ( | | t . span ) )
& & self . look_ahead ( 2 , | t | {
t = = & token ::Comma | | t = = & token ::CloseDelim ( Delimiter ::Brace )
} )
{
let span = last . pat . span . with_hi ( ident . span . lo ( ) ) ;
// We have `S { ref field: name }` instead of `S { field: ref name }`
err . multipart_suggestion (
" the pattern modifiers belong after the `:` " ,
vec! [
( span , String ::new ( ) ) ,
( name_span . shrink_to_lo ( ) , binding . prefix_str ( ) . to_string ( ) ) ,
] ,
Applicability ::MachineApplicable ,
) ;
}
}
2023-01-15 21:31:04 +00:00
/// Recover on `...` or `_` as if it were `..` to avoid further errors.
2019-08-12 12:27:43 +02:00
/// See issue #46718.
2023-01-15 21:31:04 +00:00
fn recover_bad_dot_dot ( & self ) {
if self . token = = token ::DotDot {
2019-08-12 12:27:43 +02:00
return ;
}
2023-01-15 21:31:04 +00:00
let token_str = pprust ::token_to_string ( & self . token ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( DotDotDotForRemainingFields { span : self . token . span , token_str } ) ;
2019-08-12 12:27:43 +02:00
}
2022-08-17 12:34:33 +10:00
fn parse_pat_field ( & mut self , lo : Span , attrs : AttrVec ) -> PResult < ' a , PatField > {
2019-08-11 15:24:37 +02:00
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let hi ;
let ( subpat , fieldname , is_shorthand ) = if self . look_ahead ( 1 , | t | t = = & token ::Colon ) {
2019-09-06 03:56:45 +01:00
// Parsing a pattern of the form `fieldname: pat`.
2019-08-11 15:24:37 +02:00
let fieldname = self . parse_field_name ( ) ? ;
self . bump ( ) ;
2024-11-24 17:36:52 +01:00
let pat = self . parse_pat_allow_top_guard (
2022-01-12 20:43:24 +00:00
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
) ? ;
2019-08-11 15:24:37 +02:00
hi = pat . span ;
( pat , fieldname , false )
} else {
2019-09-06 03:56:45 +01:00
// Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
2024-12-04 15:55:06 +11:00
let is_box = self . eat_keyword ( exp! ( Box ) ) ;
2019-08-11 15:24:37 +02:00
let boxed_span = self . token . span ;
2024-03-23 21:04:45 -04:00
let mutability = self . parse_mutability ( ) ;
let by_ref = self . parse_byref ( ) ;
2021-01-20 21:49:11 -05:00
let fieldname = self . parse_field_name ( ) ? ;
2020-02-29 14:56:15 +03:00
hi = self . prev_token . span ;
2024-04-16 19:23:30 -04:00
let ann = BindingMode ( by_ref , mutability ) ;
2022-08-30 17:34:35 -05:00
let fieldpat = self . mk_pat_ident ( boxed_span . to ( hi ) , ann , fieldname ) ;
2019-08-11 15:24:37 +02:00
let subpat =
if is_box { self . mk_pat ( lo . to ( hi ) , PatKind ::Box ( fieldpat ) ) } else { fieldpat } ;
( subpat , fieldname , true )
} ;
2021-03-16 00:36:07 +03:00
Ok ( PatField {
2019-08-15 02:35:36 +03:00
ident : fieldname ,
pat : subpat ,
is_shorthand ,
2022-08-17 12:34:33 +10:00
attrs ,
2019-08-15 02:35:36 +03:00
id : ast ::DUMMY_NODE_ID ,
2019-08-11 15:24:37 +02:00
span : lo . to ( hi ) ,
2019-09-09 09:26:25 -03:00
is_placeholder : false ,
2019-08-11 15:24:37 +02:00
} )
}
2024-04-16 19:23:30 -04:00
pub ( super ) fn mk_pat_ident ( & self , span : Span , ann : BindingMode , ident : Ident ) -> P < Pat > {
2022-08-30 17:34:35 -05:00
self . mk_pat ( span , PatKind ::Ident ( ann , ident , None ) )
2019-08-11 15:24:37 +02:00
}
2021-11-21 04:56:32 +00:00
pub ( super ) fn mk_pat ( & self , span : Span , kind : PatKind ) -> P < Pat > {
2020-07-27 18:02:29 -04:00
P ( Pat { kind , span , id : ast ::DUMMY_NODE_ID , tokens : None } )
2019-08-11 15:24:37 +02:00
}
}