2021-11-21 04:56:32 +00:00
use super ::pat ::Expected ;
use super ::{
2022-05-19 16:07:55 +10:00
BlockMode , CommaRecoveryMode , Parser , PathStyle , Restrictions , SemiColonMode , SeqSep ,
TokenExpectType , TokenType ,
2021-11-21 04:56:32 +00:00
} ;
2022-08-30 13:19:17 +02:00
use crate ::errors ::{
2022-09-08 18:23:31 +02:00
AmbiguousPlus , AttributeOnParamType , BadQPathStage2 , BadTypePlus , BadTypePlusSub ,
ComparisonOperatorsCannotBeChained , ComparisonOperatorsCannotBeChainedSugg ,
ConstGenericWithoutBraces , ConstGenericWithoutBracesSugg , DocCommentOnParamType ,
DoubleColonInBound , ExpectedIdentifier , ExpectedSemi , ExpectedSemiSugg ,
GenericParamsWithoutAngleBrackets , GenericParamsWithoutAngleBracketsSugg , InInTypo ,
IncorrectAwait , IncorrectSemicolon , IncorrectUseOfAwait , ParenthesesInForHead ,
ParenthesesInForHeadSugg , PatternMethodParamWithoutBody , QuestionMarkInType ,
QuestionMarkInTypeSugg , SelfParamNotFirst , StructLiteralBodyWithoutPath ,
2023-01-09 05:29:54 +00:00
StructLiteralBodyWithoutPathSugg , StructLiteralNeedingParens , StructLiteralNeedingParensSugg ,
SuggEscapeToUseAsIdentifier , SuggRemoveComma , UnexpectedConstInGenericParam ,
UnexpectedConstParamDeclaration , UnexpectedConstParamDeclarationSugg , UnmatchedAngleBrackets ,
UseEqInstead ,
2022-08-30 13:19:17 +02:00
} ;
2019-10-15 22:48:13 +02:00
2022-03-09 23:13:04 +09:00
use crate ::lexer ::UnmatchedBrace ;
2022-09-08 17:22:52 +10:00
use crate ::parser ;
2020-12-15 17:43:24 +01:00
use rustc_ast as ast ;
2020-02-29 20:37:32 +03:00
use rustc_ast ::ptr ::P ;
2022-04-26 15:40:14 +03:00
use rustc_ast ::token ::{ self , Delimiter , Lit , LitKind , TokenKind } ;
2020-02-29 20:37:32 +03:00
use rustc_ast ::util ::parser ::AssocOp ;
2021-05-15 14:56:28 -07:00
use rustc_ast ::{
2022-08-30 17:34:35 -05:00
AngleBracketedArg , AngleBracketedArgs , AnonConst , AttrVec , BinOpKind , BindingAnnotation , Block ,
BlockCheckMode , Expr , ExprKind , GenericArg , Generics , Item , ItemKind , Param , Pat , PatKind ,
Path , PathSegment , QSelf , Ty , TyKind ,
2021-05-15 14:56:28 -07:00
} ;
2020-01-11 17:02:46 +01:00
use rustc_ast_pretty ::pprust ;
2019-12-05 06:38:06 +01:00
use rustc_data_structures ::fx ::FxHashSet ;
2022-03-26 07:27:43 +00:00
use rustc_errors ::{
2022-12-28 17:56:22 -08:00
fluent , Applicability , DiagnosticBuilder , DiagnosticMessage , FatalError , Handler , MultiSpan ,
PResult ,
2022-03-26 07:27:43 +00:00
} ;
2022-09-08 18:23:31 +02:00
use rustc_errors ::{ pluralize , Diagnostic , ErrorGuaranteed , IntoDiagnostic } ;
2022-09-30 01:38:15 +00:00
use rustc_session ::errors ::ExprParenthesesNeeded ;
2020-01-11 00:19:09 +00:00
use rustc_span ::source_map ::Spanned ;
2022-08-23 17:02:40 +08:00
use rustc_span ::symbol ::{ kw , sym , Ident } ;
2022-08-30 13:19:17 +02:00
use rustc_span ::{ Span , SpanSnippetError , DUMMY_SP } ;
2021-11-21 04:56:32 +00:00
use std ::mem ::take ;
2022-09-08 17:22:52 +10:00
use std ::ops ::{ Deref , DerefMut } ;
use thin_vec ::{ thin_vec , ThinVec } ;
2019-05-23 12:55:26 -07:00
2019-05-30 18:19:48 -07:00
/// Creates a placeholder argument.
2019-10-08 09:35:34 +02:00
pub ( super ) fn dummy_arg ( ident : Ident ) -> Param {
2019-05-30 18:19:48 -07:00
let pat = P ( Pat {
id : ast ::DUMMY_NODE_ID ,
2022-08-30 17:34:35 -05:00
kind : PatKind ::Ident ( BindingAnnotation ::NONE , ident , None ) ,
2019-05-30 18:19:48 -07:00
span : ident . span ,
2020-07-27 18:02:29 -04:00
tokens : None ,
2019-05-30 18:19:48 -07:00
} ) ;
2020-08-21 18:18:04 -04:00
let ty = Ty { kind : TyKind ::Err , span : ident . span , id : ast ::DUMMY_NODE_ID , tokens : None } ;
2019-09-09 09:26:25 -03:00
Param {
2019-12-03 16:38:34 +01:00
attrs : AttrVec ::default ( ) ,
2019-09-09 09:26:25 -03:00
id : ast ::DUMMY_NODE_ID ,
pat ,
span : ident . span ,
ty : P ( ty ) ,
is_placeholder : false ,
}
2019-05-30 18:19:48 -07:00
}
2019-10-08 09:35:34 +02:00
pub ( super ) trait RecoverQPath : Sized + 'static {
2019-04-28 13:28:07 +08:00
const PATH_STYLE : PathStyle = PathStyle ::Expr ;
fn to_ty ( & self ) -> Option < P < Ty > > ;
2022-09-08 10:52:51 +10:00
fn recovered ( qself : Option < P < QSelf > > , path : ast ::Path ) -> Self ;
2019-04-28 13:28:07 +08:00
}
impl RecoverQPath for Ty {
const PATH_STYLE : PathStyle = PathStyle ::Type ;
fn to_ty ( & self ) -> Option < P < Ty > > {
Some ( P ( self . clone ( ) ) )
}
2022-09-08 10:52:51 +10:00
fn recovered ( qself : Option < P < QSelf > > , path : ast ::Path ) -> Self {
2020-08-21 18:18:04 -04:00
Self {
span : path . span ,
kind : TyKind ::Path ( qself , path ) ,
id : ast ::DUMMY_NODE_ID ,
tokens : None ,
}
2019-04-28 13:28:07 +08:00
}
}
impl RecoverQPath for Pat {
fn to_ty ( & self ) -> Option < P < Ty > > {
self . to_ty ( )
}
2022-09-08 10:52:51 +10:00
fn recovered ( qself : Option < P < QSelf > > , path : ast ::Path ) -> Self {
2020-07-27 18:02:29 -04:00
Self {
span : path . span ,
kind : PatKind ::Path ( qself , path ) ,
id : ast ::DUMMY_NODE_ID ,
tokens : None ,
}
2019-04-28 13:28:07 +08:00
}
}
impl RecoverQPath for Expr {
fn to_ty ( & self ) -> Option < P < Ty > > {
self . to_ty ( )
}
2022-09-08 10:52:51 +10:00
fn recovered ( qself : Option < P < QSelf > > , path : ast ::Path ) -> Self {
2019-04-28 13:28:07 +08:00
Self {
span : path . span ,
2019-09-26 14:39:48 +01:00
kind : ExprKind ::Path ( qself , path ) ,
2019-12-03 16:38:34 +01:00
attrs : AttrVec ::new ( ) ,
2019-04-28 13:28:07 +08:00
id : ast ::DUMMY_NODE_ID ,
2020-05-19 16:56:20 -04:00
tokens : None ,
2019-04-28 13:28:07 +08:00
}
}
}
2019-10-25 18:30:02 -07:00
/// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`.
2022-05-20 19:51:09 -04:00
pub ( crate ) enum ConsumeClosingDelim {
2019-10-25 18:30:02 -07:00
Yes ,
No ,
}
2020-08-12 15:39:15 -07:00
#[ derive(Clone, Copy) ]
pub enum AttemptLocalParseRecovery {
Yes ,
No ,
}
impl AttemptLocalParseRecovery {
pub fn yes ( & self ) -> bool {
match self {
AttemptLocalParseRecovery ::Yes = > true ,
AttemptLocalParseRecovery ::No = > false ,
}
}
pub fn no ( & self ) -> bool {
match self {
AttemptLocalParseRecovery ::Yes = > false ,
AttemptLocalParseRecovery ::No = > true ,
}
}
}
2022-02-17 12:28:07 -08:00
/// Information for emitting suggestions and recovering from
/// C-style `i++`, `--i`, etc.
2021-09-06 16:16:52 -07:00
#[ derive(Debug, Copy, Clone) ]
struct IncDecRecovery {
2022-02-17 14:52:52 -08:00
/// Is this increment/decrement its own statement?
2022-02-18 15:27:58 -08:00
standalone : IsStandalone ,
2022-02-17 12:28:07 -08:00
/// Is this an increment or decrement?
2021-09-06 16:16:52 -07:00
op : IncOrDec ,
2022-02-17 12:28:07 -08:00
/// Is this pre- or postfix?
2021-09-06 16:16:52 -07:00
fixity : UnaryFixity ,
}
2022-02-18 15:27:58 -08:00
/// Is an increment or decrement expression its own statement?
#[ derive(Debug, Copy, Clone) ]
enum IsStandalone {
/// It's standalone, i.e., its own statement.
Standalone ,
/// It's a subexpression, i.e., *not* standalone.
Subexpr ,
}
2021-09-06 16:16:52 -07:00
#[ derive(Debug, Copy, Clone, PartialEq, Eq) ]
enum IncOrDec {
Inc ,
// FIXME: `i--` recovery isn't implemented yet
#[ allow(dead_code) ]
Dec ,
}
#[ derive(Debug, Copy, Clone, PartialEq, Eq) ]
enum UnaryFixity {
Pre ,
Post ,
}
impl IncOrDec {
fn chr ( & self ) -> char {
match self {
Self ::Inc = > '+' ,
Self ::Dec = > '-' ,
}
}
fn name ( & self ) -> & 'static str {
match self {
Self ::Inc = > " increment " ,
Self ::Dec = > " decrement " ,
}
}
}
impl std ::fmt ::Display for UnaryFixity {
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
match self {
Self ::Pre = > write! ( f , " prefix " ) ,
Self ::Post = > write! ( f , " postfix " ) ,
}
}
}
2022-02-21 18:52:47 -08:00
struct MultiSugg {
msg : String ,
patches : Vec < ( Span , String ) > ,
applicability : Applicability ,
}
impl MultiSugg {
2022-08-10 03:39:41 +00:00
fn emit ( self , err : & mut Diagnostic ) {
2022-02-21 18:52:47 -08:00
err . multipart_suggestion ( & self . msg , self . patches , self . applicability ) ;
}
2022-11-25 17:11:47 +08:00
fn emit_verbose ( self , err : & mut Diagnostic ) {
err . multipart_suggestion_verbose ( & self . msg , self . patches , self . applicability ) ;
2022-02-21 18:52:47 -08:00
}
}
2022-04-26 11:12:48 +02:00
2022-11-27 11:15:06 +00:00
/// SnapshotParser is used to create a snapshot of the parser
/// without causing duplicate errors being emitted when the `Parser`
/// is dropped.
2022-06-12 17:27:36 +09:00
pub struct SnapshotParser < ' a > {
2022-03-09 23:13:04 +09:00
parser : Parser < ' a > ,
unclosed_delims : Vec < UnmatchedBrace > ,
}
impl < ' a > Deref for SnapshotParser < ' a > {
type Target = Parser < ' a > ;
fn deref ( & self ) -> & Self ::Target {
& self . parser
}
}
impl < ' a > DerefMut for SnapshotParser < ' a > {
fn deref_mut ( & mut self ) -> & mut Self ::Target {
& mut self . parser
}
}
2019-04-28 13:28:07 +08:00
impl < ' a > Parser < ' a > {
2022-07-01 15:48:23 +02:00
#[ rustc_lint_diagnostics ]
2022-01-27 09:44:25 +00:00
pub fn struct_span_err < S : Into < MultiSpan > > (
& self ,
sp : S ,
2022-03-26 07:27:43 +00:00
m : impl Into < DiagnosticMessage > ,
2022-01-23 12:34:26 -06:00
) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
2019-05-23 12:55:26 -07:00
self . sess . span_diagnostic . struct_span_err ( sp , m )
}
2022-03-26 07:27:43 +00:00
pub fn span_bug < S : Into < MultiSpan > > ( & self , sp : S , m : impl Into < DiagnosticMessage > ) -> ! {
2019-05-23 12:55:26 -07:00
self . sess . span_diagnostic . span_bug ( sp , m )
}
2019-12-05 06:38:06 +01:00
pub ( super ) fn diagnostic ( & self ) -> & ' a Handler {
2019-05-23 12:55:26 -07:00
& self . sess . span_diagnostic
}
2022-03-30 15:14:15 -04:00
/// Replace `self` with `snapshot.parser` and extend `unclosed_delims` with `snapshot.unclosed_delims`.
2022-03-10 19:34:42 +09:00
/// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears.
pub ( super ) fn restore_snapshot ( & mut self , snapshot : SnapshotParser < ' a > ) {
2022-03-09 23:13:04 +09:00
* self = snapshot . parser ;
2022-08-13 15:50:01 +02:00
self . unclosed_delims . extend ( snapshot . unclosed_delims ) ;
2022-03-09 23:13:04 +09:00
}
2022-04-02 17:05:04 +02:00
pub fn unclosed_delims ( & self ) -> & [ UnmatchedBrace ] {
& self . unclosed_delims
}
2022-03-10 19:34:42 +09:00
/// Create a snapshot of the `Parser`.
2022-06-12 17:27:36 +09:00
pub fn create_snapshot_for_diagnostic ( & self ) -> SnapshotParser < ' a > {
2022-03-09 13:48:40 +09:00
let mut snapshot = self . clone ( ) ;
2022-03-09 23:13:04 +09:00
let unclosed_delims = self . unclosed_delims . clone ( ) ;
2022-03-10 19:34:42 +09:00
// Clear `unclosed_delims` in snapshot to avoid
// duplicate errors being emitted when the `Parser`
// is dropped (which may or may not happen, depending
// if the parsing the snapshot is created for is successful)
2022-03-09 23:13:04 +09:00
snapshot . unclosed_delims . clear ( ) ;
SnapshotParser { parser : snapshot , unclosed_delims }
2022-03-09 13:48:40 +09:00
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn span_to_snippet ( & self , span : Span ) -> Result < String , SpanSnippetError > {
2019-07-24 11:01:30 +02:00
self . sess . source_map ( ) . span_to_snippet ( span )
}
2022-10-24 00:52:59 +11:00
pub ( super ) fn expected_ident_found ( & mut self ) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
2019-11-20 14:50:13 -08:00
let valid_follow = & [
TokenKind ::Eq ,
TokenKind ::Colon ,
TokenKind ::Comma ,
TokenKind ::Semi ,
TokenKind ::ModSep ,
2022-04-26 15:40:14 +03:00
TokenKind ::OpenDelim ( Delimiter ::Brace ) ,
TokenKind ::OpenDelim ( Delimiter ::Parenthesis ) ,
TokenKind ::CloseDelim ( Delimiter ::Brace ) ,
TokenKind ::CloseDelim ( Delimiter ::Parenthesis ) ,
2019-11-20 14:50:13 -08:00
] ;
2022-09-04 10:14:00 +02:00
let suggest_raw = match self . token . ident ( ) {
2020-03-04 23:37:52 +03:00
Some ( ( ident , false ) )
if ident . is_raw_guess ( )
& & self . look_ahead ( 1 , | t | valid_follow . contains ( & t . kind ) ) = >
2019-11-20 14:50:13 -08:00
{
2022-09-04 10:14:00 +02:00
Some ( SuggEscapeToUseAsIdentifier {
span : ident . span . shrink_to_lo ( ) ,
2022-09-14 18:35:22 +02:00
// `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
// which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
2022-09-04 10:14:00 +02:00
ident_name : ident . name . to_string ( ) ,
} )
2019-05-23 12:55:26 -07:00
}
2022-09-04 10:14:00 +02:00
_ = > None ,
} ;
let suggest_remove_comma =
2019-05-23 12:55:26 -07:00
if self . token = = token ::Comma & & self . look_ahead ( 1 , | t | t . is_ident ( ) ) {
2022-09-04 10:14:00 +02:00
Some ( SuggRemoveComma { span : self . token . span } )
} else {
None
} ;
let err = ExpectedIdentifier {
span : self . token . span ,
2022-09-22 18:39:17 +02:00
token : self . token . clone ( ) ,
2022-09-04 10:14:00 +02:00
suggest_raw ,
suggest_remove_comma ,
} ;
2022-10-24 00:52:59 +11:00
let mut err = err . into_diagnostic ( & self . sess . span_diagnostic ) ;
// if the token we have is a `<`
// it *might* be a misplaced generic
if self . token = = token ::Lt {
// all keywords that could have generic applied
let valid_prev_keywords =
[ kw ::Fn , kw ::Type , kw ::Struct , kw ::Enum , kw ::Union , kw ::Trait ] ;
// If we've expected an identifier,
// and the current token is a '<'
// if the previous token is a valid keyword
// that might use a generic, then suggest a correct
// generic placement (later on)
let maybe_keyword = self . prev_token . clone ( ) ;
if valid_prev_keywords . into_iter ( ) . any ( | x | maybe_keyword . is_keyword ( x ) ) {
// if we have a valid keyword, attempt to parse generics
// also obtain the keywords symbol
match self . parse_generics ( ) {
Ok ( generic ) = > {
if let TokenKind ::Ident ( symbol , _ ) = maybe_keyword . kind {
2022-12-02 00:40:33 +11:00
let ident_name = symbol ;
2022-10-24 00:52:59 +11:00
// at this point, we've found something like
// `fn <T>id`
// and current token should be Ident with the item name (i.e. the function name)
// if there is a `<` after the fn name, then don't show a suggestion, show help
if ! self . look_ahead ( 1 , | t | * t = = token ::Lt ) & &
2023-01-31 21:44:11 +11:00
let Ok ( snippet ) = self . sess . source_map ( ) . span_to_snippet ( generic . span ) {
err . multipart_suggestion_verbose (
2022-10-24 00:52:59 +11:00
format! ( " place the generic parameter name after the {ident_name} name " ) ,
2023-01-31 21:44:11 +11:00
vec! [
( self . token . span . shrink_to_hi ( ) , snippet ) ,
( generic . span , String ::new ( ) )
] ,
2022-12-01 14:12:33 +00:00
Applicability ::MaybeIncorrect ,
2022-10-24 00:52:59 +11:00
) ;
} else {
err . help ( format! (
" place the generic parameter name after the {ident_name} name "
) ) ;
}
}
}
Err ( err ) = > {
// if there's an error parsing the generics,
// then don't do a misplaced generics suggestion
// and emit the expected ident error instead;
err . cancel ( ) ;
}
}
}
}
err
2019-05-23 12:55:26 -07:00
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn expected_one_of_not_found (
2019-05-23 13:10:24 -07:00
& mut self ,
2019-06-05 14:17:56 +03:00
edible : & [ TokenKind ] ,
inedible : & [ TokenKind ] ,
2019-05-23 13:10:24 -07:00
) -> PResult < ' a , bool /* recovered */ > {
2020-12-15 17:43:24 +01:00
debug! ( " expected_one_of_not_found(edible: {:?}, inedible: {:?}) " , edible , inedible ) ;
2019-05-23 13:10:24 -07:00
fn tokens_to_string ( tokens : & [ TokenType ] ) -> String {
let mut i = tokens . iter ( ) ;
2019-09-06 03:56:45 +01:00
// This might be a sign we need a connect method on `Iterator`.
2021-02-25 04:13:42 +03:00
let b = i . next ( ) . map_or_else ( String ::new , | t | t . to_string ( ) ) ;
2019-05-23 13:10:24 -07:00
i . enumerate ( ) . fold ( b , | mut b , ( i , a ) | {
if tokens . len ( ) > 2 & & i = = tokens . len ( ) - 2 {
b . push_str ( " , or " ) ;
} else if tokens . len ( ) = = 2 & & i = = tokens . len ( ) - 2 {
b . push_str ( " or " ) ;
} else {
b . push_str ( " , " ) ;
}
b . push_str ( & a . to_string ( ) ) ;
b
} )
}
2019-12-22 17:42:04 -05:00
let mut expected = edible
. iter ( )
2019-05-23 13:10:24 -07:00
. map ( | x | TokenType ::Token ( x . clone ( ) ) )
. chain ( inedible . iter ( ) . map ( | x | TokenType ::Token ( x . clone ( ) ) ) )
. chain ( self . expected_tokens . iter ( ) . cloned ( ) )
2022-05-01 19:05:35 +02:00
. filter_map ( | token | {
// filter out suggestions which suggest the same token which was found and deemed incorrect
fn is_ident_eq_keyword ( found : & TokenKind , expected : & TokenType ) -> bool {
if let TokenKind ::Ident ( current_sym , _ ) = found {
if let TokenType ::Keyword ( suggested_sym ) = expected {
return current_sym = = suggested_sym ;
}
}
false
}
if token ! = parser ::TokenType ::Token ( self . token . kind . clone ( ) ) {
let eq = is_ident_eq_keyword ( & self . token . kind , & token ) ;
// if the suggestion is a keyword and the found token is an ident,
// the content of which are equal to the suggestion's content,
// we can remove that suggestion (see the return None statement below)
// if this isn't the case however, and the suggestion is a token the
// content of which is the same as the found token's, we remove it as well
if ! eq {
if let TokenType ::Token ( kind ) = & token {
if kind = = & self . token . kind {
return None ;
}
}
return Some ( token ) ;
}
}
return None ;
} )
2019-05-23 13:10:24 -07:00
. collect ::< Vec < _ > > ( ) ;
expected . sort_by_cached_key ( | x | x . to_string ( ) ) ;
expected . dedup ( ) ;
2020-12-15 17:43:24 +01:00
2021-07-24 10:58:55 -07:00
let sm = self . sess . source_map ( ) ;
2022-09-04 20:12:00 +02:00
// Special-case "expected `;`" errors
2021-07-24 10:58:55 -07:00
if expected . contains ( & TokenType ::Token ( token ::Semi ) ) {
if self . token . span = = DUMMY_SP | | self . prev_token . span = = DUMMY_SP {
// Likely inside a macro, can't provide meaningful suggestions.
} else if ! sm . is_multiline ( self . prev_token . span . until ( self . token . span ) ) {
// The current token is in the same line as the prior token, not recoverable.
} else if [ token ::Comma , token ::Colon ] . contains ( & self . token . kind )
2022-04-26 15:40:14 +03:00
& & self . prev_token . kind = = token ::CloseDelim ( Delimiter ::Parenthesis )
2021-07-24 10:58:55 -07:00
{
// Likely typo: The current token is on a new line and is expected to be
// `.`, `;`, `?`, or an operator after a close delimiter token.
//
// let a = std::process::Command::new("echo")
// .arg("1")
// ,arg("2")
// ^
// https://github.com/rust-lang/rust/issues/72253
} else if self . look_ahead ( 1 , | t | {
2022-04-26 15:40:14 +03:00
t = = & token ::CloseDelim ( Delimiter ::Brace )
2021-07-24 10:58:55 -07:00
| | t . can_begin_expr ( ) & & t . kind ! = token ::Colon
} ) & & [ token ::Comma , token ::Colon ] . contains ( & self . token . kind )
{
// Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
// either `,` or `:`, and the next token could either start a new statement or is a
// block close. For example:
//
// let x = 32:
// let y = 42;
2022-09-04 20:12:00 +02:00
self . sess . emit_err ( ExpectedSemi {
span : self . token . span ,
2022-09-22 18:39:17 +02:00
token : self . token . clone ( ) ,
2022-09-04 20:12:00 +02:00
unexpected_token_label : None ,
sugg : ExpectedSemiSugg ::ChangeToSemi ( self . token . span ) ,
} ) ;
2021-07-24 10:58:55 -07:00
self . bump ( ) ;
2021-09-10 22:33:44 +02:00
return Ok ( true ) ;
2021-07-24 10:58:55 -07:00
} else if self . look_ahead ( 0 , | t | {
2022-04-26 15:40:14 +03:00
t = = & token ::CloseDelim ( Delimiter ::Brace )
2022-08-15 16:10:31 +09:00
| | ( ( t . can_begin_expr ( ) | | t . can_begin_item ( ) )
& & t ! = & token ::Semi
& & t ! = & token ::Pound )
2022-04-23 19:44:25 -07:00
// Avoid triggering with too many trailing `#` in raw string.
| | ( sm . is_multiline (
2022-08-15 16:10:31 +09:00
self . prev_token . span . shrink_to_hi ( ) . until ( self . token . span . shrink_to_lo ( ) ) ,
2022-04-23 19:44:25 -07:00
) & & t = = & token ::Pound )
2022-07-02 03:04:18 +00:00
} ) & & ! expected . contains ( & TokenType ::Token ( token ::Comma ) )
{
2021-07-24 10:58:55 -07:00
// Missing semicolon typo. This is triggered if the next token could either start a
// new statement or is a block close. For example:
//
// let x = 32
// let y = 42;
2022-09-04 20:12:00 +02:00
let span = self . prev_token . span . shrink_to_hi ( ) ;
self . sess . emit_err ( ExpectedSemi {
span ,
2022-09-22 18:39:17 +02:00
token : self . token . clone ( ) ,
2022-09-04 20:12:00 +02:00
unexpected_token_label : Some ( self . token . span ) ,
sugg : ExpectedSemiSugg ::AddSemi ( span ) ,
} ) ;
2021-09-10 22:33:44 +02:00
return Ok ( true ) ;
2021-07-24 10:58:55 -07:00
}
}
2022-09-07 12:26:50 +08:00
if self . token . kind = = TokenKind ::EqEq
& & self . prev_token . is_ident ( )
& & expected . iter ( ) . any ( | tok | matches! ( tok , TokenType ::Token ( TokenKind ::Eq ) ) )
{
// Likely typo: `=` → `==` in let expr or enum item
return Err ( self . sess . create_err ( UseEqInstead { span : self . token . span } ) ) ;
}
2021-12-03 03:06:36 +01:00
let expect = tokens_to_string ( & expected ) ;
2019-12-07 03:07:35 +01:00
let actual = super ::token_descr ( & self . token ) ;
2019-05-23 13:10:24 -07:00
let ( msg_exp , ( label_sp , label_exp ) ) = if expected . len ( ) > 1 {
let short_expect = if expected . len ( ) > 6 {
format! ( " {} possible tokens " , expected . len ( ) )
} else {
expect . clone ( )
} ;
2019-12-22 17:42:04 -05:00
(
2022-03-15 19:13:56 +09:00
format! ( " expected one of {expect} , found {actual} " ) ,
( self . prev_token . span . shrink_to_hi ( ) , format! ( " expected one of {short_expect} " ) ) ,
2019-12-22 17:42:04 -05:00
)
2019-05-23 13:10:24 -07:00
} else if expected . is_empty ( ) {
2019-12-22 17:42:04 -05:00
(
2022-08-14 22:17:49 +08:00
format! ( " unexpected token: {actual} " ) ,
2020-02-29 14:56:15 +03:00
( self . prev_token . span , " unexpected token after this " . to_string ( ) ) ,
2019-12-22 17:42:04 -05:00
)
2019-05-23 13:10:24 -07:00
} else {
2019-12-22 17:42:04 -05:00
(
2022-03-15 19:13:56 +09:00
format! ( " expected {expect} , found {actual} " ) ,
( self . prev_token . span . shrink_to_hi ( ) , format! ( " expected {expect} " ) ) ,
2019-12-22 17:42:04 -05:00
)
2019-05-23 13:10:24 -07:00
} ;
2019-06-07 13:31:13 +03:00
self . last_unexpected_token_span = Some ( self . token . span ) ;
2022-09-04 20:12:00 +02:00
// FIXME: translation requires list formatting (for `expect`)
2019-12-31 04:21:58 +01:00
let mut err = self . struct_span_err ( self . token . span , & msg_exp ) ;
2020-12-15 17:43:24 +01:00
2022-07-29 19:21:30 +05:30
if let TokenKind ::Ident ( symbol , _ ) = & self . prev_token . kind {
2022-08-18 16:14:04 -05:00
if [ " def " , " fun " , " func " , " function " ] . contains ( & symbol . as_str ( ) ) {
err . span_suggestion_short (
self . prev_token . span ,
& format! ( " write `fn` instead of ` {symbol} ` to declare a function " ) ,
" fn " ,
2022-09-04 20:12:00 +02:00
Applicability ::MachineApplicable ,
2022-08-18 16:14:04 -05:00
) ;
}
2022-07-29 19:21:30 +05:30
}
2022-08-23 17:02:40 +08:00
// `pub` may be used for an item or `pub(crate)`
if self . prev_token . is_ident_named ( sym ::public )
& & ( self . token . can_begin_item ( )
| | self . token . kind = = TokenKind ::OpenDelim ( Delimiter ::Parenthesis ) )
{
err . span_suggestion_short (
self . prev_token . span ,
" write `pub` instead of `public` to make the item public " ,
" pub " ,
2022-09-04 20:12:00 +02:00
Applicability ::MachineApplicable ,
2022-08-23 17:02:40 +08:00
) ;
}
2020-12-15 17:43:24 +01:00
// Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
// there are unclosed angle brackets
if self . unmatched_angle_bracket_count > 0
& & self . token . kind = = TokenKind ::Eq
& & expected . iter ( ) . any ( | tok | matches! ( tok , TokenType ::Token ( TokenKind ::Gt ) ) )
{
err . span_label ( self . prev_token . span , " maybe try to close unmatched angle bracket " ) ;
}
2019-05-24 02:04:56 +03:00
let sp = if self . token = = token ::Eof {
2019-09-06 03:56:45 +01:00
// This is EOF; don't want to point at the following char, but rather the last token.
2020-02-29 14:56:15 +03:00
self . prev_token . span
2019-05-23 13:10:24 -07:00
} else {
label_sp
} ;
2019-12-22 17:42:04 -05:00
match self . recover_closing_delimiter (
& expected
. iter ( )
. filter_map ( | tt | match tt {
TokenType ::Token ( t ) = > Some ( t . clone ( ) ) ,
_ = > None ,
} )
. collect ::< Vec < _ > > ( ) ,
err ,
) {
2019-05-23 13:10:24 -07:00
Err ( e ) = > err = e ,
Ok ( recovered ) = > {
return Ok ( recovered ) ;
}
}
2020-03-28 01:46:20 -04:00
if self . check_too_many_raw_str_terminators ( & mut err ) {
2022-04-23 19:44:25 -07:00
if expected . contains ( & TokenType ::Token ( token ::Semi ) ) & & self . eat ( & token ::Semi ) {
err . emit ( ) ;
return Ok ( true ) ;
} else {
return Err ( err ) ;
}
2020-03-28 01:46:20 -04:00
}
2020-02-29 14:56:15 +03:00
if self . prev_token . span = = DUMMY_SP {
2019-10-24 15:57:43 -07:00
// Account for macro context where the previous span might not be
// available to avoid incorrect output (#54841).
err . span_label ( self . token . span , label_exp ) ;
} else if ! sm . is_multiline ( self . token . span . shrink_to_hi ( ) . until ( sp . shrink_to_lo ( ) ) ) {
// When the spans are in the same line, it means that the only content between
// them is whitespace, point at the found token in that case:
//
// X | () => { syntax error };
// | ^^^^^ expected one of 8 possible tokens here
//
// instead of having:
//
// X | () => { syntax error };
// | -^^^^^ unexpected token
// | |
// | expected one of 8 possible tokens here
err . span_label ( self . token . span , label_exp ) ;
} else {
err . span_label ( sp , label_exp ) ;
err . span_label ( self . token . span , " unexpected token " ) ;
2019-05-23 13:10:24 -07:00
}
2019-07-17 11:40:36 -07:00
self . maybe_annotate_with_ascription ( & mut err , false ) ;
2019-05-23 13:10:24 -07:00
Err ( err )
}
2022-01-23 20:41:46 +00:00
fn check_too_many_raw_str_terminators ( & mut self , err : & mut Diagnostic ) -> bool {
2022-04-23 19:44:25 -07:00
let sm = self . sess . source_map ( ) ;
2020-03-30 12:39:40 -04:00
match ( & self . prev_token . kind , & self . token . kind ) {
(
TokenKind ::Literal ( Lit {
kind : LitKind ::StrRaw ( n_hashes ) | LitKind ::ByteStrRaw ( n_hashes ) ,
..
} ) ,
TokenKind ::Pound ,
2022-04-23 19:44:25 -07:00
) if ! sm . is_multiline (
self . prev_token . span . shrink_to_hi ( ) . until ( self . token . span . shrink_to_lo ( ) ) ,
) = >
{
let n_hashes : u8 = * n_hashes ;
2020-03-28 01:46:20 -04:00
err . set_primary_message ( " too many `#` when terminating raw string " ) ;
2022-04-23 19:44:25 -07:00
let str_span = self . prev_token . span ;
let mut span = self . token . span ;
let mut count = 0 ;
while self . token . kind = = TokenKind ::Pound
& & ! sm . is_multiline ( span . shrink_to_hi ( ) . until ( self . token . span . shrink_to_lo ( ) ) )
{
span = span . with_hi ( self . token . span . hi ( ) ) ;
self . bump ( ) ;
count + = 1 ;
}
err . set_span ( span ) ;
2020-03-28 01:46:20 -04:00
err . span_suggestion (
2022-04-23 19:44:25 -07:00
span ,
& format! ( " remove the extra `#` {} " , pluralize! ( count ) ) ,
2022-06-13 15:48:40 +09:00
" " ,
2020-03-28 01:46:20 -04:00
Applicability ::MachineApplicable ,
) ;
2022-04-23 19:44:25 -07:00
err . span_label (
str_span ,
& format! ( " this raw string started with {n_hashes} `#` {} " , pluralize! ( n_hashes ) ) ,
) ;
2020-03-30 12:39:40 -04:00
true
2020-03-28 01:46:20 -04:00
}
2020-03-30 12:39:40 -04:00
_ = > false ,
2020-03-28 01:46:20 -04:00
}
}
2020-08-12 15:39:15 -07:00
pub fn maybe_suggest_struct_literal (
& mut self ,
lo : Span ,
s : BlockCheckMode ,
2023-01-09 05:29:54 +00:00
maybe_struct_name : token ::Token ,
can_be_struct_literal : bool ,
2020-08-12 15:39:15 -07:00
) -> Option < PResult < ' a , P < Block > > > {
if self . token . is_ident ( ) & & self . look_ahead ( 1 , | t | t = = & token ::Colon ) {
// We might be having a struct literal where people forgot to include the path:
// fn foo() -> Foo {
// field: value,
// }
2023-01-09 05:29:54 +00:00
info! ( ? maybe_struct_name , ? self . token ) ;
2022-03-10 22:11:00 +09:00
let mut snapshot = self . create_snapshot_for_diagnostic ( ) ;
2022-09-08 17:22:52 +10:00
let path = Path {
segments : ThinVec ::new ( ) ,
span : self . prev_token . span . shrink_to_lo ( ) ,
tokens : None ,
} ;
2022-08-15 09:58:38 +10:00
let struct_expr = snapshot . parse_struct_expr ( None , path , false ) ;
2020-08-12 15:39:15 -07:00
let block_tail = self . parse_block_tail ( lo , s , AttemptLocalParseRecovery ::No ) ;
return Some ( match ( struct_expr , block_tail ) {
( Ok ( expr ) , Err ( mut err ) ) = > {
// We have encountered the following:
// fn foo() -> Foo {
// field: value,
// }
// Suggest:
// fn foo() -> Foo { Path {
// field: value,
// } }
err . delay_as_bug ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2021-09-02 18:34:03 +00:00
let mut tail = self . mk_block (
2020-08-12 15:39:15 -07:00
vec! [ self . mk_stmt_err ( expr . span ) ] ,
s ,
lo . to ( self . prev_token . span ) ,
2021-09-02 18:34:03 +00:00
) ;
tail . could_be_bare_literal = true ;
2023-01-09 05:29:54 +00:00
if maybe_struct_name . is_ident ( ) & & can_be_struct_literal {
// Account for `if Example { a: one(), }.is_pos() {}`.
Err ( self . sess . create_err ( StructLiteralNeedingParens {
span : maybe_struct_name . span . to ( expr . span ) ,
sugg : StructLiteralNeedingParensSugg {
before : maybe_struct_name . span . shrink_to_lo ( ) ,
after : expr . span . shrink_to_hi ( ) ,
} ,
} ) )
} else {
self . sess . emit_err ( StructLiteralBodyWithoutPath {
span : expr . span ,
sugg : StructLiteralBodyWithoutPathSugg {
before : expr . span . shrink_to_lo ( ) ,
after : expr . span . shrink_to_hi ( ) ,
} ,
} ) ;
Ok ( tail )
}
2020-08-12 15:39:15 -07:00
}
2022-01-26 03:39:14 +00:00
( Err ( err ) , Ok ( tail ) ) = > {
2020-08-12 15:39:15 -07:00
// We have a block tail that contains a somehow valid type ascription expr.
err . cancel ( ) ;
Ok ( tail )
}
2022-01-26 03:39:14 +00:00
( Err ( snapshot_err ) , Err ( err ) ) = > {
2020-08-12 15:39:15 -07:00
// We don't know what went wrong, emit the normal error.
snapshot_err . cancel ( ) ;
2022-04-26 15:40:14 +03:00
self . consume_block ( Delimiter ::Brace , ConsumeClosingDelim ::Yes ) ;
2020-08-12 15:39:15 -07:00
Err ( err )
}
2021-09-02 18:34:03 +00:00
( Ok ( _ ) , Ok ( mut tail ) ) = > {
tail . could_be_bare_literal = true ;
Ok ( tail )
}
2020-08-12 15:39:15 -07:00
} ) ;
}
None
}
2019-07-17 11:40:36 -07:00
pub fn maybe_annotate_with_ascription (
2019-11-04 16:19:55 -08:00
& mut self ,
2022-01-23 20:41:46 +00:00
err : & mut Diagnostic ,
2019-07-17 11:40:36 -07:00
maybe_expected_semicolon : bool ,
) {
2019-11-05 10:29:54 -08:00
if let Some ( ( sp , likely_path ) ) = self . last_type_ascription . take ( ) {
2019-07-19 10:59:02 -07:00
let sm = self . sess . source_map ( ) ;
let next_pos = sm . lookup_char_pos ( self . token . span . lo ( ) ) ;
let op_pos = sm . lookup_char_pos ( sp . hi ( ) ) ;
2019-07-17 11:40:36 -07:00
2019-10-08 10:46:08 +02:00
let allow_unstable = self . sess . unstable_features . is_nightly_build ( ) ;
2019-07-17 11:40:36 -07:00
if likely_path {
err . span_suggestion (
sp ,
" maybe write a path separator here " ,
2022-06-13 15:48:40 +09:00
" :: " ,
2019-10-08 10:46:08 +02:00
if allow_unstable {
Applicability ::MaybeIncorrect
} else {
Applicability ::MachineApplicable
2019-07-17 11:40:36 -07:00
} ,
) ;
2020-07-09 13:49:55 -07:00
self . sess . type_ascription_path_suggestions . borrow_mut ( ) . insert ( sp ) ;
2019-07-17 11:40:36 -07:00
} else if op_pos . line ! = next_pos . line & & maybe_expected_semicolon {
err . span_suggestion (
sp ,
" try using a semicolon " ,
2022-06-13 15:48:40 +09:00
" ; " ,
2019-07-17 11:40:36 -07:00
Applicability ::MaybeIncorrect ,
) ;
2019-10-08 10:46:08 +02:00
} else if allow_unstable {
2019-07-17 11:40:36 -07:00
err . span_label ( sp , " tried to parse a type due to this type ascription " ) ;
2019-10-08 10:46:08 +02:00
} else {
err . span_label ( sp , " tried to parse a type due to this " ) ;
2019-07-17 11:40:36 -07:00
}
2019-10-08 10:46:08 +02:00
if allow_unstable {
2019-07-17 11:40:36 -07:00
// Give extra information about type ascription only if it's a nightly compiler.
2019-12-22 17:42:04 -05:00
err . note (
2020-07-09 09:09:25 -07:00
" `#![feature(type_ascription)]` lets you annotate an expression with a type: \
` < expr > : < type > ` " ,
2019-12-22 17:42:04 -05:00
) ;
2020-07-09 09:09:25 -07:00
if ! likely_path {
// Avoid giving too much info when it was likely an unrelated typo.
err . note (
" see issue #23416 <https://github.com/rust-lang/rust/issues/23416> \
for more information " ,
) ;
}
2019-07-17 11:40:36 -07:00
}
}
}
2019-05-23 12:55:26 -07:00
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
2019-10-08 09:35:34 +02:00
pub ( super ) fn eat_to_tokens ( & mut self , kets : & [ & TokenKind ] ) {
2022-01-26 03:39:14 +00:00
if let Err ( err ) =
2019-12-22 17:42:04 -05:00
self . parse_seq_to_before_tokens ( kets , SeqSep ::none ( ) , TokenExpectType ::Expect , | p | {
Ok ( p . parse_token_tree ( ) )
} )
{
2019-09-07 10:38:02 -04:00
err . cancel ( ) ;
2019-05-23 12:55:26 -07:00
}
}
/// This function checks if there are trailing angle brackets and produces
/// a diagnostic to suggest removing them.
///
/// ```ignore (diagnostic)
2021-12-17 18:36:18 +11:00
/// let _ = [1, 2, 3].into_iter().collect::<Vec<usize>>>>();
/// ^^ help: remove extra angle brackets
2019-05-23 12:55:26 -07:00
/// ```
2020-06-27 11:35:12 -04:00
///
/// If `true` is returned, then trailing brackets were recovered, tokens were consumed
/// up until one of the tokens in 'end' was encountered, and an error was emitted.
pub ( super ) fn check_trailing_angle_brackets (
& mut self ,
segment : & PathSegment ,
end : & [ & TokenKind ] ,
) -> bool {
2022-10-28 20:44:26 +02:00
if ! self . may_recover ( ) {
return false ;
}
2019-05-23 12:55:26 -07:00
// This function is intended to be invoked after parsing a path segment where there are two
// cases:
//
// 1. A specific token is expected after the path segment.
// eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
// `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
// 2. No specific token is expected after the path segment.
// eg. `x.foo` (field access)
//
// This function is called after parsing `.foo` and before parsing the token `end` (if
// present). This includes any angle bracket arguments, such as `.foo::<u32>` or
// `Foo::<Bar>`.
// We only care about trailing angle brackets if we previously parsed angle bracket
// arguments. This helps stop us incorrectly suggesting that extra angle brackets be
// removed in this case:
//
// `x.foo >> (3)` (where `x.foo` is a `u32` for example)
//
// This case is particularly tricky as we won't notice it just looking at the tokens -
// it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
// have already been parsed):
//
// `x.foo::<u32>>>(3)`
2019-12-22 17:42:04 -05:00
let parsed_angle_bracket_args =
2021-01-11 20:45:33 +01:00
segment . args . as_ref ( ) . map_or ( false , | args | args . is_angle_bracketed ( ) ) ;
2019-05-23 12:55:26 -07:00
debug! (
" check_trailing_angle_brackets: parsed_angle_bracket_args={:?} " ,
parsed_angle_bracket_args ,
) ;
if ! parsed_angle_bracket_args {
2020-06-27 11:35:12 -04:00
return false ;
2019-05-23 12:55:26 -07:00
}
// Keep the span at the start so we can highlight the sequence of `>` characters to be
// removed.
2019-06-07 13:31:13 +03:00
let lo = self . token . span ;
2019-05-23 12:55:26 -07:00
// We need to look-ahead to see if we have `>` characters without moving the cursor forward
// (since we might have the field access case and the characters we're eating are
// actual operators and not trailing characters - ie `x.foo >> 3`).
let mut position = 0 ;
// We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
// many of each (so we can correctly pluralize our error messages) and continue to
// advance.
let mut number_of_shr = 0 ;
let mut number_of_gt = 0 ;
while self . look_ahead ( position , | t | {
trace! ( " check_trailing_angle_brackets: t={:?} " , t ) ;
if * t = = token ::BinOp ( token ::BinOpToken ::Shr ) {
number_of_shr + = 1 ;
true
} else if * t = = token ::Gt {
number_of_gt + = 1 ;
true
} else {
false
}
} ) {
position + = 1 ;
}
// If we didn't find any trailing `>` characters, then we have nothing to error about.
debug! (
" check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?} " ,
number_of_gt , number_of_shr ,
) ;
if number_of_gt < 1 & & number_of_shr < 1 {
2020-06-27 11:35:12 -04:00
return false ;
2019-05-23 12:55:26 -07:00
}
// Finally, double check that we have our end token as otherwise this is the
// second case.
if self . look_ahead ( position , | t | {
trace! ( " check_trailing_angle_brackets: t={:?} " , t ) ;
2020-06-27 11:35:12 -04:00
end . contains ( & & t . kind )
2019-05-23 12:55:26 -07:00
} ) {
// Eat from where we started until the end token so that parsing can continue
// as if we didn't have those extra angle brackets.
2020-06-27 11:35:12 -04:00
self . eat_to_tokens ( end ) ;
2019-06-07 13:31:13 +03:00
let span = lo . until ( self . token . span ) ;
2019-05-23 12:55:26 -07:00
2022-09-08 18:23:31 +02:00
let num_extra_brackets = number_of_gt + number_of_shr * 2 ;
self . sess . emit_err ( UnmatchedAngleBrackets { span , num_extra_brackets } ) ;
2020-06-27 11:35:12 -04:00
return true ;
2019-05-23 12:55:26 -07:00
}
2020-06-27 11:35:12 -04:00
false
2019-05-23 12:55:26 -07:00
}
2020-07-23 09:34:07 -07:00
/// Check if a method call with an intended turbofish has been written without surrounding
/// angle brackets.
pub ( super ) fn check_turbofish_missing_angle_brackets ( & mut self , segment : & mut PathSegment ) {
2022-10-28 20:44:26 +02:00
if ! self . may_recover ( ) {
return ;
}
2020-07-23 09:34:07 -07:00
if token ::ModSep = = self . token . kind & & segment . args . is_none ( ) {
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2020-07-23 09:34:07 -07:00
self . bump ( ) ;
let lo = self . token . span ;
2021-05-15 14:56:28 -07:00
match self . parse_angle_args ( None ) {
2020-07-23 16:25:39 -07:00
Ok ( args ) = > {
2020-07-23 09:34:07 -07:00
let span = lo . to ( self . prev_token . span ) ;
2020-07-23 16:25:39 -07:00
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
let mut trailing_span = self . prev_token . span . shrink_to_hi ( ) ;
while self . token . kind = = token ::BinOp ( token ::Shr )
| | self . token . kind = = token ::Gt
{
trailing_span = trailing_span . to ( self . token . span ) ;
self . bump ( ) ;
}
2022-04-26 15:40:14 +03:00
if self . token . kind = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2020-07-23 16:25:39 -07:00
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
let args = AngleBracketedArgs { args , span } . into ( ) ;
segment . args = args ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( GenericParamsWithoutAngleBrackets {
2020-07-23 16:25:39 -07:00
span ,
2022-09-08 18:23:31 +02:00
sugg : GenericParamsWithoutAngleBracketsSugg {
left : span . shrink_to_lo ( ) ,
right : trailing_span ,
} ,
} ) ;
2020-07-23 16:25:39 -07:00
} else {
// This doesn't look like an invalid turbofish, can't recover parse state.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2020-07-23 16:25:39 -07:00
}
2020-07-23 09:34:07 -07:00
}
2022-01-26 03:39:14 +00:00
Err ( err ) = > {
2021-03-17 09:49:46 +09:00
// We couldn't parse generic parameters, unlikely to be a turbofish. Rely on
2020-07-23 16:25:39 -07:00
// generic parse error instead.
2020-07-23 09:34:07 -07:00
err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2020-07-23 09:34:07 -07:00
}
}
}
}
2020-08-31 10:24:37 -07:00
/// When writing a turbofish with multiple type parameters missing the leading `::`, we will
/// encounter a parse error when encountering the first `,`.
pub ( super ) fn check_mistyped_turbofish_with_multiple_type_params (
& mut self ,
2022-01-23 12:34:26 -06:00
mut e : DiagnosticBuilder < ' a , ErrorGuaranteed > ,
2020-08-31 10:24:37 -07:00
expr : & mut P < Expr > ,
) -> PResult < ' a , ( ) > {
2022-02-28 07:49:56 -03:00
if let ExprKind ::Binary ( binop , _ , _ ) = & expr . kind
& & let ast ::BinOpKind ::Lt = binop . node
& & self . eat ( & token ::Comma )
{
let x = self . parse_seq_to_before_end (
& token ::Gt ,
SeqSep ::trailing_allowed ( token ::Comma ) ,
| p | p . parse_generic_arg ( None ) ,
) ;
match x {
Ok ( ( _ , _ , false ) ) = > {
if self . eat ( & token ::Gt ) {
e . span_suggestion_verbose (
binop . span . shrink_to_lo ( ) ,
2022-11-07 19:47:32 +01:00
fluent ::parse_sugg_turbofish_syntax ,
2022-06-13 15:48:40 +09:00
" :: " ,
2022-02-28 07:49:56 -03:00
Applicability ::MaybeIncorrect ,
)
. emit ( ) ;
match self . parse_expr ( ) {
Ok ( _ ) = > {
* expr =
self . mk_expr_err ( expr . span . to ( self . prev_token . span ) ) ;
return Ok ( ( ) ) ;
}
Err ( err ) = > {
* expr = self . mk_expr_err ( expr . span ) ;
err . cancel ( ) ;
2020-08-31 10:24:37 -07:00
}
}
}
}
2022-02-28 07:49:56 -03:00
Err ( err ) = > {
err . cancel ( ) ;
}
_ = > { }
2020-08-31 10:24:37 -07:00
}
}
Err ( e )
}
2020-01-11 00:19:09 +00:00
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
/// parenthesising the leftmost comparison.
fn attempt_chained_comparison_suggestion (
& mut self ,
2022-09-08 18:23:31 +02:00
err : & mut ComparisonOperatorsCannotBeChained ,
2020-01-11 00:19:09 +00:00
inner_op : & Expr ,
outer_op : & Spanned < AssocOp > ,
2020-03-25 18:10:18 -07:00
) -> bool /* advanced the cursor */ {
2022-11-22 09:42:01 +00:00
if let ExprKind ::Binary ( op , l1 , r1 ) = & inner_op . kind {
2022-02-28 07:49:56 -03:00
if let ExprKind ::Field ( _ , ident ) = l1 . kind
& & ident . as_str ( ) . parse ::< i32 > ( ) . is_err ( )
& & ! matches! ( r1 . kind , ExprKind ::Lit ( _ ) )
{
// The parser has encountered `foo.bar<baz`, the likelihood of the turbofish
// suggestion being the only one to apply is high.
return false ;
2020-03-09 20:21:37 -07:00
}
return match ( op . node , & outer_op . node ) {
// `x == y == z`
( BinOpKind ::Eq , AssocOp ::Equal ) |
2020-01-11 00:19:09 +00:00
// `x < y < z` and friends.
2020-04-16 17:38:52 -07:00
( BinOpKind ::Lt , AssocOp ::Less | AssocOp ::LessEqual ) |
( BinOpKind ::Le , AssocOp ::LessEqual | AssocOp ::Less ) |
2020-01-11 00:19:09 +00:00
// `x > y > z` and friends.
2020-04-16 17:38:52 -07:00
( BinOpKind ::Gt , AssocOp ::Greater | AssocOp ::GreaterEqual ) |
( BinOpKind ::Ge , AssocOp ::GreaterEqual | AssocOp ::Greater ) = > {
2020-01-11 00:19:09 +00:00
let expr_to_str = | e : & Expr | {
self . span_to_snippet ( e . span )
. unwrap_or_else ( | _ | pprust ::expr_to_string ( & e ) )
} ;
2022-09-08 18:23:31 +02:00
err . chaining_sugg = Some ( ComparisonOperatorsCannotBeChainedSugg ::SplitComparison {
span : inner_op . span . shrink_to_hi ( ) ,
middle_term : expr_to_str ( & r1 ) ,
} ) ;
2020-03-09 20:21:37 -07:00
false // Keep the current parse behavior, where the AST is `(x < y) < z`.
}
// `x == y < z`
2020-04-16 17:38:52 -07:00
( BinOpKind ::Eq , AssocOp ::Less | AssocOp ::LessEqual | AssocOp ::Greater | AssocOp ::GreaterEqual ) = > {
2020-03-25 18:10:18 -07:00
// Consume `z`/outer-op-rhs.
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2020-03-09 20:21:37 -07:00
match self . parse_expr ( ) {
Ok ( r2 ) = > {
2020-03-25 18:10:18 -07:00
// We are sure that outer-op-rhs could be consumed, the suggestion is
// likely correct.
2022-09-08 18:23:31 +02:00
err . chaining_sugg = Some ( ComparisonOperatorsCannotBeChainedSugg ::Parenthesize {
left : r1 . span . shrink_to_lo ( ) ,
right : r2 . span . shrink_to_hi ( ) ,
} ) ;
2020-03-09 20:21:37 -07:00
true
}
2022-01-26 03:39:14 +00:00
Err ( expr_err ) = > {
2020-03-09 20:21:37 -07:00
expr_err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2020-03-09 20:21:37 -07:00
false
}
}
}
// `x > y == z`
2020-04-16 17:38:52 -07:00
( BinOpKind ::Lt | BinOpKind ::Le | BinOpKind ::Gt | BinOpKind ::Ge , AssocOp ::Equal ) = > {
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2020-03-25 18:10:18 -07:00
// At this point it is always valid to enclose the lhs in parentheses, no
// further checks are necessary.
2020-03-09 20:21:37 -07:00
match self . parse_expr ( ) {
Ok ( _ ) = > {
2022-09-08 18:23:31 +02:00
err . chaining_sugg = Some ( ComparisonOperatorsCannotBeChainedSugg ::Parenthesize {
left : l1 . span . shrink_to_lo ( ) ,
right : r1 . span . shrink_to_hi ( ) ,
} ) ;
2020-03-09 20:21:37 -07:00
true
}
2022-01-26 03:39:14 +00:00
Err ( expr_err ) = > {
2020-03-09 20:21:37 -07:00
expr_err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2020-03-09 20:21:37 -07:00
false
}
}
2020-01-11 00:19:09 +00:00
}
2020-03-09 20:21:37 -07:00
_ = > false ,
} ;
2020-01-11 00:19:09 +00:00
}
2020-03-09 20:21:37 -07:00
false
2020-01-11 00:19:09 +00:00
}
2019-09-06 03:56:45 +01:00
/// Produces an error if comparison operators are chained (RFC #558).
2019-09-29 19:07:26 -07:00
/// We only need to check the LHS, not the RHS, because all comparison ops have same
2019-10-01 11:24:05 -07:00
/// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
2019-09-29 19:07:26 -07:00
///
/// This can also be hit if someone incorrectly writes `foo<bar>()` when they should have used
2019-10-01 11:24:05 -07:00
/// the turbofish (`foo::<bar>()`) syntax. We attempt some heuristic recovery if that is the
/// case.
///
/// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left
/// associative we can infer that we have:
///
2020-04-18 18:39:40 +02:00
/// ```text
2019-10-01 11:24:05 -07:00
/// outer_op
/// / \
/// inner_op r2
/// / \
2020-01-11 00:19:09 +00:00
/// l1 r1
2020-04-18 18:39:40 +02:00
/// ```
2019-10-08 09:35:34 +02:00
pub ( super ) fn check_no_chained_comparison (
2019-09-29 19:07:26 -07:00
& mut self ,
2020-01-11 00:19:09 +00:00
inner_op : & Expr ,
outer_op : & Spanned < AssocOp > ,
2019-09-29 19:07:26 -07:00
) -> PResult < ' a , Option < P < Expr > > > {
debug_assert! (
2020-01-11 00:19:09 +00:00
outer_op . node . is_comparison ( ) ,
2019-09-29 19:07:26 -07:00
" check_no_chained_comparison: {:?} is not comparison " ,
2020-01-11 00:19:09 +00:00
outer_op . node ,
2019-09-29 19:07:26 -07:00
) ;
2019-10-01 15:51:50 -07:00
2022-08-15 09:58:38 +10:00
let mk_err_expr = | this : & Self , span | Ok ( Some ( this . mk_expr ( span , ExprKind ::Err ) ) ) ;
2019-10-01 15:51:50 -07:00
2022-11-22 09:42:01 +00:00
match & inner_op . kind {
ExprKind ::Binary ( op , l1 , r1 ) if op . node . is_comparison ( ) = > {
2022-09-08 18:23:31 +02:00
let mut err = ComparisonOperatorsCannotBeChained {
span : vec ! [ op . span , self . prev_token . span ] ,
suggest_turbofish : None ,
help_turbofish : None ,
chaining_sugg : None ,
2019-10-01 11:24:05 -07:00
} ;
2020-03-25 18:10:18 -07:00
// Include `<` to provide this recommendation even in a case like
// `Foo<Bar<Baz<Qux, ()>>>`
2020-03-09 20:21:37 -07:00
if op . node = = BinOpKind ::Lt & & outer_op . node = = AssocOp ::Less
| | outer_op . node = = AssocOp ::Greater
2019-12-22 17:42:04 -05:00
{
2020-01-11 00:19:09 +00:00
if outer_op . node = = AssocOp ::Less {
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2019-09-29 19:07:26 -07:00
self . bump ( ) ;
2019-10-01 11:24:05 -07:00
// So far we have parsed `foo<bar<`, consume the rest of the type args.
2019-12-22 17:42:04 -05:00
let modifiers =
[ ( token ::Lt , 1 ) , ( token ::Gt , - 1 ) , ( token ::BinOp ( token ::Shr ) , - 2 ) ] ;
2021-12-03 03:06:36 +01:00
self . consume_tts ( 1 , & modifiers ) ;
2019-09-30 12:19:22 -07:00
2022-04-26 15:40:14 +03:00
if ! & [ token ::OpenDelim ( Delimiter ::Parenthesis ) , token ::ModSep ]
2019-12-22 17:42:04 -05:00
. contains ( & self . token . kind )
{
2019-09-30 12:36:44 -07:00
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
// parser and bail out.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2019-09-29 19:07:26 -07:00
}
}
2019-10-01 15:51:50 -07:00
return if token ::ModSep = = self . token . kind {
2019-09-30 12:36:44 -07:00
// We have some certainty that this was a bad turbofish at this point.
// `foo< bar >::`
2023-01-08 22:27:13 +00:00
if let ExprKind ::Binary ( o , .. ) = inner_op . kind & & o . node = = BinOpKind ::Lt {
err . suggest_turbofish = Some ( op . span . shrink_to_lo ( ) ) ;
} else {
err . help_turbofish = Some ( ( ) ) ;
}
2019-09-30 12:36:44 -07:00
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2019-09-30 12:36:44 -07:00
self . bump ( ) ; // `::`
2019-10-01 11:24:05 -07:00
2019-09-30 12:36:44 -07:00
// Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
match self . parse_expr ( ) {
Ok ( _ ) = > {
// 99% certain that the suggestion is correct, continue parsing.
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( err ) ;
2019-09-30 12:36:44 -07:00
// FIXME: actually check that the two expressions in the binop are
// paths and resynthesize new fn call expression instead of using
// `ExprKind::Err` placeholder.
2020-02-29 14:56:15 +03:00
mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) )
2019-09-30 12:36:44 -07:00
}
2022-01-26 03:39:14 +00:00
Err ( expr_err ) = > {
2019-10-01 11:24:05 -07:00
expr_err . cancel ( ) ;
2019-09-30 12:36:44 -07:00
// Not entirely sure now, but we bubble the error up with the
// suggestion.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2022-09-08 18:23:31 +02:00
Err ( err . into_diagnostic ( & self . sess . span_diagnostic ) )
2019-09-30 12:36:44 -07:00
}
}
2022-04-26 15:40:14 +03:00
} else if token ::OpenDelim ( Delimiter ::Parenthesis ) = = self . token . kind {
2019-09-30 12:19:22 -07:00
// We have high certainty that this was a bad turbofish at this point.
// `foo< bar >(`
2023-01-08 22:27:13 +00:00
if let ExprKind ::Binary ( o , .. ) = inner_op . kind & & o . node = = BinOpKind ::Lt {
err . suggest_turbofish = Some ( op . span . shrink_to_lo ( ) ) ;
} else {
err . help_turbofish = Some ( ( ) ) ;
}
2019-09-30 12:19:22 -07:00
// Consume the fn call arguments.
2019-10-03 13:22:18 -07:00
match self . consume_fn_args ( ) {
2022-09-08 18:23:31 +02:00
Err ( ( ) ) = > Err ( err . into_diagnostic ( & self . sess . span_diagnostic ) ) ,
2019-10-03 13:22:18 -07:00
Ok ( ( ) ) = > {
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( err ) ;
2019-10-03 13:22:18 -07:00
// FIXME: actually check that the two expressions in the binop are
// paths and resynthesize new fn call expression instead of using
// `ExprKind::Err` placeholder.
2020-02-29 14:56:15 +03:00
mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) )
2019-10-03 13:22:18 -07:00
}
2019-09-29 19:07:26 -07:00
}
} else {
2020-03-09 20:21:37 -07:00
if ! matches! ( l1 . kind , ExprKind ::Lit ( _ ) )
& & ! matches! ( r1 . kind , ExprKind ::Lit ( _ ) )
{
// All we know is that this is `foo < bar >` and *nothing* else. Try to
// be helpful, but don't attempt to recover.
2022-09-08 18:23:31 +02:00
err . help_turbofish = Some ( ( ) ) ;
2020-03-09 20:21:37 -07:00
}
// If it looks like a genuine attempt to chain operators (as opposed to a
// misformatted turbofish, for instance), suggest a correct form.
if self . attempt_chained_comparison_suggestion ( & mut err , inner_op , outer_op )
{
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( err ) ;
2020-03-09 20:21:37 -07:00
mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) )
} else {
// These cases cause too many knock-down errors, bail out (#61329).
2022-09-08 18:23:31 +02:00
Err ( err . into_diagnostic ( & self . sess . span_diagnostic ) )
2020-03-09 20:21:37 -07:00
}
2019-10-01 15:51:50 -07:00
} ;
2019-05-23 12:55:26 -07:00
}
2020-03-09 20:21:37 -07:00
let recover =
self . attempt_chained_comparison_suggestion ( & mut err , inner_op , outer_op ) ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( err ) ;
2020-03-09 20:21:37 -07:00
if recover {
return mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) ) ;
}
2019-05-23 12:55:26 -07:00
}
_ = > { }
}
2019-09-29 19:07:26 -07:00
Ok ( None )
2019-05-23 12:55:26 -07:00
}
2019-10-03 13:22:18 -07:00
fn consume_fn_args ( & mut self ) -> Result < ( ) , ( ) > {
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2019-10-03 13:22:18 -07:00
self . bump ( ) ; // `(`
// Consume the fn call arguments.
2022-04-26 15:40:14 +03:00
let modifiers = [
( token ::OpenDelim ( Delimiter ::Parenthesis ) , 1 ) ,
( token ::CloseDelim ( Delimiter ::Parenthesis ) , - 1 ) ,
] ;
2021-12-03 03:06:36 +01:00
self . consume_tts ( 1 , & modifiers ) ;
2019-10-03 13:22:18 -07:00
if self . token . kind = = token ::Eof {
// Not entirely sure that what we consumed were fn arguments, rollback.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2019-10-03 13:22:18 -07:00
Err ( ( ) )
} else {
// 99% certain that the suggestion is correct, continue parsing.
Ok ( ( ) )
}
2019-05-23 12:55:26 -07:00
}
2022-05-19 15:59:52 +10:00
pub ( super ) fn maybe_report_ambiguous_plus ( & mut self , impl_dyn_multi : bool , ty : & Ty ) {
if impl_dyn_multi {
2022-04-27 12:03:16 +02:00
self . sess . emit_err ( AmbiguousPlus { sum_ty : pprust ::ty_to_string ( & ty ) , span : ty . span } ) ;
2019-04-28 13:28:07 +08:00
}
}
2022-01-10 22:02:19 +00:00
/// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
2022-05-19 15:52:52 +10:00
pub ( super ) fn maybe_recover_from_question_mark ( & mut self , ty : P < Ty > ) -> P < Ty > {
2022-01-10 22:02:19 +00:00
if self . token = = token ::Question {
self . bump ( ) ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( QuestionMarkInType {
span : self . prev_token . span ,
sugg : QuestionMarkInTypeSugg {
left : ty . span . shrink_to_lo ( ) ,
right : self . prev_token . span ,
} ,
} ) ;
2022-01-10 22:02:19 +00:00
self . mk_ty ( ty . span . to ( self . prev_token . span ) , TyKind ::Err )
} else {
ty
}
}
2022-05-19 15:59:52 +10:00
pub ( super ) fn maybe_recover_from_bad_type_plus ( & mut self , ty : & Ty ) -> PResult < ' a , ( ) > {
2019-04-28 13:28:07 +08:00
// Do not add `+` to expected tokens.
2022-05-19 15:59:52 +10:00
if ! self . token . is_like_plus ( ) {
2019-04-28 13:28:07 +08:00
return Ok ( ( ) ) ;
}
self . bump ( ) ; // `+`
2022-05-16 22:23:32 -05:00
let bounds = self . parse_generic_bounds ( None ) ? ;
2020-02-29 14:56:15 +03:00
let sum_span = ty . span . to ( self . prev_token . span ) ;
2019-04-28 13:28:07 +08:00
2022-11-22 09:42:01 +00:00
let sub = match & ty . kind {
2022-12-28 18:06:11 +01:00
TyKind ::Ref ( lifetime , mut_ty ) = > {
2022-05-17 13:10:15 -05:00
let sum_with_parens = pprust ::to_string ( | s | {
2019-06-24 14:15:11 -04:00
s . s . word ( " & " ) ;
s . print_opt_lifetime ( lifetime ) ;
2019-11-23 14:15:49 +00:00
s . print_mutability ( mut_ty . mutbl , false ) ;
2019-06-24 14:15:11 -04:00
s . popen ( ) ;
s . print_type ( & mut_ty . ty ) ;
2022-06-16 17:14:51 -07:00
if ! bounds . is_empty ( ) {
s . word ( " + " ) ;
s . print_type_bounds ( & bounds ) ;
}
2019-04-28 13:28:07 +08:00
s . pclose ( )
} ) ;
2022-05-16 17:16:27 -05:00
2022-05-17 13:10:15 -05:00
BadTypePlusSub ::AddParen { sum_with_parens , span : sum_span }
2019-04-28 13:28:07 +08:00
}
2022-05-16 17:16:27 -05:00
TyKind ::Ptr ( .. ) | TyKind ::BareFn ( .. ) = > BadTypePlusSub ::ForgotParen { span : sum_span } ,
_ = > BadTypePlusSub ::ExpectPath { span : sum_span } ,
} ;
self . sess . emit_err ( BadTypePlus { ty : pprust ::ty_to_string ( ty ) , span : sum_span , sub } ) ;
2019-04-28 13:28:07 +08:00
Ok ( ( ) )
}
2022-02-17 16:24:22 -08:00
pub ( super ) fn recover_from_prefix_increment (
2021-09-06 16:16:52 -07:00
& mut self ,
operand_expr : P < Expr > ,
op_span : Span ,
2022-11-26 05:33:13 +08:00
start_stmt : bool ,
2021-09-06 16:16:52 -07:00
) -> PResult < ' a , P < Expr > > {
2022-11-26 05:33:13 +08:00
let standalone = if start_stmt { IsStandalone ::Standalone } else { IsStandalone ::Subexpr } ;
2022-02-18 15:27:58 -08:00
let kind = IncDecRecovery { standalone , op : IncOrDec ::Inc , fixity : UnaryFixity ::Pre } ;
2021-09-06 16:16:52 -07:00
self . recover_from_inc_dec ( operand_expr , kind , op_span )
}
2022-02-17 16:24:22 -08:00
pub ( super ) fn recover_from_postfix_increment (
2021-09-06 16:16:52 -07:00
& mut self ,
operand_expr : P < Expr > ,
op_span : Span ,
2022-11-26 05:33:13 +08:00
start_stmt : bool ,
2021-09-06 16:16:52 -07:00
) -> PResult < ' a , P < Expr > > {
2022-02-18 15:27:58 -08:00
let kind = IncDecRecovery {
2022-11-26 05:33:13 +08:00
standalone : if start_stmt { IsStandalone ::Standalone } else { IsStandalone ::Subexpr } ,
2022-02-18 15:27:58 -08:00
op : IncOrDec ::Inc ,
fixity : UnaryFixity ::Post ,
} ;
2021-09-06 16:16:52 -07:00
self . recover_from_inc_dec ( operand_expr , kind , op_span )
}
fn recover_from_inc_dec (
& mut self ,
base : P < Expr > ,
kind : IncDecRecovery ,
op_span : Span ,
) -> PResult < ' a , P < Expr > > {
let mut err = self . struct_span_err (
op_span ,
& format! ( " Rust has no {} {} operator " , kind . fixity , kind . op . name ( ) ) ,
) ;
err . span_label ( op_span , & format! ( " not a valid {} operator " , kind . fixity ) ) ;
2022-03-23 19:47:45 -07:00
let help_base_case = | mut err : DiagnosticBuilder < '_ , _ > , base | {
2022-02-15 20:05:24 -08:00
err . help ( & format! ( " use ` {} = 1` instead " , kind . op . chr ( ) ) ) ;
err . emit ( ) ;
Ok ( base )
} ;
2021-09-06 16:16:52 -07:00
2022-02-15 20:05:24 -08:00
// (pre, post)
let spans = match kind . fixity {
2022-02-17 14:19:59 -08:00
UnaryFixity ::Pre = > ( op_span , base . span . shrink_to_hi ( ) ) ,
UnaryFixity ::Post = > ( base . span . shrink_to_lo ( ) , op_span ) ,
2022-02-15 20:05:24 -08:00
} ;
2022-02-17 14:52:52 -08:00
match kind . standalone {
2022-11-25 17:11:47 +08:00
IsStandalone ::Standalone = > {
self . inc_dec_standalone_suggest ( kind , spans ) . emit_verbose ( & mut err )
2021-09-06 16:16:52 -07:00
}
2022-02-18 15:27:58 -08:00
IsStandalone ::Subexpr = > {
2022-02-17 14:52:52 -08:00
let Ok ( base_src ) = self . span_to_snippet ( base . span )
2022-11-26 05:33:13 +08:00
else { return help_base_case ( err , base ) } ;
2022-02-17 14:52:52 -08:00
match kind . fixity {
UnaryFixity ::Pre = > {
2022-02-21 18:52:47 -08:00
self . prefix_inc_dec_suggest ( base_src , kind , spans ) . emit ( & mut err )
2022-02-17 14:52:52 -08:00
}
UnaryFixity ::Post = > {
2022-11-26 07:10:04 +08:00
// won't suggest since we can not handle the precedences
// for example: `a + b++` has been parsed (a + b)++ and we can not suggest here
if ! matches! ( base . kind , ExprKind ::Binary ( _ , _ , _ ) ) {
self . postfix_inc_dec_suggest ( base_src , kind , spans ) . emit ( & mut err )
}
2022-02-17 14:52:52 -08:00
}
}
}
2021-09-06 16:16:52 -07:00
}
2022-02-17 14:52:52 -08:00
Err ( err )
2021-09-06 16:16:52 -07:00
}
2022-02-17 12:28:07 -08:00
fn prefix_inc_dec_suggest (
2021-09-06 16:16:52 -07:00
& mut self ,
2022-02-17 14:19:59 -08:00
base_src : String ,
2021-09-06 16:16:52 -07:00
kind : IncDecRecovery ,
( pre_span , post_span ) : ( Span , Span ) ,
2022-02-21 18:52:47 -08:00
) -> MultiSugg {
MultiSugg {
msg : format ! ( " use `{}= 1` instead " , kind . op . chr ( ) ) ,
patches : vec ! [
2021-09-06 16:16:52 -07:00
( pre_span , " { " . to_string ( ) ) ,
2022-02-17 14:19:59 -08:00
( post_span , format! ( " {} = 1; {} }} " , kind . op . chr ( ) , base_src ) ) ,
2021-09-06 16:16:52 -07:00
] ,
2022-02-21 18:52:47 -08:00
applicability : Applicability ::MachineApplicable ,
}
2021-09-06 16:16:52 -07:00
}
2022-02-17 12:28:07 -08:00
fn postfix_inc_dec_suggest (
2021-09-06 16:16:52 -07:00
& mut self ,
2022-02-17 14:19:59 -08:00
base_src : String ,
2021-09-06 16:16:52 -07:00
kind : IncDecRecovery ,
( pre_span , post_span ) : ( Span , Span ) ,
2022-02-21 18:52:47 -08:00
) -> MultiSugg {
2022-02-18 15:32:46 -08:00
let tmp_var = if base_src . trim ( ) = = " tmp " { " tmp_ " } else { " tmp " } ;
2022-02-21 18:52:47 -08:00
MultiSugg {
msg : format ! ( " use `{}= 1` instead " , kind . op . chr ( ) ) ,
patches : vec ! [
2022-08-14 22:17:49 +08:00
( pre_span , format! ( " {{ let {tmp_var} = " ) ) ,
2022-02-18 15:32:46 -08:00
( post_span , format! ( " ; {} {} = 1; {} }} " , base_src , kind . op . chr ( ) , tmp_var ) ) ,
2021-09-06 16:16:52 -07:00
] ,
2022-02-21 18:52:47 -08:00
applicability : Applicability ::HasPlaceholders ,
}
2021-09-06 16:16:52 -07:00
}
2022-02-21 18:52:47 -08:00
fn inc_dec_standalone_suggest (
2021-09-06 16:16:52 -07:00
& mut self ,
kind : IncDecRecovery ,
( pre_span , post_span ) : ( Span , Span ) ,
2022-02-21 18:52:47 -08:00
) -> MultiSugg {
2022-10-11 16:17:59 +00:00
let mut patches = Vec ::new ( ) ;
if ! pre_span . is_empty ( ) {
patches . push ( ( pre_span , String ::new ( ) ) ) ;
}
patches . push ( ( post_span , format! ( " {} = 1 " , kind . op . chr ( ) ) ) ) ;
2022-02-21 18:52:47 -08:00
MultiSugg {
msg : format ! ( " use `{}= 1` instead " , kind . op . chr ( ) ) ,
2022-10-11 16:17:59 +00:00
patches ,
2022-02-21 18:52:47 -08:00
applicability : Applicability ::MachineApplicable ,
}
2021-09-06 16:16:52 -07:00
}
2019-09-06 03:56:45 +01:00
/// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`.
/// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem`
/// tail, and combines them into a `<Ty>::AssocItem` expression/pattern/type.
2019-10-08 09:35:34 +02:00
pub ( super ) fn maybe_recover_from_bad_qpath < T : RecoverQPath > (
2019-04-28 13:28:07 +08:00
& mut self ,
base : P < T > ,
) -> PResult < ' a , P < T > > {
2022-10-28 20:44:26 +02:00
if ! self . may_recover ( ) {
return Ok ( base ) ;
}
2019-04-28 13:28:07 +08:00
// Do not add `::` to expected tokens.
2022-05-19 15:51:49 +10:00
if self . token = = token ::ModSep {
2019-04-28 13:28:07 +08:00
if let Some ( ty ) = base . to_ty ( ) {
return self . maybe_recover_from_bad_qpath_stage_2 ( ty . span , ty ) ;
}
}
Ok ( base )
}
2019-09-06 03:56:45 +01:00
/// Given an already parsed `Ty`, parses the `::AssocItem` tail and
/// combines them into a `<Ty>::AssocItem` expression/pattern/type.
2019-10-08 09:35:34 +02:00
pub ( super ) fn maybe_recover_from_bad_qpath_stage_2 < T : RecoverQPath > (
2019-04-28 13:28:07 +08:00
& mut self ,
ty_span : Span ,
ty : P < Ty > ,
) -> PResult < ' a , P < T > > {
self . expect ( & token ::ModSep ) ? ;
2022-09-08 17:22:52 +10:00
let mut path = ast ::Path { segments : ThinVec ::new ( ) , span : DUMMY_SP , tokens : None } ;
2021-05-15 14:56:28 -07:00
self . parse_path_segments ( & mut path . segments , T ::PATH_STYLE , None ) ? ;
2020-02-29 14:56:15 +03:00
path . span = ty_span . to ( self . prev_token . span ) ;
2019-04-28 13:28:07 +08:00
2019-12-22 17:42:04 -05:00
let ty_str = self . span_to_snippet ( ty_span ) . unwrap_or_else ( | _ | pprust ::ty_to_string ( & ty ) ) ;
2022-05-31 11:22:26 -05:00
self . sess . emit_err ( BadQPathStage2 {
span : path . span ,
ty : format ! ( " <{}>::{} " , ty_str , pprust ::path_to_string ( & path ) ) ,
} ) ;
2019-04-28 13:28:07 +08:00
2019-09-06 03:56:45 +01:00
let path_span = ty_span . shrink_to_hi ( ) ; // Use an empty path since `position == 0`.
2022-09-08 10:52:51 +10:00
Ok ( P ( T ::recovered ( Some ( P ( QSelf { ty , path_span , position : 0 } ) ) , path ) ) )
2019-04-28 13:28:07 +08:00
}
2021-11-22 19:47:58 -07:00
pub fn maybe_consume_incorrect_semicolon ( & mut self , items : & [ P < Item > ] ) -> bool {
2021-12-04 11:05:30 -07:00
if self . token . kind = = TokenKind ::Semi {
self . bump ( ) ;
2022-05-31 11:45:44 -05:00
let mut err =
IncorrectSemicolon { span : self . prev_token . span , opt_help : None , name : " " } ;
2019-04-28 13:28:07 +08:00
if ! items . is_empty ( ) {
let previous_item = & items [ items . len ( ) - 1 ] ;
2019-09-26 17:51:36 +01:00
let previous_item_kind_name = match previous_item . kind {
2019-09-06 03:56:45 +01:00
// Say "braced struct" because tuple-structs and
// braceless-empty-struct declarations do take a semicolon.
2019-04-28 13:28:07 +08:00
ItemKind ::Struct ( .. ) = > Some ( " braced struct " ) ,
ItemKind ::Enum ( .. ) = > Some ( " enum " ) ,
ItemKind ::Trait ( .. ) = > Some ( " trait " ) ,
ItemKind ::Union ( .. ) = > Some ( " union " ) ,
_ = > None ,
} ;
if let Some ( name ) = previous_item_kind_name {
2022-05-31 11:45:44 -05:00
err . opt_help = Some ( ( ) ) ;
err . name = name ;
2019-04-28 13:28:07 +08:00
}
}
2022-05-31 11:45:44 -05:00
self . sess . emit_err ( err ) ;
2019-04-28 13:28:07 +08:00
true
} else {
false
}
}
2019-05-16 13:33:26 -07:00
2019-09-06 03:56:45 +01:00
/// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a
2019-05-21 22:17:53 -07:00
/// closing delimiter.
2019-10-08 09:35:34 +02:00
pub ( super ) fn unexpected_try_recover (
2019-05-21 22:17:53 -07:00
& mut self ,
2019-06-05 14:17:56 +03:00
t : & TokenKind ,
2019-05-21 22:17:53 -07:00
) -> PResult < ' a , bool /* recovered */ > {
2019-06-08 22:38:23 +03:00
let token_str = pprust ::token_kind_to_string ( t ) ;
2019-12-07 03:07:35 +01:00
let this_token_str = super ::token_descr ( & self . token ) ;
2019-06-05 01:17:07 +03:00
let ( prev_sp , sp ) = match ( & self . token . kind , self . subparser_name ) {
2019-05-21 22:17:53 -07:00
// Point at the end of the macro call when reaching end of macro arguments.
2019-05-24 02:04:56 +03:00
( token ::Eof , Some ( _ ) ) = > {
2022-10-18 02:00:06 +08:00
let sp = self . prev_token . span . shrink_to_hi ( ) ;
2019-05-21 22:17:53 -07:00
( sp , sp )
}
// We don't want to point at the following span after DUMMY_SP.
// This happens when the parser finds an empty TokenStream.
2020-02-29 14:56:15 +03:00
_ if self . prev_token . span = = DUMMY_SP = > ( self . token . span , self . token . span ) ,
2019-05-21 22:17:53 -07:00
// EOF, don't want to point at the following char, but rather the last token.
2020-02-29 14:56:15 +03:00
( token ::Eof , None ) = > ( self . prev_token . span , self . token . span ) ,
_ = > ( self . prev_token . span . shrink_to_hi ( ) , self . token . span ) ,
2019-05-21 22:17:53 -07:00
} ;
let msg = format! (
" expected `{}`, found {} " ,
token_str ,
2019-06-05 01:17:07 +03:00
match ( & self . token . kind , self . subparser_name ) {
2022-03-15 19:13:56 +09:00
( token ::Eof , Some ( origin ) ) = > format! ( " end of {origin} " ) ,
2019-05-21 22:17:53 -07:00
_ = > this_token_str ,
} ,
) ;
let mut err = self . struct_span_err ( sp , & msg ) ;
2022-03-15 19:13:56 +09:00
let label_exp = format! ( " expected ` {token_str} ` " ) ;
2019-05-21 22:17:53 -07:00
match self . recover_closing_delimiter ( & [ t . clone ( ) ] , err ) {
Err ( e ) = > err = e ,
Ok ( recovered ) = > {
return Ok ( recovered ) ;
}
}
2019-07-19 10:59:02 -07:00
let sm = self . sess . source_map ( ) ;
2019-10-20 14:35:46 -07:00
if ! sm . is_multiline ( prev_sp . until ( sp ) ) {
// When the spans are in the same line, it means that the only content
// between them is whitespace, point only at the found token.
err . span_label ( sp , label_exp ) ;
} else {
err . span_label ( prev_sp , label_exp ) ;
err . span_label ( sp , " unexpected token " ) ;
}
Err ( err )
}
pub ( super ) fn expect_semi ( & mut self ) -> PResult < ' a , ( ) > {
if self . eat ( & token ::Semi ) {
return Ok ( ( ) ) ;
}
2020-01-02 08:56:12 +00:00
self . expect ( & token ::Semi ) . map ( drop ) // Error unconditionally
2019-05-21 22:17:53 -07:00
}
2019-09-06 03:56:45 +01:00
/// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
2019-07-02 06:30:21 +02:00
/// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
2019-12-03 14:21:03 +01:00
pub ( super ) fn recover_incorrect_await_syntax (
2019-05-16 13:33:26 -07:00
& mut self ,
lo : Span ,
await_sp : Span ,
2019-12-03 14:21:03 +01:00
) -> PResult < ' a , P < Expr > > {
let ( hi , expr , is_question ) = if self . token = = token ::Not {
2019-07-02 06:30:21 +02:00
// Handle `await!(<expr>)`.
2019-12-03 14:21:03 +01:00
self . recover_await_macro ( ) ?
} else {
self . recover_await_prefix ( await_sp ) ?
} ;
let sp = self . error_on_incorrect_await ( lo , hi , & expr , is_question ) ;
2020-10-22 10:51:49 -07:00
let kind = match expr . kind {
// Avoid knock-down errors as we don't know whether to interpret this as `foo().await?`
// or `foo()?.await` (the very reason we went with postfix syntax 😅).
ExprKind ::Try ( _ ) = > ExprKind ::Err ,
_ = > ExprKind ::Await ( expr ) ,
} ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( lo . to ( sp ) , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 14:21:03 +01:00
}
fn recover_await_macro ( & mut self ) -> PResult < ' a , ( Span , P < Expr > , bool ) > {
self . expect ( & token ::Not ) ? ;
2022-04-26 15:40:14 +03:00
self . expect ( & token ::OpenDelim ( Delimiter ::Parenthesis ) ) ? ;
2019-12-03 14:21:03 +01:00
let expr = self . parse_expr ( ) ? ;
2022-04-26 15:40:14 +03:00
self . expect ( & token ::CloseDelim ( Delimiter ::Parenthesis ) ) ? ;
2020-02-29 14:56:15 +03:00
Ok ( ( self . prev_token . span , expr , false ) )
2019-12-03 14:21:03 +01:00
}
2019-07-02 06:30:21 +02:00
2019-12-03 14:21:03 +01:00
fn recover_await_prefix ( & mut self , await_sp : Span ) -> PResult < ' a , ( Span , P < Expr > , bool ) > {
2019-05-16 13:33:26 -07:00
let is_question = self . eat ( & token ::Question ) ; // Handle `await? <expr>`.
2022-04-26 15:40:14 +03:00
let expr = if self . token = = token ::OpenDelim ( Delimiter ::Brace ) {
2019-05-16 13:33:26 -07:00
// Handle `await { <expr> }`.
2021-03-17 09:49:46 +09:00
// This needs to be handled separately from the next arm to avoid
2019-05-16 13:33:26 -07:00
// interpreting `await { <expr> }?` as `<expr>?.await`.
2022-08-15 09:58:38 +10:00
self . parse_block_expr ( None , self . token . span , BlockCheckMode ::Default )
2019-05-16 13:33:26 -07:00
} else {
self . parse_expr ( )
2019-12-22 17:42:04 -05:00
}
. map_err ( | mut err | {
2019-05-16 13:33:26 -07:00
err . span_label ( await_sp , " while parsing this incorrect await expression " ) ;
err
} ) ? ;
2019-12-03 14:21:03 +01:00
Ok ( ( expr . span , expr , is_question ) )
2019-07-02 06:30:21 +02:00
}
fn error_on_incorrect_await ( & self , lo : Span , hi : Span , expr : & Expr , is_question : bool ) -> Span {
2022-05-31 14:32:07 -05:00
let span = lo . to ( hi ) ;
let applicability = match expr . kind {
2019-05-16 13:33:26 -07:00
ExprKind ::Try ( _ ) = > Applicability ::MaybeIncorrect , // `await <expr>?`
_ = > Applicability ::MachineApplicable ,
} ;
2022-05-31 14:32:07 -05:00
self . sess . emit_err ( IncorrectAwait {
span ,
sugg_span : ( span , applicability ) ,
expr : self . span_to_snippet ( expr . span ) . unwrap_or_else ( | _ | pprust ::expr_to_string ( & expr ) ) ,
question_mark : if is_question { " ? " } else { " " } ,
} ) ;
span
2019-05-16 13:33:26 -07:00
}
2019-05-16 14:31:07 -07:00
2019-09-06 03:56:45 +01:00
/// If encountering `future.await()`, consumes and emits an error.
2019-10-08 09:35:34 +02:00
pub ( super ) fn recover_from_await_method_call ( & mut self ) {
2022-04-26 15:40:14 +03:00
if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis )
& & self . look_ahead ( 1 , | t | t = = & token ::CloseDelim ( Delimiter ::Parenthesis ) )
2019-05-16 14:31:07 -07:00
{
// future.await()
2019-06-07 13:31:13 +03:00
let lo = self . token . span ;
2019-05-16 14:31:07 -07:00
self . bump ( ) ; // (
2022-06-01 07:14:33 -05:00
let span = lo . to ( self . token . span ) ;
2019-05-16 14:31:07 -07:00
self . bump ( ) ; // )
2022-05-31 12:33:35 -05:00
2022-06-01 07:14:33 -05:00
self . sess . emit_err ( IncorrectUseOfAwait { span } ) ;
2019-05-16 14:31:07 -07:00
}
}
2020-04-17 19:10:29 +02:00
pub ( super ) fn try_macro_suggestion ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-04-17 18:26:39 +02:00
let is_try = self . token . is_keyword ( kw ::Try ) ;
2020-04-17 14:07:44 +02:00
let is_questionmark = self . look_ahead ( 1 , | t | t = = & token ::Not ) ; //check for !
2022-04-26 15:40:14 +03:00
let is_open = self . look_ahead ( 2 , | t | t = = & token ::OpenDelim ( Delimiter ::Parenthesis ) ) ; //check for (
2020-04-17 14:07:44 +02:00
2020-04-17 18:26:39 +02:00
if is_try & & is_questionmark & & is_open {
2020-04-17 14:07:44 +02:00
let lo = self . token . span ;
self . bump ( ) ; //remove try
self . bump ( ) ; //remove !
let try_span = lo . to ( self . token . span ) ; //we take the try!( span
self . bump ( ) ; //remove (
2022-04-26 15:40:14 +03:00
let is_empty = self . token = = token ::CloseDelim ( Delimiter ::Parenthesis ) ; //check if the block is empty
self . consume_block ( Delimiter ::Parenthesis , ConsumeClosingDelim ::No ) ; //eat the block
2020-04-17 14:07:44 +02:00
let hi = self . token . span ;
self . bump ( ) ; //remove )
let mut err = self . struct_span_err ( lo . to ( hi ) , " use of deprecated `try` macro " ) ;
err . note ( " in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated " ) ;
2020-04-17 19:29:36 +02:00
let prefix = if is_empty { " " } else { " alternatively, " } ;
2020-04-17 14:07:44 +02:00
if ! is_empty {
err . multipart_suggestion (
" you can use the `?` operator instead " ,
vec! [ ( try_span , " " . to_owned ( ) ) , ( hi , " ? " . to_owned ( ) ) ] ,
Applicability ::MachineApplicable ,
) ;
}
2022-06-13 15:48:40 +09:00
err . span_suggestion ( lo . shrink_to_lo ( ) , & format! ( " {prefix} you can still access the deprecated `try!()` macro using the \" raw identifier \" syntax " ) , " r# " , Applicability ::MachineApplicable ) ;
2020-04-17 19:10:29 +02:00
err . emit ( ) ;
Ok ( self . mk_expr_err ( lo . to ( hi ) ) )
2020-04-17 14:07:44 +02:00
} else {
2020-04-17 19:10:29 +02:00
Err ( self . expected_expression_found ( ) ) // The user isn't trying to invoke the try! macro
2020-04-17 14:07:44 +02:00
}
}
2019-09-06 03:56:45 +01:00
/// Recovers a situation like `for ( $pat in $expr )`
2019-07-24 10:26:32 +02:00
/// and suggest writing `for $pat in $expr` instead.
///
/// This should be called before parsing the `$block`.
2019-10-08 09:35:34 +02:00
pub ( super ) fn recover_parens_around_for_head (
2019-07-24 10:26:32 +02:00
& mut self ,
pat : P < Pat > ,
begin_paren : Option < Span > ,
) -> P < Pat > {
match ( & self . token . kind , begin_paren ) {
2022-04-26 15:40:14 +03:00
( token ::CloseDelim ( Delimiter ::Parenthesis ) , Some ( begin_par_sp ) ) = > {
2019-07-24 10:26:32 +02:00
self . bump ( ) ;
2022-10-24 18:24:10 +08:00
let sm = self . sess . source_map ( ) ;
let left = begin_par_sp ;
let right = self . prev_token . span ;
let left_snippet = if let Ok ( snip ) = sm . span_to_prev_source ( left ) & &
2022-11-18 10:30:47 +01:00
! snip . ends_with ( ' ' ) {
2022-10-24 18:24:10 +08:00
" " . to_string ( )
} else {
" " . to_string ( )
} ;
let right_snippet = if let Ok ( snip ) = sm . span_to_next_source ( right ) & &
2022-11-18 10:30:47 +01:00
! snip . starts_with ( ' ' ) {
2022-10-24 18:24:10 +08:00
" " . to_string ( )
} else {
" " . to_string ( )
} ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( ParenthesesInForHead {
2022-10-24 18:24:10 +08:00
span : vec ! [ left , right ] ,
2021-09-17 13:39:26 +09:00
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
// However, this is prevented before we get here.
2022-10-24 18:24:10 +08:00
sugg : ParenthesesInForHeadSugg { left , right , left_snippet , right_snippet } ,
2022-09-08 18:23:31 +02:00
} ) ;
2019-07-24 10:26:32 +02:00
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
2019-09-26 16:18:31 +01:00
pat . and_then ( | pat | match pat . kind {
2019-07-24 10:26:32 +02:00
PatKind ::Paren ( pat ) = > pat ,
_ = > P ( pat ) ,
} )
}
_ = > pat ,
}
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn could_ascription_be_path ( & self , node : & ast ::ExprKind ) -> bool {
2019-11-05 10:29:54 -08:00
( self . token = = token ::Lt & & // `foo:<bar`, likely a typoed turbofish.
2019-12-22 17:42:04 -05:00
self . look_ahead ( 1 , | t | t . is_ident ( ) & & ! t . is_reserved_ident ( ) ) )
| | self . token . is_ident ( ) & &
2020-10-26 21:02:48 -04:00
matches! ( node , ast ::ExprKind ::Path ( .. ) | ast ::ExprKind ::Field ( .. ) ) & &
2019-05-16 14:31:07 -07:00
! self . token . is_reserved_ident ( ) & & // v `foo:bar(baz)`
2022-04-26 15:40:14 +03:00
self . look_ahead ( 1 , | t | t = = & token ::OpenDelim ( Delimiter ::Parenthesis ) )
| | self . look_ahead ( 1 , | t | t = = & token ::OpenDelim ( Delimiter ::Brace ) ) // `foo:bar {`
2020-07-09 09:09:25 -07:00
| | self . look_ahead ( 1 , | t | t = = & token ::Colon ) & & // `foo:bar::<baz`
self . look_ahead ( 2 , | t | t = = & token ::Lt ) & &
self . look_ahead ( 3 , | t | t . is_ident ( ) )
2019-12-22 17:42:04 -05:00
| | self . look_ahead ( 1 , | t | t = = & token ::Colon ) & & // `foo:bar:baz`
self . look_ahead ( 2 , | t | t . is_ident ( ) )
| | self . look_ahead ( 1 , | t | t = = & token ::ModSep )
& & ( self . look_ahead ( 2 , | t | t . is_ident ( ) ) | | // `foo:bar::baz`
2020-03-29 12:02:28 -04:00
self . look_ahead ( 2 , | t | t = = & token ::Lt ) ) // `foo:bar::<baz>`
2019-05-16 14:31:07 -07:00
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn recover_seq_parse_error (
2019-05-16 14:31:07 -07:00
& mut self ,
2022-04-26 15:40:14 +03:00
delim : Delimiter ,
2019-05-16 14:31:07 -07:00
lo : Span ,
result : PResult < ' a , P < Expr > > ,
) -> P < Expr > {
match result {
Ok ( x ) = > x ,
Err ( mut err ) = > {
err . emit ( ) ;
2019-10-25 18:30:02 -07:00
// Recover from parse error, callers expect the closing delim to be consumed.
self . consume_block ( delim , ConsumeClosingDelim ::Yes ) ;
2022-08-15 09:58:38 +10:00
self . mk_expr ( lo . to ( self . prev_token . span ) , ExprKind ::Err )
2019-05-16 14:31:07 -07:00
}
}
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn recover_closing_delimiter (
2019-05-16 14:31:07 -07:00
& mut self ,
2019-06-05 14:17:56 +03:00
tokens : & [ TokenKind ] ,
2022-01-23 12:34:26 -06:00
mut err : DiagnosticBuilder < ' a , ErrorGuaranteed > ,
2019-05-16 14:31:07 -07:00
) -> PResult < ' a , bool > {
let mut pos = None ;
2019-09-06 03:56:45 +01:00
// We want to use the last closing delim that would apply.
2019-05-16 14:31:07 -07:00
for ( i , unmatched ) in self . unclosed_delims . iter ( ) . enumerate ( ) . rev ( ) {
if tokens . contains ( & token ::CloseDelim ( unmatched . expected_delim ) )
2019-06-07 13:31:13 +03:00
& & Some ( self . token . span ) > unmatched . unclosed_span
2019-05-16 14:31:07 -07:00
{
pos = Some ( i ) ;
}
}
match pos {
Some ( pos ) = > {
// Recover and assume that the detected unclosed delimiter was meant for
// this location. Emit the diagnostic and act as if the delimiter was
// present for the parser's sake.
2019-12-22 17:42:04 -05:00
// Don't attempt to recover from this unclosed delimiter more than once.
2019-05-16 14:31:07 -07:00
let unmatched = self . unclosed_delims . remove ( pos ) ;
let delim = TokenType ::Token ( token ::CloseDelim ( unmatched . expected_delim ) ) ;
2019-10-28 17:44:20 -07:00
if unmatched . found_delim . is_none ( ) {
// We encountered `Eof`, set this fact here to avoid complaining about missing
// `fn main()` when we found place to suggest the closing brace.
* self . sess . reached_eof . borrow_mut ( ) = true ;
}
2019-05-16 14:31:07 -07:00
2019-09-06 03:56:45 +01:00
// We want to suggest the inclusion of the closing delimiter where it makes
2019-05-16 14:31:07 -07:00
// the most sense, which is immediately after the last token:
//
// {foo(bar {}}
2021-08-27 10:57:28 +00:00
// ^ ^
2019-05-16 14:31:07 -07:00
// | |
2019-06-26 11:21:59 -05:00
// | help: `)` may belong here
2019-05-16 14:31:07 -07:00
// |
// unclosed delimiter
if let Some ( sp ) = unmatched . unclosed_span {
2021-08-27 10:57:28 +00:00
let mut primary_span : Vec < Span > =
err . span . primary_spans ( ) . iter ( ) . cloned ( ) . collect ( ) ;
primary_span . push ( sp ) ;
let mut primary_span : MultiSpan = primary_span . into ( ) ;
for span_label in err . span . span_labels ( ) {
if let Some ( label ) = span_label . label {
2022-03-26 07:27:43 +00:00
primary_span . push_span_label ( span_label . span , label ) ;
2021-08-27 10:57:28 +00:00
}
}
err . set_span ( primary_span ) ;
2019-05-16 14:31:07 -07:00
err . span_label ( sp , " unclosed delimiter " ) ;
}
2020-07-02 14:32:12 +09:00
// Backticks should be removed to apply suggestions.
let mut delim = delim . to_string ( ) ;
delim . retain ( | c | c ! = '`' ) ;
2019-05-16 14:31:07 -07:00
err . span_suggestion_short (
2020-02-29 14:56:15 +03:00
self . prev_token . span . shrink_to_hi ( ) ,
2022-03-15 19:13:56 +09:00
& format! ( " ` {delim} ` may belong here " ) ,
2020-07-02 14:32:12 +09:00
delim ,
2019-05-16 14:31:07 -07:00
Applicability ::MaybeIncorrect ,
) ;
2019-10-25 18:30:02 -07:00
if unmatched . found_delim . is_none ( ) {
// Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown
// errors which would be emitted elsewhere in the parser and let other error
// recovery consume the rest of the file.
Err ( err )
} else {
err . emit ( ) ;
2019-12-22 17:42:04 -05:00
self . expected_tokens . clear ( ) ; // Reduce the number of errors.
2019-10-25 18:30:02 -07:00
Ok ( true )
}
2019-05-16 14:31:07 -07:00
}
_ = > Err ( err ) ,
}
}
2019-09-06 03:56:45 +01:00
/// Eats tokens until we can be relatively sure we reached the end of the
/// statement. This is something of a best-effort heuristic.
///
/// We terminate when we find an unmatched `}` (without consuming it).
2019-10-08 09:35:34 +02:00
pub ( super ) fn recover_stmt ( & mut self ) {
2019-05-16 14:31:07 -07:00
self . recover_stmt_ ( SemiColonMode ::Ignore , BlockMode ::Ignore )
}
2019-09-06 03:56:45 +01:00
/// If `break_on_semi` is `Break`, then we will stop consuming tokens after
/// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
/// approximate -- it can mean we break too early due to macros, but that
/// should only lead to sub-optimal recovery, not inaccurate parsing).
///
/// If `break_on_block` is `Break`, then we will stop consuming tokens
/// after finding (and consuming) a brace-delimited block.
2019-10-12 06:12:00 +02:00
pub ( super ) fn recover_stmt_ (
& mut self ,
break_on_semi : SemiColonMode ,
break_on_block : BlockMode ,
) {
2019-05-16 14:31:07 -07:00
let mut brace_depth = 0 ;
let mut bracket_depth = 0 ;
let mut in_block = false ;
2019-12-22 17:42:04 -05:00
debug! ( " recover_stmt_ enter loop (semi={:?}, block={:?}) " , break_on_semi , break_on_block ) ;
2019-05-16 14:31:07 -07:00
loop {
debug! ( " recover_stmt_ loop {:?} " , self . token ) ;
2019-06-05 01:17:07 +03:00
match self . token . kind {
2022-04-26 15:40:14 +03:00
token ::OpenDelim ( Delimiter ::Brace ) = > {
2019-05-16 14:31:07 -07:00
brace_depth + = 1 ;
self . bump ( ) ;
2019-12-22 17:42:04 -05:00
if break_on_block = = BlockMode ::Break & & brace_depth = = 1 & & bracket_depth = = 0
{
2019-05-16 14:31:07 -07:00
in_block = true ;
}
}
2022-04-26 15:40:14 +03:00
token ::OpenDelim ( Delimiter ::Bracket ) = > {
2019-05-16 14:31:07 -07:00
bracket_depth + = 1 ;
self . bump ( ) ;
}
2022-04-26 15:40:14 +03:00
token ::CloseDelim ( Delimiter ::Brace ) = > {
2019-05-16 14:31:07 -07:00
if brace_depth = = 0 {
debug! ( " recover_stmt_ return - close delim {:?} " , self . token ) ;
break ;
}
brace_depth - = 1 ;
self . bump ( ) ;
if in_block & & bracket_depth = = 0 & & brace_depth = = 0 {
debug! ( " recover_stmt_ return - block end {:?} " , self . token ) ;
break ;
}
}
2022-04-26 15:40:14 +03:00
token ::CloseDelim ( Delimiter ::Bracket ) = > {
2019-05-16 14:31:07 -07:00
bracket_depth - = 1 ;
if bracket_depth < 0 {
bracket_depth = 0 ;
}
self . bump ( ) ;
}
token ::Eof = > {
debug! ( " recover_stmt_ return - Eof " ) ;
break ;
}
token ::Semi = > {
self . bump ( ) ;
2019-12-22 17:42:04 -05:00
if break_on_semi = = SemiColonMode ::Break
& & brace_depth = = 0
& & bracket_depth = = 0
{
2019-05-16 14:31:07 -07:00
debug! ( " recover_stmt_ return - Semi " ) ;
break ;
}
}
2019-12-22 17:42:04 -05:00
token ::Comma
if break_on_semi = = SemiColonMode ::Comma
& & brace_depth = = 0
& & bracket_depth = = 0 = >
2019-05-16 15:25:58 -07:00
{
debug! ( " recover_stmt_ return - Semi " ) ;
break ;
2019-05-16 14:31:07 -07:00
}
2019-12-22 17:42:04 -05:00
_ = > self . bump ( ) ,
2019-05-16 14:31:07 -07:00
}
}
2019-05-23 12:55:26 -07:00
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn check_for_for_in_in_typo ( & mut self , in_span : Span ) {
2019-05-23 12:55:26 -07:00
if self . eat_keyword ( kw ::In ) {
// a common typo: `for _ in in bar {}`
2022-05-31 16:28:05 -05:00
self . sess . emit_err ( InInTypo {
span : self . prev_token . span ,
sugg_span : in_span . until ( self . prev_token . span ) ,
} ) ;
2019-05-23 12:55:26 -07:00
}
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn eat_incorrect_doc_comment_for_param_type ( & mut self ) {
2020-07-21 22:16:19 +03:00
if let token ::DocComment ( .. ) = self . token . kind {
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( DocCommentOnParamType { span : self . token . span } ) ;
2019-05-23 12:55:26 -07:00
self . bump ( ) ;
2019-12-22 17:42:04 -05:00
} else if self . token = = token ::Pound
2022-04-26 15:40:14 +03:00
& & self . look_ahead ( 1 , | t | * t = = token ::OpenDelim ( Delimiter ::Bracket ) )
2019-12-22 17:42:04 -05:00
{
2019-06-07 13:31:13 +03:00
let lo = self . token . span ;
2019-05-23 12:55:26 -07:00
// Skip every token until next possible arg.
2022-04-26 15:40:14 +03:00
while self . token ! = token ::CloseDelim ( Delimiter ::Bracket ) {
2019-05-23 12:55:26 -07:00
self . bump ( ) ;
}
2019-06-07 13:31:13 +03:00
let sp = lo . to ( self . token . span ) ;
2019-05-23 12:55:26 -07:00
self . bump ( ) ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( AttributeOnParamType { span : sp } ) ;
2019-05-23 12:55:26 -07:00
}
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn parameter_without_type (
2019-05-23 12:55:26 -07:00
& mut self ,
2022-01-23 20:41:46 +00:00
err : & mut Diagnostic ,
2019-05-23 12:55:26 -07:00
pat : P < ast ::Pat > ,
require_name : bool ,
2020-02-02 11:10:27 +01:00
first_param : bool ,
2019-05-29 15:25:46 -07:00
) -> Option < Ident > {
2019-05-23 12:55:26 -07:00
// If we find a pattern followed by an identifier, it could be an (incorrect)
// C-style parameter declaration.
2019-12-22 17:42:04 -05:00
if self . check_ident ( )
2022-04-26 15:40:14 +03:00
& & self . look_ahead ( 1 , | t | {
* t = = token ::Comma | | * t = = token ::CloseDelim ( Delimiter ::Parenthesis )
} )
2019-12-22 17:42:04 -05:00
{
// `fn foo(String s) {}`
2019-05-23 12:55:26 -07:00
let ident = self . parse_ident ( ) . unwrap ( ) ;
let span = pat . span . with_hi ( ident . span . hi ( ) ) ;
err . span_suggestion (
span ,
" declare the type after the parameter binding " ,
2022-06-13 15:48:40 +09:00
" <identifier>: <type> " ,
2019-05-23 12:55:26 -07:00
Applicability ::HasPlaceholders ,
) ;
2019-05-29 15:25:46 -07:00
return Some ( ident ) ;
2021-03-05 04:19:15 +09:00
} else if require_name
& & ( self . token = = token ::Comma
| | self . token = = token ::Lt
2022-04-26 15:40:14 +03:00
| | self . token = = token ::CloseDelim ( Delimiter ::Parenthesis ) )
2021-03-05 04:19:15 +09:00
{
2021-03-17 09:49:46 +09:00
let rfc_note = " anonymous parameters are removed in the 2018 edition (see RFC 1685) " ;
2021-08-10 10:53:43 +00:00
let ( ident , self_sugg , param_sugg , type_sugg , self_span , param_span , type_span ) =
match pat . kind {
PatKind ::Ident ( _ , ident , _ ) = > (
ident ,
2022-06-17 18:48:09 +09:00
" self: " ,
2021-08-10 10:53:43 +00:00
" : TypeName " . to_string ( ) ,
2022-06-17 18:48:09 +09:00
" _: " ,
2021-08-10 10:53:43 +00:00
pat . span . shrink_to_lo ( ) ,
pat . span . shrink_to_hi ( ) ,
pat . span . shrink_to_lo ( ) ,
) ,
// Also catches `fn foo(&a)`.
PatKind ::Ref ( ref inner_pat , mutab )
if matches! ( inner_pat . clone ( ) . into_inner ( ) . kind , PatKind ::Ident ( .. ) ) = >
{
match inner_pat . clone ( ) . into_inner ( ) . kind {
PatKind ::Ident ( _ , ident , _ ) = > {
let mutab = mutab . prefix_str ( ) ;
(
ident ,
2022-06-17 18:48:09 +09:00
" self: " ,
2022-03-15 19:13:56 +09:00
format! ( " {ident} : & {mutab} TypeName " ) ,
2022-06-17 18:48:09 +09:00
" _: " ,
2021-08-10 10:53:43 +00:00
pat . span . shrink_to_lo ( ) ,
pat . span ,
pat . span . shrink_to_lo ( ) ,
)
}
_ = > unreachable! ( ) ,
2021-03-05 14:52:45 +09:00
}
2021-03-17 09:49:46 +09:00
}
2021-08-10 10:53:43 +00:00
_ = > {
// Otherwise, try to get a type and emit a suggestion.
if let Some ( ty ) = pat . to_ty ( ) {
err . span_suggestion_verbose (
pat . span ,
" explicitly ignore the parameter name " ,
format! ( " _: {} " , pprust ::ty_to_string ( & ty ) ) ,
Applicability ::MachineApplicable ,
) ;
err . note ( rfc_note ) ;
}
2021-03-17 09:49:46 +09:00
2021-08-10 10:53:43 +00:00
return None ;
}
} ;
2021-03-05 04:19:15 +09:00
// `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}`
if first_param {
2019-05-23 12:55:26 -07:00
err . span_suggestion (
2021-08-10 10:53:43 +00:00
self_span ,
2021-03-05 04:19:15 +09:00
" if this is a `self` type, give it a parameter name " ,
self_sugg ,
Applicability ::MaybeIncorrect ,
) ;
}
// Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to
// `fn foo(HashMap: TypeName<u32>)`.
if self . token ! = token ::Lt {
err . span_suggestion (
2021-08-10 10:53:43 +00:00
param_span ,
2021-03-05 04:19:15 +09:00
" if this is a parameter name, give it a type " ,
param_sugg ,
Applicability ::HasPlaceholders ,
2019-05-23 12:55:26 -07:00
) ;
}
2021-03-05 04:19:15 +09:00
err . span_suggestion (
2021-08-10 10:53:43 +00:00
type_span ,
2021-03-05 04:19:15 +09:00
" if this is a type, explicitly ignore the parameter name " ,
type_sugg ,
Applicability ::MachineApplicable ,
) ;
2021-03-17 09:49:46 +09:00
err . note ( rfc_note ) ;
2021-03-05 04:19:15 +09:00
// Don't attempt to recover by using the `X` in `X<Y>` as the parameter name.
return if self . token = = token ::Lt { None } else { Some ( ident ) } ;
2019-05-23 12:55:26 -07:00
}
2019-05-29 15:25:46 -07:00
None
2019-05-16 14:31:07 -07:00
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn recover_arg_parse ( & mut self ) -> PResult < ' a , ( P < ast ::Pat > , P < ast ::Ty > ) > {
2021-02-07 20:40:33 -06:00
let pat = self . parse_pat_no_top_alt ( Some ( " argument name " ) ) ? ;
2019-05-23 12:54:27 -07:00
self . expect ( & token ::Colon ) ? ;
let ty = self . parse_ty ( ) ? ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( PatternMethodParamWithoutBody { span : pat . span } ) ;
2019-05-23 12:54:27 -07:00
// Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
2020-07-27 18:02:29 -04:00
let pat =
P ( Pat { kind : PatKind ::Wild , span : pat . span , id : ast ::DUMMY_NODE_ID , tokens : None } ) ;
2019-05-23 12:54:27 -07:00
Ok ( ( pat , ty ) )
}
2020-02-02 11:10:27 +01:00
pub ( super ) fn recover_bad_self_param ( & mut self , mut param : Param ) -> PResult < ' a , Param > {
2022-09-08 18:23:31 +02:00
let span = param . pat . span ;
2019-09-26 17:25:31 +01:00
param . ty . kind = TyKind ::Err ;
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( SelfParamNotFirst { span } ) ;
2019-08-27 13:24:32 +02:00
Ok ( param )
2019-05-23 12:54:27 -07:00
}
2022-04-26 15:40:14 +03:00
pub ( super ) fn consume_block ( & mut self , delim : Delimiter , consume_close : ConsumeClosingDelim ) {
2019-05-16 14:31:07 -07:00
let mut brace_depth = 0 ;
loop {
if self . eat ( & token ::OpenDelim ( delim ) ) {
brace_depth + = 1 ;
2019-10-25 18:30:02 -07:00
} else if self . check ( & token ::CloseDelim ( delim ) ) {
2019-05-16 14:31:07 -07:00
if brace_depth = = 0 {
2019-10-25 18:30:02 -07:00
if let ConsumeClosingDelim ::Yes = consume_close {
// Some of the callers of this method expect to be able to parse the
// closing delimiter themselves, so we leave it alone. Otherwise we advance
// the parser.
self . bump ( ) ;
}
2019-05-16 14:31:07 -07:00
return ;
} else {
2019-10-25 18:30:02 -07:00
self . bump ( ) ;
2019-05-16 14:31:07 -07:00
brace_depth - = 1 ;
continue ;
}
2022-05-11 10:14:49 +10:00
} else if self . token = = token ::Eof {
2019-05-16 14:31:07 -07:00
return ;
} else {
self . bump ( ) ;
}
}
}
2022-01-23 12:34:26 -06:00
pub ( super ) fn expected_expression_found ( & self ) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
2019-06-05 01:17:07 +03:00
let ( span , msg ) = match ( & self . token . kind , self . subparser_name ) {
2019-05-24 02:04:56 +03:00
( & token ::Eof , Some ( origin ) ) = > {
2022-10-18 02:00:06 +08:00
let sp = self . prev_token . span . shrink_to_hi ( ) ;
2022-03-15 19:13:56 +09:00
( sp , format! ( " expected expression, found end of {origin} " ) )
2019-05-21 23:16:46 -07:00
}
2019-12-22 17:42:04 -05:00
_ = > (
self . token . span ,
2019-12-07 03:07:35 +01:00
format! ( " expected expression, found {} " , super ::token_descr ( & self . token ) , ) ,
2019-12-22 17:42:04 -05:00
) ,
2019-05-21 23:16:46 -07:00
} ;
let mut err = self . struct_span_err ( span , & msg ) ;
2019-06-07 13:31:13 +03:00
let sp = self . sess . source_map ( ) . start_point ( self . token . span ) ;
2019-05-21 23:16:46 -07:00
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-05-21 23:16:46 -07:00
}
err . span_label ( span , " expected expression " ) ;
err
}
2019-05-30 18:19:48 -07:00
2019-09-30 12:19:22 -07:00
fn consume_tts (
& mut self ,
2019-10-01 11:24:05 -07:00
mut acc : i64 , // `i64` because malformed code can have more closing delims than opening.
2019-10-01 15:51:50 -07:00
// Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`.
modifier : & [ ( token ::TokenKind , i64 ) ] ,
2019-09-30 12:19:22 -07:00
) {
while acc > 0 {
2019-10-01 11:24:05 -07:00
if let Some ( ( _ , val ) ) = modifier . iter ( ) . find ( | ( t , _ ) | * t = = self . token . kind ) {
2019-09-30 12:19:22 -07:00
acc + = * val ;
}
2019-10-01 15:51:50 -07:00
if self . token . kind = = token ::Eof {
2019-09-30 12:19:22 -07:00
break ;
}
self . bump ( ) ;
}
}
2019-11-26 22:19:54 -05:00
/// Replace duplicated recovered parameters with `_` pattern to avoid unnecessary errors.
2019-06-01 14:13:57 -07:00
///
/// This is necessary because at this point we don't know whether we parsed a function with
2019-08-27 13:24:32 +02:00
/// anonymous parameters or a function with names but no types. In order to minimize
2019-11-26 22:19:54 -05:00
/// unnecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where
2019-08-27 13:24:32 +02:00
/// the parameters are *names* (so we don't emit errors about not being able to find `b` in
2019-06-01 14:13:57 -07:00
/// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`,
2019-08-27 13:24:32 +02:00
/// we deduplicate them to not complain about duplicated parameter names.
2019-10-08 09:35:34 +02:00
pub ( super ) fn deduplicate_recovered_params_names ( & self , fn_inputs : & mut Vec < Param > ) {
2019-05-30 18:19:48 -07:00
let mut seen_inputs = FxHashSet ::default ( ) ;
for input in fn_inputs . iter_mut ( ) {
2019-12-22 17:42:04 -05:00
let opt_ident = if let ( PatKind ::Ident ( _ , ident , _ ) , TyKind ::Err ) =
( & input . pat . kind , & input . ty . kind )
{
2019-05-30 18:19:48 -07:00
Some ( * ident )
} else {
None
} ;
if let Some ( ident ) = opt_ident {
if seen_inputs . contains ( & ident ) {
2019-09-26 16:18:31 +01:00
input . pat . kind = PatKind ::Wild ;
2019-05-30 18:19:48 -07:00
}
seen_inputs . insert ( ident ) ;
}
}
}
2020-10-03 19:30:32 +01:00
/// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this
/// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
/// like the user has forgotten them.
pub fn handle_ambiguous_unbraced_const_arg (
& mut self ,
args : & mut Vec < AngleBracketedArg > ,
) -> PResult < ' a , bool > {
// If we haven't encountered a closing `>`, then the argument is malformed.
// It's likely that the user has written a const expression without enclosing it
// in braces, so we try to recover here.
let arg = args . pop ( ) . unwrap ( ) ;
// FIXME: for some reason using `unexpected` or `expected_one_of_not_found` has
// adverse side-effects to subsequent errors and seems to advance the parser.
// We are causing this error here exclusively in case that a `const` expression
// could be recovered from the current parser state, even if followed by more
// arguments after a comma.
let mut err = self . struct_span_err (
self . token . span ,
& format! ( " expected one of `,` or `>`, found {} " , super ::token_descr ( & self . token ) ) ,
) ;
err . span_label ( self . token . span , " expected one of `,` or `>` " ) ;
match self . recover_const_arg ( arg . span ( ) , err ) {
Ok ( arg ) = > {
args . push ( AngleBracketedArg ::Arg ( arg ) ) ;
if self . eat ( & token ::Comma ) {
return Ok ( true ) ; // Continue
}
}
Err ( mut err ) = > {
args . push ( arg ) ;
// We will emit a more generic error later.
err . delay_as_bug ( ) ;
}
}
return Ok ( false ) ; // Don't continue.
}
2020-11-18 12:49:39 +00:00
/// Attempt to parse a generic const argument that has not been enclosed in braces.
/// There are a limited number of expressions that are permitted without being encoded
/// in braces:
/// - Literals.
/// - Single-segment paths (i.e. standalone generic const parameters).
/// All other expressions that can be parsed will emit an error suggesting the expression be
/// wrapped in braces.
2020-10-03 19:30:32 +01:00
pub fn handle_unambiguous_unbraced_const_arg ( & mut self ) -> PResult < ' a , P < Expr > > {
let start = self . token . span ;
let expr = self . parse_expr_res ( Restrictions ::CONST_EXPR , None ) . map_err ( | mut err | {
err . span_label (
start . shrink_to_lo ( ) ,
" while parsing a const generic argument starting here " ,
) ;
err
} ) ? ;
if ! self . expr_is_valid_const_arg ( & expr ) {
2022-09-08 18:23:31 +02:00
self . sess . emit_err ( ConstGenericWithoutBraces {
span : expr . span ,
sugg : ConstGenericWithoutBracesSugg {
left : expr . span . shrink_to_lo ( ) ,
right : expr . span . shrink_to_hi ( ) ,
} ,
} ) ;
2020-10-03 19:30:32 +01:00
}
Ok ( expr )
}
2022-01-26 03:39:14 +00:00
fn recover_const_param_decl ( & mut self , ty_generics : Option < & Generics > ) -> Option < GenericArg > {
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2022-08-17 12:34:33 +10:00
let param = match self . parse_const_param ( AttrVec ::new ( ) ) {
2021-05-15 14:56:28 -07:00
Ok ( param ) = > param ,
2022-01-26 03:39:14 +00:00
Err ( err ) = > {
2021-05-15 14:56:28 -07:00
err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2022-01-26 03:39:14 +00:00
return None ;
2021-05-15 14:56:28 -07:00
}
} ;
2022-09-08 18:23:31 +02:00
let ident = param . ident . to_string ( ) ;
let sugg = match ( ty_generics , self . sess . source_map ( ) . span_to_snippet ( param . span ( ) ) ) {
( Some ( Generics { params , span : impl_generics , .. } ) , Ok ( snippet ) ) = > {
Some ( match & params [ .. ] {
[ ] = > UnexpectedConstParamDeclarationSugg ::AddParam {
impl_generics : * impl_generics ,
incorrect_decl : param . span ( ) ,
snippet ,
ident ,
} ,
[ .. , generic ] = > UnexpectedConstParamDeclarationSugg ::AppendParam {
impl_generics_end : generic . span ( ) . shrink_to_hi ( ) ,
incorrect_decl : param . span ( ) ,
snippet ,
ident ,
} ,
} )
}
_ = > None ,
} ;
self . sess . emit_err ( UnexpectedConstParamDeclaration { span : param . span ( ) , sugg } ) ;
2021-05-15 14:56:28 -07:00
let value = self . mk_expr_err ( param . span ( ) ) ;
2022-01-26 03:39:14 +00:00
Some ( GenericArg ::Const ( AnonConst { id : ast ::DUMMY_NODE_ID , value } ) )
2021-05-15 14:56:28 -07:00
}
pub fn recover_const_param_declaration (
& mut self ,
ty_generics : Option < & Generics > ,
) -> PResult < ' a , Option < GenericArg > > {
// We have to check for a few different cases.
2022-01-26 03:39:14 +00:00
if let Some ( arg ) = self . recover_const_param_decl ( ty_generics ) {
return Ok ( Some ( arg ) ) ;
2021-05-15 14:56:28 -07:00
}
// We haven't consumed `const` yet.
let start = self . token . span ;
self . bump ( ) ; // `const`
// Detect and recover from the old, pre-RFC2000 syntax for const generics.
2022-09-08 18:23:31 +02:00
let mut err = UnexpectedConstInGenericParam { span : start , to_remove : None } ;
2021-05-15 14:56:28 -07:00
if self . check_const_arg ( ) {
2022-09-08 18:23:31 +02:00
err . to_remove = Some ( start . until ( self . token . span ) ) ;
self . sess . emit_err ( err ) ;
2021-05-15 14:56:28 -07:00
Ok ( Some ( GenericArg ::Const ( self . parse_const_arg ( ) ? ) ) )
} else {
let after_kw_const = self . token . span ;
2022-09-08 18:23:31 +02:00
self . recover_const_arg ( after_kw_const , err . into_diagnostic ( & self . sess . span_diagnostic ) )
. map ( Some )
2021-05-15 14:56:28 -07:00
}
}
2020-10-03 19:30:32 +01:00
/// Try to recover from possible generic const argument without `{` and `}`.
///
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
/// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
2022-10-14 00:25:34 +08:00
/// if we think that the resulting expression would be well formed.
2020-10-03 19:30:32 +01:00
pub fn recover_const_arg (
& mut self ,
start : Span ,
2022-01-23 12:34:26 -06:00
mut err : DiagnosticBuilder < ' a , ErrorGuaranteed > ,
2020-10-03 19:30:32 +01:00
) -> PResult < ' a , GenericArg > {
2022-01-13 23:03:10 -08:00
let is_op_or_dot = AssocOp ::from_token ( & self . token )
2020-10-03 19:30:32 +01:00
. and_then ( | op | {
if let AssocOp ::Greater
| AssocOp ::Less
| AssocOp ::ShiftRight
| AssocOp ::GreaterEqual
// Don't recover from `foo::<bar = baz>`, because this could be an attempt to
// assign a value to a defaulted generic parameter.
| AssocOp ::Assign
| AssocOp ::AssignOp ( _ ) = op
{
None
} else {
Some ( op )
}
} )
2022-01-13 23:03:10 -08:00
. is_some ( )
| | self . token . kind = = TokenKind ::Dot ;
2020-10-03 19:30:32 +01:00
// This will be true when a trait object type `Foo +` or a path which was a `const fn` with
// type params has been parsed.
let was_op =
matches! ( self . prev_token . kind , token ::BinOp ( token ::Plus | token ::Shr ) | token ::Gt ) ;
2022-01-13 23:03:10 -08:00
if ! is_op_or_dot & & ! was_op {
2020-10-03 19:30:32 +01:00
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
return Err ( err ) ;
}
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2022-01-13 23:03:10 -08:00
if is_op_or_dot {
2020-10-03 19:30:32 +01:00
self . bump ( ) ;
}
match self . parse_expr_res ( Restrictions ::CONST_EXPR , None ) {
Ok ( expr ) = > {
2021-07-29 05:49:56 +09:00
// Find a mistake like `MyTrait<Assoc == S::Assoc>`.
if token ::EqEq = = snapshot . token . kind {
err . span_suggestion (
snapshot . token . span ,
2021-09-17 14:10:41 +09:00
" if you meant to use an associated type binding, replace `==` with `=` " ,
2022-06-13 15:48:40 +09:00
" = " ,
2021-07-29 05:49:56 +09:00
Applicability ::MaybeIncorrect ,
) ;
2021-09-17 14:10:41 +09:00
let value = self . mk_expr_err ( start . to ( expr . span ) ) ;
2021-07-29 05:49:56 +09:00
err . emit ( ) ;
return Ok ( GenericArg ::Const ( AnonConst { id : ast ::DUMMY_NODE_ID , value } ) ) ;
2022-03-11 15:26:19 -07:00
} else if token ::Colon = = snapshot . token . kind
& & expr . span . lo ( ) = = snapshot . token . span . hi ( )
& & matches! ( expr . kind , ExprKind ::Path ( .. ) )
{
// Find a mistake like "foo::var:A".
err . span_suggestion (
snapshot . token . span ,
2022-03-12 08:20:36 -07:00
" write a path separator here " ,
2022-06-13 15:48:40 +09:00
" :: " ,
2022-03-11 15:26:19 -07:00
Applicability ::MaybeIncorrect ,
) ;
err . emit ( ) ;
return Ok ( GenericArg ::Type ( self . mk_ty ( start . to ( expr . span ) , TyKind ::Err ) ) ) ;
2021-07-29 05:49:56 +09:00
} else if token ::Comma = = self . token . kind | | self . token . kind . should_end_const_arg ( )
{
2020-10-03 19:30:32 +01:00
// Avoid the following output by checking that we consumed a full const arg:
// help: expressions must be enclosed in braces to be used as const generic
// arguments
// |
// LL | let sr: Vec<{ (u32, _, _) = vec![] };
// | ^ ^
2022-01-13 23:03:10 -08:00
return Ok ( self . dummy_const_arg_needs_braces ( err , start . to ( expr . span ) ) ) ;
2020-10-03 19:30:32 +01:00
}
}
2022-01-26 03:39:14 +00:00
Err ( err ) = > {
2020-10-03 19:30:32 +01:00
err . cancel ( ) ;
}
}
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2020-10-03 19:30:32 +01:00
Err ( err )
}
2020-12-18 17:32:26 +01:00
2022-01-13 23:03:10 -08:00
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
pub fn dummy_const_arg_needs_braces (
& self ,
2022-01-23 12:34:26 -06:00
mut err : DiagnosticBuilder < ' a , ErrorGuaranteed > ,
2022-01-13 23:03:10 -08:00
span : Span ,
) -> GenericArg {
err . multipart_suggestion (
" expressions must be enclosed in braces to be used as const generic \
arguments " ,
vec! [ ( span . shrink_to_lo ( ) , " { " . to_string ( ) ) , ( span . shrink_to_hi ( ) , " } " . to_string ( ) ) ] ,
Applicability ::MaybeIncorrect ,
) ;
let value = self . mk_expr_err ( span ) ;
err . emit ( ) ;
GenericArg ::Const ( AnonConst { id : ast ::DUMMY_NODE_ID , value } )
}
2021-11-21 04:56:32 +00:00
/// Some special error handling for the "top-level" patterns in a match arm,
/// `for` loop, `let`, &c. (in contrast to subpatterns within such).
2022-05-20 19:51:09 -04:00
pub ( crate ) fn maybe_recover_colon_colon_in_pat_typo (
2021-11-21 04:56:32 +00:00
& mut self ,
mut first_pat : P < Pat > ,
expected : Expected ,
) -> P < Pat > {
2022-05-19 16:04:35 +10:00
if token ::Colon ! = self . token . kind {
2021-11-21 04:56:32 +00:00
return first_pat ;
}
if ! matches! ( first_pat . kind , PatKind ::Ident ( _ , _ , None ) | PatKind ::Path ( .. ) )
| | ! self . look_ahead ( 1 , | token | token . is_ident ( ) & & ! token . is_reserved_ident ( ) )
{
return first_pat ;
}
// The pattern looks like it might be a path with a `::` -> `:` typo:
// `match foo { bar:baz => {} }`
let span = self . token . span ;
// We only emit "unexpected `:`" error here if we can successfully parse the
// whole pattern correctly in that case.
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2021-11-21 04:56:32 +00:00
// Create error for "unexpected `:`".
match self . expected_one_of_not_found ( & [ ] , & [ ] ) {
Err ( mut err ) = > {
self . bump ( ) ; // Skip the `:`.
match self . parse_pat_no_top_alt ( expected ) {
2022-01-26 03:39:14 +00:00
Err ( inner_err ) = > {
2021-11-21 04:56:32 +00:00
// Carry on as if we had not done anything, callers will emit a
// reasonable error.
inner_err . cancel ( ) ;
err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2021-11-21 04:56:32 +00:00
}
Ok ( mut pat ) = > {
// We've parsed the rest of the pattern.
let new_span = first_pat . span . to ( pat . span ) ;
let mut show_sugg = false ;
// Try to construct a recovered pattern.
match & mut pat . kind {
PatKind ::Struct ( qself @ None , path , .. )
| PatKind ::TupleStruct ( qself @ None , path , _ )
| PatKind ::Path ( qself @ None , path ) = > match & first_pat . kind {
PatKind ::Ident ( _ , ident , _ ) = > {
2022-02-03 23:12:25 +01:00
path . segments . insert ( 0 , PathSegment ::from_ident ( * ident ) ) ;
2021-11-21 04:56:32 +00:00
path . span = new_span ;
show_sugg = true ;
first_pat = pat ;
}
PatKind ::Path ( old_qself , old_path ) = > {
path . segments = old_path
. segments
. iter ( )
. cloned ( )
. chain ( take ( & mut path . segments ) )
. collect ( ) ;
path . span = new_span ;
* qself = old_qself . clone ( ) ;
first_pat = pat ;
show_sugg = true ;
}
_ = > { }
} ,
2022-08-30 17:34:35 -05:00
PatKind ::Ident ( BindingAnnotation ::NONE , ident , None ) = > {
2021-11-21 04:56:32 +00:00
match & first_pat . kind {
PatKind ::Ident ( _ , old_ident , _ ) = > {
let path = PatKind ::Path (
None ,
Path {
span : new_span ,
2022-09-08 17:22:52 +10:00
segments : thin_vec ! [
2022-02-03 23:12:25 +01:00
PathSegment ::from_ident ( * old_ident ) ,
PathSegment ::from_ident ( * ident ) ,
2021-11-21 04:56:32 +00:00
] ,
tokens : None ,
} ,
) ;
first_pat = self . mk_pat ( new_span , path ) ;
show_sugg = true ;
}
PatKind ::Path ( old_qself , old_path ) = > {
let mut segments = old_path . segments . clone ( ) ;
2022-02-03 23:12:25 +01:00
segments . push ( PathSegment ::from_ident ( * ident ) ) ;
2021-11-21 04:56:32 +00:00
let path = PatKind ::Path (
old_qself . clone ( ) ,
Path { span : new_span , segments , tokens : None } ,
) ;
first_pat = self . mk_pat ( new_span , path ) ;
show_sugg = true ;
}
_ = > { }
}
}
_ = > { }
}
if show_sugg {
err . span_suggestion (
span ,
" maybe write a path separator here " ,
2022-06-13 15:48:40 +09:00
" :: " ,
2021-11-21 04:56:32 +00:00
Applicability ::MaybeIncorrect ,
) ;
} else {
first_pat = self . mk_pat ( new_span , PatKind ::Wild ) ;
}
err . emit ( ) ;
}
}
}
_ = > {
// Carry on as if we had not done anything. This should be unreachable.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2021-11-21 04:56:32 +00:00
}
} ;
first_pat
}
2022-05-20 19:51:09 -04:00
pub ( crate ) fn maybe_recover_unexpected_block_label ( & mut self ) -> bool {
2022-11-04 21:16:20 +00:00
// Check for `'a : {`
if ! ( self . check_lifetime ( )
& & self . look_ahead ( 1 , | tok | tok . kind = = token ::Colon )
& & self . look_ahead ( 2 , | tok | tok . kind = = token ::OpenDelim ( Delimiter ::Brace ) ) )
{
2022-01-12 20:43:24 +00:00
return false ;
2022-11-04 21:16:20 +00:00
}
let label = self . eat_label ( ) . expect ( " just checked if a label exists " ) ;
self . bump ( ) ; // eat `:`
2022-01-12 20:43:24 +00:00
let span = label . ident . span . to ( self . prev_token . span ) ;
let mut err = self . struct_span_err ( span , " block label not supported here " ) ;
err . span_label ( span , " not supported here " ) ;
err . tool_only_span_suggestion (
label . ident . span . until ( self . token . span ) ,
" remove this block label " ,
2022-06-13 16:01:16 +09:00
" " ,
2022-01-12 20:43:24 +00:00
Applicability ::MachineApplicable ,
) ;
err . emit ( ) ;
true
}
2021-11-21 04:56:32 +00:00
/// Some special error handling for the "top-level" patterns in a match arm,
/// `for` loop, `let`, &c. (in contrast to subpatterns within such).
2022-05-20 19:51:09 -04:00
pub ( crate ) fn maybe_recover_unexpected_comma (
2021-11-21 04:56:32 +00:00
& mut self ,
lo : Span ,
2022-01-12 20:43:24 +00:00
rt : CommaRecoveryMode ,
2021-11-21 04:56:32 +00:00
) -> PResult < ' a , ( ) > {
2022-05-19 16:07:55 +10:00
if self . token ! = token ::Comma {
2021-11-21 04:56:32 +00:00
return Ok ( ( ) ) ;
}
// An unexpected comma after a top-level pattern is a clue that the
// user (perhaps more accustomed to some other language) forgot the
// parentheses in what should have been a tuple pattern; return a
// suggestion-enhanced error here rather than choking on the comma later.
let comma_span = self . token . span ;
self . bump ( ) ;
2022-01-26 03:39:14 +00:00
if let Err ( err ) = self . skip_pat_list ( ) {
2021-11-21 04:56:32 +00:00
// We didn't expect this to work anyway; we just wanted to advance to the
// end of the comma-sequence so we know the span to suggest parenthesizing.
err . cancel ( ) ;
}
let seq_span = lo . to ( self . prev_token . span ) ;
let mut err = self . struct_span_err ( comma_span , " unexpected `,` in pattern " ) ;
if let Ok ( seq_snippet ) = self . span_to_snippet ( seq_span ) {
2022-01-12 20:43:24 +00:00
err . multipart_suggestion (
& format! (
" try adding parentheses to match on a tuple{} " ,
if let CommaRecoveryMode ::LikelyTuple = rt { " " } else { " ... " } ,
) ,
vec! [
( seq_span . shrink_to_lo ( ) , " ( " . to_string ( ) ) ,
( seq_span . shrink_to_hi ( ) , " ) " . to_string ( ) ) ,
] ,
2021-11-21 04:56:32 +00:00
Applicability ::MachineApplicable ,
) ;
2022-01-12 20:43:24 +00:00
if let CommaRecoveryMode ::EitherTupleOrPipe = rt {
err . span_suggestion (
seq_span ,
" ...or a vertical bar to match on multiple alternatives " ,
seq_snippet . replace ( ',' , " | " ) ,
Applicability ::MachineApplicable ,
) ;
}
2021-11-21 04:56:32 +00:00
}
Err ( err )
}
2022-05-20 19:51:09 -04:00
pub ( crate ) fn maybe_recover_bounds_doubled_colon ( & mut self , ty : & Ty ) -> PResult < ' a , ( ) > {
2022-03-25 13:53:03 -07:00
let TyKind ::Path ( qself , path ) = & ty . kind else { return Ok ( ( ) ) } ;
let qself_position = qself . as_ref ( ) . map ( | qself | qself . position ) ;
for ( i , segments ) in path . segments . windows ( 2 ) . enumerate ( ) {
if qself_position . map ( | pos | i < pos ) . unwrap_or ( false ) {
continue ;
}
if let [ a , b ] = segments {
let ( a_span , b_span ) = ( a . span ( ) , b . span ( ) ) ;
let between_span = a_span . shrink_to_hi ( ) . to ( b_span . shrink_to_lo ( ) ) ;
2022-11-16 21:58:58 +00:00
if self . span_to_snippet ( between_span ) . as_deref ( ) = = Ok ( " :: " ) {
2022-09-08 18:23:31 +02:00
return Err ( DoubleColonInBound {
span : path . span . shrink_to_hi ( ) ,
between : between_span ,
}
. into_diagnostic ( & self . sess . span_diagnostic ) ) ;
2022-03-25 13:53:03 -07:00
}
}
}
Ok ( ( ) )
}
2022-12-28 17:56:22 -08:00
pub fn is_diff_marker ( & mut self , long_kind : & TokenKind , short_kind : & TokenKind ) -> bool {
( 0 .. 3 ) . all ( | i | self . look_ahead ( i , | tok | tok = = long_kind ) )
& & self . look_ahead ( 3 , | tok | tok = = short_kind )
}
fn diff_marker ( & mut self , long_kind : & TokenKind , short_kind : & TokenKind ) -> Option < Span > {
if self . is_diff_marker ( long_kind , short_kind ) {
let lo = self . token . span ;
for _ in 0 .. 4 {
self . bump ( ) ;
}
return Some ( lo . to ( self . prev_token . span ) ) ;
}
None
}
pub fn recover_diff_marker ( & mut self ) {
let Some ( start ) = self . diff_marker ( & TokenKind ::BinOp ( token ::Shl ) , & TokenKind ::Lt ) else {
return ;
} ;
let mut spans = Vec ::with_capacity ( 3 ) ;
spans . push ( start ) ;
2022-12-28 20:55:46 -08:00
let mut middlediff3 = None ;
2022-12-28 17:56:22 -08:00
let mut middle = None ;
let mut end = None ;
loop {
if self . token . kind = = TokenKind ::Eof {
break ;
}
2022-12-28 20:55:46 -08:00
if let Some ( span ) = self . diff_marker ( & TokenKind ::OrOr , & TokenKind ::BinOp ( token ::Or ) ) {
middlediff3 = Some ( span ) ;
}
2022-12-28 17:56:22 -08:00
if let Some ( span ) = self . diff_marker ( & TokenKind ::EqEq , & TokenKind ::Eq ) {
middle = Some ( span ) ;
}
if let Some ( span ) = self . diff_marker ( & TokenKind ::BinOp ( token ::Shr ) , & TokenKind ::Gt ) {
spans . push ( span ) ;
end = Some ( span ) ;
break ;
}
self . bump ( ) ;
}
let mut err = self . struct_span_err ( spans , " encountered diff marker " ) ;
2022-12-28 18:46:20 -08:00
err . span_label ( start , " after this is the code before the merge " ) ;
2022-12-28 20:55:46 -08:00
if let Some ( middle ) = middlediff3 {
err . span_label ( middle , " " ) ;
}
2022-12-28 17:56:22 -08:00
if let Some ( middle ) = middle {
2022-12-28 18:46:20 -08:00
err . span_label ( middle , " " ) ;
2022-12-28 17:56:22 -08:00
}
if let Some ( end ) = end {
2022-12-28 18:46:20 -08:00
err . span_label ( end , " above this are the incoming code changes " ) ;
2022-12-28 17:56:22 -08:00
}
2022-12-28 18:46:20 -08:00
err . help (
" if you're having merge conflicts after pulling new code, the top section is the code \
you already had and the bottom section is the remote code " ,
) ;
err . help (
" if you're in the middle of a rebase, the top section is the code being rebased onto \
and the bottom section is the code coming from the current commit being rebased " ,
) ;
err . note (
" for an explanation on these markers from the `git` documentation, visit \
< https ://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
) ;
2022-12-28 17:56:22 -08:00
err . emit ( ) ;
FatalError . raise ( )
}
2021-11-21 04:56:32 +00:00
/// Parse and throw away a parenthesized comma separated
/// sequence of patterns until `)` is reached.
fn skip_pat_list ( & mut self ) -> PResult < ' a , ( ) > {
2022-04-26 15:40:14 +03:00
while ! self . check ( & token ::CloseDelim ( Delimiter ::Parenthesis ) ) {
2021-11-21 04:56:32 +00:00
self . parse_pat_no_top_alt ( None ) ? ;
if ! self . eat ( & token ::Comma ) {
return Ok ( ( ) ) ;
}
}
Ok ( ( ) )
}
2019-04-28 13:28:07 +08:00
}