2021-11-21 04:56:32 +00:00
use std ::mem ::take ;
2024-06-05 17:02:18 -04:00
use std ::ops ::{ Deref , DerefMut } ;
2024-07-29 08:13:50 +10:00
2024-02-13 23:28:27 +00:00
use ast ::token ::IdentIsRaw ;
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 ;
2023-12-22 21:56:58 -08:00
use rustc_ast ::token ::{ self , Delimiter , Lit , LitKind , Token , TokenKind } ;
2023-07-31 14:55:47 +00:00
use rustc_ast ::tokenstream ::AttrTokenTree ;
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 ::{
2024-04-16 19:23:30 -04:00
AngleBracketedArg , AngleBracketedArgs , AnonConst , AttrVec , BinOpKind , BindingMode , Block ,
2023-07-31 14:55:47 +00:00
BlockCheckMode , Expr , ExprKind , GenericArg , Generics , HasTokens , Item , ItemKind , Param , Pat ,
2024-05-09 18:44:40 +10:00
PatKind , Path , PathSegment , QSelf , Recovered , 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 ::{
2024-06-18 10:35:56 +00:00
Applicability , Diag , DiagCtxtHandle , ErrorGuaranteed , FatalError , PErr , PResult , Subdiagnostic ,
2024-09-08 15:59:05 -04:00
Suggestions , pluralize ,
2022-03-26 07:27:43 +00:00
} ;
2022-09-30 01:38:15 +00:00
use rustc_session ::errors ::ExprParenthesesNeeded ;
2024-09-02 12:43:35 -04:00
use rustc_span ::edit_distance ::find_best_match_for_name ;
2020-01-11 00:19:09 +00:00
use rustc_span ::source_map ::Spanned ;
2024-09-02 12:43:35 -04:00
use rustc_span ::symbol ::{ AllKeywords , Ident , kw , sym } ;
2023-10-20 02:54:45 +00:00
use rustc_span ::{ BytePos , DUMMY_SP , Span , SpanSnippetError , Symbol } ;
2022-09-08 17:22:52 +10:00
use thin_vec ::{ ThinVec , thin_vec } ;
2024-05-22 14:42:14 +10:00
use tracing ::{ debug , trace } ;
2019-05-23 12:55:26 -07:00
2021-11-21 04:56:32 +00:00
use super ::pat ::Expected ;
use super ::{
2024-06-05 17:02:18 -04:00
BlockMode , CommaRecoveryMode , Parser , PathStyle , Restrictions , SemiColonMode , SeqSep , TokenType ,
2024-07-29 08:13:50 +10:00
} ;
2022-08-30 13:19:17 +02:00
use crate ::errors ::{
2024-07-11 22:07:11 +00:00
AddParen , AmbiguousPlus , AsyncMoveBlockIn2015 , AttributeOnParamType , AwaitSuggestion ,
BadQPathStage2 , BadTypePlus , BadTypePlusSub , ColonAsSemi , ComparisonOperatorsCannotBeChained ,
2023-07-30 15:49:33 +08:00
ComparisonOperatorsCannotBeChainedSugg , ConstGenericWithoutBraces ,
ConstGenericWithoutBracesSugg , DocCommentDoesNotDocumentAnything , DocCommentOnParamType ,
DoubleColonInBound , ExpectedIdentifier , ExpectedSemi , ExpectedSemiSugg ,
2023-03-07 23:01:26 +13:00
GenericParamsWithoutAngleBrackets , GenericParamsWithoutAngleBracketsSugg ,
2023-12-06 16:56:45 -08:00
HelpIdentifierStartsWithNumber , HelpUseLatestEdition , InInTypo , IncorrectAwait ,
IncorrectSemicolon , IncorrectUseOfAwait , PatternMethodParamWithoutBody , QuestionMarkInType ,
QuestionMarkInTypeSugg , SelfParamNotFirst , StructLiteralBodyWithoutPath ,
StructLiteralBodyWithoutPathSugg , StructLiteralNeedingParens , StructLiteralNeedingParensSugg ,
SuggAddMissingLetStmt , SuggEscapeIdentifier , SuggRemoveComma , TernaryOperator ,
UnexpectedConstInGenericParam , UnexpectedConstParamDeclaration ,
UnexpectedConstParamDeclarationSugg , UnmatchedAngleBrackets , UseEqInstead , WrapType ,
2024-07-29 08:13:50 +10:00
} ;
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
use crate ::parser ::attr ::InnerAttrPolicy ;
2022-10-13 10:13:02 +01:00
use crate ::{ fluent_generated as fluent , parser } ;
2024-07-29 08:13:50 +10:00
2019-05-30 18:19:48 -07:00
/// Creates a placeholder argument.
2024-02-14 14:50:49 +11:00
pub ( super ) fn dummy_arg ( ident : Ident , guar : ErrorGuaranteed ) -> Param {
2019-05-30 18:19:48 -07:00
let pat = P ( Pat {
id : ast ::DUMMY_NODE_ID ,
2024-04-16 19:23:30 -04:00
kind : PatKind ::Ident ( BindingMode ::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
} ) ;
2024-02-14 14:50:49 +11:00
let ty = Ty { kind : TyKind ::Err ( guar ) , 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 {
2022-11-16 21:46:06 +01:00
const PATH_STYLE : PathStyle = PathStyle ::Pat ;
2019-04-28 13:28:07 +08:00
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 {
2024-06-03 15:47:46 +10:00
pub ( super ) fn yes ( & self ) -> bool {
2020-08-12 15:39:15 -07:00
match self {
AttemptLocalParseRecovery ::Yes = > true ,
AttemptLocalParseRecovery ::No = > false ,
}
}
2024-06-03 15:47:46 +10:00
pub ( super ) fn no ( & self ) -> bool {
2020-08-12 15:39:15 -07:00
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 ,
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 " ) ,
}
}
}
2024-09-02 12:43:35 -04:00
#[ derive(Debug, rustc_macros::Subdiagnostic) ]
#[ suggestion(
parse_misspelled_kw ,
applicability = " machine-applicable " ,
code = " {similar_kw} " ,
style = " verbose "
) ]
struct MisspelledKw {
similar_kw : String ,
#[ primary_span ]
span : Span ,
is_incorrect_case : bool ,
}
/// Checks if the given `lookup` identifier is similar to any keyword symbol in `candidates`.
fn find_similar_kw ( lookup : Ident , candidates : & [ Symbol ] ) -> Option < MisspelledKw > {
let lowercase = lookup . name . as_str ( ) . to_lowercase ( ) ;
let lowercase_sym = Symbol ::intern ( & lowercase ) ;
if candidates . contains ( & lowercase_sym ) {
Some ( MisspelledKw { similar_kw : lowercase , span : lookup . span , is_incorrect_case : true } )
} else if let Some ( similar_sym ) = find_best_match_for_name ( candidates , lookup . name , None ) {
Some ( MisspelledKw {
similar_kw : similar_sym . to_string ( ) ,
span : lookup . span ,
is_incorrect_case : false ,
} )
} else {
None
}
}
2022-02-21 18:52:47 -08:00
struct MultiSugg {
msg : String ,
patches : Vec < ( Span , String ) > ,
applicability : Applicability ,
}
impl MultiSugg {
2024-02-23 10:20:45 +11:00
fn emit ( self , err : & mut Diag < '_ > ) {
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
err . multipart_suggestion ( self . msg , self . patches , self . applicability ) ;
2022-02-21 18:52:47 -08:00
}
2024-02-23 10:20:45 +11:00
fn emit_verbose ( self , err : & mut Diag < '_ > ) {
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
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 > ,
}
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 > {
2024-06-18 10:35:56 +00:00
pub fn dcx ( & self ) -> DiagCtxtHandle < ' a > {
2024-06-18 09:43:28 +00:00
self . psess . dcx ( )
2019-05-23 12:55:26 -07:00
}
2023-03-03 22:48:21 +00:00
/// Replace `self` with `snapshot.parser`.
2022-03-10 19:34:42 +09:00
pub ( super ) fn restore_snapshot ( & mut self , snapshot : SnapshotParser < ' a > ) {
2022-03-09 23:13:04 +09:00
* self = snapshot . parser ;
2022-04-02 17:05:04 +02:00
}
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 > {
2023-03-03 22:48:21 +00:00
let snapshot = self . clone ( ) ;
SnapshotParser { parser : snapshot }
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 > {
2024-03-04 16:31:49 +11:00
self . psess . source_map ( ) . span_to_snippet ( span )
2019-07-24 11:01:30 +02:00
}
2023-03-17 21:35:43 +13:00
/// Emits an error with suggestions if an identifier was expected but not found.
2023-03-17 22:27:17 +13:00
///
/// Returns a possibly recovered identifier.
pub ( super ) fn expected_ident_found (
& mut self ,
recover : bool ,
2024-02-13 23:28:27 +00:00
) -> PResult < ' a , ( Ident , IdentIsRaw ) > {
2023-03-17 21:35:43 +13:00
if let TokenKind ::DocComment ( .. ) = self . prev_token . kind {
2023-12-18 14:00:17 +11:00
return Err ( self . dcx ( ) . create_err ( DocCommentDoesNotDocumentAnything {
2023-03-17 21:35:43 +13:00
span : self . prev_token . span ,
missing_comma : None ,
2023-12-18 14:00:17 +11:00
} ) ) ;
2023-03-17 21:35:43 +13:00
}
2019-11-20 14:50:13 -08:00
let valid_follow = & [
TokenKind ::Eq ,
TokenKind ::Colon ,
TokenKind ::Comma ,
TokenKind ::Semi ,
2024-04-04 19:03:32 +02:00
TokenKind ::PathSep ,
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
] ;
2023-03-07 23:01:26 +13:00
2023-03-17 22:27:17 +13:00
let mut recovered_ident = None ;
// we take this here so that the correct original token is retained in
// the diagnostic, regardless of eager recovery.
let bad_token = self . token . clone ( ) ;
// suggest prepending a keyword in identifier position with `r#`
2024-02-13 23:28:27 +00:00
let suggest_raw = if let Some ( ( ident , IdentIsRaw ::No ) ) = self . token . ident ( )
2023-03-17 22:27:17 +13:00
& & ident . is_raw_guess ( )
& & self . look_ahead ( 1 , | t | valid_follow . contains ( & t . kind ) )
{
2024-02-13 23:28:27 +00:00
recovered_ident = Some ( ( ident , IdentIsRaw ::Yes ) ) ;
2023-03-17 22:27:17 +13:00
2024-03-05 16:53:24 +11:00
// `Symbol::to_string()` is different from `Symbol::into_diag_arg()`,
2023-03-17 22:27:17 +13:00
// which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
let ident_name = ident . name . to_string ( ) ;
Some ( SuggEscapeIdentifier { span : ident . span . shrink_to_lo ( ) , ident_name } )
} else {
None
} ;
let suggest_remove_comma =
if self . token = = token ::Comma & & self . look_ahead ( 1 , | t | t . is_ident ( ) ) {
if recover {
self . bump ( ) ;
recovered_ident = self . ident_or_err ( false ) . ok ( ) ;
} ;
Some ( SuggRemoveComma { span : bad_token . span } )
} else {
None
} ;
let help_cannot_start_number = self . is_lit_bad_ident ( ) . map ( | ( len , valid_portion ) | {
let ( invalid , valid ) = self . token . span . split_at ( len as u32 ) ;
2024-02-13 23:28:27 +00:00
recovered_ident = Some ( ( Ident ::new ( valid_portion , valid ) , IdentIsRaw ::No ) ) ;
2023-03-17 21:41:26 +13:00
HelpIdentifierStartsWithNumber { num_span : invalid }
} ) ;
2022-09-04 10:14:00 +02:00
let err = ExpectedIdentifier {
2023-03-17 22:27:17 +13:00
span : bad_token . span ,
token : bad_token ,
2022-09-04 10:14:00 +02:00
suggest_raw ,
suggest_remove_comma ,
2023-03-07 23:01:26 +13:00
help_cannot_start_number ,
2022-09-04 10:14:00 +02:00
} ;
2023-12-18 14:00:17 +11:00
let mut err = self . dcx ( ) . create_err ( err ) ;
2022-10-24 00:52:59 +11:00
// if the token we have is a `<`
// it *might* be a misplaced generic
2023-03-17 22:27:17 +13:00
// FIXME: could we recover with this?
2022-10-24 00:52:59 +11:00
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 ) =
2024-03-04 16:31:49 +11:00
self . psess . source_map ( ) . span_to_snippet ( generic . span )
2023-01-31 21:44:11 +11:00
{
2023-02-01 18:11:37 +11:00
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 ( ) ;
}
}
}
}
2023-03-17 22:27:17 +13:00
if let Some ( recovered_ident ) = recovered_ident
& & recover
{
err . emit ( ) ;
Ok ( recovered_ident )
} else {
Err ( err )
}
}
2024-02-23 10:20:45 +11:00
pub ( super ) fn expected_ident_found_err ( & mut self ) -> Diag < ' a > {
2023-03-17 22:27:17 +13:00
self . expected_ident_found ( false ) . unwrap_err ( )
2019-05-23 12:55:26 -07:00
}
2023-03-07 23:01:26 +13:00
/// Checks if the current token is a integer or float literal and looks like
/// it could be a invalid identifier with digits at the start.
2023-03-17 21:41:26 +13:00
///
/// Returns the number of characters (bytes) composing the invalid portion
/// of the identifier and the valid portion of the identifier.
pub ( super ) fn is_lit_bad_ident ( & mut self ) -> Option < ( usize , Symbol ) > {
// ensure that the integer literal is followed by a *invalid*
// suffix: this is how we know that it is a identifier with an
// invalid beginning.
if let token ::Literal ( Lit {
kind : token ::LitKind ::Integer | token ::LitKind ::Float ,
symbol ,
2023-04-07 08:54:13 +12:00
suffix : Some ( suffix ) , // no suffix makes it a valid literal
2023-03-17 22:27:17 +13:00
} ) = self . token . kind
2023-03-17 21:41:26 +13:00
& & rustc_ast ::MetaItemLit ::from_token ( & self . token ) . is_none ( )
{
2023-04-07 08:54:13 +12:00
Some ( ( symbol . as_str ( ) . len ( ) , suffix ) )
2023-03-17 21:41:26 +13:00
} else {
None
}
2023-03-07 23:01:26 +13: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 ] ,
2024-07-04 19:19:15 -04:00
) -> PResult < ' a , ErrorGuaranteed > {
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
} )
}
2023-12-22 21:56:58 -08:00
self . expected_tokens . extend ( edible . iter ( ) . chain ( inedible ) . cloned ( ) . map ( TokenType ::Token ) ) ;
let mut expected = self
. expected_tokens
2019-05-23 13:10:24 -07:00
. iter ( )
2023-12-28 21:19:41 +01:00
. filter ( | token | {
// Filter out suggestions that suggest the same token which was found and deemed incorrect.
2022-05-01 19:05:35 +02:00
fn is_ident_eq_keyword ( found : & TokenKind , expected : & TokenType ) -> bool {
2023-12-28 21:19:41 +01:00
if let TokenKind ::Ident ( current_sym , _ ) = found
& & let TokenType ::Keyword ( suggested_sym ) = expected
{
return current_sym = = suggested_sym ;
2022-05-01 19:05:35 +02:00
}
false
}
2023-12-28 21:19:41 +01:00
2024-02-17 12:46:18 +01:00
if * * token ! = parser ::TokenType ::Token ( self . token . kind . clone ( ) ) {
2022-05-01 19:05:35 +02:00
let eq = is_ident_eq_keyword ( & self . token . kind , & token ) ;
2023-12-28 21:19:41 +01:00
// If the suggestion is a keyword and the found token is an ident,
2022-05-01 19:05:35 +02:00
// the content of which are equal to the suggestion's content,
2023-12-28 21:19:41 +01:00
// we can remove that suggestion (see the `return false` below).
2022-05-01 19:05:35 +02:00
2023-12-28 21:19:41 +01:00
// 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.
2022-05-01 19:05:35 +02:00
if ! eq {
2024-08-09 17:44:47 +10:00
if let TokenType ::Token ( kind ) = token {
if self . token = = * kind {
2023-12-28 21:19:41 +01:00
return false ;
2022-05-01 19:05:35 +02:00
}
}
2023-12-28 21:19:41 +01:00
return true ;
2022-05-01 19:05:35 +02:00
}
}
2023-12-28 21:19:41 +01:00
false
2022-05-01 19:05:35 +02:00
} )
2024-02-17 12:46:18 +01:00
. cloned ( )
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
2024-03-04 16:31:49 +11:00
let sm = self . psess . source_map ( ) ;
2022-09-04 20:12:00 +02:00
2023-12-28 21:19:41 +01:00
// Special-case "expected `;`" errors.
2021-07-24 10:58:55 -07:00
if expected . contains ( & TokenType ::Token ( token ::Semi ) ) {
2023-10-26 11:35:11 +00:00
// If the user is trying to write a ternary expression, recover it and
2023-12-28 21:19:41 +01:00
// return an Err to prevent a cascade of irrelevant diagnostics.
2023-11-13 08:24:55 -05:00
if self . prev_token = = token ::Question
& & let Err ( e ) = self . maybe_recover_from_ternary_operator ( )
{
2023-10-26 11:35:11 +00:00
return Err ( e ) ;
2023-07-25 18:27:24 +00:00
}
2021-07-24 10:58:55 -07:00
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 )
2024-08-09 17:44:47 +10:00
& & self . prev_token = = 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 )
2024-08-09 17:44:47 +10:00
| | t . can_begin_expr ( ) & & * t ! = token ::Colon
2021-07-24 10:58:55 -07:00
} ) & & [ 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;
2024-05-09 18:44:40 +10:00
let guar = self . dcx ( ) . emit_err ( ExpectedSemi {
2022-09-04 20:12:00 +02:00
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 ( ) ;
2024-07-04 19:19:15 -04:00
return Ok ( guar ) ;
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 ( ) ;
2024-05-09 18:44:40 +10:00
let guar = self . dcx ( ) . emit_err ( ExpectedSemi {
2022-09-04 20:12:00 +02:00
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 ) ,
} ) ;
2024-07-04 19:19:15 -04:00
return Ok ( guar ) ;
2021-07-24 10:58:55 -07:00
}
}
2024-08-09 17:44:47 +10:00
if self . token = = TokenKind ::EqEq
2022-09-07 12:26:50 +08:00
& & self . prev_token . is_ident ( )
& & expected . iter ( ) . any ( | tok | matches! ( tok , TokenType ::Token ( TokenKind ::Eq ) ) )
{
// Likely typo: `=` → `==` in let expr or enum item
2024-07-16 22:43:30 +00:00
return Err ( self . dcx ( ) . create_err ( UseEqInstead { span : self . token . span } ) ) ;
2022-09-07 12:26:50 +08:00
}
2023-07-30 15:49:33 +08:00
if self . token . is_keyword ( kw ::Move ) & & self . prev_token . is_keyword ( kw ::Async ) {
// The 2015 edition is in use because parsing of `async move` has failed.
let span = self . prev_token . span . to ( self . token . span ) ;
2023-12-18 21:14:02 +11:00
return Err ( self . dcx ( ) . create_err ( AsyncMoveBlockIn2015 { span } ) ) ;
2023-07-30 15:49:33 +08:00
}
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 {
2023-04-15 18:04:51 +02:00
let fmt = format! ( " expected one of {expect} , found {actual} " ) ;
2019-05-23 13:10:24 -07:00
let short_expect = if expected . len ( ) > 6 {
format! ( " {} possible tokens " , expected . len ( ) )
} else {
2023-04-15 18:04:51 +02:00
expect
2019-05-23 13:10:24 -07:00
} ;
2023-04-15 18:04:51 +02:00
( fmt , ( self . prev_token . span . shrink_to_hi ( ) , format! ( " expected one of {short_expect} " ) ) )
2019-05-23 13:10:24 -07:00
} else if expected . is_empty ( ) {
2019-10-22 11:46:19 -07: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-05-23 13:10:24 -07:00
)
} else {
2019-10-22 11:46:19 -07: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-10-22 11:46:19 -07: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`)
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( self . token . span , msg_exp ) ;
2020-12-15 17:43:24 +01:00
2023-10-27 15:14:55 -07:00
// Look for usages of '=>' where '>=' was probably intended
if self . token = = token ::FatArrow
& & expected
. iter ( )
. any ( | tok | matches! ( tok , TokenType ::Operator | TokenType ::Token ( TokenKind ::Le ) ) )
& & ! expected . iter ( ) . any ( | tok | {
matches! (
tok ,
TokenType ::Token ( TokenKind ::FatArrow ) | TokenType ::Token ( TokenKind ::Comma )
)
} )
{
err . span_suggestion (
self . token . span ,
" you might have meant to write a \" greater than or equal to \" comparison " ,
" >= " ,
Applicability ::MaybeIncorrect ,
) ;
}
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 ,
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
format! ( " write `fn` instead of ` {symbol} ` to declare a function " ) ,
2022-08-18 16:14:04 -05:00
" 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
}
2023-07-03 23:54:49 +08:00
if let TokenKind ::Ident ( prev , _ ) = & self . prev_token . kind
& & let TokenKind ::Ident ( cur , _ ) = & self . token . kind
{
2023-07-25 22:00:13 +02:00
let concat = Symbol ::intern ( & format! ( " {prev} {cur} " ) ) ;
2023-07-03 23:54:49 +08:00
let ident = Ident ::new ( concat , DUMMY_SP ) ;
if ident . is_used_keyword ( ) | | ident . is_reserved ( ) | | ident . is_raw_guess ( ) {
2024-09-02 12:43:35 -04:00
let concat_span = self . prev_token . span . to ( self . token . span ) ;
2023-07-03 23:54:49 +08:00
err . span_suggestion_verbose (
2024-09-02 12:43:35 -04:00
concat_span ,
2023-07-25 22:00:13 +02:00
format! ( " consider removing the space to spell keyword ` {concat} ` " ) ,
2023-07-03 23:54:49 +08:00
concat ,
Applicability ::MachineApplicable ,
) ;
}
}
2023-12-06 16:56:45 -08:00
// Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
// here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
// a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
// where c-string literals are not allowed. There is the very slight possibility of a false
// positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
// that in the parser requires unbounded lookahead, so we only add a hint to the existing
// error rather than replacing it entirely.
2024-08-09 17:44:47 +10:00
if ( ( self . prev_token = = TokenKind ::Ident ( sym ::c , IdentIsRaw ::No )
2023-12-06 16:56:45 -08:00
& & matches! ( & self . token . kind , TokenKind ::Literal ( token ::Lit { kind : token ::Str , .. } ) ) )
2024-08-09 17:44:47 +10:00
| | ( self . prev_token = = TokenKind ::Ident ( sym ::cr , IdentIsRaw ::No )
2023-12-06 16:56:45 -08:00
& & matches! (
& self . token . kind ,
TokenKind ::Literal ( token ::Lit { kind : token ::Str , .. } ) | token ::Pound
) ) )
& & self . prev_token . span . hi ( ) = = self . token . span . lo ( )
& & ! self . token . span . at_least_rust_2021 ( )
{
err . note ( " you may be trying to write a c-string literal " ) ;
err . note ( " c-string literals require Rust 2021 or later " ) ;
2024-06-18 11:10:18 +00:00
err . subdiagnostic ( HelpUseLatestEdition ::new ( ) ) ;
2023-12-06 16:56:45 -08:00
}
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 ( )
2024-08-09 17:44:47 +10:00
| | self . token = = TokenKind ::OpenDelim ( Delimiter ::Parenthesis ) )
2022-08-23 17:02:40 +08:00
{
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
) ;
}
2023-10-20 02:54:45 +00:00
if let token ::DocComment ( kind , style , _ ) = self . token . kind {
// We have something like `expr //!val` where the user likely meant `expr // !val`
let pos = self . token . span . lo ( ) + BytePos ( 2 ) ;
let span = self . token . span . with_lo ( pos ) . with_hi ( pos ) ;
err . span_suggestion_verbose (
span ,
format! ( " add a space before {} to write a regular comment " , match ( kind , style ) {
( token ::CommentKind ::Line , ast ::AttrStyle ::Inner ) = > " `!` " ,
( token ::CommentKind ::Block , ast ::AttrStyle ::Inner ) = > " `!` " ,
( token ::CommentKind ::Line , ast ::AttrStyle ::Outer ) = > " the last `/` " ,
( token ::CommentKind ::Block , ast ::AttrStyle ::Outer ) = > " the last `*` " ,
} , ) ,
" " . to_string ( ) ,
Applicability ::MachineApplicable ,
) ;
}
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
} ;
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 ) {
2024-05-09 18:44:40 +10:00
let guar = err . emit ( ) ;
2024-07-04 19:19:15 -04:00
return Ok ( guar ) ;
2022-04-23 19:44:25 -07:00
} 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
}
2024-09-02 12:43:35 -04:00
// Check for misspelled keywords if there are no suggestions added to the diagnostic.
2024-09-08 15:59:05 -04:00
if matches! ( & err . suggestions , Suggestions ::Enabled ( list ) if list . is_empty ( ) ) {
2024-09-02 12:43:35 -04:00
self . check_for_misspelled_kw ( & mut err , & expected ) ;
}
2019-05-23 13:10:24 -07:00
Err ( err )
}
2024-09-02 12:43:35 -04:00
/// Checks if the current token or the previous token are misspelled keywords
/// and adds a helpful suggestion.
fn check_for_misspelled_kw ( & self , err : & mut Diag < '_ > , expected : & [ TokenType ] ) {
let Some ( ( curr_ident , _ ) ) = self . token . ident ( ) else {
return ;
} ;
let expected_tokens : & [ TokenType ] =
expected . len ( ) . checked_sub ( 10 ) . map_or ( & expected , | index | & expected [ index .. ] ) ;
let expected_keywords : Vec < Symbol > = expected_tokens
. iter ( )
. filter_map ( | token | if let TokenType ::Keyword ( kw ) = token { Some ( * kw ) } else { None } )
. collect ( ) ;
// When there are a few keywords in the last ten elements of `self.expected_tokens` and the current
// token is an identifier, it's probably a misspelled keyword.
// This handles code like `async Move {}`, misspelled `if` in match guard, misspelled `else` in `if`-`else`
// and mispelled `where` in a where clause.
if ! expected_keywords . is_empty ( )
& & ! curr_ident . is_used_keyword ( )
& & let Some ( misspelled_kw ) = find_similar_kw ( curr_ident , & expected_keywords )
{
err . subdiagnostic ( misspelled_kw ) ;
2024-09-08 15:59:05 -04:00
// We don't want other suggestions to be added as they are most likely meaningless
// when there is a misspelled keyword.
err . seal_suggestions ( ) ;
2024-09-02 12:43:35 -04:00
} else if let Some ( ( prev_ident , _ ) ) = self . prev_token . ident ( )
& & ! prev_ident . is_used_keyword ( )
{
// We generate a list of all keywords at runtime rather than at compile time
// so that it gets generated only when the diagnostic needs it.
// Also, it is unlikely that this list is generated multiple times because the
// parser halts after execution hits this path.
let all_keywords = AllKeywords ::new ( ) . collect_used ( | | prev_ident . span . edition ( ) ) ;
// Otherwise, check the previous token with all the keywords as possible candidates.
// This handles code like `Struct Human;` and `While a < b {}`.
// We check the previous token only when the current token is an identifier to avoid false
// positives like suggesting keyword `for` for `extern crate foo {}`.
if let Some ( misspelled_kw ) = find_similar_kw ( prev_ident , & all_keywords ) {
err . subdiagnostic ( misspelled_kw ) ;
2024-09-08 15:59:05 -04:00
// We don't want other suggestions to be added as they are most likely meaningless
// when there is a misspelled keyword.
err . seal_suggestions ( ) ;
2024-09-02 12:43:35 -04:00
}
}
}
2024-02-25 22:22:11 +01:00
/// The user has written `#[attr] expr` which is unsupported. (#106020)
pub ( super ) fn attr_on_non_tail_expr ( & self , expr : & Expr ) -> ErrorGuaranteed {
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
// Missing semicolon typo error.
let span = self . prev_token . span . shrink_to_hi ( ) ;
2023-12-18 21:14:02 +11:00
let mut err = self . dcx ( ) . create_err ( ExpectedSemi {
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
span ,
token : self . token . clone ( ) ,
unexpected_token_label : Some ( self . token . span ) ,
sugg : ExpectedSemiSugg ::AddSemi ( span ) ,
} ) ;
let attr_span = match & expr . attrs [ .. ] {
[ ] = > unreachable! ( ) ,
[ only ] = > only . span ,
[ first , rest @ .. ] = > {
for attr in rest {
err . span_label ( attr . span , " " ) ;
}
first . span
}
} ;
err . span_label (
attr_span ,
format! (
" only `;` terminated statements or tail expressions are allowed after {} " ,
if expr . attrs . len ( ) = = 1 { " this attribute " } else { " these attributes " } ,
) ,
) ;
if self . token = = token ::Pound
2024-08-09 17:44:47 +10:00
& & self . look_ahead ( 1 , | t | * t = = token ::OpenDelim ( Delimiter ::Bracket ) )
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
{
// We have
// #[attr]
// expr
// #[not_attr]
// other_expr
err . span_label ( span , " expected `;` here " ) ;
err . multipart_suggestion (
" alternatively, consider surrounding the expression with a block " ,
vec! [
( expr . span . shrink_to_lo ( ) , " { " . to_string ( ) ) ,
( expr . span . shrink_to_hi ( ) , " } " . to_string ( ) ) ,
] ,
Applicability ::MachineApplicable ,
) ;
2024-02-25 22:22:11 +01:00
// Special handling for `#[cfg(...)]` chains
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
let mut snapshot = self . create_snapshot_for_diagnostic ( ) ;
if let [ attr ] = & expr . attrs [ .. ]
& & let ast ::AttrKind ::Normal ( attr_kind ) = & attr . kind
& & let [ segment ] = & attr_kind . item . path . segments [ .. ]
& & segment . ident . name = = sym ::cfg
2023-12-02 23:46:45 +08:00
& & let Some ( args_span ) = attr_kind . item . args . span ( )
2023-11-22 19:53:24 +00:00
& & let next_attr = match snapshot . parse_attribute ( InnerAttrPolicy ::Forbidden ( None ) )
{
Ok ( next_attr ) = > next_attr ,
Err ( inner_err ) = > {
inner_err . cancel ( ) ;
2024-02-26 21:47:10 +01:00
return err . emit ( ) ;
2023-11-22 19:53:24 +00:00
}
}
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
& & let ast ::AttrKind ::Normal ( next_attr_kind ) = next_attr . kind
2023-12-02 23:46:45 +08:00
& & let Some ( next_attr_args_span ) = next_attr_kind . item . args . span ( )
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
& & let [ next_segment ] = & next_attr_kind . item . path . segments [ .. ]
& & segment . ident . name = = sym ::cfg
{
2023-11-22 19:53:24 +00:00
let next_expr = match snapshot . parse_expr ( ) {
Ok ( next_expr ) = > next_expr ,
Err ( inner_err ) = > {
inner_err . cancel ( ) ;
2024-02-26 21:47:10 +01:00
return err . emit ( ) ;
2023-11-22 19:53:24 +00:00
}
} ;
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
// We have for sure
// #[cfg(..)]
// expr
// #[cfg(..)]
// other_expr
// So we suggest using `if cfg!(..) { expr } else if cfg!(..) { other_expr }`.
2024-03-04 16:31:49 +11:00
let margin = self . psess . source_map ( ) . span_to_margin ( next_expr . span ) . unwrap_or ( 0 ) ;
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
let sugg = vec! [
( attr . span . with_hi ( segment . span ( ) . hi ( ) ) , " if cfg! " . to_string ( ) ) ,
2023-12-02 23:46:45 +08:00
( args_span . shrink_to_hi ( ) . with_hi ( attr . span . hi ( ) ) , " { " . to_string ( ) ) ,
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
( expr . span . shrink_to_lo ( ) , " " . to_string ( ) ) ,
(
next_attr . span . with_hi ( next_segment . span ( ) . hi ( ) ) ,
" } else if cfg! " . to_string ( ) ,
) ,
(
2023-12-02 23:46:45 +08:00
next_attr_args_span . shrink_to_hi ( ) . with_hi ( next_attr . span . hi ( ) ) ,
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
" { " . to_string ( ) ,
) ,
( next_expr . span . shrink_to_lo ( ) , " " . to_string ( ) ) ,
( next_expr . span . shrink_to_hi ( ) , format! ( " \n {} }} " , " " . repeat ( margin ) ) ) ,
] ;
err . multipart_suggestion (
" it seems like you are trying to provide different expressions depending on \
` cfg ` , consider using ` if cfg! ( .. ) ` " ,
sugg ,
Applicability ::MachineApplicable ,
) ;
}
}
2024-09-02 12:43:35 -04:00
2024-02-25 22:22:11 +01:00
err . emit ( )
Handle attempts to have multiple `cfg`d tail expressions
When encountering code that seems like it might be trying to have
multiple tail expressions depending on `cfg` information, suggest
alternatives that will success to parse.
```rust
fn foo() -> String {
#[cfg(feature = "validation")]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
#[cfg(not(feature = "validation"))]
String::new()
}
```
```
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
LL | #[cfg(feature = "validation")]
| ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
LL | #[cfg(not(feature = "validation"))]
| - unexpected token
|
help: add `;` here
|
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>();
| +
help: alternatively, consider surrounding the expression with a block
|
LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
LL ~ if cfg!(feature = "validation") {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(feature = "validation")) {
LL ~ String::new()
LL + }
|
```
Fix #106020.
2023-11-16 21:21:26 +00:00
}
2023-11-15 00:18:26 +00:00
2024-02-23 10:20:45 +11:00
fn check_too_many_raw_str_terminators ( & mut self , err : & mut Diag < '_ > ) -> bool {
2024-03-04 16:31:49 +11:00
let sm = self . psess . 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 ;
2023-12-24 09:08:41 +11:00
err . 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 ;
2024-08-09 17:44:47 +10:00
while self . token = = TokenKind ::Pound
2022-04-23 19:44:25 -07:00
& & ! 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 ;
}
2023-12-24 09:08:41 +11:00
err . span ( span ) ;
2020-03-28 01:46:20 -04:00
err . span_suggestion (
2022-04-23 19:44:25 -07:00
span ,
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
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 ,
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
format! ( " this raw string started with {n_hashes} `#` {} " , pluralize! ( n_hashes ) ) ,
2022-04-23 19:44:25 -07:00
) ;
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
}
}
2024-06-03 15:47:46 +10:00
pub ( super ) fn maybe_suggest_struct_literal (
2020-08-12 15:39:15 -07:00
& 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,
// }
2024-02-06 03:30:16 +00:00
debug! ( ? 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 ,
} ;
2023-02-24 04:38:45 +01:00
let struct_expr = snapshot . parse_expr_struct ( 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 ) {
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
( Ok ( expr ) , Err ( err ) ) = > {
2020-08-12 15:39:15 -07:00
// We have encountered the following:
// fn foo() -> Foo {
// field: value,
// }
// Suggest:
// fn foo() -> Foo { Path {
// field: value,
// } }
2024-02-25 22:22:11 +01:00
let guar = 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 (
2024-02-25 22:22:11 +01:00
thin_vec! [ self . mk_stmt_err ( expr . span , guar ) ] ,
2020-08-12 15:39:15 -07:00
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() {}`.
2023-06-06 23:51:09 +08:00
// expand `before` so that we take care of module path such as:
// `foo::Bar { ... } `
// we expect to suggest `(foo::Bar { ... })` instead of `foo::(Bar { ... })`
2024-03-04 16:31:49 +11:00
let sm = self . psess . source_map ( ) ;
2023-06-06 23:51:09 +08:00
let before = maybe_struct_name . span . shrink_to_lo ( ) ;
2023-06-10 10:34:19 +08:00
if let Ok ( extend_before ) = sm . span_extend_prev_while ( before , | t | {
2023-06-06 23:51:09 +08:00
t . is_alphanumeric ( ) | | t = = ':' | | t = = '_'
2023-06-10 10:34:19 +08:00
} ) {
2023-12-18 21:14:02 +11:00
Err ( self . dcx ( ) . create_err ( StructLiteralNeedingParens {
2023-06-10 10:34:19 +08:00
span : maybe_struct_name . span . to ( expr . span ) ,
sugg : StructLiteralNeedingParensSugg {
before : extend_before . shrink_to_lo ( ) ,
after : expr . span . shrink_to_hi ( ) ,
} ,
} ) )
} else {
return None ;
}
2023-01-09 05:29:54 +00:00
} else {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( StructLiteralBodyWithoutPath {
2023-01-09 05:29:54 +00:00
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
}
2023-10-11 23:20:41 +00:00
pub ( super ) fn recover_closure_body (
& mut self ,
2024-02-23 10:20:45 +11:00
mut err : Diag < ' a > ,
2023-10-11 23:20:41 +00:00
before : token ::Token ,
prev : token ::Token ,
token : token ::Token ,
lo : Span ,
decl_hi : Span ,
) -> PResult < ' a , P < Expr > > {
err . span_label ( lo . to ( decl_hi ) , " while parsing the body of this closure " ) ;
2024-02-25 22:22:11 +01:00
let guar = match before . kind {
2023-10-11 23:20:41 +00:00
token ::OpenDelim ( Delimiter ::Brace )
if ! matches! ( token . kind , token ::OpenDelim ( Delimiter ::Brace ) ) = >
{
// `{ || () }` should have been `|| { () }`
err . multipart_suggestion (
" you might have meant to open the body of the closure, instead of enclosing \
the closure in a block " ,
vec! [
( before . span , String ::new ( ) ) ,
( prev . span . shrink_to_hi ( ) , " { " . to_string ( ) ) ,
] ,
Applicability ::MaybeIncorrect ,
) ;
2024-02-25 22:22:11 +01:00
let guar = err . emit ( ) ;
2023-10-11 23:20:41 +00:00
self . eat_to_tokens ( & [ & token ::CloseDelim ( Delimiter ::Brace ) ] ) ;
2024-02-25 22:22:11 +01:00
guar
2023-10-11 23:20:41 +00:00
}
token ::OpenDelim ( Delimiter ::Parenthesis )
if ! matches! ( token . kind , token ::OpenDelim ( Delimiter ::Brace ) ) = >
{
// We are within a function call or tuple, we can emit the error
// and recover.
self . eat_to_tokens ( & [ & token ::CloseDelim ( Delimiter ::Parenthesis ) , & token ::Comma ] ) ;
err . multipart_suggestion_verbose (
" you might have meant to open the body of the closure " ,
vec! [
( prev . span . shrink_to_hi ( ) , " { " . to_string ( ) ) ,
( self . token . span . shrink_to_lo ( ) , " } " . to_string ( ) ) ,
] ,
Applicability ::MaybeIncorrect ,
) ;
2024-02-25 22:22:11 +01:00
err . emit ( )
2023-10-11 23:20:41 +00:00
}
_ if ! matches! ( token . kind , token ::OpenDelim ( Delimiter ::Brace ) ) = > {
// We don't have a heuristic to correctly identify where the block
// should be closed.
err . multipart_suggestion_verbose (
" you might have meant to open the body of the closure " ,
vec! [ ( prev . span . shrink_to_hi ( ) , " { " . to_string ( ) ) ] ,
Applicability ::HasPlaceholders ,
) ;
return Err ( err ) ;
}
_ = > return Err ( err ) ,
2024-02-25 22:22:11 +01:00
} ;
Ok ( self . mk_expr_err ( lo . to ( self . token . span ) , guar ) )
2023-10-11 23:20:41 +00: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 ) =
2024-06-05 17:02:18 -04:00
self . parse_seq_to_before_tokens ( kets , & [ ] , SeqSep ::none ( ) , | p | Ok ( p . parse_token_tree ( ) ) )
2019-05-23 12:55:26 -07:00
{
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 ] ,
2024-01-05 11:10:18 +11:00
) -> Option < ErrorGuaranteed > {
2022-10-28 20:44:26 +02:00
if ! self . may_recover ( ) {
2024-01-05 11:10:18 +11:00
return None ;
2022-10-28 20:44:26 +02:00
}
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)`
let parsed_angle_bracket_args =
2023-05-24 14:19:22 +00:00
segment . args . as_ref ( ) . is_some_and ( | 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 {
2024-01-05 11:10:18 +11:00
return None ;
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 {
2024-01-05 11:10:18 +11:00
return None ;
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 ) ;
2024-07-06 03:07:46 +00:00
let span = lo . to ( self . prev_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 ;
2024-01-05 11:10:18 +11:00
return Some ( self . dcx ( ) . emit_err ( UnmatchedAngleBrackets { span , num_extra_brackets } ) ) ;
2019-05-23 12:55:26 -07:00
}
2024-01-05 11:10:18 +11:00
None
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 ;
}
2024-08-09 17:44:47 +10:00
if self . token = = token ::PathSep & & 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 ( ) ;
2024-08-09 17:44:47 +10:00
while self . token = = token ::BinOp ( token ::Shr ) | | self . token = = token ::Gt {
2020-07-23 16:25:39 -07:00
trailing_span = trailing_span . to ( self . token . span ) ;
self . bump ( ) ;
}
2024-08-09 17:44:47 +10:00
if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2020-07-23 16:25:39 -07:00
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
2023-03-16 22:00:08 +00:00
segment . args = Some ( AngleBracketedArgs { args , span } . into ( ) ) ;
2020-07-23 16:25:39 -07:00
2023-12-18 21:14:02 +11:00
self . dcx ( ) . 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 ,
2024-02-23 10:20:45 +11:00
mut e : Diag < ' a > ,
2020-08-31 10:24:37 -07:00
expr : & mut P < Expr > ,
2024-02-25 22:22:11 +01:00
) -> PResult < ' a , ErrorGuaranteed > {
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 ) ,
2024-05-09 10:47:07 -04:00
| p | match p . parse_generic_arg ( None ) ? {
Some ( arg ) = > Ok ( arg ) ,
// If we didn't eat a generic arg, then we should error.
None = > p . unexpected_any ( ) ,
} ,
2022-02-28 07:49:56 -03:00
) ;
match x {
2024-02-13 23:44:33 +00:00
Ok ( ( _ , _ , Recovered ::No ) ) = > {
2022-02-28 07:49:56 -03:00
if self . eat ( & token ::Gt ) {
2024-01-05 09:55:07 +11:00
// We made sense of it. Improve the error message.
2022-02-28 07:49:56 -03:00
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 ,
2024-01-05 09:55:07 +11:00
) ;
2022-02-28 07:49:56 -03:00
match self . parse_expr ( ) {
Ok ( _ ) = > {
2024-01-05 09:55:07 +11:00
// The subsequent expression is valid. Mark
// `expr` as erroneous and emit `e` now, but
// return `Ok` so parsing can continue.
2024-02-25 22:22:11 +01:00
let guar = e . emit ( ) ;
* expr = self . mk_expr_err ( expr . span . to ( self . prev_token . span ) , guar ) ;
return Ok ( guar ) ;
2022-02-28 07:49:56 -03:00
}
Err ( err ) = > {
err . cancel ( ) ;
2020-08-31 10:24:37 -07:00
}
}
}
}
2024-05-09 18:44:40 +10:00
Ok ( ( _ , _ , Recovered ::Yes ( _ ) ) ) = > { }
2022-02-28 07:49:56 -03:00
Err ( err ) = > {
err . cancel ( ) ;
}
2020-08-31 10:24:37 -07:00
}
}
Err ( e )
}
2023-05-08 14:52:52 +08:00
/// Suggest add the missing `let` before the identifier in stmt
/// `a: Ty = 1` -> `let a: Ty = 1`
2024-02-23 10:20:45 +11:00
pub ( super ) fn suggest_add_missing_let_for_stmt ( & mut self , err : & mut Diag < ' a > ) {
2023-05-08 14:52:52 +08:00
if self . token = = token ::Colon {
let prev_span = self . prev_token . span . shrink_to_lo ( ) ;
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
self . bump ( ) ;
match self . parse_ty ( ) {
Ok ( _ ) = > {
if self . token = = token ::Eq {
2023-05-09 11:51:04 +08:00
let sugg = SuggAddMissingLetStmt { span : prev_span } ;
2024-03-06 14:00:16 +11:00
sugg . add_to_diag ( err ) ;
2023-05-08 14:52:52 +08:00
}
}
Err ( e ) = > {
e . cancel ( ) ;
}
}
self . restore_snapshot ( snapshot ) ;
}
}
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
2024-05-09 18:44:40 +10:00
/// parenthesising the leftmost comparison. The return value indicates if recovery happened.
2020-01-11 00:19:09 +00:00
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 > ,
2024-05-09 18:44:40 +10:00
) -> bool {
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.
2024-05-09 18:44:40 +10:00
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 )
2023-11-21 20:07:32 +01:00
. unwrap_or_else ( | _ | pprust ::expr_to_string ( e ) )
2020-01-11 00:19:09 +00:00
} ;
2022-09-08 18:23:31 +02:00
err . chaining_sugg = Some ( ComparisonOperatorsCannotBeChainedSugg ::SplitComparison {
span : inner_op . span . shrink_to_hi ( ) ,
2023-11-21 20:07:32 +01:00
middle_term : expr_to_str ( r1 ) ,
2022-09-08 18:23:31 +02:00
} ) ;
2024-05-09 18:44:40 +10:00
false // Keep the current parse behavior, where the AST is `(x < y) < z`.
2020-03-09 20:21:37 -07:00
}
// `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 ( ) ,
} ) ;
2024-05-09 18:44:40 +10:00
true
2020-03-09 20:21:37 -07:00
}
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 ) ;
2024-05-09 18:44:40 +10:00
true
2020-03-09 20:21:37 -07:00
}
}
}
// `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 ( ) ,
} ) ;
2024-05-09 18:44:40 +10:00
true
2020-03-09 20:21:37 -07:00
}
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 ) ;
2024-05-09 18:44:40 +10:00
false
2020-03-09 20:21:37 -07:00
}
}
2020-01-11 00:19:09 +00:00
}
2024-05-09 18:44:40 +10:00
_ = > false
2020-03-09 20:21:37 -07:00
} ;
2020-01-11 00:19:09 +00:00
}
2024-05-09 18:44:40 +10: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
2024-02-25 22:22:11 +01:00
let mk_err_expr =
| this : & Self , span , guar | Ok ( Some ( this . mk_expr ( span , ExprKind ::Err ( guar ) ) ) ) ;
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 ,
2024-08-21 00:57:58 -04:00
help_turbofish : false ,
2022-09-08 18:23:31 +02:00
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-05-23 12:55:26 -07: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.
let modifiers =
2019-09-30 12:19:22 -07:00
[ ( 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
2024-04-04 19:03:32 +02:00
if ! & [ token ::OpenDelim ( Delimiter ::Parenthesis ) , token ::PathSep ]
2019-09-30 12:36:44 -07:00
. contains ( & self . token . kind )
{
// 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
}
}
2024-08-09 17:44:47 +10:00
return if self . token = = token ::PathSep {
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 {
2024-08-21 00:57:58 -04:00
err . help_turbofish = true ;
2023-01-08 22:27:13 +00:00
}
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.
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . 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.
2024-02-25 22:22:11 +01:00
mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) , guar )
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 ) ;
2023-12-18 14:00:17 +11:00
Err ( self . dcx ( ) . create_err ( err ) )
2019-09-30 12:36:44 -07:00
}
}
2024-08-09 17:44:47 +10:00
} else if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
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 {
2024-08-21 00:57:58 -04:00
err . help_turbofish = true ;
2023-01-08 22:27:13 +00:00
}
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 ( ) {
2023-12-18 14:00:17 +11:00
Err ( ( ) ) = > Err ( self . dcx ( ) . create_err ( err ) ) ,
2019-10-03 13:22:18 -07:00
Ok ( ( ) ) = > {
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . 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.
2024-02-25 22:22:11 +01:00
mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) , guar )
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.
2024-08-21 00:57:58 -04:00
err . help_turbofish = true ;
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.
2024-02-13 23:50:50 +00:00
let recovered = self
. attempt_chained_comparison_suggestion ( & mut err , inner_op , outer_op ) ;
2024-05-09 18:44:40 +10:00
if recovered {
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . emit_err ( err ) ;
mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) , guar )
2020-03-09 20:21:37 -07:00
} else {
// These cases cause too many knock-down errors, bail out (#61329).
2023-12-18 14:00:17 +11:00
Err ( self . dcx ( ) . create_err ( err ) )
2020-03-09 20:21:37 -07:00
}
2019-10-01 15:51:50 -07:00
} ;
2019-05-23 12:55:26 -07:00
}
2024-05-09 18:44:40 +10:00
let recovered =
2020-03-09 20:21:37 -07:00
self . attempt_chained_comparison_suggestion ( & mut err , inner_op , outer_op ) ;
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . emit_err ( err ) ;
2024-05-09 18:44:40 +10:00
if recovered {
2024-02-25 22:22:11 +01:00
return mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) , guar ) ;
2020-03-09 20:21:37 -07:00
}
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
2024-08-09 17:44:47 +10:00
if self . token = = token ::Eof {
2019-10-03 13:22:18 -07:00
// 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 {
2024-07-06 03:07:46 +00:00
self . dcx ( ) . emit_err ( AmbiguousPlus {
span : ty . span ,
suggestion : AddParen { lo : ty . span . shrink_to_lo ( ) , hi : ty . span . shrink_to_hi ( ) } ,
} ) ;
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 ( ) ;
2024-02-14 14:50:49 +11:00
let guar = self . dcx ( ) . emit_err ( QuestionMarkInType {
2022-09-08 18:23:31 +02:00
span : self . prev_token . span ,
sugg : QuestionMarkInTypeSugg {
left : ty . span . shrink_to_lo ( ) ,
right : self . prev_token . span ,
} ,
} ) ;
2024-02-14 14:50:49 +11:00
self . mk_ty ( ty . span . to ( self . prev_token . span ) , TyKind ::Err ( guar ) )
2022-01-10 22:02:19 +00:00
} else {
ty
}
}
2023-07-25 18:27:24 +00:00
/// Rust has no ternary operator (`cond ? then : else`). Parse it and try
2023-07-25 19:15:19 +00:00
/// to recover from it if `then` and `else` are valid expressions. Returns
2023-10-26 11:35:11 +00:00
/// an err if this appears to be a ternary expression.
pub ( super ) fn maybe_recover_from_ternary_operator ( & mut self ) -> PResult < ' a , ( ) > {
2023-07-25 19:15:19 +00:00
if self . prev_token ! = token ::Question {
2023-10-26 11:35:11 +00:00
return PResult ::Ok ( ( ) ) ;
2023-07-25 19:15:19 +00:00
}
2023-07-25 18:27:24 +00:00
let lo = self . prev_token . span . lo ( ) ;
2023-07-25 19:15:19 +00:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2023-07-25 18:27:24 +00:00
2023-07-25 19:15:19 +00:00
if match self . parse_expr ( ) {
Ok ( _ ) = > true ,
Err ( err ) = > {
err . cancel ( ) ;
// The colon can sometimes be mistaken for type
// ascription. Catch when this happens and continue.
self . token = = token ::Colon
2023-07-25 18:27:24 +00:00
}
2023-07-25 19:15:19 +00:00
} {
2023-07-25 18:27:24 +00:00
if self . eat_noexpect ( & token ::Colon ) {
match self . parse_expr ( ) {
Ok ( _ ) = > {
2023-10-26 11:35:11 +00:00
return Err ( self
2023-12-18 21:14:02 +11:00
. dcx ( )
2023-10-26 11:35:11 +00:00
. create_err ( TernaryOperator { span : self . token . span . with_lo ( lo ) } ) ) ;
2023-07-25 18:27:24 +00:00
}
Err ( err ) = > {
err . cancel ( ) ;
}
} ;
}
2023-10-26 11:11:36 +00:00
}
self . restore_snapshot ( snapshot ) ;
2023-10-26 11:35:11 +00:00
Ok ( ( ) )
2023-07-25 18:27:24 +00:00
}
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 ( ) ; // `+`
2024-07-12 03:04:06 +00:00
let _bounds = self . parse_generic_bounds ( ) ? ;
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 {
2024-07-06 03:07:46 +00:00
TyKind ::Ref ( _lifetime , mut_ty ) = > {
let lo = mut_ty . ty . span . shrink_to_lo ( ) ;
let hi = self . prev_token . span . shrink_to_hi ( ) ;
BadTypePlusSub ::AddParen { suggestion : AddParen { lo , hi } }
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 } ,
} ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( BadTypePlus { ty : pprust ::ty_to_string ( ty ) , span : sum_span , sub } ) ;
2022-05-16 17:16:27 -05:00
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 )
}
2023-02-26 16:17:23 +00:00
pub ( super ) fn recover_from_postfix_decrement (
& mut self ,
operand_expr : P < Expr > ,
op_span : Span ,
start_stmt : bool ,
) -> PResult < ' a , P < Expr > > {
let kind = IncDecRecovery {
standalone : if start_stmt { IsStandalone ::Standalone } else { IsStandalone ::Subexpr } ,
op : IncOrDec ::Dec ,
fixity : UnaryFixity ::Post ,
} ;
self . recover_from_inc_dec ( operand_expr , kind , op_span )
}
2023-02-28 19:28:14 +04:00
2021-09-06 16:16:52 -07:00
fn recover_from_inc_dec (
& mut self ,
base : P < Expr > ,
kind : IncDecRecovery ,
op_span : Span ,
) -> PResult < ' a , P < Expr > > {
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err (
2021-09-06 16:16:52 -07:00
op_span ,
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
format! ( " Rust has no {} {} operator " , kind . fixity , kind . op . name ( ) ) ,
2021-09-06 16:16:52 -07:00
) ;
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
err . span_label ( op_span , format! ( " not a valid {} operator " , kind . fixity ) ) ;
2021-09-06 16:16:52 -07:00
2024-02-23 10:20:45 +11:00
let help_base_case = | mut err : Diag < '_ , _ > , base | {
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
err . help ( format! ( " use ` {} = 1` instead " , kind . op . chr ( ) ) ) ;
2022-02-15 20:05:24 -08:00
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 ) else {
2022-11-26 05:33:13 +08:00
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.
2024-04-04 19:03:32 +02:00
if self . token = = token ::PathSep {
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 > > {
2024-04-04 19:03:32 +02:00
self . expect ( & token ::PathSep ) ? ;
2019-04-28 13:28:07 +08:00
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
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( BadQPathStage2 {
2023-09-28 00:37:20 +00:00
span : ty_span ,
wrap : WrapType { lo : ty_span . shrink_to_lo ( ) , hi : ty_span . shrink_to_hi ( ) } ,
2022-05-31 11:22:26 -05:00
} ) ;
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
}
2024-05-14 12:23:33 +02:00
/// This function gets called in places where a semicolon is NOT expected and if there's a
/// semicolon it emits the appropriate error and returns true.
pub fn maybe_consume_incorrect_semicolon ( & mut self , previous_item : Option < & Item > ) -> bool {
2024-08-09 17:44:47 +10:00
if self . token ! = TokenKind ::Semi {
2024-05-14 12:23:33 +02:00
return false ;
}
2022-05-31 11:45:44 -05:00
2024-05-14 12:23:33 +02:00
// Check previous item to add it to the diagnostic, for example to say
// `enum declarations are not followed by a semicolon`
let err = match previous_item {
Some ( previous_item ) = > {
let 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.
2024-05-14 12:23:33 +02:00
ItemKind ::Struct ( .. ) = > " braced struct " ,
_ = > previous_item . kind . descr ( ) ,
2019-04-28 13:28:07 +08:00
} ;
2024-05-14 12:23:33 +02:00
IncorrectSemicolon { span : self . token . span , name , show_help : true }
2019-04-28 13:28:07 +08:00
}
2024-05-14 12:23:33 +02:00
None = > IncorrectSemicolon { span : self . token . span , name : " " , show_help : false } ,
} ;
self . dcx ( ) . emit_err ( err ) ;
self . bump ( ) ;
true
2019-04-28 13:28:07 +08:00
}
2019-05-16 13:33:26 -07:00
2024-02-23 10:20:45 +11:00
/// Creates a `Diag` for an unexpected token `t` and tries to recover if it is a
2019-05-21 22:17:53 -07:00
/// closing delimiter.
2024-02-13 23:44:33 +00:00
pub ( super ) fn unexpected_try_recover ( & mut self , t : & TokenKind ) -> PResult < ' a , 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 , match (
2019-06-05 01:17:07 +03:00
& 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 ,
} , ) ;
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( sp , msg ) ;
2022-03-15 19:13:56 +09:00
let label_exp = format! ( " expected ` {token_str} ` " ) ;
2024-03-04 16:31:49 +11:00
let sm = self . psess . 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 , ( ) > {
2023-04-28 09:55:38 +08:00
if self . eat ( & token ::Semi ) | | self . recover_colon_as_semi ( ) {
2019-10-20 14:35:46 -07:00
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
}
2022-11-16 21:46:06 +01:00
pub ( super ) fn recover_colon_as_semi ( & mut self ) -> bool {
let line_idx = | span : Span | {
2024-03-04 16:31:49 +11:00
self . psess
2022-11-16 21:46:06 +01:00
. source_map ( )
. span_to_lines ( span )
. ok ( )
. and_then ( | lines | Some ( lines . lines . get ( 0 ) ? . line_index ) )
} ;
if self . may_recover ( )
& & self . token = = token ::Colon
& & self . look_ahead ( 1 , | next | line_idx ( self . token . span ) < line_idx ( next . span ) )
{
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( ColonAsSemi {
2022-11-16 21:46:06 +01:00
span : self . token . span ,
2024-08-21 00:57:58 -04:00
type_ascription : self . psess . unstable_features . is_nightly_build ( ) ,
2022-11-16 21:46:06 +01:00
} ) ;
self . bump ( ) ;
return true ;
}
false
}
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 ) ?
} ;
2024-02-25 22:22:11 +01:00
let ( sp , guar ) = self . error_on_incorrect_await ( lo , hi , & expr , is_question ) ;
let expr = self . mk_expr_err ( lo . to ( sp ) , guar ) ;
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`.
2023-02-24 04:38:45 +01:00
self . parse_expr_block ( None , self . token . span , BlockCheckMode ::Default )
2019-05-16 13:33:26 -07:00
} else {
self . parse_expr ( )
}
. map_err ( | mut err | {
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
}
2024-02-25 22:22:11 +01:00
fn error_on_incorrect_await (
& self ,
lo : Span ,
hi : Span ,
expr : & Expr ,
is_question : bool ,
) -> ( Span , ErrorGuaranteed ) {
2022-05-31 14:32:07 -05:00
let span = lo . to ( hi ) ;
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . emit_err ( IncorrectAwait {
2022-05-31 14:32:07 -05:00
span ,
2024-07-11 22:07:11 +00:00
suggestion : AwaitSuggestion {
removal : lo . until ( expr . span ) ,
dot_await : expr . span . shrink_to_hi ( ) ,
question_mark : if is_question { " ? " } else { " " } ,
} ,
2022-05-31 14:32:07 -05:00
} ) ;
2024-02-25 22:22:11 +01:00
( span , guar )
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
2023-12-18 21:14:02 +11:00
self . dcx ( ) . 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 )
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( lo . to ( hi ) , " use of deprecated `try` macro " ) ;
2020-04-17 14:07:44 +02:00
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 ,
) ;
}
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10: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 ) ;
2024-02-25 22:22:11 +01:00
let guar = err . emit ( ) ;
Ok ( self . mk_expr_err ( lo . to ( hi ) , guar ) )
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
}
}
2023-11-15 00:18:26 +00:00
/// When trying to close a generics list and encountering code like
/// ```text
/// impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {}
/// // ^ missing > here
/// ```
/// we provide a structured suggestion on the error from `expect_gt`.
pub ( super ) fn expect_gt_or_maybe_suggest_closing_generics (
& mut self ,
params : & [ ast ::GenericParam ] ,
) -> PResult < ' a , ( ) > {
let Err ( mut err ) = self . expect_gt ( ) else {
return Ok ( ( ) ) ;
} ;
// Attempt to find places where a missing `>` might belong.
if let [ .. , ast ::GenericParam { bounds , .. } ] = params
& & let Some ( poly ) = bounds
. iter ( )
. filter_map ( | bound | match bound {
2024-10-13 09:31:22 -04:00
ast ::GenericBound ::Trait ( poly ) = > Some ( poly ) ,
2023-11-15 00:18:26 +00:00
_ = > None ,
} )
. last ( )
{
err . span_suggestion_verbose (
poly . span . shrink_to_hi ( ) ,
" you might have meant to end the type parameters here " ,
" > " ,
Applicability ::MaybeIncorrect ,
) ;
}
Err ( err )
}
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 ,
2024-01-05 10:42:31 +11:00
err : PErr < ' a > ,
2019-05-16 14:31:07 -07:00
) -> P < Expr > {
2024-02-25 22:22:11 +01:00
let guar = err . emit ( ) ;
2024-01-05 10:42:31 +11:00
// Recover from parse error, callers expect the closing delim to be consumed.
self . consume_block ( delim , ConsumeClosingDelim ::Yes ) ;
2024-02-25 22:22:11 +01:00
self . mk_expr ( lo . to ( self . prev_token . span ) , ExprKind ::Err ( guar ) )
2019-05-16 14:31:07 -07:00
}
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 ;
debug! ( " recover_stmt_ enter loop (semi={:?}, block={:?}) " , break_on_semi , break_on_block ) ;
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 ( ) ;
if break_on_block = = BlockMode ::Break & & brace_depth = = 1 & & bracket_depth = = 0
{
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 ( ) ;
if break_on_semi = = SemiColonMode ::Break
& & brace_depth = = 0
& & bracket_depth = = 0
{
debug! ( " recover_stmt_ return - Semi " ) ;
break ;
}
}
2019-05-16 15:25:58 -07:00
token ::Comma
if break_on_semi = = SemiColonMode ::Comma
2019-05-16 14:31:07 -07:00
& & brace_depth = = 0
2019-05-16 15:25:58 -07:00
& & bracket_depth = = 0 = >
{
break ;
2019-05-16 14:31:07 -07:00
}
_ = > self . bump ( ) ,
}
}
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 {}`
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( InInTypo {
2022-05-31 16:28:05 -05:00
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 {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( DocCommentOnParamType { span : self . token . span } ) ;
2019-05-23 12:55:26 -07:00
self . bump ( ) ;
} 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-05-23 12:55:26 -07: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 ( ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . 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 ,
2024-02-23 10:20:45 +11:00
err : & mut Diag < '_ > ,
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.
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-05-29 15:25:46 -07: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.
2024-07-10 22:11:51 +00:00
if let Some ( _ ) = pat . to_ty ( ) {
2021-08-10 10:53:43 +00:00
err . span_suggestion_verbose (
2024-07-10 22:11:51 +00:00
pat . span . shrink_to_lo ( ) ,
2021-08-10 10:53:43 +00:00
" explicitly ignore the parameter name " ,
2024-07-10 22:11:51 +00:00
" _: " . to_string ( ) ,
2021-08-10 10:53:43 +00:00
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 {
2024-07-10 22:11:51 +00:00
err . span_suggestion_verbose (
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 {
2024-07-10 22:11:51 +00:00
err . span_suggestion_verbose (
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
) ;
}
2024-07-10 22:11:51 +00:00
err . span_suggestion_verbose (
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 > ) > {
2023-08-03 00:00:56 +08:00
let pat = self . parse_pat_no_top_alt ( Some ( Expected ::ArgumentName ) , None ) ? ;
2019-05-23 12:54:27 -07:00
self . expect ( & token ::Colon ) ? ;
let ty = self . parse_ty ( ) ? ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . 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 ;
2024-02-14 14:50:49 +11:00
let guar = self . dcx ( ) . emit_err ( SelfParamNotFirst { span } ) ;
param . ty . kind = TyKind ::Err ( guar ) ;
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 ( ) ;
}
}
}
2024-02-23 10:20:45 +11:00
pub ( super ) fn expected_expression_found ( & self ) -> Diag < ' a > {
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-06-07 13:31:13 +03:00
_ = > (
self . token . span ,
2023-07-25 18:27:24 +00:00
format! ( " expected expression, found {} " , super ::token_descr ( & self . token ) ) ,
2019-05-21 23:16:46 -07:00
) ,
} ;
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( span , msg ) ;
2024-03-04 16:31:49 +11:00
let sp = self . psess . source_map ( ) . start_point ( self . token . span ) ;
if let Some ( sp ) = self . psess . ambiguous_block_expr_parse . borrow ( ) . get ( & sp ) {
2024-06-18 11:10:18 +00:00
err . subdiagnostic ( ExprParenthesesNeeded ::surrounding ( * sp ) ) ;
2019-05-21 23:16:46 -07:00
}
err . span_label ( span , " expected expression " ) ;
2023-07-31 14:55:47 +00:00
// Walk the chain of macro expansions for the current token to point at how the original
// code was interpreted. This helps the user realize when a macro argument of one type is
// later reinterpreted as a different type, like `$x:expr` being reinterpreted as `$x:pat`
// in a subsequent macro invocation (#71039).
let mut tok = self . token . clone ( ) ;
let mut labels = vec! [ ] ;
2024-04-22 16:29:27 +10:00
while let TokenKind ::Interpolated ( nt ) = & tok . kind {
let tokens = nt . tokens ( ) ;
labels . push ( nt . clone ( ) ) ;
2023-07-31 14:55:47 +00:00
if let Some ( tokens ) = tokens
& & let tokens = tokens . to_attr_token_stream ( )
& & let tokens = tokens . 0. deref ( )
& & let [ AttrTokenTree ::Token ( token , _ ) ] = & tokens [ .. ]
{
tok = token . clone ( ) ;
} else {
break ;
}
}
let mut iter = labels . into_iter ( ) . peekable ( ) ;
let mut show_link = false ;
2024-04-22 16:29:27 +10:00
while let Some ( nt ) = iter . next ( ) {
let descr = nt . descr ( ) ;
2023-07-31 14:55:47 +00:00
if let Some ( next ) = iter . peek ( ) {
2024-04-22 16:29:27 +10:00
let next_descr = next . descr ( ) ;
2023-07-31 14:55:47 +00:00
if next_descr ! = descr {
2024-04-22 16:29:27 +10:00
err . span_label ( next . use_span ( ) , format! ( " this is expected to be {next_descr} " ) ) ;
2023-07-31 14:55:47 +00:00
err . span_label (
2024-04-22 16:29:27 +10:00
nt . use_span ( ) ,
2023-07-31 14:55:47 +00:00
format! (
" this is interpreted as {}, but it is expected to be {} " ,
next_descr , descr ,
) ,
) ;
show_link = true ;
}
}
}
if show_link {
err . note (
" when forwarding a matched fragment to another macro-by-example, matchers in the \
second macro will see an opaque AST of the fragment type , not the underlying \
tokens " ,
) ;
}
2019-05-21 23:16:46 -07:00
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 {
2024-08-09 17:44:47 +10:00
if let Some ( ( _ , val ) ) = modifier . iter ( ) . find ( | ( t , _ ) | self . token = = * t ) {
2019-09-30 12:19:22 -07:00
acc + = * val ;
}
2024-08-09 17:44:47 +10:00
if self . token = = 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.
2022-11-23 11:55:16 +11:00
pub ( super ) fn deduplicate_recovered_params_names ( & self , fn_inputs : & mut ThinVec < Param > ) {
2019-05-30 18:19:48 -07:00
let mut seen_inputs = FxHashSet ::default ( ) ;
for input in fn_inputs . iter_mut ( ) {
2024-02-14 14:50:49 +11:00
let opt_ident = if let ( PatKind ::Ident ( _ , ident , _ ) , TyKind ::Err ( _ ) ) =
2019-09-26 17:25:31 +01:00
( & 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.
2024-06-03 15:47:46 +10:00
pub ( super ) fn handle_ambiguous_unbraced_const_arg (
2020-10-03 19:30:32 +01:00
& mut self ,
2023-01-30 14:37:06 +11:00
args : & mut ThinVec < AngleBracketedArg > ,
2020-10-03 19:30:32 +01:00
) -> 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.
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err (
2020-10-03 19:30:32 +01:00
self . token . span ,
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
format! ( " expected one of `,` or `>`, found {} " , super ::token_descr ( & self . token ) ) ,
2020-10-03 19:30:32 +01:00
) ;
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
}
}
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
Err ( err ) = > {
2020-10-03 19:30:32 +01:00
args . push ( arg ) ;
// We will emit a more generic error later.
err . delay_as_bug ( ) ;
}
}
2024-09-09 12:22:00 +02:00
Ok ( false ) // Don't continue.
2020-10-03 19:30:32 +01:00
}
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.
2024-06-03 15:47:46 +10:00
pub ( super ) fn handle_unambiguous_unbraced_const_arg ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-10-03 19:30:32 +01:00
let start = self . token . span ;
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
let ( expr , _ ) =
self . parse_expr_res ( Restrictions ::CONST_EXPR , attrs ) . map_err ( | mut err | {
err . span_label (
start . shrink_to_lo ( ) ,
" while parsing a const generic argument starting here " ,
) ;
err
} ) ? ;
2020-10-03 19:30:32 +01:00
if ! self . expr_is_valid_const_arg ( & expr ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( ConstGenericWithoutBraces {
2022-09-08 18:23:31 +02:00
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 ( ) ;
2024-03-04 16:31:49 +11:00
let sugg = match ( ty_generics , self . psess . source_map ( ) . span_to_snippet ( param . span ( ) ) ) {
2022-09-08 18:23:31 +02:00
( 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 ,
} ;
2024-02-25 22:22:11 +01:00
let guar =
self . dcx ( ) . emit_err ( UnexpectedConstParamDeclaration { span : param . span ( ) , sugg } ) ;
2022-09-08 18:23:31 +02:00
2024-02-25 22:22:11 +01:00
let value = self . mk_expr_err ( param . span ( ) , guar ) ;
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
}
2024-06-03 15:47:46 +10:00
pub ( super ) fn recover_const_param_declaration (
2021-05-15 14:56:28 -07:00
& 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 ) ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . 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 ;
2023-12-18 14:00:17 +11:00
self . recover_const_arg ( after_kw_const , self . dcx ( ) . create_err ( err ) ) . 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.
2024-06-03 15:47:46 +10:00
pub ( super ) fn recover_const_arg (
& mut self ,
start : Span ,
mut err : Diag < ' a > ,
) -> 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 ( )
2024-08-09 17:44:47 +10:00
| | self . token = = 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 ( ) ;
}
2024-06-19 16:24:21 +10:00
match ( | | {
let attrs = self . parse_outer_attributes ( ) ? ;
self . parse_expr_res ( Restrictions ::CONST_EXPR , attrs )
} ) ( ) {
2024-08-06 17:16:40 +10:00
Ok ( ( expr , _ ) ) = > {
2021-07-29 05:49:56 +09:00
// Find a mistake like `MyTrait<Assoc == S::Assoc>`.
2024-08-09 17:44:47 +10:00
if snapshot . token = = token ::EqEq {
2021-07-29 05:49:56 +09:00
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 ,
) ;
2024-02-25 22:22:11 +01:00
let guar = err . emit ( ) ;
let value = self . mk_expr_err ( start . to ( expr . span ) , guar ) ;
2021-07-29 05:49:56 +09:00
return Ok ( GenericArg ::Const ( AnonConst { id : ast ::DUMMY_NODE_ID , value } ) ) ;
2024-08-09 17:44:47 +10:00
} else if snapshot . token = = token ::Colon
2022-03-11 15:26:19 -07:00
& & 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 ,
) ;
2024-02-14 14:50:49 +11:00
let guar = err . emit ( ) ;
return Ok ( GenericArg ::Type (
self . mk_ty ( start . to ( expr . span ) , TyKind ::Err ( guar ) ) ,
) ) ;
2024-08-09 17:44:47 +10:00
} else if self . token = = token ::Comma | | 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
2023-01-22 12:05:36 +01:00
/// Try to recover from an unbraced const argument whose first token [could begin a type][ty].
///
/// [ty]: token::Token::can_begin_type
pub ( crate ) fn recover_unbraced_const_arg_that_can_begin_ty (
& mut self ,
mut snapshot : SnapshotParser < ' a > ,
) -> Option < P < ast ::Expr > > {
2024-06-19 16:24:21 +10:00
match ( | | {
let attrs = self . parse_outer_attributes ( ) ? ;
snapshot . parse_expr_res ( Restrictions ::CONST_EXPR , attrs )
} ) ( ) {
2023-01-22 12:05:36 +01:00
// Since we don't know the exact reason why we failed to parse the type or the
// expression, employ a simple heuristic to weed out some pathological cases.
2024-08-06 17:16:40 +10:00
Ok ( ( expr , _ ) ) if let token ::Comma | token ::Gt = snapshot . token . kind = > {
2023-01-22 12:05:36 +01:00
self . restore_snapshot ( snapshot ) ;
Some ( expr )
}
Ok ( _ ) = > None ,
Err ( err ) = > {
err . cancel ( ) ;
None
}
}
}
2022-01-13 23:03:10 -08:00
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
2024-06-03 15:47:46 +10:00
pub ( super ) fn dummy_const_arg_needs_braces ( & self , mut err : Diag < ' a > , span : Span ) -> GenericArg {
2022-01-13 23:03:10 -08:00
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 ,
) ;
2024-02-25 22:22:11 +01:00
let guar = err . emit ( ) ;
let value = self . mk_expr_err ( span , guar ) ;
2022-01-13 23:03:10 -08:00
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).
2023-01-30 18:08:50 +00: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 > ,
2022-11-08 22:03:17 +01:00
expected : Option < Expected > ,
2021-11-21 04:56:32 +00:00
) -> 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 ( ) )
{
2023-02-02 16:42:21 +00:00
let mut snapshot_type = self . create_snapshot_for_diagnostic ( ) ;
snapshot_type . bump ( ) ; // `:`
match snapshot_type . parse_ty ( ) {
Err ( inner_err ) = > {
inner_err . cancel ( ) ;
}
Ok ( ty ) = > {
let Err ( mut err ) = self . expected_one_of_not_found ( & [ ] , & [ ] ) else {
return first_pat ;
} ;
err . span_label ( ty . span , " specifying the type of a pattern isn't supported " ) ;
self . restore_snapshot ( snapshot_type ) ;
let span = first_pat . span . to ( ty . span ) ;
first_pat = self . mk_pat ( span , PatKind ::Wild ) ;
err . emit ( ) ;
}
}
2021-11-21 04:56:32 +00:00
return first_pat ;
}
// The pattern looks like it might be a path with a `::` -> `:` typo:
// `match foo { bar:baz => {} }`
2023-02-02 16:42:21 +00:00
let colon_span = self . token . span ;
2021-11-21 04:56:32 +00:00
// We only emit "unexpected `:`" error here if we can successfully parse the
// whole pattern correctly in that case.
2023-02-02 16:42:21 +00:00
let mut snapshot_pat = self . create_snapshot_for_diagnostic ( ) ;
let mut snapshot_type = 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 ) = > {
2023-02-02 16:42:21 +00:00
// Skip the `:`.
snapshot_pat . bump ( ) ;
snapshot_type . bump ( ) ;
2023-08-03 00:00:56 +08:00
match snapshot_pat . parse_pat_no_top_alt ( expected , None ) {
2022-01-26 03:39:14 +00:00
Err ( inner_err ) = > {
2021-11-21 04:56:32 +00:00
inner_err . cancel ( ) ;
}
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 ;
}
_ = > { }
} ,
2024-04-16 19:23:30 -04:00
PatKind ::Ident ( BindingMode ::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 {
2023-02-02 16:42:21 +00:00
err . span_suggestion_verbose (
colon_span . until ( self . look_ahead ( 1 , | t | t . span ) ) ,
2021-11-21 04:56:32 +00:00
" 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 ) ;
}
2023-02-02 16:42:21 +00:00
self . restore_snapshot ( snapshot_pat ) ;
2021-11-21 04:56:32 +00:00
}
}
2023-02-02 16:42:21 +00:00
match snapshot_type . parse_ty ( ) {
Err ( inner_err ) = > {
inner_err . cancel ( ) ;
}
Ok ( ty ) = > {
err . span_label ( ty . span , " specifying the type of a pattern isn't supported " ) ;
self . restore_snapshot ( snapshot_type ) ;
let new_span = first_pat . span . to ( ty . span ) ;
first_pat = self . mk_pat ( new_span , PatKind ::Wild ) ;
}
}
err . emit ( ) ;
2021-11-21 04:56:32 +00:00
}
_ = > {
// Carry on as if we had not done anything. This should be unreachable.
}
} ;
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 ( )
2024-08-09 17:44:47 +10:00
& & self . look_ahead ( 1 , | t | * t = = token ::Colon )
& & self . look_ahead ( 2 , | t | * t = = token ::OpenDelim ( Delimiter ::Brace ) ) )
2022-11-04 21:16:20 +00:00
{
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 ) ;
2024-01-03 17:03:10 +11:00
self . dcx ( )
. struct_span_err ( span , " block label not supported here " )
2024-01-09 09:08:49 +11:00
. with_span_label ( span , " not supported here " )
. with_tool_only_span_suggestion (
2024-01-03 17:03:10 +11:00
label . ident . span . until ( self . token . span ) ,
" remove this block label " ,
" " ,
Applicability ::MachineApplicable ,
)
. emit ( ) ;
2022-01-12 20:43:24 +00:00
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 ) ;
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( comma_span , " unexpected `,` in pattern " ) ;
2021-11-21 04:56:32 +00:00
if let Ok ( seq_snippet ) = self . span_to_snippet ( seq_span ) {
2023-11-27 00:50:51 +01: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 ( ) ) ,
] ,
Applicability ::MachineApplicable ,
) ;
if let CommaRecoveryMode ::EitherTupleOrPipe = rt {
err . span_suggestion (
seq_span ,
" ...or a vertical bar to match on multiple alternatives " ,
seq_snippet . replace ( ',' , " | " ) ,
2022-01-12 20:43:24 +00:00
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 ( ) {
2023-05-24 14:33:43 +00:00
if qself_position . is_some_and ( | pos | i < pos ) {
2022-03-25 13:53:03 -07:00
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 ( " :: " ) {
2023-12-18 14:00:17 +11:00
return Err ( self . dcx ( ) . create_err ( DoubleColonInBound {
2022-09-08 18:23:31 +02:00
span : path . span . shrink_to_hi ( ) ,
between : between_span ,
2023-12-18 14:00:17 +11:00
} ) ) ;
2022-03-25 13:53:03 -07:00
}
}
}
Ok ( ( ) )
}
2023-12-22 21:56:58 -08:00
/// Check for exclusive ranges written as `..<`
pub ( crate ) fn maybe_err_dotdotlt_syntax ( & self , maybe_lt : Token , mut err : PErr < ' a > ) -> PErr < ' a > {
if maybe_lt = = token ::Lt
& & ( self . expected_tokens . contains ( & TokenType ::Token ( token ::Gt ) )
| | matches! ( self . token . kind , token ::Literal ( .. ) ) )
{
err . span_suggestion (
maybe_lt . span ,
" remove the `<` to write an exclusive range " ,
" " ,
Applicability ::MachineApplicable ,
) ;
}
err
}
2024-05-08 14:22:09 +02:00
/// This checks if this is a conflict marker, depending of the parameter passed.
///
2024-06-10 10:16:51 +02:00
/// * `<<<<<<<`
/// * `|||||||`
/// * `=======`
/// * `>>>>>>>`
2024-05-08 14:22:09 +02:00
///
2024-06-03 15:47:46 +10:00
pub ( super ) fn is_vcs_conflict_marker (
2024-05-08 14:22:09 +02:00
& mut self ,
long_kind : & TokenKind ,
short_kind : & TokenKind ,
) -> bool {
2022-12-28 17:56:22 -08:00
( 0 .. 3 ) . all ( | i | self . look_ahead ( i , | tok | tok = = long_kind ) )
& & self . look_ahead ( 3 , | tok | tok = = short_kind )
}
2024-05-08 14:22:09 +02:00
fn conflict_marker ( & mut self , long_kind : & TokenKind , short_kind : & TokenKind ) -> Option < Span > {
if self . is_vcs_conflict_marker ( long_kind , short_kind ) {
2022-12-28 17:56:22 -08:00
let lo = self . token . span ;
for _ in 0 .. 4 {
self . bump ( ) ;
}
return Some ( lo . to ( self . prev_token . span ) ) ;
}
None
}
2024-06-03 15:47:46 +10:00
pub ( super ) fn recover_vcs_conflict_marker ( & mut self ) {
2024-05-08 14:22:09 +02:00
if let Err ( err ) = self . err_vcs_conflict_marker ( ) {
2023-10-13 22:43:48 +00:00
err . emit ( ) ;
FatalError . raise ( ) ;
}
}
2024-06-03 15:47:46 +10:00
pub ( crate ) fn err_vcs_conflict_marker ( & mut self ) -> PResult < ' a , ( ) > {
2024-06-07 16:25:43 +02:00
// <<<<<<<
2024-05-08 14:22:09 +02:00
let Some ( start ) = self . conflict_marker ( & TokenKind ::BinOp ( token ::Shl ) , & TokenKind ::Lt )
else {
2023-10-13 22:43:48 +00:00
return Ok ( ( ) ) ;
2022-12-28 17:56:22 -08:00
} ;
let mut spans = Vec ::with_capacity ( 3 ) ;
spans . push ( start ) ;
2024-06-07 16:25:43 +02:00
// |||||||
2022-12-28 20:55:46 -08:00
let mut middlediff3 = None ;
2024-06-07 16:25:43 +02:00
// =======
2022-12-28 17:56:22 -08:00
let mut middle = None ;
2024-06-07 16:25:43 +02:00
// >>>>>>>
2022-12-28 17:56:22 -08:00
let mut end = None ;
loop {
2024-08-09 17:44:47 +10:00
if self . token = = TokenKind ::Eof {
2022-12-28 17:56:22 -08:00
break ;
}
2024-05-08 14:22:09 +02:00
if let Some ( span ) = self . conflict_marker ( & TokenKind ::OrOr , & TokenKind ::BinOp ( token ::Or ) )
{
2022-12-28 20:55:46 -08:00
middlediff3 = Some ( span ) ;
}
2024-05-08 14:22:09 +02:00
if let Some ( span ) = self . conflict_marker ( & TokenKind ::EqEq , & TokenKind ::Eq ) {
2022-12-28 17:56:22 -08:00
middle = Some ( span ) ;
}
2024-05-08 14:22:09 +02:00
if let Some ( span ) = self . conflict_marker ( & TokenKind ::BinOp ( token ::Shr ) , & TokenKind ::Gt )
{
2022-12-28 17:56:22 -08:00
spans . push ( span ) ;
end = Some ( span ) ;
break ;
}
self . bump ( ) ;
}
2024-06-07 16:25:43 +02:00
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( spans , " encountered diff marker " ) ;
2024-06-07 16:25:43 +02:00
match middlediff3 {
// We're using diff3
Some ( middlediff3 ) = > {
err . span_label (
start ,
" between this marker and `|||||||` is the code that we're merging into " ,
) ;
err . span_label ( middlediff3 , " between this marker and `=======` is the base code (what the two refs diverged from) " ) ;
}
None = > {
err . span_label (
start ,
" between this marker and `=======` is the code that we're merging into " ,
) ;
}
} ;
2022-12-28 17:56:22 -08:00
if let Some ( middle ) = middle {
2024-06-07 16:25:43 +02:00
err . span_label ( middle , " between this marker and `>>>>>>>` is the incoming code " ) ;
2022-12-28 17:56:22 -08:00
}
if let Some ( end ) = end {
2024-06-07 16:25:43 +02:00
err . span_label ( end , " this marker concludes the conflict region " ) ;
2022-12-28 17:56:22 -08:00
}
2024-06-07 16:25:43 +02:00
err . note (
" conflict markers indicate that a merge was started but could not be completed due \
to merge conflicts \ n \
to resolve a conflict , keep only the code you want and then delete the lines \
containing conflict markers " ,
2022-12-28 18:46:20 -08:00
) ;
err . help (
2024-06-07 16:25:43 +02:00
" if you're having merge conflicts after pulling new code: \n \
the top section is the code you already had and the bottom section is the remote code \ n \
if you ' re in the middle of a rebase :\ n \
the top section is the code being rebased onto and the bottom section is the code \
coming from the current commit being rebased " ,
2022-12-28 18:46:20 -08:00
) ;
2024-06-07 16:25:43 +02:00
2022-12-28 18:46:20 -08:00
err . note (
2024-06-07 16:25:43 +02:00
" for an explanation on these markers from the `git` documentation: \n \
visit < https ://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
2022-12-28 18:46:20 -08:00
) ;
2024-06-07 16:25:43 +02:00
2023-10-13 22:43:48 +00:00
Err ( err )
2022-12-28 17:56:22 -08:00
}
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 ) ) {
2023-08-03 00:00:56 +08:00
self . parse_pat_no_top_alt ( None , None ) ? ;
2021-11-21 04:56:32 +00:00
if ! self . eat ( & token ::Comma ) {
return Ok ( ( ) ) ;
}
}
Ok ( ( ) )
}
2019-04-28 13:28:07 +08:00
}