2021-01-22 18:28:08 +00:00
use super ::{ ForceCollect , Parser , PathStyle , TrailingToken } ;
2023-01-28 21:16:50 +00:00
use crate ::errors ::{
2023-04-27 00:53:06 +00:00
self , AmbiguousRangePattern , DotDotDotForRemainingFields , DotDotDotRangeToPatternNotAllowed ,
2022-10-14 21:16:25 +00:00
DotDotDotRestPattern , EnumPatternInsteadOfIdentifier , ExpectedBindingLeftOfAt ,
ExpectedCommaAfterPatternField , InclusiveRangeExtraEquals , InclusiveRangeMatchArrow ,
InclusiveRangeNoEnd , InvalidMutInPattern , PatternOnWrongSideOfAt , RefMutOrderIncorrect ,
RemoveLet , RepeatedMutInPattern , TopLevelOrPatternNotAllowed , TopLevelOrPatternNotAllowedSugg ,
TrailingVertNotAllowed , UnexpectedLifetimeInPattern , UnexpectedVertVertBeforeFunctionParam ,
UnexpectedVertVertInPattern ,
2023-01-28 21:16:50 +00:00
} ;
2019-08-11 13:24:37 +00:00
use crate ::{ maybe_recover_from_interpolated_ty_qpath , maybe_whole } ;
2020-11-03 17:34:57 +00:00
use rustc_ast ::mut_visit ::{ noop_visit_pat , MutVisitor } ;
2020-02-29 17:37:32 +00:00
use rustc_ast ::ptr ::P ;
2022-04-26 12:40:14 +00:00
use rustc_ast ::token ::{ self , Delimiter } ;
2021-07-15 15:36:19 +00:00
use rustc_ast ::{
2022-08-30 22:34:35 +00:00
self as ast , AttrVec , BindingAnnotation , ByRef , Expr , ExprKind , MacCall , Mutability , Pat ,
PatField , PatKind , Path , QSelf , RangeEnd , RangeSyntax ,
2021-07-15 15:36:19 +00:00
} ;
2020-01-11 16:02:46 +00:00
use rustc_ast_pretty ::pprust ;
2022-10-13 09:13:02 +00:00
use rustc_errors ::{ Applicability , DiagnosticBuilder , ErrorGuaranteed , IntoDiagnostic , PResult } ;
2022-09-30 01:38:15 +00:00
use rustc_session ::errors ::ExprParenthesesNeeded ;
2019-12-31 17:15:40 +00:00
use rustc_span ::source_map ::{ respan , Span , Spanned } ;
2020-04-19 11:00:18 +00:00
use rustc_span ::symbol ::{ kw , sym , Ident } ;
2023-01-30 03:58:23 +00:00
use thin_vec ::{ thin_vec , ThinVec } ;
2019-08-11 13:24:37 +00:00
2022-11-08 21:03:17 +00:00
#[ derive(PartialEq, Copy, Clone) ]
pub enum Expected {
ParameterName ,
ArgumentName ,
Identifier ,
BindingPattern ,
}
2019-08-18 13:31:34 +00:00
2022-11-08 21:03:17 +00: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 02:39:28 +00:00
2019-09-29 04:21:20 +00:00
const WHILE_PARSING_OR_MSG : & str = " while parsing this or-pattern starting here " ;
2019-08-25 04:15:11 +00:00
/// Whether or not to recover a `,` when parsing or-patterns.
2019-08-24 20:12:19 +00:00
#[ derive(PartialEq, Copy, Clone) ]
2021-02-08 02:40:33 +00:00
pub enum RecoverComma {
2019-08-25 04:15:11 +00:00
Yes ,
No ,
}
2019-08-24 20:12:19 +00:00
2021-07-13 11:18:03 +00: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-13 00:04:37 +00: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 21:16:25 +00:00
/// The syntax location of a given pattern. Used for diagnostics.
pub ( super ) enum PatternLocation {
LetBinding ,
FunctionParameter ,
}
2019-08-11 13:24:37 +00:00
impl < ' a > Parser < ' a > {
/// Parses a pattern.
2019-08-18 20:35:53 +00:00
///
/// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
/// at the top level. Used when parsing the parameters of lambda expressions,
/// functions, function pointers, and `pat` macro fragments.
2022-11-08 21:03:17 +00:00
pub fn parse_pat_no_top_alt ( & mut self , expected : Option < Expected > ) -> PResult < ' a , P < Pat > > {
2019-08-11 13:24:37 +00:00
self . parse_pat_with_range_pat ( true , expected )
}
2021-02-08 02:40:33 +00:00
/// Parses a pattern.
///
2019-08-18 20:04:28 +00:00
/// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
2021-02-08 02:40:33 +00:00
/// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
///
/// 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.
pub fn parse_pat_allow_top_alt (
2020-11-11 00:00:53 +00:00
& mut self ,
2022-11-08 21:03:17 +00:00
expected : Option < Expected > ,
2020-11-11 00:00:53 +00:00
rc : RecoverComma ,
2021-07-13 11:18:03 +00:00
ra : RecoverColon ,
2022-01-12 20:43:24 +00:00
rt : CommaRecoveryMode ,
2020-11-11 00:00:53 +00:00
) -> PResult < ' a , P < Pat > > {
2022-01-12 20:43:24 +00:00
self . parse_pat_allow_top_alt_inner ( expected , rc , ra , rt ) . map ( | ( pat , _ ) | pat )
2021-02-13 00:04:37 +00:00
}
/// Returns the pattern and a bool indicating whether we recovered from a trailing vert (true =
/// recovered).
fn parse_pat_allow_top_alt_inner (
& mut self ,
2022-11-08 21:03:17 +00:00
expected : Option < Expected > ,
2021-02-13 00:04:37 +00:00
rc : RecoverComma ,
2021-07-13 11:18:03 +00:00
ra : RecoverColon ,
2022-01-12 20:43:24 +00:00
rt : CommaRecoveryMode ,
2021-02-13 00:04:37 +00: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 20:04:28 +00:00
// Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
2021-02-13 00:04:37 +00: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 13:28:14 +00:00
2019-09-29 04:21:20 +00:00
// Parse the first pattern (`p_0`).
2022-05-19 06:04:35 +00:00
let mut first_pat = self . parse_pat_no_top_alt ( expected ) ? ;
2022-05-19 06:07:55 +00:00
if rc = = RecoverComma ::Yes {
self . maybe_recover_unexpected_comma ( first_pat . span , rt ) ? ;
}
2019-07-14 01:05:52 +00:00
2019-08-18 13:45:44 +00:00
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
2019-08-18 14:35:19 +00:00
if ! self . check ( & token ::BinOp ( token ::Or ) ) & & self . token ! = token ::OrOr {
2021-02-08 02:40:33 +00: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 11:18:03 +00:00
2021-11-21 04:56:32 +00:00
// Check if the user wrote `foo:bar` instead of `foo::bar`.
2022-05-19 06:04:35 +00: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 06:04:35 +00:00
}
2021-07-13 11:18:03 +00:00
2021-02-08 02:40:33 +00: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 00:55:16 +00:00
return Ok ( ( self . mk_pat ( span , PatKind ::Or ( thin_vec! [ first_pat ] ) ) , trailing_vert ) ) ;
2021-02-08 02:40:33 +00:00
}
2021-02-13 00:04:37 +00:00
return Ok ( ( first_pat , trailing_vert ) ) ;
2019-07-14 01:05:52 +00:00
}
2019-09-29 04:21:20 +00:00
// Parse the patterns `p_1 | ... | p_n` where `n > 0`.
2021-02-08 02:40:33 +00:00
let lo = leading_vert_span . unwrap_or ( first_pat . span ) ;
2022-11-23 00:55:16 +00:00
let mut pats = thin_vec! [ first_pat ] ;
2021-02-13 00:04:37 +00:00
loop {
match self . eat_or_separator ( Some ( lo ) ) {
EatOrResult ::AteOr = > { }
EatOrResult ::None = > break ,
EatOrResult ::TrailingVert = > {
trailing_vert = true ;
break ;
}
}
2021-02-08 02:40:33 +00:00
let pat = self . parse_pat_no_top_alt ( expected ) . map_err ( | mut err | {
2019-09-29 04:21:20 +00:00
err . span_label ( lo , WHILE_PARSING_OR_MSG ) ;
2019-08-24 23:50:21 +00:00
err
} ) ? ;
2022-05-19 06:07:55 +00:00
if rc = = RecoverComma ::Yes {
self . maybe_recover_unexpected_comma ( pat . span , rt ) ? ;
}
2019-08-18 15:44:27 +00:00
pats . push ( pat ) ;
2019-07-14 01:05:52 +00:00
}
2020-02-29 11:56:15 +00:00
let or_pattern_span = lo . to ( self . prev_token . span ) ;
2019-07-14 01:05:52 +00:00
2021-02-13 00:04:37 +00:00
Ok ( ( self . mk_pat ( or_pattern_span , PatKind ::Or ( pats ) ) , trailing_vert ) )
2019-07-14 01:05:52 +00:00
}
2021-02-13 00:04:37 +00: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 21:03:17 +00:00
expected : Option < Expected > ,
2021-02-13 00:04:37 +00:00
rc : RecoverComma ,
2022-10-14 21:16:25 +00:00
syntax_loc : PatternLocation ,
2021-02-13 00:04:37 +00: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.
2022-01-12 20:43:24 +00:00
let ( pat , trailing_vert ) = self . parse_pat_allow_top_alt_inner (
expected ,
rc ,
RecoverColon ::No ,
CommaRecoveryMode ::LikelyTuple ,
) ? ;
2021-02-13 00:04:37 +00:00
let colon = self . eat ( & token ::Colon ) ;
if let PatKind ::Or ( pats ) = & pat . kind {
2022-10-14 21:16:25 +00:00
let span = pat . span ;
2023-07-20 09:51:47 +00:00
let pat = pprust ::pat_to_string ( & pat ) ;
let sub = if pats . len ( ) = = 1 {
Some ( TopLevelOrPatternNotAllowedSugg ::RemoveLeadingVert { span , pat } )
2021-02-13 00:04:37 +00:00
} else {
2023-07-20 09:51:47 +00:00
Some ( TopLevelOrPatternNotAllowedSugg ::WrapInParens { span , pat } )
} ;
2022-10-14 21:16:25 +00:00
2023-07-20 09:51:47 +00:00
let mut err = self . sess . create_err ( match syntax_loc {
PatternLocation ::LetBinding = > {
TopLevelOrPatternNotAllowed ::LetBinding { span , sub }
}
PatternLocation ::FunctionParameter = > {
TopLevelOrPatternNotAllowed ::FunctionParameter { span , sub }
}
} ) ;
if trailing_vert {
err . delay_as_bug ( ) ;
2021-02-13 00:04:37 +00:00
}
2023-07-20 09:51:47 +00:00
err . emit ( ) ;
2021-02-13 00:04:37 +00: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-08 02:40:33 +00: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 {
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( UnexpectedVertVertBeforeFunctionParam { span : self . token . span } ) ;
2021-02-08 02:40:33 +00:00
self . bump ( ) ;
}
2022-10-14 21:16:25 +00:00
self . parse_pat_before_ty (
2022-11-08 21:03:17 +00:00
Some ( Expected ::ParameterName ) ,
2022-10-14 21:16:25 +00:00
RecoverComma ::No ,
PatternLocation ::FunctionParameter ,
)
2021-02-08 02:40:33 +00:00
}
2019-08-18 16:13:19 +00:00
/// Eat the or-pattern `|` separator.
/// If instead a `||` token is encountered, recover and pretend we parsed `|`.
2021-02-13 00:04:37 +00:00
fn eat_or_separator ( & mut self , lo : Option < Span > ) -> EatOrResult {
2019-09-29 04:21:20 +00:00
if self . recover_trailing_vert ( lo ) {
2021-02-13 00:04:37 +00:00
EatOrResult ::TrailingVert
} else if matches! ( self . token . kind , token ::OrOr ) {
// Found `||`; Recover and pretend we parsed `|`.
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( UnexpectedVertVertInPattern { span : self . token . span , start : lo } ) ;
2021-02-13 00:04:37 +00:00
self . bump ( ) ;
EatOrResult ::AteOr
} else if self . eat ( & token ::BinOp ( token ::Or ) ) {
EatOrResult ::AteOr
} else {
EatOrResult ::None
2019-08-18 16:13:19 +00:00
}
}
2019-09-29 04:21:20 +00: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-27 01:02:48 +00:00
let is_end_ahead = self . look_ahead ( 1 , | token | {
matches! (
& token . uninterpolate ( ) . kind ,
token ::FatArrow // e.g. `a | => 0,`.
2021-02-13 00:04:37 +00:00
| token ::Ident ( kw ::If , false ) // e.g. `a | if expr`.
| 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 12:40:14 +00: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-27 01:02:48 +00:00
)
2019-09-29 04:21:20 +00:00
} ) ;
match ( is_end_ahead , & self . token . kind ) {
2020-04-17 00:38:52 +00:00
( true , token ::BinOp ( token ::Or ) | token ::OrOr ) = > {
2022-10-14 21:16:25 +00:00
// A `|` or possibly `||` token shouldn't be here. Ban it.
self . sess . emit_err ( TrailingVertNotAllowed {
span : self . token . span ,
start : lo ,
token : self . token . clone ( ) ,
note_double_vert : matches ! ( self . token . kind , token ::OrOr ) . then_some ( ( ) ) ,
} ) ;
2019-09-29 04:21:20 +00:00
self . bump ( ) ;
true
}
_ = > false ,
}
}
2019-08-11 13:24:37 +00: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 21:03:17 +00:00
expected : Option < Expected > ,
2019-08-11 13:24:37 +00:00
) -> PResult < ' a , P < Pat > > {
maybe_recover_from_interpolated_ty_qpath! ( self , true ) ;
maybe_whole! ( self , NtPat , | x | x ) ;
2022-09-03 05:39:46 +00:00
let mut lo = self . token . span ;
if self . token . is_keyword ( kw ::Let ) & & self . look_ahead ( 1 , | tok | tok . can_begin_pattern ( ) ) {
self . bump ( ) ;
self . sess . emit_err ( RemoveLet { span : lo } ) ;
lo = self . token . span ;
}
2019-12-11 09:04:34 +00:00
let pat = if self . check ( & token ::BinOp ( token ::And ) ) | | self . token . kind = = token ::AndAnd {
self . parse_pat_deref ( expected ) ?
2022-04-26 12:40:14 +00:00
} else if self . check ( & token ::OpenDelim ( Delimiter ::Parenthesis ) ) {
2019-12-11 09:04:34 +00:00
self . parse_pat_tuple_or_parens ( ) ?
2022-04-26 12:40:14 +00:00
} else if self . check ( & token ::OpenDelim ( Delimiter ::Bracket ) ) {
2019-12-11 09:04:34 +00:00
// Parse `[pat, pat,...]` as a slice pattern.
2022-04-26 12:40:14 +00:00
let ( pats , _ ) = self . parse_delim_comma_seq ( Delimiter ::Bracket , | p | {
2022-01-12 20:43:24 +00:00
p . parse_pat_allow_top_alt (
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
)
2021-02-08 02:40:33 +00:00
} ) ? ;
2019-12-11 09:04:34 +00:00
PatKind ::Slice ( pats )
} else if self . check ( & token ::DotDot ) & & ! self . is_pat_range_end_start ( 1 ) {
// A rest pattern `..`.
self . bump ( ) ; // `..`
PatKind ::Rest
2020-03-26 05:06:52 +00:00
} else if self . check ( & token ::DotDotDot ) & & ! self . is_pat_range_end_start ( 1 ) {
self . recover_dotdotdot_rest_pat ( lo )
2019-12-11 09:04:34 +00:00
} else if let Some ( form ) = self . parse_range_end ( ) {
self . parse_pat_range_to ( form ) ? // `..=X`, `...X`, or `..X`.
} else if self . eat_keyword ( kw ::Underscore ) {
// Parse _
PatKind ::Wild
} else if self . eat_keyword ( kw ::Mut ) {
self . parse_pat_ident_mut ( ) ?
} else if self . eat_keyword ( kw ::Ref ) {
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self . parse_mutability ( ) ;
2022-08-30 22:34:35 +00:00
self . parse_pat_ident ( BindingAnnotation ( ByRef ::Yes , mutbl ) ) ?
2019-12-11 09:04:34 +00:00
} else if self . eat_keyword ( kw ::Box ) {
2022-06-08 04:40:55 +00:00
self . parse_pat_box ( ) ?
2020-10-19 21:44:37 +00:00
} else if self . check_inline_const ( 0 ) {
2020-09-23 21:34:44 +00: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 19:18:47 +00:00
if let Some ( re ) = self . parse_range_end ( ) {
self . parse_pat_range_begin_with ( const_expr , re ) ?
} else {
PatKind ::Lit ( const_expr )
}
2023-03-17 09:27:17 +00: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.
} else if self . can_be_ident_pat ( )
| | ( self . is_lit_bad_ident ( ) . is_some ( ) & & self . may_recover ( ) )
{
2019-12-11 09:04:34 +00:00
// Parse `ident @ pat`
// This can give false positives and parse nullary enums,
// they are dealt with later in resolve.
2022-08-30 22:34:35 +00:00
self . parse_pat_ident ( BindingAnnotation ::NONE ) ?
2019-12-11 09:04:34 +00: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 20:46:06 +00:00
let ( qself , path ) = self . parse_qpath ( PathStyle ::Pat ) ? ;
2019-12-11 09:04:34 +00:00
( Some ( qself ) , path )
} else {
// Parse an unqualified path
2022-11-16 20:46:06 +00:00
( None , self . parse_path ( PathStyle ::Pat ) ? )
2019-12-11 09:04:34 +00:00
} ;
2020-02-29 11:56:15 +00:00
let span = lo . to ( self . prev_token . span ) ;
2019-12-11 09:04:34 +00:00
if qself . is_none ( ) & & self . check ( & token ::Not ) {
self . parse_pat_mac_invoc ( path ) ?
} else if let Some ( form ) = self . parse_range_end ( ) {
2022-08-14 23:58:38 +00:00
let begin = self . mk_expr ( span , ExprKind ::Path ( qself , path ) ) ;
2019-12-11 09:04:34 +00:00
self . parse_pat_range_begin_with ( begin , form ) ?
2022-04-26 12:40:14 +00:00
} else if self . check ( & token ::OpenDelim ( Delimiter ::Brace ) ) {
2019-12-11 09:04:34 +00:00
self . parse_pat_struct ( qself , path ) ?
2022-04-26 12:40:14 +00:00
} else if self . check ( & token ::OpenDelim ( Delimiter ::Parenthesis ) ) {
2019-12-11 09:04:34 +00:00
self . parse_pat_tuple_struct ( qself , path ) ?
} else {
PatKind ::Path ( qself , path )
2019-08-11 13:24:37 +00:00
}
2022-09-01 18:48:09 +00:00
} else if matches! ( self . token . kind , token ::Lifetime ( _ ) )
// 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 = ..`
& & ! 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 03:39:56 +00:00
let ( lit , _ ) =
self . recover_unclosed_char ( lt . ident , Parser ::mk_token_lit_char , | self_ | {
2022-11-08 21:03:17 +00:00
let expected = Expected ::to_string_or_fallback ( expected ) ;
2022-12-05 03:39:56 +00:00
let msg = format! (
" expected {}, found {} " ,
expected ,
super ::token_descr ( & self_ . token )
) ;
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
let mut err = self_ . struct_span_err ( self_ . token . span , msg ) ;
2022-12-05 03:39:56 +00:00
err . span_label ( self_ . token . span , format! ( " expected {} " , expected ) ) ;
err
} ) ;
PatKind ::Lit ( self . mk_expr ( lo , ExprKind ::Lit ( lit ) ) )
2019-12-11 09:04:34 +00:00
} else {
// Try to parse everything else as literal with optional minus
match self . parse_literal_maybe_minus ( ) {
Ok ( begin ) = > match self . parse_range_end ( ) {
Some ( form ) = > self . parse_pat_range_begin_with ( begin , form ) ? ,
None = > PatKind ::Lit ( begin ) ,
} ,
Err ( err ) = > return self . fatal_unexpected_non_pat ( err , expected ) ,
2019-08-11 13:24:37 +00:00
}
2019-08-12 05:34:08 +00:00
} ;
2019-08-11 13:24:37 +00:00
2020-02-29 11:56:15 +00:00
let pat = self . mk_pat ( lo . to ( self . prev_token . span ) , pat ) ;
2022-05-19 05:51:49 +00:00
let pat = self . maybe_recover_from_bad_qpath ( pat ) ? ;
2019-10-14 14:47:12 +00:00
let pat = self . recover_intersection_pat ( pat ) ? ;
2019-08-11 13:24:37 +00:00
if ! allow_range_pat {
2019-12-11 09:04:34 +00:00
self . ban_pat_range_if_ambiguous ( & pat )
2019-08-11 13:24:37 +00:00
}
Ok ( pat )
}
2020-03-26 05:06:52 +00:00
/// 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 `..`.
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( DotDotDotRestPattern { span : lo } ) ;
2020-03-26 05:06:52 +00:00
PatKind ::Rest
}
2019-10-14 14:47:12 +00: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 17:23:40 +00:00
/// should already have been parsed by now at this point,
2019-10-14 14:47:12 +00: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 > > {
if self . token . kind ! = token ::At {
// 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 ( ) ; // `@`
2021-02-08 02:40:33 +00:00
let mut rhs = self . parse_pat_no_top_alt ( None ) ? ;
2022-10-14 21:16:25 +00:00
let whole_span = lhs . span . to ( rhs . span ) ;
2019-10-14 14:47:12 +00:00
2022-11-22 09:42:01 +00:00
if let PatKind ::Ident ( _ , _ , sub @ None ) = & mut rhs . kind {
2019-10-14 14:47:12 +00: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 ) ;
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( PatternOnWrongSideOfAt {
whole_span ,
whole_pat : pprust ::pat_to_string ( & rhs ) ,
pattern : lhs_span ,
binding : rhs . span ,
} ) ;
2019-10-14 15:25:50 +00:00
} else {
// The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
rhs . kind = PatKind ::Wild ;
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( ExpectedBindingLeftOfAt {
whole_span ,
lhs : lhs . span ,
rhs : rhs . span ,
} ) ;
2019-10-14 14:47:12 +00:00
}
2022-10-14 21:16:25 +00:00
rhs . span = whole_span ;
2019-10-14 15:25:50 +00:00
Ok ( rhs )
2019-10-14 14:47:12 +00:00
}
2019-08-12 06:16:04 +00:00
/// Ban a range pattern if it has an ambiguous interpretation.
2019-12-11 09:04:34 +00:00
fn ban_pat_range_if_ambiguous ( & self , pat : & Pat ) {
2019-09-26 15:18:31 +00:00
match pat . kind {
2019-08-12 06:16:04 +00:00
PatKind ::Range (
.. ,
Spanned { node : RangeEnd ::Included ( RangeSyntax ::DotDotDot ) , .. } ,
2019-12-11 09:04:34 +00:00
) = > return ,
2019-08-12 06:16:04 +00:00
PatKind ::Range ( .. ) = > { }
2019-12-11 09:04:34 +00:00
_ = > return ,
2019-08-12 06:16:04 +00:00
}
2022-10-14 21:16:25 +00:00
self . sess
. emit_err ( AmbiguousRangePattern { span : pat . span , pat : pprust ::pat_to_string ( & pat ) } ) ;
2019-08-12 06:16:04 +00:00
}
2019-08-12 05:37:08 +00:00
/// Parse `&pat` / `&mut pat`.
2022-11-08 21:03:17 +00:00
fn parse_pat_deref ( & mut self , expected : Option < Expected > ) -> PResult < ' a , PatKind > {
2019-08-12 05:37:08 +00:00
self . expect_and ( ) ? ;
if let token ::Lifetime ( name ) = self . token . kind {
2019-12-12 23:59:33 +00:00
self . bump ( ) ; // `'a`
2022-10-14 21:16:25 +00:00
self . sess
. emit_err ( UnexpectedLifetimeInPattern { span : self . prev_token . span , symbol : name } ) ;
2019-08-12 05:37:08 +00:00
}
2022-10-14 21:16:25 +00:00
let mutbl = self . parse_mutability ( ) ;
let subpat = self . parse_pat_with_range_pat ( false , expected ) ? ;
Ok ( PatKind ::Ref ( subpat , mutbl ) )
2019-08-12 05:37:08 +00:00
}
2019-08-12 05:41:50 +00:00
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens ( & mut self ) -> PResult < ' a , PatKind > {
2021-07-13 11:18:03 +00:00
let ( fields , trailing_comma ) = self . parse_paren_comma_seq ( | p | {
2022-01-12 20:43:24 +00:00
p . parse_pat_allow_top_alt (
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::LikelyTuple ,
)
2021-07-13 11:18:03 +00:00
} ) ? ;
2019-08-12 05:41:50 +00:00
// Here, `(pat,)` is a tuple pattern.
// For backward compatibility, `(..)` is a tuple pattern as well.
Ok ( if fields . len ( ) = = 1 & & ! ( trailing_comma | | fields [ 0 ] . is_rest ( ) ) {
2020-03-03 00:19:00 +00:00
PatKind ::Paren ( fields . into_iter ( ) . next ( ) . unwrap ( ) )
2019-08-12 05:41:50 +00:00
} else {
PatKind ::Tuple ( fields )
} )
}
2019-08-27 17:51:21 +00:00
/// Parse a mutable binding with the `mut` token already eaten.
2019-08-27 11:04:48 +00:00
fn parse_pat_ident_mut ( & mut self ) -> PResult < ' a , PatKind > {
2020-02-29 11:56:15 +00:00
let mut_span = self . prev_token . span ;
2019-08-27 11:04:48 +00:00
if self . eat_keyword ( kw ::Ref ) {
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( RefMutOrderIncorrect { span : mut_span . to ( self . prev_token . span ) } ) ;
return self . parse_pat_ident ( BindingAnnotation ::REF_MUT ) ;
2019-08-27 11:04:48 +00:00
}
self . recover_additional_muts ( ) ;
2019-08-27 17:51:21 +00:00
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
2022-11-22 09:42:01 +00:00
if let token ::Interpolated ( nt ) = & self . token . kind {
2019-08-27 17:51:21 +00:00
if let token ::NtPat ( _ ) = * * nt {
2023-03-17 09:27:17 +00:00
self . expected_ident_found_err ( ) . emit ( ) ;
2019-08-27 17:51:21 +00:00
}
}
// Parse the pattern we hope to be an identifier.
2022-11-08 21:03:17 +00:00
let mut pat = self . parse_pat_no_top_alt ( Some ( Expected ::Identifier ) ) ? ;
2019-08-27 11:04:48 +00:00
2020-02-17 15:03:07 +00:00
// If we don't have `mut $ident (@ pat)?`, error.
2022-08-30 22:34:35 +00:00
if let PatKind ::Ident ( BindingAnnotation ( ByRef ::No , m @ Mutability ::Not ) , .. ) = & mut pat . kind
{
2020-02-17 15:03:07 +00:00
// Don't recurse into the subpattern.
// `mut` on the outer binding doesn't affect the inner bindings.
* 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 11:04:48 +00:00
}
2020-02-17 15:03:07 +00:00
Ok ( pat . into_inner ( ) . kind )
2019-08-27 11:04:48 +00:00
}
2019-08-27 21:44:44 +00: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 > ) {
2022-08-30 22:34:35 +00:00
if let PatKind ::Ident ( BindingAnnotation ( ByRef ::No , m @ Mutability ::Not ) , .. ) =
& mut pat . kind
2020-02-17 15:03:07 +00:00
{
2019-08-27 21:44:44 +00:00
self . 0 = true ;
2020-02-17 15:03:07 +00:00
* m = Mutability ::Mut ;
2019-08-27 21:44:44 +00:00
}
noop_visit_pat ( pat , self ) ;
}
}
let mut add_mut = AddMut ( false ) ;
add_mut . visit_pat ( pat ) ;
add_mut . 0
}
2019-08-27 11:04:48 +00:00
/// Error on `mut $pat` where `$pat` is not an ident.
2019-08-27 21:44:44 +00:00
fn ban_mut_general_pat ( & self , lo : Span , pat : & Pat , changed_any_binding : bool ) {
2019-08-27 11:04:48 +00:00
let span = lo . to ( pat . span ) ;
2022-10-14 21:16:25 +00:00
let pat = pprust ::pat_to_string ( & pat ) ;
self . sess . emit_err ( if changed_any_binding {
InvalidMutInPattern ::NestedIdent { span , pat }
2019-08-12 05:45:55 +00:00
} else {
2022-10-14 21:16:25 +00:00
InvalidMutInPattern ::NonIdent { span , pat }
} ) ;
2019-08-27 11:04:48 +00:00
}
/// Eat any extraneous `mut`s and error + recover if we ate any.
fn recover_additional_muts ( & mut self ) {
let lo = self . token . span ;
while self . eat_keyword ( kw ::Mut ) { }
if lo = = self . token . span {
return ;
}
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( RepeatedMutInPattern { span : lo . to ( self . prev_token . span ) } ) ;
2019-08-12 05:45:55 +00:00
}
2019-08-12 06:27:01 +00:00
/// Parse macro invocation
2019-12-01 12:55:32 +00:00
fn parse_pat_mac_invoc ( & mut self , path : Path ) -> PResult < ' a , PatKind > {
2019-08-12 06:27:01 +00:00
self . bump ( ) ;
2022-11-18 00:24:21 +00:00
let args = self . parse_delim_args ( ) ? ;
2022-11-16 20:46:06 +00:00
let mac = P ( MacCall { path , args } ) ;
2020-02-29 16:32:20 +00:00
Ok ( PatKind ::MacCall ( mac ) )
2019-08-12 06:27:01 +00:00
}
2019-08-12 09:39:44 +00:00
fn fatal_unexpected_non_pat (
& mut self ,
2022-01-23 18:34:26 +00:00
err : DiagnosticBuilder < ' a , ErrorGuaranteed > ,
2022-11-08 21:03:17 +00:00
expected : Option < Expected > ,
2019-08-12 09:39:44 +00:00
) -> PResult < ' a , P < Pat > > {
2019-09-07 14:38:02 +00:00
err . cancel ( ) ;
2019-08-12 09:39:44 +00:00
2022-11-08 21:03:17 +00:00
let expected = Expected ::to_string_or_fallback ( expected ) ;
2019-12-07 02:07:35 +00:00
let msg = format! ( " expected {} , found {} " , expected , super ::token_descr ( & self . token ) ) ;
2019-08-12 09:39:44 +00:00
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
let mut err = self . struct_span_err ( self . token . span , msg ) ;
2019-08-12 09:39:44 +00:00
err . span_label ( self . token . span , format! ( " expected {} " , expected ) ) ;
let sp = self . sess . source_map ( ) . start_point ( self . token . span ) ;
if let Some ( sp ) = self . sess . ambiguous_block_expr_parse . borrow ( ) . get ( & sp ) {
2022-09-30 01:38:15 +00:00
err . subdiagnostic ( ExprParenthesesNeeded ::surrounding ( * sp ) ) ;
2019-08-12 09:39:44 +00:00
}
Err ( err )
}
2019-12-11 09:04:34 +00:00
/// Parses the range pattern end form `".." | "..." | "..=" ;`.
fn parse_range_end ( & mut self ) -> Option < Spanned < RangeEnd > > {
let re = if self . eat ( & token ::DotDotDot ) {
RangeEnd ::Included ( RangeSyntax ::DotDotDot )
} else if self . eat ( & token ::DotDotEq ) {
RangeEnd ::Included ( RangeSyntax ::DotDotEq )
} else if self . eat ( & token ::DotDot ) {
RangeEnd ::Excluded
} else {
return None ;
} ;
2020-02-29 11:56:15 +00:00
Some ( respan ( self . prev_token . span , re ) )
2019-08-11 13:24:37 +00:00
}
2019-12-11 09:04:34 +00: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 13:24:37 +00:00
// Parsing e.g. `X..=Y`.
2019-12-11 09:04:34 +00:00
Some ( self . parse_pat_range_end ( ) ? )
2019-08-11 13:24:37 +00:00
} else {
// Parsing e.g. `X..`.
2019-12-11 09:04:34 +00: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 09:04:34 +00:00
}
None
} ;
Ok ( PatKind ::Range ( Some ( begin ) , end , re ) )
}
2019-08-11 13:24:37 +00:00
2023-01-28 20:02:00 +00:00
pub ( super ) fn inclusive_range_with_incorrect_end ( & mut self ) {
2021-06-26 02:46:41 +00:00
let tok = & self . token ;
2023-01-28 20:02:00 +00:00
let span = self . prev_token . span ;
2021-06-26 02:46:41 +00: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-26 02:46:41 +00: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-26 02:46:41 +00: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-26 02:46:41 +00:00
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( InclusiveRangeExtraEquals { span : span_with_eq } ) ;
2023-01-28 20:02:00 +00:00
}
token ::Gt if no_space = > {
2022-10-14 21:16:25 +00:00
let after_pat = span . with_hi ( span . hi ( ) - rustc_span ::BytePos ( 1 ) ) . shrink_to_hi ( ) ;
2023-01-30 23:47:10 +00:00
self . sess . emit_err ( InclusiveRangeMatchArrow { span , arrow : tok . span , after_pat } ) ;
2022-10-14 21:16:25 +00:00
}
_ = > {
self . sess . emit_err ( InclusiveRangeNoEnd { span } ) ;
2023-01-28 20:02:00 +00:00
}
2021-06-26 02:46:41 +00:00
}
}
2020-01-11 05:49:43 +00: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 09:04:34 +00: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 05:49:43 +00:00
* syn = RangeSyntax ::DotDotEq ;
2022-10-14 21:16:25 +00:00
self . sess . emit_err ( DotDotDotRangeToPatternNotAllowed { span : re . span } ) ;
2020-01-11 05:49:43 +00:00
}
2019-12-11 09:04:34 +00: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 21:44:37 +00:00
fn is_pat_range_end_start ( & self , dist : usize ) -> bool {
self . check_inline_const ( dist )
2020-10-19 19:18:47 +00:00
| | self . look_ahead ( dist , | t | {
t . is_path_start ( ) // e.g. `MY_CONST`;
2019-12-11 09:04:34 +00:00
| | t . kind = = token ::Dot // e.g. `.5` for recovery;
2020-03-16 22:36:14 +00:00
| | t . can_begin_literal_maybe_minus ( ) // e.g. `42`.
2019-12-11 09:04:34 +00:00
| | t . is_whole_expr ( )
2022-09-01 18:48:09 +00:00
| | t . is_lifetime ( ) // recover `'a` instead of `'a'`
2020-10-19 19:18:47 +00:00
} )
2019-08-11 13:24:37 +00:00
}
fn parse_pat_range_end ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-10-19 21:44:37 +00:00
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 19:18:47 +00:00
} else if self . check_path ( ) {
2019-08-11 13:24:37 +00:00
let lo = self . token . span ;
let ( qself , path ) = if self . eat_lt ( ) {
// Parse a qualified path
2022-11-16 20:46:06 +00:00
let ( qself , path ) = self . parse_qpath ( PathStyle ::Pat ) ? ;
2019-08-11 13:24:37 +00:00
( Some ( qself ) , path )
} else {
// Parse an unqualified path
2022-11-16 20:46:06 +00:00
( None , self . parse_path ( PathStyle ::Pat ) ? )
2019-08-11 13:24:37 +00:00
} ;
2020-02-29 11:56:15 +00:00
let hi = self . prev_token . span ;
2022-08-14 23:58:38 +00:00
Ok ( self . mk_expr ( lo . to ( hi ) , ExprKind ::Path ( qself , path ) ) )
2019-08-11 13:24:37 +00:00
} else {
self . parse_literal_maybe_minus ( )
}
}
2019-08-27 11:04:48 +00: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 14:55:26 +00:00
// Try to do something more complex?
2022-04-26 12:40:14 +00: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 11:04:48 +00:00
| token ::DotDotDot | token ::DotDotEq | token ::DotDot // A range pattern.
| token ::ModSep // A tuple / struct variant pattern.
2020-10-27 14:55:26 +00:00
| token ::Not ) ) // A macro expanding to a pattern.
2023-08-01 15:30:40 +00:00
& & ! ( self . look_ahead ( 1 , | t | t . kind = = token ::Lt ) & & self . look_ahead ( 2 , | t | t . can_begin_type ( ) ) ) // May suggest the turbofish syntax for generics, only valid for recoveries.
2019-08-27 11:04:48 +00:00
}
2019-08-11 13:24:37 +00:00
/// Parses `ident` or `ident @ pat`.
2019-08-12 07:28:30 +00:00
/// Used by the copy foo and ref foo patterns to give a good
2019-08-11 13:24:37 +00:00
/// error message when parsing mistakes like `ref foo(a, b)`.
2022-08-30 22:34:35 +00:00
fn parse_pat_ident ( & mut self , binding_annotation : BindingAnnotation ) -> PResult < ' a , PatKind > {
2019-08-11 13:24:37 +00:00
let ident = self . parse_ident ( ) ? ;
let sub = if self . eat ( & token ::At ) {
2022-11-08 21:03:17 +00:00
Some ( self . parse_pat_no_top_alt ( Some ( Expected ::BindingPattern ) ) ? )
2019-08-11 13:24:37 +00:00
} else {
None
} ;
2019-08-12 07:28:30 +00: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 13:24:37 +00:00
// binding mode then we do not end up here, because the lookahead
2019-08-12 07:28:30 +00:00
// will direct us over to `parse_enum_variant()`.
2022-04-26 12:40:14 +00:00
if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2022-10-14 21:16:25 +00:00
return Err ( EnumPatternInsteadOfIdentifier { span : self . prev_token . span }
. into_diagnostic ( & self . sess . span_diagnostic ) ) ;
2019-08-11 13:24:37 +00:00
}
2022-08-30 22:34:35 +00:00
Ok ( PatKind ::Ident ( binding_annotation , ident , sub ) )
2019-08-11 13:24:37 +00:00
}
2019-08-12 10:27:43 +00:00
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
2022-09-08 00:52:51 +00:00
fn parse_pat_struct ( & mut self , qself : Option < P < QSelf > > , path : Path ) -> PResult < ' a , PatKind > {
2019-08-12 10:27:43 +00:00
if qself . is_some ( ) {
2020-12-10 12:20:07 +00:00
// Feature gate the use of qualified paths in patterns
self . sess . gated_spans . gate ( sym ::more_qualified_paths , path . span ) ;
2019-08-12 10:27:43 +00:00
}
self . bump ( ) ;
let ( fields , etc ) = self . parse_pat_fields ( ) . unwrap_or_else ( | mut e | {
2020-10-02 07:44:16 +00:00
e . span_label ( path . span , " while parsing the fields for this pattern " ) ;
2019-08-12 10:27:43 +00:00
e . emit ( ) ;
self . recover_stmt ( ) ;
2023-01-30 03:58:23 +00:00
( ThinVec ::new ( ) , true )
2019-08-12 10:27:43 +00:00
} ) ;
self . bump ( ) ;
2020-12-10 12:20:07 +00:00
Ok ( PatKind ::Struct ( qself , path , fields , etc ) )
2019-08-12 10:27:43 +00:00
}
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
2022-09-08 00:52:51 +00:00
fn parse_pat_tuple_struct (
& mut self ,
qself : Option < P < QSelf > > ,
path : Path ,
) -> PResult < ' a , PatKind > {
2021-07-13 11:18:03 +00:00
let ( fields , _ ) = self . parse_paren_comma_seq ( | p | {
2022-01-12 20:43:24 +00:00
p . parse_pat_allow_top_alt (
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
)
2021-07-13 11:18:03 +00:00
} ) ? ;
2020-12-10 12:20:07 +00:00
if qself . is_some ( ) {
self . sess . gated_spans . gate ( sym ::more_qualified_paths , path . span ) ;
}
Ok ( PatKind ::TupleStruct ( qself , path , fields ) )
2019-12-31 02:36:45 +00: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 )
}
/// 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 00:53:06 +00:00
let descr = super ::token_descr ( & self . token ) ;
self . sess . emit_err ( errors ::BoxNotPat {
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.
let sub = if self . eat ( & token ::At ) {
2022-11-08 21:03:17 +00:00
Some ( self . parse_pat_no_top_alt ( Some ( Expected ::BindingPattern ) ) ? )
2022-06-08 04:40:55 +00:00
} else {
None
} ;
2022-08-30 22:34:35 +00:00
Ok ( PatKind ::Ident ( BindingAnnotation ::NONE , Ident ::new ( kw ::Box , box_span ) , sub ) )
2022-06-08 04:40:55 +00:00
} else {
let pat = self . parse_pat_with_range_pat ( false , None ) ? ;
self . sess . gated_spans . gate ( sym ::box_patterns , box_span . to ( self . prev_token . span ) ) ;
Ok ( PatKind ::Box ( pat ) )
}
}
2019-08-11 13:24:37 +00:00
/// Parses the fields of a struct-like pattern.
2023-01-30 03:58:23 +00:00
fn parse_pat_fields ( & mut self ) -> PResult < ' a , ( ThinVec < PatField > , bool ) > {
let mut fields = ThinVec ::new ( ) ;
2019-08-11 13:24:37 +00:00
let mut etc = false ;
let mut ate_comma = true ;
2022-01-23 18:34:26 +00:00
let mut delayed_err : Option < DiagnosticBuilder < ' a , ErrorGuaranteed > > = None ;
2023-06-02 06:40:44 +00:00
let mut first_etc_and_maybe_comma_span = None ;
let mut last_non_comma_dotdot_span = None ;
2019-08-11 13:24:37 +00:00
2022-04-26 12:40:14 +00:00
while self . token ! = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 13:24:37 +00:00
let attrs = match self . parse_outer_attributes ( ) {
Ok ( attrs ) = > attrs ,
Err ( err ) = > {
if let Some ( mut delayed ) = delayed_err {
delayed . emit ( ) ;
}
return Err ( err ) ;
}
} ;
let lo = self . token . span ;
// check that a comma comes after every field
if ! ate_comma {
2022-10-14 21:16:25 +00:00
let err = ExpectedCommaAfterPatternField { span : self . token . span }
. into_diagnostic ( & self . sess . span_diagnostic ) ;
2019-08-11 13:24:37 +00:00
if let Some ( mut delayed ) = delayed_err {
delayed . emit ( ) ;
}
return Err ( err ) ;
}
ate_comma = false ;
2023-01-15 21:31:04 +00:00
if self . check ( & token ::DotDot )
| | self . check_noexpect ( & token ::DotDotDot )
| | self . check_keyword ( kw ::Underscore )
{
2019-08-11 13:24:37 +00:00
etc = true ;
let mut etc_sp = self . token . span ;
2023-06-02 06:40:44 +00: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
. sess
. source_map ( )
. span_extend_to_line ( comma_tok . span )
. trim_start ( comma_tok . span . shrink_to_lo ( ) )
. map ( | s | self . sess . source_map ( ) . span_until_non_whitespace ( s ) ) ;
first_etc_and_maybe_comma_span = nw_span . map ( | s | etc_sp . to ( s ) ) ;
} else {
first_etc_and_maybe_comma_span =
Some ( self . sess . source_map ( ) . span_until_non_whitespace ( etc_sp ) ) ;
}
}
2019-08-11 13:24:37 +00:00
2023-01-15 21:31:04 +00:00
self . recover_bad_dot_dot ( ) ;
self . bump ( ) ; // `..` || `...` || `_`
2019-08-11 13:24:37 +00:00
2022-04-26 12:40:14 +00:00
if self . token = = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 13:24:37 +00:00
break ;
}
2019-12-07 02:07:35 +00:00
let token_str = super ::token_descr ( & self . token ) ;
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
let msg = format! ( " expected ` }} `, found {} " , token_str ) ;
2019-12-31 02:36:45 +00:00
let mut err = self . struct_span_err ( self . token . span , msg ) ;
2019-08-11 13:24:37 +00:00
err . span_label ( self . token . span , " expected `}` " ) ;
let mut comma_sp = None ;
if self . token = = token ::Comma {
// Issue #49257
let nw_span = self . sess . source_map ( ) . span_until_non_whitespace ( self . token . span ) ;
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 12:40:14 +00:00
if self . token = = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 13:24:37 +00: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 06:48:40 +00:00
" " ,
2019-08-11 13:24:37 +00: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.
if let Some ( mut delayed_err ) = delayed_err {
delayed_err . emit ( ) ;
return Err ( err ) ;
} else {
delayed_err = Some ( err ) ;
}
} else {
if let Some ( mut err ) = delayed_err {
err . emit ( ) ;
}
return Err ( err ) ;
}
}
2021-01-22 18:28:08 +00:00
let field =
self . collect_tokens_trailing_token ( attrs , ForceCollect ::No , | this , attrs | {
let field = match this . parse_pat_field ( lo , attrs ) {
Ok ( field ) = > Ok ( field ) ,
Err ( err ) = > {
if let Some ( mut delayed_err ) = delayed_err . take ( ) {
delayed_err . emit ( ) ;
}
return Err ( err ) ;
}
} ? ;
ate_comma = this . eat ( & token ::Comma ) ;
2023-06-02 06:40:44 +00:00
last_non_comma_dotdot_span = Some ( this . prev_token . span ) ;
2021-01-22 18:28:08 +00:00
// We just ate a comma, so there's no need to use
// `TrailingToken::Comma`
Ok ( ( field , TrailingToken ::None ) )
} ) ? ;
fields . push ( field )
2019-08-11 13:24:37 +00:00
}
if let Some ( mut err ) = delayed_err {
2023-06-02 06:40:44 +00: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 ,
) ;
} 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 ,
) ;
}
}
2019-08-11 13:24:37 +00:00
}
err . emit ( ) ;
}
2020-03-20 14:03:11 +00:00
Ok ( ( fields , etc ) )
2019-08-11 13:24:37 +00:00
}
2023-01-15 21:31:04 +00:00
/// Recover on `...` or `_` as if it were `..` to avoid further errors.
2019-08-12 10:27:43 +00: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 10:27:43 +00:00
return ;
}
2023-01-15 21:31:04 +00:00
let token_str = pprust ::token_to_string ( & self . token ) ;
self . sess . emit_err ( DotDotDotForRemainingFields { span : self . token . span , token_str } ) ;
2019-08-12 10:27:43 +00:00
}
2022-08-17 02:34:33 +00:00
fn parse_pat_field ( & mut self , lo : Span , attrs : AttrVec ) -> PResult < ' a , PatField > {
2019-08-11 13:24:37 +00: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 02:56:45 +00:00
// Parsing a pattern of the form `fieldname: pat`.
2019-08-11 13:24:37 +00:00
let fieldname = self . parse_field_name ( ) ? ;
self . bump ( ) ;
2022-01-12 20:43:24 +00:00
let pat = self . parse_pat_allow_top_alt (
None ,
RecoverComma ::No ,
RecoverColon ::No ,
CommaRecoveryMode ::EitherTupleOrPipe ,
) ? ;
2019-08-11 13:24:37 +00:00
hi = pat . span ;
( pat , fieldname , false )
} else {
2019-09-06 02:56:45 +00:00
// Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
2019-08-11 13:24:37 +00:00
let is_box = self . eat_keyword ( kw ::Box ) ;
let boxed_span = self . token . span ;
let is_ref = self . eat_keyword ( kw ::Ref ) ;
let is_mut = self . eat_keyword ( kw ::Mut ) ;
2021-01-21 02:49:11 +00:00
let fieldname = self . parse_field_name ( ) ? ;
2020-02-29 11:56:15 +00:00
hi = self . prev_token . span ;
2019-08-11 13:24:37 +00:00
2022-08-30 22:34:35 +00:00
let mutability = match is_mut {
false = > Mutability ::Not ,
true = > Mutability ::Mut ,
2019-08-11 13:24:37 +00:00
} ;
2022-08-30 22:34:35 +00:00
let ann = BindingAnnotation ( ByRef ::from ( is_ref ) , mutability ) ;
let fieldpat = self . mk_pat_ident ( boxed_span . to ( hi ) , ann , fieldname ) ;
2019-08-11 13:24:37 +00:00
let subpat =
if is_box { self . mk_pat ( lo . to ( hi ) , PatKind ::Box ( fieldpat ) ) } else { fieldpat } ;
( subpat , fieldname , true )
} ;
2021-03-15 21:36:07 +00:00
Ok ( PatField {
2019-08-14 23:35:36 +00:00
ident : fieldname ,
pat : subpat ,
is_shorthand ,
2022-08-17 02:34:33 +00:00
attrs ,
2019-08-14 23:35:36 +00:00
id : ast ::DUMMY_NODE_ID ,
2019-08-11 13:24:37 +00:00
span : lo . to ( hi ) ,
2019-09-09 12:26:25 +00:00
is_placeholder : false ,
2019-08-11 13:24:37 +00:00
} )
}
2022-08-30 22:34:35 +00:00
pub ( super ) fn mk_pat_ident ( & self , span : Span , ann : BindingAnnotation , ident : Ident ) -> P < Pat > {
self . mk_pat ( span , PatKind ::Ident ( ann , ident , None ) )
2019-08-11 13:24:37 +00:00
}
2021-11-21 04:56:32 +00:00
pub ( super ) fn mk_pat ( & self , span : Span , kind : PatKind ) -> P < Pat > {
2020-07-27 22:02:29 +00:00
P ( Pat { kind , span , id : ast ::DUMMY_NODE_ID , tokens : None } )
2019-08-11 13:24:37 +00:00
}
}