11use super :: ty:: { AllowPlus , RecoverQPath , RecoverReturnSign } ;
22use super :: { Parser , Restrictions , TokenType } ;
33use crate :: errors:: PathSingleColon ;
4+ use crate :: parser:: { CommaRecoveryMode , RecoverColon , RecoverComma } ;
45use crate :: { errors, maybe_whole} ;
56use ast:: token:: IdentIsRaw ;
67use rustc_ast:: ptr:: P ;
@@ -10,7 +11,7 @@ use rustc_ast::{
1011 AssocConstraintKind , BlockCheckMode , GenericArg , GenericArgs , Generics , ParenthesizedArgs ,
1112 Path , PathSegment , QSelf ,
1213} ;
13- use rustc_errors:: { Applicability , PResult } ;
14+ use rustc_errors:: { Applicability , Diag , PResult } ;
1415use rustc_span:: symbol:: { kw, sym, Ident } ;
1516use rustc_span:: { BytePos , Span } ;
1617use std:: mem;
@@ -373,7 +374,38 @@ impl<'a> Parser<'a> {
373374 . into ( )
374375 } else {
375376 // `(T, U) -> R`
376- let ( inputs, _) = self . parse_paren_comma_seq ( |p| p. parse_ty ( ) ) ?;
377+
378+ let prev_token_before_parsing = self . prev_token . clone ( ) ;
379+ let token_before_parsing = self . token . clone ( ) ;
380+ let mut snapshot = None ;
381+ if self . may_recover ( )
382+ && prev_token_before_parsing. kind == token:: ModSep
383+ && ( style == PathStyle :: Expr && self . token . can_begin_expr ( )
384+ || style == PathStyle :: Pat && self . token . can_begin_pattern ( ) )
385+ {
386+ snapshot = Some ( self . create_snapshot_for_diagnostic ( ) ) ;
387+ }
388+
389+ let ( inputs, _) = match self . parse_paren_comma_seq ( |p| p. parse_ty ( ) ) {
390+ Ok ( output) => output,
391+ Err ( mut error) if prev_token_before_parsing. kind == token:: ModSep => {
392+ error. span_label (
393+ prev_token_before_parsing. span . to ( token_before_parsing. span ) ,
394+ "while parsing this parenthesized list of type arguments starting here" ,
395+ ) ;
396+
397+ if let Some ( mut snapshot) = snapshot {
398+ snapshot. recover_fn_call_leading_path_sep (
399+ style,
400+ prev_token_before_parsing,
401+ & mut error,
402+ )
403+ }
404+
405+ return Err ( error) ;
406+ }
407+ Err ( error) => return Err ( error) ,
408+ } ;
377409 let inputs_span = lo. to ( self . prev_token . span ) ;
378410 let output =
379411 self . parse_ret_ty ( AllowPlus :: No , RecoverQPath :: No , RecoverReturnSign :: No ) ?;
@@ -399,6 +431,56 @@ impl<'a> Parser<'a> {
399431 }
400432 }
401433
434+ /// Recover `$path::(...)` as `$path(...)`.
435+ ///
436+ /// ```ignore (diagnostics)
437+ /// foo::(420, "bar")
438+ /// ^^ remove extra separator to make the function call
439+ /// // or
440+ /// match x {
441+ /// Foo::(420, "bar") => { ... },
442+ /// ^^ remove extra separator to turn this into tuple struct pattern
443+ /// _ => { ... },
444+ /// }
445+ /// ```
446+ fn recover_fn_call_leading_path_sep (
447+ & mut self ,
448+ style : PathStyle ,
449+ prev_token_before_parsing : Token ,
450+ error : & mut Diag < ' _ > ,
451+ ) {
452+ if ( ( style == PathStyle :: Expr && self . parse_paren_comma_seq ( |p| p. parse_expr ( ) ) . is_ok ( ) )
453+ || ( style == PathStyle :: Pat
454+ && self
455+ . parse_paren_comma_seq ( |p| {
456+ p. parse_pat_allow_top_alt (
457+ None ,
458+ RecoverComma :: No ,
459+ RecoverColon :: No ,
460+ CommaRecoveryMode :: LikelyTuple ,
461+ )
462+ } )
463+ . is_ok ( ) ) )
464+ && !matches ! ( self . token. kind, token:: ModSep | token:: RArrow )
465+ {
466+ error. span_suggestion_verbose (
467+ prev_token_before_parsing. span ,
468+ format ! (
469+ "consider removing the `::` here to {}" ,
470+ match style {
471+ PathStyle :: Expr => "call the expresion" ,
472+ PathStyle :: Pat => "turn this into a tuple struct pattern" ,
473+ _ => {
474+ return ;
475+ }
476+ }
477+ ) ,
478+ "" ,
479+ Applicability :: MaybeIncorrect ,
480+ ) ;
481+ }
482+ }
483+
402484 /// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
403485 /// For the purposes of understanding the parsing logic of generic arguments, this function
404486 /// can be thought of being the same as just calling `self.parse_angle_args()` if the source
0 commit comments