@@ -289,7 +289,7 @@ impl PatStack {
289
289
Self :: from_slice ( & self . 0 [ 1 ..] )
290
290
}
291
291
292
- fn replace_head_with ( & self , pat_ids : & [ PatId ] ) -> PatStack {
292
+ fn replace_head_with < T : Into < PatIdOrWild > + Copy > ( & self , pat_ids : & [ T ] ) -> PatStack {
293
293
let mut patterns: PatStackInner = smallvec ! [ ] ;
294
294
for pat in pat_ids {
295
295
patterns. push ( ( * pat) . into ( ) ) ;
@@ -320,12 +320,14 @@ impl PatStack {
320
320
constructor : & Constructor ,
321
321
) -> MatchCheckResult < Option < PatStack > > {
322
322
let result = match ( self . head ( ) . as_pat ( cx) , constructor) {
323
- ( Pat :: Tuple ( ref pat_ids) , Constructor :: Tuple { arity } ) => {
324
- debug_assert_eq ! (
325
- pat_ids. len( ) ,
326
- * arity,
327
- "we type check before calling this code, so we should never hit this case" ,
328
- ) ;
323
+ ( Pat :: Tuple { args : ref pat_ids, ellipsis } , Constructor :: Tuple { arity : _ } ) => {
324
+ if ellipsis. is_some ( ) {
325
+ // If there are ellipsis here, we should add the correct number of
326
+ // Pat::Wild patterns to `pat_ids`. We should be able to use the
327
+ // constructors arity for this, but at the time of writing we aren't
328
+ // correctly calculating this arity when ellipsis are present.
329
+ return Err ( MatchCheckErr :: NotImplemented ) ;
330
+ }
329
331
330
332
Some ( self . replace_head_with ( pat_ids) )
331
333
}
@@ -351,19 +353,47 @@ impl PatStack {
351
353
Some ( self . to_tail ( ) )
352
354
}
353
355
}
354
- ( Pat :: TupleStruct { args : ref pat_ids, .. } , Constructor :: Enum ( enum_constructor) ) => {
356
+ (
357
+ Pat :: TupleStruct { args : ref pat_ids, ellipsis, .. } ,
358
+ Constructor :: Enum ( enum_constructor) ,
359
+ ) => {
355
360
let pat_id = self . head ( ) . as_id ( ) . expect ( "we know this isn't a wild" ) ;
356
361
if !enum_variant_matches ( cx, pat_id, * enum_constructor) {
357
362
None
358
363
} else {
359
- // If the enum variant matches, then we need to confirm
360
- // that the number of patterns aligns with the expected
361
- // number of patterns for that enum variant.
362
- if pat_ids. len ( ) != constructor. arity ( cx) ? {
363
- return Err ( MatchCheckErr :: MalformedMatchArm ) ;
364
+ let constructor_arity = constructor. arity ( cx) ?;
365
+ if let Some ( ellipsis_position) = ellipsis {
366
+ // If there are ellipsis in the pattern, the ellipsis must take the place
367
+ // of at least one sub-pattern, so `pat_ids` should be smaller than the
368
+ // constructor arity.
369
+ if pat_ids. len ( ) < constructor_arity {
370
+ let mut new_patterns: Vec < PatIdOrWild > = vec ! [ ] ;
371
+
372
+ for pat_id in & pat_ids[ 0 ..ellipsis_position] {
373
+ new_patterns. push ( ( * pat_id) . into ( ) ) ;
374
+ }
375
+
376
+ for _ in 0 ..( constructor_arity - pat_ids. len ( ) ) {
377
+ new_patterns. push ( PatIdOrWild :: Wild ) ;
378
+ }
379
+
380
+ for pat_id in & pat_ids[ ellipsis_position..pat_ids. len ( ) ] {
381
+ new_patterns. push ( ( * pat_id) . into ( ) ) ;
382
+ }
383
+
384
+ Some ( self . replace_head_with ( & new_patterns) )
385
+ } else {
386
+ return Err ( MatchCheckErr :: MalformedMatchArm ) ;
387
+ }
388
+ } else {
389
+ // If there is no ellipsis in the tuple pattern, the number
390
+ // of patterns must equal the constructor arity.
391
+ if pat_ids. len ( ) == constructor_arity {
392
+ Some ( self . replace_head_with ( pat_ids) )
393
+ } else {
394
+ return Err ( MatchCheckErr :: MalformedMatchArm ) ;
395
+ }
364
396
}
365
-
366
- Some ( self . replace_head_with ( pat_ids) )
367
397
}
368
398
}
369
399
( Pat :: Or ( _) , _) => return Err ( MatchCheckErr :: NotImplemented ) ,
@@ -644,7 +674,11 @@ impl Constructor {
644
674
fn pat_constructor ( cx : & MatchCheckCtx , pat : PatIdOrWild ) -> MatchCheckResult < Option < Constructor > > {
645
675
let res = match pat. as_pat ( cx) {
646
676
Pat :: Wild => None ,
647
- Pat :: Tuple ( pats) => Some ( Constructor :: Tuple { arity : pats. len ( ) } ) ,
677
+ // FIXME somehow create the Tuple constructor with the proper arity. If there are
678
+ // ellipsis, the arity is not equal to the number of patterns.
679
+ Pat :: Tuple { args : pats, ellipsis } if ellipsis. is_none ( ) => {
680
+ Some ( Constructor :: Tuple { arity : pats. len ( ) } )
681
+ }
648
682
Pat :: Lit ( lit_expr) => match cx. body . exprs [ lit_expr] {
649
683
Expr :: Literal ( Literal :: Bool ( val) ) => Some ( Constructor :: Bool ( val) ) ,
650
684
_ => return Err ( MatchCheckErr :: NotImplemented ) ,
@@ -1506,6 +1540,67 @@ mod tests {
1506
1540
check_no_diagnostic ( content) ;
1507
1541
}
1508
1542
1543
+ #[ test]
1544
+ fn enum_tuple_partial_ellipsis_2_no_diagnostic ( ) {
1545
+ let content = r"
1546
+ enum Either {
1547
+ A(bool, bool, bool, bool),
1548
+ B,
1549
+ }
1550
+ fn test_fn() {
1551
+ match Either::B {
1552
+ Either::A(true, .., true) => {},
1553
+ Either::A(true, .., false) => {},
1554
+ Either::A(.., true) => {},
1555
+ Either::A(.., false) => {},
1556
+ Either::B => {},
1557
+ }
1558
+ }
1559
+ " ;
1560
+
1561
+ check_no_diagnostic ( content) ;
1562
+ }
1563
+
1564
+ #[ test]
1565
+ fn enum_tuple_partial_ellipsis_missing_arm ( ) {
1566
+ let content = r"
1567
+ enum Either {
1568
+ A(bool, bool, bool, bool),
1569
+ B,
1570
+ }
1571
+ fn test_fn() {
1572
+ match Either::B {
1573
+ Either::A(true, .., true) => {},
1574
+ Either::A(true, .., false) => {},
1575
+ Either::A(false, .., false) => {},
1576
+ Either::B => {},
1577
+ }
1578
+ }
1579
+ " ;
1580
+
1581
+ check_diagnostic ( content) ;
1582
+ }
1583
+
1584
+ #[ test]
1585
+ fn enum_tuple_partial_ellipsis_2_missing_arm ( ) {
1586
+ let content = r"
1587
+ enum Either {
1588
+ A(bool, bool, bool, bool),
1589
+ B,
1590
+ }
1591
+ fn test_fn() {
1592
+ match Either::B {
1593
+ Either::A(true, .., true) => {},
1594
+ Either::A(true, .., false) => {},
1595
+ Either::A(.., true) => {},
1596
+ Either::B => {},
1597
+ }
1598
+ }
1599
+ " ;
1600
+
1601
+ check_diagnostic ( content) ;
1602
+ }
1603
+
1509
1604
#[ test]
1510
1605
fn enum_tuple_ellipsis_no_diagnostic ( ) {
1511
1606
let content = r"
@@ -1645,11 +1740,7 @@ mod false_negatives {
1645
1740
" ;
1646
1741
1647
1742
// This is a false negative.
1648
- // The `..` pattern is currently lowered to a single `Pat::Wild`
1649
- // no matter how many fields the `..` pattern is covering. This
1650
- // causes the match arm in this test not to type check against
1651
- // the match expression, which causes this diagnostic not to
1652
- // fire.
1743
+ // We don't currently handle tuple patterns with ellipsis.
1653
1744
check_no_diagnostic ( content) ;
1654
1745
}
1655
1746
@@ -1664,32 +1755,7 @@ mod false_negatives {
1664
1755
" ;
1665
1756
1666
1757
// This is a false negative.
1667
- // See comments on `tuple_of_bools_with_ellipsis_at_end_missing_arm`.
1668
- check_no_diagnostic ( content) ;
1669
- }
1670
-
1671
- #[ test]
1672
- fn enum_tuple_partial_ellipsis_missing_arm ( ) {
1673
- let content = r"
1674
- enum Either {
1675
- A(bool, bool, bool, bool),
1676
- B,
1677
- }
1678
- fn test_fn() {
1679
- match Either::B {
1680
- Either::A(true, .., true) => {},
1681
- Either::A(true, .., false) => {},
1682
- Either::A(false, .., false) => {},
1683
- Either::B => {},
1684
- }
1685
- }
1686
- " ;
1687
-
1688
- // This is a false negative.
1689
- // The `..` pattern is currently lowered to a single `Pat::Wild`
1690
- // no matter how many fields the `..` pattern is covering. This
1691
- // causes us to return a `MatchCheckErr::MalformedMatchArm` in
1692
- // `Pat::specialize_constructor`.
1758
+ // We don't currently handle tuple patterns with ellipsis.
1693
1759
check_no_diagnostic ( content) ;
1694
1760
}
1695
1761
}
0 commit comments