@@ -542,9 +542,18 @@ impl ExprCollector<'_> {
542
542
self . alloc_expr ( Expr :: BinaryOp { lhs, rhs, op } , syntax_ptr)
543
543
}
544
544
ast:: Expr :: TupleExpr ( e) => {
545
- let exprs = e. fields ( ) . map ( |expr| self . collect_expr ( expr) ) . collect ( ) ;
545
+ let mut exprs: Vec < _ > = e. fields ( ) . map ( |expr| self . collect_expr ( expr) ) . collect ( ) ;
546
+ // if there is a leading comma, the user is most likely to type out a leading expression
547
+ // so we insert a missing expression at the beginning for IDE features
548
+ if comma_follows_token ( e. l_paren_token ( ) ) {
549
+ exprs. insert ( 0 , self . missing_expr ( ) ) ;
550
+ }
551
+
546
552
self . alloc_expr (
547
- Expr :: Tuple { exprs, is_assignee_expr : self . is_lowering_assignee_expr } ,
553
+ Expr :: Tuple {
554
+ exprs : exprs. into_boxed_slice ( ) ,
555
+ is_assignee_expr : self . is_lowering_assignee_expr ,
556
+ } ,
548
557
syntax_ptr,
549
558
)
550
559
}
@@ -1180,7 +1189,11 @@ impl ExprCollector<'_> {
1180
1189
ast:: Pat :: TupleStructPat ( p) => {
1181
1190
let path =
1182
1191
p. path ( ) . and_then ( |path| self . expander . parse_path ( self . db , path) ) . map ( Box :: new) ;
1183
- let ( args, ellipsis) = self . collect_tuple_pat ( p. fields ( ) , binding_list) ;
1192
+ let ( args, ellipsis) = self . collect_tuple_pat (
1193
+ p. fields ( ) ,
1194
+ comma_follows_token ( p. l_paren_token ( ) ) ,
1195
+ binding_list,
1196
+ ) ;
1184
1197
Pat :: TupleStruct { path, args, ellipsis }
1185
1198
}
1186
1199
ast:: Pat :: RefPat ( p) => {
@@ -1199,7 +1212,11 @@ impl ExprCollector<'_> {
1199
1212
}
1200
1213
ast:: Pat :: ParenPat ( p) => return self . collect_pat_opt ( p. pat ( ) , binding_list) ,
1201
1214
ast:: Pat :: TuplePat ( p) => {
1202
- let ( args, ellipsis) = self . collect_tuple_pat ( p. fields ( ) , binding_list) ;
1215
+ let ( args, ellipsis) = self . collect_tuple_pat (
1216
+ p. fields ( ) ,
1217
+ comma_follows_token ( p. l_paren_token ( ) ) ,
1218
+ binding_list,
1219
+ ) ;
1203
1220
Pat :: Tuple { args, ellipsis }
1204
1221
}
1205
1222
ast:: Pat :: WildcardPat ( _) => Pat :: Wild ,
@@ -1323,18 +1340,24 @@ impl ExprCollector<'_> {
1323
1340
fn collect_tuple_pat (
1324
1341
& mut self ,
1325
1342
args : AstChildren < ast:: Pat > ,
1343
+ has_leading_comma : bool ,
1326
1344
binding_list : & mut BindingList ,
1327
1345
) -> ( Box < [ PatId ] > , Option < usize > ) {
1328
1346
// Find the location of the `..`, if there is one. Note that we do not
1329
1347
// consider the possibility of there being multiple `..` here.
1330
1348
let ellipsis = args. clone ( ) . position ( |p| matches ! ( p, ast:: Pat :: RestPat ( _) ) ) ;
1331
1349
// We want to skip the `..` pattern here, since we account for it above.
1332
- let args = args
1350
+ let mut args: Vec < _ > = args
1333
1351
. filter ( |p| !matches ! ( p, ast:: Pat :: RestPat ( _) ) )
1334
1352
. map ( |p| self . collect_pat ( p, binding_list) )
1335
1353
. collect ( ) ;
1354
+ // if there is a leading comma, the user is most likely to type out a leading pattern
1355
+ // so we insert a missing pattern at the beginning for IDE features
1356
+ if has_leading_comma {
1357
+ args. insert ( 0 , self . missing_pat ( ) ) ;
1358
+ }
1336
1359
1337
- ( args, ellipsis)
1360
+ ( args. into_boxed_slice ( ) , ellipsis)
1338
1361
}
1339
1362
1340
1363
// endregion: patterns
@@ -1493,3 +1516,8 @@ impl ExprCollector<'_> {
1493
1516
self . body . labels . alloc ( label)
1494
1517
}
1495
1518
}
1519
+
1520
+ fn comma_follows_token ( t : Option < syntax:: SyntaxToken > ) -> bool {
1521
+ ( || syntax:: algo:: skip_trivia_token ( t?. next_token ( ) ?, syntax:: Direction :: Next ) ) ( )
1522
+ . map_or ( false , |it| it. kind ( ) == syntax:: T ![ , ] )
1523
+ }
0 commit comments