@@ -10,7 +10,7 @@ use crate::errors::{
10
10
UnexpectedParenInRangePatSugg , UnexpectedVertVertBeforeFunctionParam ,
11
11
UnexpectedVertVertInPattern ,
12
12
} ;
13
- use crate :: parser:: expr:: could_be_unclosed_char_literal;
13
+ use crate :: parser:: expr:: { could_be_unclosed_char_literal, DestructuredFloat } ;
14
14
use crate :: { maybe_recover_from_interpolated_ty_qpath, maybe_whole} ;
15
15
use rustc_ast:: mut_visit:: { noop_visit_pat, MutVisitor } ;
16
16
use rustc_ast:: ptr:: P ;
@@ -346,37 +346,51 @@ impl<'a> Parser<'a> {
346
346
/// ^^^^^
347
347
/// ```
348
348
/// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter.
349
+ /// This function returns `Some` if a trailing expression was recovered, and said expression's span.
349
350
#[ must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some" ]
350
351
fn maybe_recover_trailing_expr (
351
352
& mut self ,
352
353
pat_span : Span ,
353
354
is_end_bound : bool ,
354
- ) -> Option < ErrorGuaranteed > {
355
+ ) -> Option < ( ErrorGuaranteed , Span ) > {
355
356
if self . prev_token . is_keyword ( kw:: Underscore ) || !self . may_recover ( ) {
356
357
// Don't recover anything after an `_` or if recovery is disabled.
357
358
return None ;
358
359
}
359
360
360
- // Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`.
361
- let has_trailing_method = self . check_noexpect ( & token:: Dot )
361
+ // Returns `true` iff `token` is a `x.y` float
362
+ let is_float_literal = |that : & Self , token : & Token | -> bool {
363
+ use token:: { Lit , LitKind } ;
364
+
365
+ let token:: Literal ( Lit { kind : LitKind :: Float , symbol, suffix : None } ) = token. kind
366
+ else {
367
+ return false ;
368
+ } ;
369
+
370
+ matches ! ( that. break_up_float( symbol, token. span) , DestructuredFloat :: MiddleDot ( ..) )
371
+ } ;
372
+
373
+ // Check for `.hello` or `.0`.
374
+ let has_dot_expr = self . check_noexpect ( & token:: Dot ) // `.`
362
375
&& self . look_ahead ( 1 , |tok| {
363
- tok. ident ( )
364
- . and_then ( |( ident, _) | ident. name . as_str ( ) . chars ( ) . next ( ) )
365
- . is_some_and ( char:: is_lowercase)
366
- } )
367
- && self . look_ahead ( 2 , |tok| tok. kind == token:: OpenDelim ( Delimiter :: Parenthesis ) ) ;
376
+ tok. is_ident ( ) // `hello`
377
+ || tok. is_integer_lit ( ) // `0`
378
+ || is_float_literal ( & self , & tok) // `0.0`
379
+ } ) ;
368
380
369
381
// Check for operators.
370
382
// `|` is excluded as it is used in pattern alternatives and lambdas,
371
383
// `?` is included for error propagation,
372
384
// `[` is included for indexing operations,
373
- // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`)
385
+ // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`),
386
+ // `as` is included for type casts
374
387
let has_trailing_operator = matches ! ( self . token. kind, token:: BinOp ( op) if op != BinOpToken :: Or )
375
388
|| self . token . kind == token:: Question
376
389
|| ( self . token . kind == token:: OpenDelim ( Delimiter :: Bracket )
377
- && self . look_ahead ( 1 , |tok| tok. kind != token:: CloseDelim ( Delimiter :: Bracket ) ) ) ;
390
+ && self . look_ahead ( 1 , |tok| tok. kind != token:: CloseDelim ( Delimiter :: Bracket ) ) ) // excludes `[]`
391
+ || self . token . is_keyword ( kw:: As ) ;
378
392
379
- if !has_trailing_method && !has_trailing_operator {
393
+ if !has_dot_expr && !has_trailing_operator {
380
394
// Nothing to recover here.
381
395
return None ;
382
396
}
@@ -394,8 +408,6 @@ impl<'a> Parser<'a> {
394
408
)
395
409
. map_err ( |err| err. cancel ( ) )
396
410
{
397
- let non_assoc_span = expr. span ;
398
-
399
411
// Parse an associative expression such as `+ expr`, `% expr`, ...
400
412
// Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
401
413
if let Ok ( expr) =
@@ -411,14 +423,11 @@ impl<'a> Parser<'a> {
411
423
|| self . token . kind == token:: CloseDelim ( Delimiter :: Parenthesis )
412
424
&& self . look_ahead ( 1 , Token :: is_range_separator) ;
413
425
414
- // Check that `parse_expr_assoc_with` didn't eat a rhs.
415
- let is_method_call = has_trailing_method && non_assoc_span == expr. span ;
416
-
417
- return Some ( self . dcx ( ) . emit_err ( UnexpectedExpressionInPattern {
418
- span : expr. span ,
419
- is_bound,
420
- is_method_call,
421
- } ) ) ;
426
+ return Some ( (
427
+ self . dcx ( )
428
+ . emit_err ( UnexpectedExpressionInPattern { span : expr. span , is_bound } ) ,
429
+ expr. span ,
430
+ ) ) ;
422
431
}
423
432
}
424
433
@@ -535,7 +544,7 @@ impl<'a> Parser<'a> {
535
544
self . parse_pat_tuple_struct ( qself, path) ?
536
545
} else {
537
546
match self . maybe_recover_trailing_expr ( span, false ) {
538
- Some ( guar) => PatKind :: Err ( guar) ,
547
+ Some ( ( guar, _ ) ) => PatKind :: Err ( guar) ,
539
548
None => PatKind :: Path ( qself, path) ,
540
549
}
541
550
}
@@ -568,10 +577,10 @@ impl<'a> Parser<'a> {
568
577
// Try to parse everything else as literal with optional minus
569
578
match self . parse_literal_maybe_minus ( ) {
570
579
Ok ( begin) => {
571
- let begin = match self . maybe_recover_trailing_expr ( begin . span , false ) {
572
- Some ( guar ) => self . mk_expr_err ( begin. span , guar ) ,
573
- None => begin ,
574
- } ;
580
+ let begin = self
581
+ . maybe_recover_trailing_expr ( begin. span , false )
582
+ . map ( | ( guar , sp ) | self . mk_expr_err ( sp , guar ) )
583
+ . unwrap_or ( begin ) ;
575
584
576
585
match self . parse_range_end ( ) {
577
586
Some ( form) => self . parse_pat_range_begin_with ( begin, form) ?,
@@ -701,7 +710,8 @@ impl<'a> Parser<'a> {
701
710
// For backward compatibility, `(..)` is a tuple pattern as well.
702
711
let paren_pattern =
703
712
fields. len ( ) == 1 && !( matches ! ( trailing_comma, Trailing :: Yes ) || fields[ 0 ] . is_rest ( ) ) ;
704
- if paren_pattern {
713
+
714
+ let pat = if paren_pattern {
705
715
let pat = fields. into_iter ( ) . next ( ) . unwrap ( ) ;
706
716
let close_paren = self . prev_token . span ;
707
717
@@ -719,7 +729,7 @@ impl<'a> Parser<'a> {
719
729
} ,
720
730
} ) ;
721
731
722
- self . parse_pat_range_begin_with ( begin. clone ( ) , form)
732
+ self . parse_pat_range_begin_with ( begin. clone ( ) , form) ?
723
733
}
724
734
// recover ranges with parentheses around the `(start)..`
725
735
PatKind :: Err ( guar)
@@ -734,15 +744,20 @@ impl<'a> Parser<'a> {
734
744
} ,
735
745
} ) ;
736
746
737
- self . parse_pat_range_begin_with ( self . mk_expr_err ( pat. span , * guar) , form)
747
+ self . parse_pat_range_begin_with ( self . mk_expr_err ( pat. span , * guar) , form) ?
738
748
}
739
749
740
750
// (pat) with optional parentheses
741
- _ => Ok ( PatKind :: Paren ( pat) ) ,
751
+ _ => PatKind :: Paren ( pat) ,
742
752
}
743
753
} else {
744
- Ok ( PatKind :: Tuple ( fields) )
745
- }
754
+ PatKind :: Tuple ( fields)
755
+ } ;
756
+
757
+ Ok ( match self . maybe_recover_trailing_expr ( open_paren. to ( self . prev_token . span ) , false ) {
758
+ None => pat,
759
+ Some ( ( guar, _) ) => PatKind :: Err ( guar) ,
760
+ } )
746
761
}
747
762
748
763
/// Parse a mutable binding with the `mut` token already eaten.
@@ -991,7 +1006,7 @@ impl<'a> Parser<'a> {
991
1006
}
992
1007
993
1008
Ok ( match recovered {
994
- Some ( guar) => self . mk_expr_err ( bound . span , guar) ,
1009
+ Some ( ( guar, sp ) ) => self . mk_expr_err ( sp , guar) ,
995
1010
None => bound,
996
1011
} )
997
1012
}
@@ -1060,7 +1075,7 @@ impl<'a> Parser<'a> {
1060
1075
// but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`.
1061
1076
1062
1077
let pat = if sub. is_none ( )
1063
- && let Some ( guar) = self . maybe_recover_trailing_expr ( ident. span , false )
1078
+ && let Some ( ( guar, _ ) ) = self . maybe_recover_trailing_expr ( ident. span , false )
1064
1079
{
1065
1080
PatKind :: Err ( guar)
1066
1081
} else {
0 commit comments