@@ -1344,6 +1344,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
1344
1344
fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
1345
1345
mcx : MatchCtxt < ' a , ' p , Cx > ,
1346
1346
matrix : & mut Matrix < ' p , Cx > ,
1347
+ overlapping_range_endpoints : & mut Vec < OverlappingRanges < ' p , Cx > > ,
1347
1348
is_top_level : bool ,
1348
1349
) -> WitnessMatrix < Cx > {
1349
1350
debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
@@ -1423,30 +1424,102 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1423
1424
let ctor_is_relevant = matches ! ( ctor, Constructor :: Missing ) || missing_ctors. is_empty ( ) ;
1424
1425
let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor, ctor_is_relevant) ;
1425
1426
let mut witnesses = ensure_sufficient_stack ( || {
1426
- compute_exhaustiveness_and_usefulness ( mcx, & mut spec_matrix, false )
1427
+ compute_exhaustiveness_and_usefulness (
1428
+ mcx,
1429
+ & mut spec_matrix,
1430
+ overlapping_range_endpoints,
1431
+ false ,
1432
+ )
1427
1433
} ) ;
1428
1434
1429
1435
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1430
1436
witnesses. apply_constructor ( pcx, & missing_ctors, & ctor, report_individual_missing_ctors) ;
1431
1437
// Accumulate the found witnesses.
1432
1438
ret. extend ( witnesses) ;
1433
1439
1434
- for ( child_row_id , child_row) in spec_matrix. rows ( ) . enumerate ( ) {
1440
+ for child_row in spec_matrix. rows ( ) {
1435
1441
let parent_row_id = child_row. parent_row ;
1436
1442
let parent_row = & mut matrix. rows [ parent_row_id] ;
1437
1443
// A parent row is useful if any of its children is.
1438
1444
parent_row. useful |= child_row. useful ;
1439
1445
for child_intersects in child_row. intersects . iter ( ) {
1440
1446
// Convert the intersecting ids into ids for the parent matrix.
1441
1447
let parent_intersects = spec_matrix. rows [ child_intersects] . parent_row ;
1442
- debug ! ( "child row {child_row_id} intersects with child row {child_intersects}" ) ;
1443
- debug ! ( "parent row {parent_row_id} intersects with parent row {parent_intersects}" ) ;
1448
+ // Note: self-intersection can happen with or-patterns.
1444
1449
if parent_intersects != parent_row_id {
1445
- // self-intersect can happen with or-patterns
1446
1450
parent_row. intersects . insert ( parent_intersects) ;
1447
1451
}
1448
1452
}
1449
1453
}
1454
+
1455
+ // Detect ranges that overlap on their endpoints.
1456
+ if let Constructor :: IntRange ( overlap_range) = ctor {
1457
+ // If two ranges overlap on their endpoing, that endpoint will show up as a singleton in
1458
+ // the splitted set.
1459
+ if overlap_range. is_singleton ( )
1460
+ && spec_matrix. rows . len ( ) >= 2
1461
+ && spec_matrix. rows . iter ( ) . any ( |row| !row. intersects . is_empty ( ) )
1462
+ {
1463
+ let overlap = overlap_range. lo ;
1464
+ // Ranges that look like `lo..=overlap`.
1465
+ let mut prefixes: SmallVec < [ _ ; 1 ] > = Default :: default ( ) ;
1466
+ // Ranges that look like `overlap..=hi`.
1467
+ let mut suffixes: SmallVec < [ _ ; 1 ] > = Default :: default ( ) ;
1468
+ // Iterate on patterns that contained `overlap`. We iterate on `spec_matrix` which
1469
+ // contains only rows that match the current `ctor` as well as accurate intersection
1470
+ // information. It doesn't contain the range; those are in `matrix`.
1471
+ for ( child_row_id, child_row) in spec_matrix. rows ( ) . enumerate ( ) {
1472
+ let parent_row = & matrix. rows [ child_row. parent_row ] ;
1473
+ let pat = parent_row. head ( ) ;
1474
+ let Constructor :: IntRange ( this_range) = pat. ctor ( ) else { continue } ;
1475
+ // Don't lint when one of the ranges is a singleton.
1476
+ if this_range. is_singleton ( ) {
1477
+ continue ;
1478
+ }
1479
+ if this_range. lo == overlap {
1480
+ // `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
1481
+ // ranges that look like `lo..=overlap`.
1482
+ if !prefixes. is_empty ( ) {
1483
+ let overlaps_with: Vec < _ > = prefixes
1484
+ . iter ( )
1485
+ . filter ( |& & ( other_child_row_id, _) | {
1486
+ child_row. intersects . contains ( other_child_row_id)
1487
+ } )
1488
+ . map ( |& ( _, pat) | pat)
1489
+ . collect ( ) ;
1490
+ if !overlaps_with. is_empty ( ) {
1491
+ overlapping_range_endpoints. push ( OverlappingRanges {
1492
+ pat,
1493
+ overlaps_on : overlap_range,
1494
+ overlaps_with,
1495
+ } ) ;
1496
+ }
1497
+ }
1498
+ suffixes. push ( ( child_row_id, pat) )
1499
+ } else if this_range. hi == overlap. plus_one ( ) {
1500
+ // `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
1501
+ // ranges that look like `overlap..=hi`.
1502
+ if !suffixes. is_empty ( ) {
1503
+ let overlaps_with: Vec < _ > = suffixes
1504
+ . iter ( )
1505
+ . filter ( |& & ( other_child_row_id, _) | {
1506
+ child_row. intersects . contains ( other_child_row_id)
1507
+ } )
1508
+ . map ( |& ( _, pat) | pat)
1509
+ . collect ( ) ;
1510
+ if !overlaps_with. is_empty ( ) {
1511
+ overlapping_range_endpoints. push ( OverlappingRanges {
1512
+ pat,
1513
+ overlaps_on : overlap_range,
1514
+ overlaps_with,
1515
+ } ) ;
1516
+ }
1517
+ }
1518
+ prefixes. push ( ( child_row_id, pat) )
1519
+ }
1520
+ }
1521
+ }
1522
+ }
1450
1523
}
1451
1524
1452
1525
// Record usefulness in the patterns.
@@ -1486,6 +1559,7 @@ pub struct UsefulnessReport<'p, Cx: TypeCx> {
1486
1559
/// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
1487
1560
/// exhaustiveness.
1488
1561
pub non_exhaustiveness_witnesses : Vec < WitnessPat < Cx > > ,
1562
+ pub overlapping_range_endpoints : Vec < OverlappingRanges < ' p , Cx > > ,
1489
1563
}
1490
1564
1491
1565
/// Computes whether a match is exhaustive and which of its arms are useful.
@@ -1496,8 +1570,14 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
1496
1570
scrut_ty : Cx :: Ty ,
1497
1571
scrut_validity : ValidityConstraint ,
1498
1572
) -> UsefulnessReport < ' p , Cx > {
1573
+ let mut overlapping_range_endpoints = Vec :: new ( ) ;
1499
1574
let mut matrix = Matrix :: new ( cx. wildcard_arena , arms, scrut_ty, scrut_validity) ;
1500
- let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness ( cx, & mut matrix, true ) ;
1575
+ let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness (
1576
+ cx,
1577
+ & mut matrix,
1578
+ & mut overlapping_range_endpoints,
1579
+ true ,
1580
+ ) ;
1501
1581
1502
1582
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1503
1583
let arm_usefulness: Vec < _ > = arms
@@ -1514,5 +1594,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
1514
1594
( arm, usefulness)
1515
1595
} )
1516
1596
. collect ( ) ;
1517
- UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
1597
+ UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses, overlapping_range_endpoints }
1518
1598
}
0 commit comments