@@ -560,6 +560,7 @@ impl<'a> Parser<'a> {
560
560
) ;
561
561
match lhs. kind {
562
562
ExprKind :: Binary ( op, _, _) if op. node . is_comparison ( ) => {
563
+
563
564
// Respan to include both operators.
564
565
let op_span = op. span . to ( self . prev_span ) ;
565
566
let mut err = self . struct_span_err (
@@ -573,70 +574,63 @@ impl<'a> Parser<'a> {
573
574
let msg = "use `::<...>` instead of `<...>` if you meant to specify type \
574
575
arguments";
575
576
if * outer_op == AssocOp :: Less {
576
- // if self.look_ahead(1, |t| t.kind == token::Lt || t.kind == token::ModSep) {
577
577
let snapshot = self . clone ( ) ;
578
578
self . bump ( ) ;
579
- // So far we have parsed `foo<bar<`
580
- let mut acc = 1 ;
581
- while acc > 0 {
582
- match & self . token . kind {
583
- token:: Lt => {
584
- acc += 1 ;
585
- }
586
- token:: Gt => {
587
- acc -= 1 ;
588
- }
589
- token:: BinOp ( token:: Shr ) => {
590
- acc -= 2 ;
591
- }
592
- token:: Eof => {
593
- break ;
594
- }
595
- _ => { }
596
- }
597
- self . bump ( ) ;
598
- }
579
+ // So far we have parsed `foo<bar<`, consume the rest of the type params
580
+ let modifiers = vec ! [
581
+ ( token:: Lt , 1 ) ,
582
+ ( token:: Gt , -1 ) ,
583
+ ( token:: BinOp ( token:: Shr ) , -2 ) ,
584
+ ] ;
585
+ let early_return = vec ! [ token:: Eof ] ;
586
+ self . consume_tts ( 1 , & modifiers[ ..] , & early_return[ ..] ) ;
587
+
599
588
if self . token . kind != token:: OpenDelim ( token:: Paren ) {
589
+ // We don't have `foo< bar >(`, so we rewind the parser and bail out.
600
590
mem:: replace ( self , snapshot. clone ( ) ) ;
601
591
}
602
592
}
603
593
if self . token . kind == token:: OpenDelim ( token:: Paren ) {
594
+ // We have high certainty that this was a bad turbofish at this point.
595
+ // `foo< bar >(`
604
596
err. span_suggestion (
605
597
op_span. shrink_to_lo ( ) ,
606
598
msg,
607
599
"::" . to_string ( ) ,
608
600
Applicability :: MaybeIncorrect ,
609
601
) ;
602
+
610
603
let snapshot = self . clone ( ) ;
611
- self . bump ( ) ;
612
- let mut acc = 1 ;
613
- while acc > 0 {
614
- match & self . token . kind {
615
- token:: OpenDelim ( token:: Paren ) => {
616
- acc += 1 ;
617
- }
618
- token:: CloseDelim ( token:: Paren ) => {
619
- acc -= 1 ;
620
- }
621
- token:: Eof => {
622
- break ;
623
- }
624
- _ => { }
625
- }
626
- self . bump ( ) ;
627
- }
604
+
605
+ // Consume the fn call arguments.
606
+ let modifiers = vec ! [
607
+ ( token:: OpenDelim ( token:: Paren ) , 1 ) ,
608
+ ( token:: CloseDelim ( token:: Paren ) , -1 ) ,
609
+ ] ;
610
+ let early_return = vec ! [ token:: Eof ] ;
611
+ self . bump ( ) ; // `(`
612
+ self . consume_tts ( 1 , & modifiers[ ..] , & early_return[ ..] ) ;
613
+
628
614
if self . token . kind == token:: Eof {
615
+ // Not entirely sure now, but we bubble the error up with the
616
+ // suggestion.
629
617
mem:: replace ( self , snapshot) ;
630
618
return Err ( err) ;
631
619
} else {
620
+ // 99% certain that the suggestion is correct, continue parsing.
632
621
err. emit ( ) ;
622
+ // FIXME: actually check that the two expressions in the binop are
623
+ // paths and resynthesize new fn call expression instead of using
624
+ // `ExprKind::Err` placeholder.
633
625
return Ok ( Some ( self . mk_expr (
634
626
lhs. span . to ( self . prev_span ) ,
635
627
ExprKind :: Err ,
636
628
ThinVec :: new ( ) ,
637
629
) ) ) ;
638
630
}
639
631
} else {
632
+ // All we know is that this is `foo < bar >` and *nothing* else. Try to
633
+ // be helpful, but don't attempt to recover.
640
634
err. help ( msg) ;
641
635
err. help ( "or use `(...)` if you meant to specify fn arguments" ) ;
642
636
// These cases cause too many knock-down errors, bail out (#61329).
@@ -1424,6 +1418,23 @@ impl<'a> Parser<'a> {
1424
1418
err
1425
1419
}
1426
1420
1421
+ fn consume_tts (
1422
+ & mut self ,
1423
+ mut acc : i64 ,
1424
+ modifier : & [ ( token:: TokenKind , i64 ) ] , // Not using FxHasMap and FxHashSet due to
1425
+ early_return : & [ token:: TokenKind ] , // `token::TokenKind: !Eq + !Hash`.
1426
+ ) {
1427
+ while acc > 0 {
1428
+ if let Some ( ( _, val) ) = modifier. iter ( ) . filter ( |( t, _) | * t == self . token . kind ) . next ( ) {
1429
+ acc += * val;
1430
+ }
1431
+ if early_return. contains ( & self . token . kind ) {
1432
+ break ;
1433
+ }
1434
+ self . bump ( ) ;
1435
+ }
1436
+ }
1437
+
1427
1438
/// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors.
1428
1439
///
1429
1440
/// This is necessary because at this point we don't know whether we parsed a function with
0 commit comments