@@ -166,7 +166,7 @@ use self::Constructor::*;
166166use self :: Usefulness :: * ;
167167use self :: WitnessPreference :: * ;
168168
169- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
169+ use rustc_data_structures:: fx:: FxHashMap ;
170170use rustc_data_structures:: indexed_vec:: Idx ;
171171
172172use super :: { FieldPattern , Pattern , PatternKind } ;
@@ -321,7 +321,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
321321 tcx,
322322 module,
323323 pattern_arena : & pattern_arena,
324- byte_array_map : FxHashMap ( ) ,
324+ byte_array_map : FxHashMap :: default ( ) ,
325325 } )
326326 }
327327
@@ -1422,50 +1422,77 @@ fn split_grouped_constructors<'p, 'a: 'p, 'tcx: 'a>(
14221422 }
14231423 // We're going to collect all the endpoints in the new pattern so we can create
14241424 // subranges between them.
1425- let mut points = FxHashSet :: default ( ) ;
1425+ // If there's a single point, we need to identify it as belonging
1426+ // to a length-1 range, so it can be treated as an individual
1427+ // constructor, rather than as an endpoint. To do this, we keep track of which
1428+ // endpoint a point corresponds to. Whenever a point corresponds to both a start
1429+ // and an end, then we create a unit range for it.
1430+ #[ derive( PartialEq , Clone , Copy , Debug ) ]
1431+ enum Endpoint {
1432+ Start ,
1433+ End ,
1434+ Both ,
1435+ } ;
1436+ let mut points = FxHashMap :: default ( ) ;
1437+ let add_endpoint = |points : & mut FxHashMap < _ , _ > , x, endpoint| {
1438+ points. entry ( x) . and_modify ( |ex_x| {
1439+ if * ex_x != endpoint {
1440+ * ex_x = Endpoint :: Both
1441+ }
1442+ } ) . or_insert ( endpoint) ;
1443+ } ;
1444+ let add_endpoints = |points : & mut FxHashMap < _ , _ > , lo, hi| {
1445+ // Insert the endpoints, taking care to keep track of to
1446+ // which endpoints a point corresponds.
1447+ add_endpoint ( points, lo, Endpoint :: Start ) ;
1448+ add_endpoint ( points, hi, Endpoint :: End ) ;
1449+ } ;
14261450 let ( lo, hi) = ( * ctor_range. range . start ( ) , * ctor_range. range . end ( ) ) ;
1427- points. insert ( lo) ;
1428- points. insert ( hi) ;
1451+ add_endpoints ( & mut points, lo, hi) ;
14291452 // We're going to iterate through every row pattern, adding endpoints in.
14301453 for row in m. iter ( ) {
14311454 if let Some ( r) = IntRange :: from_pat ( tcx, row[ 0 ] ) {
14321455 // We're only interested in endpoints that lie (at least partially)
14331456 // within the subrange domain.
14341457 if let Some ( r) = ctor_range. intersection ( & r) {
14351458 let ( r_lo, r_hi) = r. range . into_inner ( ) ;
1436- // Insert the endpoints.
1437- points. insert ( r_lo) ;
1438- points. insert ( r_hi) ;
1439- // There's a slight subtlety here, which involves the fact we're using
1440- // inclusive ranges everywhere. When we subdivide the range into
1441- // subranges, they can't overlap, or the subranges effectively
1442- // coalesce. We need hard boundaries between subranges. The simplest
1443- // way to do this is by adding extra "boundary points" to prevent this
1444- // intersection. Technically this means we occasionally check a few more
1445- // cases for usefulness than we need to (because they're part of another
1446- // equivalence class), but it's still linear and very simple to verify,
1447- // which is handy when it comes to matching, which can often be quite
1448- // fiddly.
1449- if r_lo > lo {
1450- points. insert ( r_lo - 1 ) ;
1451- }
1452- if r_hi < hi {
1453- points. insert ( r_hi + 1 ) ;
1454- }
1459+ add_endpoints ( & mut points, r_lo, r_hi) ;
14551460 }
14561461 }
14571462 }
14581463
14591464 // The patterns were iterated in an arbitrary order (i.e. in the order the user
14601465 // wrote them), so we need to make sure our endpoints are sorted.
1461- let mut points: Vec < _ > = points. into_iter ( ) . collect ( ) ;
1462- points. sort ( ) ;
1466+ let mut points: Vec < ( u128 , Endpoint ) > = points. into_iter ( ) . collect ( ) ;
1467+ points. sort_unstable_by_key ( | ( x , _ ) | * x ) ;
14631468 let mut points = points. into_iter ( ) ;
1464- let mut start = points. next ( ) . unwrap ( ) ;
1469+ let mut a = points. next ( ) . unwrap ( ) ;
1470+
14651471 // Iterate through pairs of points, adding the subranges to `split_ctors`.
1466- while let Some ( end) = points. next ( ) {
1467- split_ctors. push ( IntRange :: range_to_ctor ( tcx, ty, start..=end) ) ;
1468- start = end;
1472+ // We have to be careful about the orientation of the points as endpoints, to make
1473+ // sure we're enumerating precisely the correct ranges. Too few and the matching is
1474+ // actually incorrect. Too many and our diagnostics are poorer. This involves some
1475+ // case analysis.
1476+ while let Some ( b) = points. next ( ) {
1477+ // a < b (strictly)
1478+ if let Endpoint :: Both = a. 1 {
1479+ split_ctors. push ( IntRange :: range_to_ctor ( tcx, ty, a. 0 ..=a. 0 ) ) ;
1480+ }
1481+ let c = match a. 1 {
1482+ Endpoint :: Start => a. 0 ,
1483+ Endpoint :: End | Endpoint :: Both => a. 0 + 1 ,
1484+ } ;
1485+ let d = match b. 1 {
1486+ Endpoint :: Start | Endpoint :: Both => b. 0 - 1 ,
1487+ Endpoint :: End => b. 0 ,
1488+ } ;
1489+ // In some cases, we won't need an intermediate range between two ranges
1490+ // lie immediately adjacent to one another.
1491+ if c <= d {
1492+ split_ctors. push ( IntRange :: range_to_ctor ( tcx, ty, c..=d) ) ;
1493+ }
1494+
1495+ a = b;
14691496 }
14701497 }
14711498 // Any other constructor can be used unchanged.
0 commit comments