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 ;
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
use rustc_ast ::token ::{ self , Lit , LitKind , Token , TokenKind } ;
2020-02-29 20:37:32 +03:00
use rustc_ast ::util ::parser ::AssocOp ;
2021-05-15 14:56:28 -07:00
use rustc_ast ::{
2024-04-16 19:23:30 -04:00
AngleBracketedArg , AngleBracketedArgs , AnonConst , AttrVec , BinOpKind , BindingMode , Block ,
Remove `NtPat`.
The one notable test change is `tests/ui/macros/trace_faulty_macros.rs`.
This commit removes the complicated `Interpolated` handling in
`expected_expression_found` that results in a longer error message. But
I think the new, shorter message is actually an improvement.
The original complaint was in #71039, when the error message started
with "error: expected expression, found `1 + 1`". That was confusing
because `1 + 1` is an expression. Other than that, the reporter said
"the whole error message is not too bad if you ignore the first line".
Subsequently, extra complexity and wording was added to the error
message. But I don't think the extra wording actually helps all that
much. In particular, it still says of the `1+1` that "this is expected
to be expression". This repeats the problem from the original complaint!
This commit removes the extra complexity, reverting to a simpler error
message. This is primarily because the traversal is a pain without
`Interpolated` tokens. Nonetheless, I think the error message is
*improved*. It now starts with "expected expression, found `pat`
metavariable", which is much clearer and the real problem. It also
doesn't say anything specific about `1+1`, which is good, because the
`1+1` isn't really relevant to the error -- it's the `$e:pat` that's
important.
2024-04-18 12:44:11 +10:00
BlockCheckMode , Expr , ExprKind , GenericArg , Generics , Item , ItemKind , Param , Pat , 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-12-20 14:08:24 +00:00
Applicability , Diag , DiagCtxtHandle , ErrorGuaranteed , PResult , Subdiagnostic , 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-12-13 20:54:36 +11:00
use rustc_span ::symbol ::used_keywords ;
2024-12-13 10:29:23 +11:00
use rustc_span ::{ BytePos , DUMMY_SP , Ident , Span , SpanSnippetError , Symbol , kw , sym } ;
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-12-04 15:55:06 +11:00
BlockMode , CommaRecoveryMode , ExpTokenPair , 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 ::{
2025-02-21 17:24:46 -03:00
AddParen , AmbiguousPlus , AsyncMoveBlockIn2015 , AsyncUseBlockIn2015 , AttributeOnParamType ,
AwaitSuggestion , BadQPathStage2 , BadTypePlus , BadTypePlusSub , ColonAsSemi ,
ComparisonOperatorsCannotBeChained , 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 ,
2024-10-02 16:35:37 -03:00
IncorrectSemicolon , IncorrectUseOfAwait , IncorrectUseOfUse , PatternMethodParamWithoutBody ,
QuestionMarkInType , QuestionMarkInTypeSugg , SelfParamNotFirst , StructLiteralBodyWithoutPath ,
2025-03-24 00:12:53 +01:00
StructLiteralBodyWithoutPathSugg , SuggAddMissingLetStmt , SuggEscapeIdentifier , SuggRemoveComma ,
TernaryOperator , UnexpectedConstInGenericParam , UnexpectedConstParamDeclaration ,
2023-12-06 16:56:45 -08:00
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 ;
2024-12-04 15:55:06 +11:00
use crate ::{ exp , fluent_generated as fluent } ;
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 ) > {
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 ,
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
TokenKind ::OpenBrace ,
TokenKind ::OpenParen ,
TokenKind ::CloseBrace ,
TokenKind ::CloseParen ,
2019-11-20 14:50:13 -08:00
] ;
Tweak "expected ident" parse error to avoid talking about doc comments
When encountering a doc comment without an identifier after, we'd unconditionally state "this doc comment doesn't document anything", swallowing the *actual* error which is that the thing *after* the doc comment wasn't expected. Added a check that the found token is something that "conceptually" closes the previous item before emitting that error, otherwise just complain about the missing identifier.
In both of the following cases, the syntax error follows a doc comment:
```
error: expected identifier, found keyword `Self`
--> $DIR/doc-before-bad-variant.rs:4:5
|
LL | enum TestEnum {
| -------- while parsing this enum
...
LL | Self,
| ^^^^ expected identifier, found keyword
|
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
```
```
error: expected identifier, found `<`
--> $DIR/doc-before-syntax-error.rs:2:1
|
LL | <>
| ^ expected identifier
```
Fix #71982.
2025-02-19 17:26:03 +00:00
if let TokenKind ::DocComment ( .. ) = self . prev_token . kind
& & valid_follow . contains ( & self . token . kind )
{
let err = self . dcx ( ) . create_err ( DocCommentDoesNotDocumentAnything {
span : self . prev_token . span ,
missing_comma : None ,
} ) ;
return Err ( err ) ;
}
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.
2024-05-16 09:22:37 +10:00
let bad_token = self . token ;
2023-03-17 22:27:17 +13:00
// 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)
2024-05-16 09:22:37 +10:00
let maybe_keyword = self . prev_token ;
2022-10-24 00:52:59 +11:00
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 ,
2024-12-04 15:55:06 +11:00
edible : & [ ExpTokenPair < '_ > ] ,
inedible : & [ ExpTokenPair < '_ > ] ,
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
} )
}
2024-12-04 15:55:06 +11:00
for exp in edible . iter ( ) . chain ( inedible . iter ( ) ) {
self . expected_token_types . insert ( exp . token_type ) ;
}
let mut expected : Vec < _ > = self . expected_token_types . iter ( ) . collect ( ) ;
2019-05-23 13:10:24 -07:00
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.
2024-12-04 15:55:06 +11:00
if expected . contains ( & TokenType ::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 )
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
& & self . prev_token = = token ::CloseParen
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 | {
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
t = = & token ::CloseBrace | | 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 ,
2024-05-16 09:22:37 +10:00
token : self . token ,
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 | {
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
t = = & token ::CloseBrace
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 )
2024-12-04 15:55:06 +11:00
} ) & & ! expected . contains ( & TokenType ::Comma )
2022-07-02 03:04:18 +00:00
{
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 ,
2024-05-16 09:22:37 +10:00
token : self . token ,
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 ( )
2024-12-04 15:55:06 +11:00
& & expected . contains ( & TokenType ::Eq )
2022-09-07 12:26:50 +08:00
{
// 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
}
2025-02-21 17:24:46 -03:00
if ( self . token . is_keyword ( kw ::Move ) | | self . token . is_keyword ( kw ::Use ) )
& & self . prev_token . is_keyword ( kw ::Async )
{
// The 2015 edition is in use because parsing of `async move` or `async use` has failed.
2023-07-30 15:49:33 +08:00
let span = self . prev_token . span . to ( self . token . span ) ;
2025-02-21 17:24:46 -03:00
if self . token . is_keyword ( kw ::Move ) {
return Err ( self . dcx ( ) . create_err ( AsyncMoveBlockIn2015 { span } ) ) ;
} else {
// kw::Use
return Err ( self . dcx ( ) . create_err ( AsyncUseBlockIn2015 { 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
2025-04-04 21:36:03 +00:00
self . label_expected_raw_ref ( & mut err ) ;
2023-10-27 15:14:55 -07:00
// Look for usages of '=>' where '>=' was probably intended
if self . token = = token ::FatArrow
2024-12-04 15:55:06 +11:00
& & expected . iter ( ) . any ( | tok | matches! ( tok , TokenType ::Operator | TokenType ::Le ) )
& & ! expected . iter ( ) . any ( | tok | matches! ( tok , TokenType ::FatArrow | TokenType ::Comma ) )
2023-10-27 15:14:55 -07:00
{
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 )
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
& & ( self . token . can_begin_item ( ) | | self . token = = TokenKind ::OpenParen )
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 ) {
2024-12-04 15:55:06 +11:00
if expected . contains ( & TokenType ::Semi ) & & self . eat ( exp! ( 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 )
}
2025-04-04 21:36:03 +00:00
/// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`.
///
/// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this
/// label may need added to other diagnostics emission paths as needed.
pub ( super ) fn label_expected_raw_ref ( & mut self , err : & mut Diag < '_ > ) {
if self . prev_token . is_keyword ( kw ::Raw )
& & self . expected_token_types . contains ( TokenType ::KwMut )
& & self . expected_token_types . contains ( TokenType ::KwConst )
& & self . token . can_begin_expr ( )
{
err . span_suggestions (
self . prev_token . span . shrink_to_hi ( ) ,
" `&raw` must be followed by `const` or `mut` to be a raw reference expression " ,
[ " const " . to_string ( ) , " mut " . to_string ( ) ] ,
Applicability ::MaybeIncorrect ,
) ;
}
}
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 ;
} ;
2024-12-03 20:09:29 +11:00
let expected_token_types : & [ TokenType ] =
2024-09-02 12:43:35 -04:00
expected . len ( ) . checked_sub ( 10 ) . map_or ( & expected , | index | & expected [ index .. ] ) ;
2024-12-04 15:55:06 +11:00
let expected_keywords : Vec < Symbol > =
expected_token_types . iter ( ) . filter_map ( | token | token . is_keyword ( ) ) . collect ( ) ;
2024-09-02 12:43:35 -04:00
2024-12-03 20:09:29 +11:00
// When there are a few keywords in the last ten elements of `self.expected_token_types`
// 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
2024-12-29 18:03:37 +08:00
// `if`-`else` and misspelled `where` in a where clause.
2024-09-02 12:43:35 -04:00
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.
2024-12-13 20:54:36 +11:00
let all_keywords = used_keywords ( | | prev_ident . span . edition ( ) ) ;
2024-09-02 12:43:35 -04:00
// Otherwise, check the previous token with all the keywords as possible candidates.
// This handles code like `Struct Human;` and `While a < b {}`.
Only have one source of truth for keywords.
`rustc_symbol` is the source of truth for keywords.
rustdoc has its own implicit definition of keywords, via the
`is_doc_keyword`. It (presumably) intends to include all keywords, but
it omits `yeet`.
rustfmt has its own explicit list of Rust keywords. It also (presumably)
intends to include all keywords, but it omits `await`, `builtin`, `gen`,
`macro_rules`, `raw`, `reuse`, `safe`, and `yeet`. Also, it does linear
searches through this list, which is inefficient.
This commit fixes all of the above problems by introducing a new
predicate `is_any_keyword` in rustc and using it in rustdoc and rustfmt.
It documents that it's not the right predicate in most cases.
2024-12-13 21:07:58 +11:00
// 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 {}`.
2024-09-02 12:43:35 -04:00
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 ,
2024-05-16 09:22:37 +10:00
token : self . token ,
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
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 " } ,
) ,
) ;
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
if self . token = = token ::Pound & & self . look_ahead ( 1 , | t | * t = = token ::OpenBracket ) {
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 ,
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,
// }
2025-03-24 00:12:53 +01:00
// Suggest:
// fn foo() -> Foo { Path {
// field: value,
// } }
err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2025-03-24 00:12:53 +01:00
let guar = self . dcx ( ) . emit_err ( StructLiteralBodyWithoutPath {
span : expr . span ,
sugg : StructLiteralBodyWithoutPathSugg {
before : expr . span . shrink_to_lo ( ) ,
after : expr . span . shrink_to_hi ( ) ,
} ,
} ) ;
Ok ( self . mk_block (
thin_vec! [ self . mk_stmt_err ( expr . span , guar ) ] ,
s ,
lo . to ( self . prev_token . span ) ,
) )
2020-08-12 15:39:15 -07:00
}
2022-01-26 03:39:14 +00:00
( Err ( err ) , Ok ( tail ) ) = > {
2025-03-24 00:12:53 +01:00
// We have a block tail that contains a somehow valid expr.
2020-08-12 15:39:15 -07:00
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 ( ) ;
2024-12-04 15:55:06 +11:00
self . consume_block ( exp! ( OpenBrace ) , exp! ( CloseBrace ) , ConsumeClosingDelim ::Yes ) ;
2020-08-12 15:39:15 -07:00
Err ( err )
}
2025-03-23 22:00:39 +01:00
( Ok ( _ ) , Ok ( tail ) ) = > 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 {
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
token ::OpenBrace if token . kind ! = token ::OpenBrace = > {
2023-10-11 23:20:41 +00:00
// `{ || () }` 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 ( ) ;
2024-12-04 15:55:06 +11:00
self . eat_to_tokens ( & [ exp! ( CloseBrace ) ] ) ;
2024-02-25 22:22:11 +01:00
guar
2023-10-11 23:20:41 +00:00
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
token ::OpenParen if token . kind ! = token ::OpenBrace = > {
2023-10-11 23:20:41 +00:00
// We are within a function call or tuple, we can emit the error
// and recover.
2024-12-04 15:55:06 +11:00
self . eat_to_tokens ( & [ exp! ( CloseParen ) , exp! ( Comma ) ] ) ;
2023-10-11 23:20:41 +00:00
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
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
_ if token . kind ! = token ::OpenBrace = > {
2023-10-11 23:20:41 +00:00
// 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
}
2024-12-04 15:50:46 +11:00
/// Eats and discards tokens until one of `closes` is encountered. Respects token trees,
2019-05-23 12:55:26 -07:00
/// passes through any errors encountered. Used for error recovery.
2024-12-04 15:55:06 +11:00
pub ( super ) fn eat_to_tokens ( & mut self , closes : & [ ExpTokenPair < '_ > ] ) {
2024-12-04 15:50:46 +11:00
if let Err ( err ) = self
. parse_seq_to_before_tokens ( closes , & [ ] , 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 ,
2024-12-04 15:55:06 +11:00
end : & [ ExpTokenPair < '_ > ] ,
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 ) ;
2024-12-20 07:28:16 +11:00
if * t = = token ::Shr {
2019-05-23 12:55:26 -07:00
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 ) ;
2024-12-04 15:55:06 +11:00
end . iter ( ) . any ( | exp | exp . tok = = & 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-12-20 07:28:16 +11:00
while self . token = = token ::Shr | | self . token = = token ::Gt {
2020-07-23 16:25:39 -07:00
trailing_span = trailing_span . to ( self . token . span ) ;
self . bump ( ) ;
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
if self . token = = token ::OpenParen {
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
2024-12-04 15:55:06 +11:00
& & self . eat ( exp! ( Comma ) )
2022-02-28 07:49:56 -03:00
{
let x = self . parse_seq_to_before_end (
2024-12-04 15:55:06 +11:00
exp! ( Gt ) ,
SeqSep ::trailing_allowed ( exp! ( 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 ) ) = > {
2024-12-04 15:55:06 +11:00
if self . eat ( exp! ( 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
2024-12-27 14:25:08 -08:00
& & ! ident . is_numeric ( )
2022-02-28 07:49:56 -03:00
& & ! 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`
2024-12-19 18:24:07 +11:00
( BinOpKind ::Eq , AssocOp ::Binary ( BinOpKind ::Eq ) ) |
2020-01-11 00:19:09 +00:00
// `x < y < z` and friends.
2024-12-19 18:24:07 +11:00
( BinOpKind ::Lt , AssocOp ::Binary ( BinOpKind ::Lt | BinOpKind ::Le ) ) |
( BinOpKind ::Le , AssocOp ::Binary ( BinOpKind ::Lt | BinOpKind ::Le ) ) |
2020-01-11 00:19:09 +00:00
// `x > y > z` and friends.
2024-12-19 18:24:07 +11:00
( BinOpKind ::Gt , AssocOp ::Binary ( BinOpKind ::Gt | BinOpKind ::Ge ) ) |
( BinOpKind ::Ge , AssocOp ::Binary ( BinOpKind ::Gt | BinOpKind ::Ge ) ) = > {
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`
2024-12-19 18:24:07 +11:00
(
BinOpKind ::Eq ,
AssocOp ::Binary ( BinOpKind ::Lt | BinOpKind ::Le | BinOpKind ::Gt | BinOpKind ::Ge )
) = > {
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`
2024-12-19 18:24:07 +11:00
(
BinOpKind ::Lt | BinOpKind ::Le | BinOpKind ::Gt | BinOpKind ::Ge ,
AssocOp ::Binary ( BinOpKind ::Eq )
) = > {
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, ()>>>`
2024-12-19 18:24:07 +11:00
if op . node = = BinOpKind ::Lt & & outer_op . node = = AssocOp ::Binary ( BinOpKind ::Lt )
| | outer_op . node = = AssocOp ::Binary ( BinOpKind ::Gt )
2019-05-23 12:55:26 -07:00
{
2024-12-19 18:24:07 +11:00
if outer_op . node = = AssocOp ::Binary ( BinOpKind ::Lt ) {
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.
2024-12-20 07:28:16 +11:00
let modifiers = [ ( token ::Lt , 1 ) , ( token ::Gt , - 1 ) , ( token ::Shr , - 2 ) ] ;
2021-12-03 03:06:36 +01:00
self . consume_tts ( 1 , & modifiers ) ;
2019-09-30 12:19:22 -07:00
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
if ! matches! ( self . token . kind , token ::OpenParen | token ::PathSep ) {
2019-09-30 12:36:44 -07:00
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
// parser and bail out.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2019-09-29 19:07:26 -07:00
}
}
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
}
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
} else if self . token = = token ::OpenParen {
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.
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
let modifiers = [ ( token ::OpenParen , 1 ) , ( token ::CloseParen , - 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 ( ) ? ;
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
}
2025-04-15 07:44:24 +02:00
TyKind ::Ptr ( .. ) | TyKind ::BareFn ( .. ) = > {
BadTypePlusSub ::ForgotParen { span : ty . span . to ( self . prev_token . span ) }
}
_ = > BadTypePlusSub ::ExpectPath { span : ty . span } ,
2022-05-16 17:16:27 -05:00
} ;
2025-04-15 07:44:24 +02:00
self . dcx ( ) . emit_err ( BadTypePlus { span : ty . 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-12-04 15:55:06 +11:00
self . expect ( exp! ( 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 ,
2019-06-05 01:17:07 +03:00
match ( & self . token . kind , self . subparser_name ) {
2022-03-15 19:13:56 +09:00
( token ::Eof , Some ( origin ) ) = > format! ( " end of {origin} " ) ,
2019-05-21 22:17:53 -07:00
_ = > this_token_str ,
} ,
) ;
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 , ( ) > {
2024-12-04 15:55:06 +11:00
if self . eat ( exp! ( Semi ) ) | | self . recover_colon_as_semi ( ) {
2019-10-20 14:35:46 -07:00
return Ok ( ( ) ) ;
}
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( 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 ) )
{
2025-04-16 20:03:18 +10:00
self . dcx ( ) . emit_err ( ColonAsSemi { span : self . token . span } ) ;
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 ,
await_sp : Span ,
2019-12-03 14:21:03 +01:00
) -> PResult < ' a , P < Expr > > {
2024-12-20 14:04:25 +11:00
let ( hi , expr , is_question ) = if self . token = = token ::Bang {
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-11-28 15:06:37 +11:00
let ( sp , guar ) = self . error_on_incorrect_await ( await_sp , hi , & expr , is_question ) ;
let expr = self . mk_expr_err ( await_sp . 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 ) > {
2024-12-20 14:04:25 +11:00
self . expect ( exp! ( Bang ) ) ? ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( OpenParen ) ) ? ;
2019-12-03 14:21:03 +01:00
let expr = self . parse_expr ( ) ? ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( CloseParen ) ) ? ;
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 ) > {
2024-12-04 15:55:06 +11:00
let is_question = self . eat ( exp! ( Question ) ) ; // Handle `await? <expr>`.
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
let expr = if self . token = = token ::OpenBrace {
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 | {
2024-10-02 16:35:37 -03:00
err . span_label ( await_sp , format! ( " while parsing this incorrect await expression " ) ) ;
2019-05-16 13:33:26 -07:00
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 ) {
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
if self . token = = token ::OpenParen & & self . look_ahead ( 1 , | t | t = = & token ::CloseParen ) {
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
}
}
2024-10-02 16:35:37 -03:00
///
/// If encountering `x.use()`, consumes and emits an error.
pub ( super ) fn recover_from_use ( & mut self ) {
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
if self . token = = token ::OpenParen & & self . look_ahead ( 1 , | t | t = = & token ::CloseParen ) {
2024-10-02 16:35:37 -03:00
// var.use()
let lo = self . token . span ;
self . bump ( ) ; // (
let span = lo . to ( self . token . span ) ;
self . bump ( ) ; // )
self . dcx ( ) . emit_err ( IncorrectUseOfUse { 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 ) ;
2024-12-20 14:04:25 +11:00
let is_questionmark = self . look_ahead ( 1 , | t | t = = & token ::Bang ) ; //check for !
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
let is_open = self . look_ahead ( 2 , | t | t = = & token ::OpenParen ) ; //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 (
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
let is_empty = self . token = = token ::CloseParen ; //check if the block is empty
2024-12-04 15:55:06 +11:00
self . consume_block ( exp! ( OpenParen ) , exp! ( CloseParen ) , 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 ,
} )
2025-03-10 19:03:51 +01:00
. next_back ( )
2023-11-15 00:18:26 +00:00
{
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 ,
2024-12-04 15:55:06 +11:00
open : ExpTokenPair < '_ > ,
close : ExpTokenPair < '_ > ,
2019-05-16 14:31:07 -07:00
lo : Span ,
2024-12-12 11:31:10 +11:00
err : Diag < ' 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.
2024-12-04 15:55:06 +11:00
self . consume_block ( open , close , 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 {
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
token ::OpenBrace = > {
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 ;
}
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
token ::OpenBracket = > {
2019-05-16 14:31:07 -07:00
bracket_depth + = 1 ;
self . bump ( ) ;
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
token ::CloseBrace = > {
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 ;
}
}
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
token ::CloseBracket = > {
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 ) {
2024-12-04 15:55:06 +11:00
if self . eat_keyword ( exp! ( In ) ) {
2019-05-23 12:55:26 -07:00
// 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 ( ) ;
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
} else if self . token = = token ::Pound & & self . look_ahead ( 1 , | t | * t = = token ::OpenBracket ) {
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.
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
while self . token ! = token ::CloseBracket {
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 ( )
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
& & self . look_ahead ( 1 , | t | * t = = token ::Comma | | * t = = token ::CloseParen )
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
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
| | self . token = = token ::CloseParen )
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 ) ? ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( Colon ) ) ? ;
2019-05-23 12:54:27 -07:00
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
}
2024-12-04 15:55:06 +11:00
pub ( super ) fn consume_block (
& mut self ,
open : ExpTokenPair < '_ > ,
close : ExpTokenPair < '_ > ,
consume_close : ConsumeClosingDelim ,
) {
2019-05-16 14:31:07 -07:00
let mut brace_depth = 0 ;
loop {
2024-12-04 15:55:06 +11:00
if self . eat ( open ) {
2019-05-16 14:31:07 -07:00
brace_depth + = 1 ;
2024-12-04 15:55:06 +11:00
} else if self . check ( close ) {
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 " ) ;
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 ) ) ;
2024-12-04 15:55:06 +11:00
if self . eat ( exp! ( Comma ) ) {
2020-10-03 19:30:32 +01:00
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 | {
2024-12-19 18:24:07 +11:00
if let AssocOp ::Binary (
BinOpKind ::Gt
| BinOpKind ::Lt
| BinOpKind ::Shr
| BinOpKind ::Ge
)
2020-10-03 19:30:32 +01:00
// 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.
2024-12-20 07:28:16 +11:00
let was_op = matches! ( self . prev_token . kind , 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
}
2025-03-17 00:25:15 -05:00
/// If `loop_header` is `Some` and an unexpected block label is encountered,
/// it is suggested to be moved just before `loop_header`, else it is suggested to be removed.
pub ( crate ) fn maybe_recover_unexpected_block_label (
& mut self ,
loop_header : Option < Span > ,
) -> 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 )
Remove `token::{Open,Close}Delim`.
By replacing them with `{Open,Close}{Param,Brace,Bracket,Invisible}`.
PR #137902 made `ast::TokenKind` more like `lexer::TokenKind` by
replacing the compound `BinOp{,Eq}(BinOpToken)` variants with fieldless
variants `Plus`, `Minus`, `Star`, etc. This commit does a similar thing
with delimiters. It also makes `ast::TokenKind` more similar to
`parser::TokenType`.
This requires a few new methods:
- `TokenKind::is_{,open_,close_}delim()` replace various kinds of
pattern matches.
- `Delimiter::as_{open,close}_token_kind` are used to convert
`Delimiter` values to `TokenKind`.
Despite these additions, it's a net reduction in lines of code. This is
because e.g. `token::OpenParen` is so much shorter than
`token::OpenDelim(Delimiter::Parenthesis)` that many multi-line forms
reduce to single line forms. And many places where the number of lines
doesn't change are still easier to read, just because the names are
shorter, e.g.:
```
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
```
2025-04-16 16:13:50 +10:00
& & self . look_ahead ( 2 , | t | * t = = token ::OpenBrace ) )
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 ) ;
2025-03-17 00:25:15 -05:00
let mut diag = self
. dcx ( )
2024-01-03 17:03:10 +11:00
. struct_span_err ( span , " block label not supported here " )
2025-03-17 00:25:15 -05:00
. with_span_label ( span , " not supported here " ) ;
if let Some ( loop_header ) = loop_header {
diag . multipart_suggestion (
" if you meant to label the loop, move this label before the loop " ,
vec! [
( label . ident . span . until ( self . token . span ) , String ::from ( " " ) ) ,
( loop_header . shrink_to_lo ( ) , format! ( " {} : " , label . ident ) ) ,
] ,
Applicability ::MachineApplicable ,
) ;
} else {
diag . 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 ,
2025-03-17 00:25:15 -05:00
) ;
}
diag . 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 `..<`
2024-12-12 11:31:10 +11:00
pub ( crate ) fn maybe_err_dotdotlt_syntax ( & self , maybe_lt : Token , mut err : Diag < ' a > ) -> Diag < ' a > {
2023-12-22 21:56:58 -08:00
if maybe_lt = = token ::Lt
2024-12-04 15:55:06 +11:00
& & ( self . expected_token_types . contains ( TokenType ::Gt )
2023-12-22 21:56:58 -08:00
| | 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-06-07 16:25:43 +02:00
// <<<<<<<
2024-12-20 07:28:16 +11:00
let Some ( start ) = self . conflict_marker ( & TokenKind ::Shl , & TokenKind ::Lt ) else {
2024-12-20 14:08:24 +00:00
return ;
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-12-20 07:28:16 +11:00
if let Some ( span ) = self . conflict_marker ( & TokenKind ::OrOr , & TokenKind ::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-12-20 07:28:16 +11:00
if let Some ( span ) = self . conflict_marker ( & TokenKind ::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
2024-12-20 14:08:24 +00:00
let mut err = self . dcx ( ) . struct_span_fatal ( 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
2024-12-20 14:08:24 +00:00
err . emit ( ) ;
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 , ( ) > {
2024-12-04 15:55:06 +11:00
while ! self . check ( exp! ( CloseParen ) ) {
2023-08-03 00:00:56 +08:00
self . parse_pat_no_top_alt ( None , None ) ? ;
2024-12-04 15:55:06 +11:00
if ! self . eat ( exp! ( Comma ) ) {
2021-11-21 04:56:32 +00:00
return Ok ( ( ) ) ;
}
}
Ok ( ( ) )
}
2019-04-28 13:28:07 +08:00
}