@@ -8,8 +8,8 @@ use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
88use rustc_ast:: util:: parser:: AssocOp ;
99use rustc_ast:: {
1010 AngleBracketedArg , AngleBracketedArgs , AnonConst , AttrVec , BinOpKind , BindingMode , Block ,
11- BlockCheckMode , Expr , ExprKind , GenericArg , Generics , Item , ItemKind , Param , Pat , PatKind ,
12- Path , PathSegment , QSelf , Recovered , Ty , TyKind ,
11+ BlockCheckMode , DUMMY_NODE_ID , Expr , ExprKind , GenericArg , GenericArgs , Generics , Item ,
12+ ItemKind , Param , Pat , PatKind , Path , PathSegment , QSelf , Recovered , Ty , TyKind ,
1313} ;
1414use rustc_ast_pretty:: pprust;
1515use rustc_data_structures:: fx:: FxHashSet ;
@@ -1453,6 +1453,70 @@ impl<'a> Parser<'a> {
14531453 let mk_err_expr =
14541454 |this : & Self , span, guar| Ok ( Some ( this. mk_expr ( span, ExprKind :: Err ( guar) ) ) ) ;
14551455
1456+ // Helper function to check if we should attempt turbofish recovery and resynthesize
1457+ // FIXME: Check more cases
1458+ let mk_turbofish_expr = |this : & Self ,
1459+ span : Span ,
1460+ l1 : & P < Expr > ,
1461+ r1 : & P < Expr > ,
1462+ as_call : bool |
1463+ -> Option < P < Expr > > {
1464+ // First, actually check that the two expressions in the binop are paths.
1465+ // Only proceed if both sides are simple paths.
1466+ let ( func_path, type_arg_path) = match ( & l1. kind , & r1. kind ) {
1467+ ( ExprKind :: Path ( None , func_path) , ExprKind :: Path ( None , type_arg_path) ) => {
1468+ // Ensure both paths have no existing generic arguments to avoid confusion
1469+ let func_has_generics = func_path. segments . iter ( ) . any ( |seg| seg. args . is_some ( ) ) ;
1470+ let type_has_generics =
1471+ type_arg_path. segments . iter ( ) . any ( |seg| seg. args . is_some ( ) ) ;
1472+ if func_has_generics || type_has_generics {
1473+ return None ;
1474+ }
1475+ ( func_path, type_arg_path)
1476+ }
1477+ _ => return None ,
1478+ } ;
1479+
1480+ // Only handle simple function calls (not complex paths)
1481+ if func_path. segments . len ( ) != 1 || type_arg_path. segments . len ( ) != 1 {
1482+ return None ;
1483+ }
1484+
1485+ // Build the corrected turbofish expression
1486+ let type_arg = P ( Ty {
1487+ id : DUMMY_NODE_ID ,
1488+ kind : TyKind :: Path ( None , type_arg_path. clone ( ) ) ,
1489+ span : r1. span ,
1490+ tokens : None ,
1491+ } ) ;
1492+
1493+ let generic_arg = GenericArg :: Type ( type_arg) ;
1494+ let angle_bracketed_arg = AngleBracketedArg :: Arg ( generic_arg) ;
1495+ let angle_bracketed_args = AngleBracketedArgs {
1496+ span : l1. span . to ( r1. span ) ,
1497+ args : thin_vec ! [ angle_bracketed_arg] ,
1498+ } ;
1499+ let generic_args = GenericArgs :: AngleBracketed ( angle_bracketed_args) ;
1500+
1501+ // Create the function path with generic arguments
1502+ let mut func_path_with_generics = func_path. clone ( ) ;
1503+ if let Some ( last_segment) = func_path_with_generics. segments . last_mut ( ) {
1504+ last_segment. args = Some ( P ( generic_args) ) ;
1505+ }
1506+
1507+ // Create the appropriate expression based on context
1508+ if as_call {
1509+ // For `foo<bar>()` case - create a function call expression
1510+ let func_expr = this
1511+ . mk_expr ( l1. span . to ( r1. span ) , ExprKind :: Path ( None , func_path_with_generics) ) ;
1512+ let args = thin_vec ! [ ] ; // Empty arguments since they were already consumed
1513+ Some ( this. mk_expr ( span, ExprKind :: Call ( func_expr, args) ) )
1514+ } else {
1515+ // For `foo<bar>::` case - create a path expression
1516+ Some ( this. mk_expr ( span, ExprKind :: Path ( None , func_path_with_generics) ) )
1517+ }
1518+ } ;
1519+
14561520 match & inner_op. kind {
14571521 ExprKind :: Binary ( op, l1, r1) if op. node . is_comparison ( ) => {
14581522 let mut err = ComparisonOperatorsCannotBeChained {
@@ -1496,13 +1560,84 @@ impl<'a> Parser<'a> {
14961560
14971561 // Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
14981562 match self . parse_expr ( ) {
1499- Ok ( _ ) => {
1563+ Ok ( parsed_expr ) => {
15001564 // 99% certain that the suggestion is correct, continue parsing.
15011565 let guar = self . dcx ( ) . emit_err ( err) ;
1502- // FIXME: actually check that the two expressions in the binop are
1503- // paths and resynthesize new fn call expression instead of using
1504- // `ExprKind::Err` placeholder.
1505- mk_err_expr ( self , inner_op. span . to ( self . prev_token . span ) , guar)
1566+ // Check if we can resynthesize the complete expression combining
1567+ // the corrected path with the parsed suffix
1568+ if let Some ( corrected_path_expr) =
1569+ mk_turbofish_expr ( self , l1. span . to ( r1. span ) , l1, r1, false )
1570+ {
1571+ // We have a corrected path (e.g., Vec::<i32>), now combine it with
1572+ // the parsed expression (e.g., new()) to form the complete expression
1573+ // (e.g., Vec::<i32>::new())
1574+
1575+ // Try to construct the complete path expression
1576+ if let ExprKind :: Path ( qself, corrected_path) =
1577+ corrected_path_expr. kind
1578+ {
1579+ // Combine the corrected path with the parsed expression
1580+ // The parsed_expr should be handled as a continuation of the path
1581+ match & parsed_expr. kind {
1582+ ExprKind :: Call ( func, args) => {
1583+ // Handle case like Vec::<i32>::new()
1584+ if let ExprKind :: Path ( None , method_path) =
1585+ & func. kind
1586+ {
1587+ // Extend the corrected path with the method path
1588+ let mut extended_path = corrected_path;
1589+ extended_path
1590+ . segments
1591+ . extend ( method_path. segments . clone ( ) ) ;
1592+ let extended_func = self . mk_expr (
1593+ l1. span . to ( func. span ) ,
1594+ ExprKind :: Path ( qself, extended_path) ,
1595+ ) ;
1596+ let complete_expr = self . mk_expr (
1597+ inner_op. span . to ( self . prev_token . span ) ,
1598+ ExprKind :: Call ( extended_func, args. clone ( ) ) ,
1599+ ) ;
1600+ Ok ( Some ( complete_expr) )
1601+ } else {
1602+ mk_err_expr (
1603+ self ,
1604+ inner_op. span . to ( self . prev_token . span ) ,
1605+ guar,
1606+ )
1607+ }
1608+ }
1609+ ExprKind :: Path ( None , method_path) => {
1610+ // Handle case like Vec::<i32>::CONSTANT
1611+ let mut extended_path = corrected_path;
1612+ extended_path
1613+ . segments
1614+ . extend ( method_path. segments . clone ( ) ) ;
1615+ let complete_expr = self . mk_expr (
1616+ inner_op. span . to ( self . prev_token . span ) ,
1617+ ExprKind :: Path ( qself, extended_path) ,
1618+ ) ;
1619+ Ok ( Some ( complete_expr) )
1620+ }
1621+ _ => {
1622+ // For other cases, fall back to error expr
1623+ mk_err_expr (
1624+ self ,
1625+ inner_op. span . to ( self . prev_token . span ) ,
1626+ guar,
1627+ )
1628+ }
1629+ }
1630+ } else {
1631+ mk_err_expr (
1632+ self ,
1633+ inner_op. span . to ( self . prev_token . span ) ,
1634+ guar,
1635+ )
1636+ }
1637+ } else {
1638+ // Validation failed: not both paths, use error expr
1639+ mk_err_expr ( self , inner_op. span . to ( self . prev_token . span ) , guar)
1640+ }
15061641 }
15071642 Err ( expr_err) => {
15081643 expr_err. cancel ( ) ;
@@ -1527,10 +1662,18 @@ impl<'a> Parser<'a> {
15271662 Err ( ( ) ) => Err ( self . dcx ( ) . create_err ( err) ) ,
15281663 Ok ( ( ) ) => {
15291664 let guar = self . dcx ( ) . emit_err ( err) ;
1530- // FIXME: actually check that the two expressions in the binop are
1531- // paths and resynthesize new fn call expression instead of using
1532- // `ExprKind::Err` placeholder.
1533- mk_err_expr ( self , inner_op. span . to ( self . prev_token . span ) , guar)
1665+ // Try to resynthesize the function call expression (for `foo<bar>()` case)
1666+ if let Some ( call_expr) = mk_turbofish_expr (
1667+ self ,
1668+ inner_op. span . to ( self . prev_token . span ) ,
1669+ l1,
1670+ r1,
1671+ true ,
1672+ ) {
1673+ Ok ( Some ( call_expr) )
1674+ } else {
1675+ mk_err_expr ( self , inner_op. span . to ( self . prev_token . span ) , guar)
1676+ }
15341677 }
15351678 }
15361679 } else {
0 commit comments