3939//!
4040//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for
4141//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
42- //! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange `]; for slices, see
42+ //! wildcards, see [`SplitWildcard`]; for integer ranges, see [`IntRange::split `]; for slices, see
4343//! [`SplitVarLenSlice`].
4444
4545use std:: cell:: Cell ;
@@ -186,6 +186,93 @@ impl IntRange {
186186 ( lo == other_hi || hi == other_lo) && !self . is_singleton ( ) && !other. is_singleton ( )
187187 }
188188
189+ /// See `Constructor::is_covered_by`
190+ fn is_covered_by ( & self , other : & Self ) -> bool {
191+ if self . intersection ( other) . is_some ( ) {
192+ // Constructor splitting should ensure that all intersections we encounter are actually
193+ // inclusions.
194+ assert ! ( self . is_subrange( other) ) ;
195+ true
196+ } else {
197+ false
198+ }
199+ }
200+
201+ /// Partition a range of integers into disjoint subranges. This does constructor splitting for
202+ /// integer ranges as explained at the top of the file.
203+ ///
204+ /// This returns an output that covers `self`. The output is split so that the only
205+ /// intersections between an output range and a column range are inclusions. No output range
206+ /// straddles the boundary of one of the inputs.
207+ ///
208+ /// The following input:
209+ /// ```text
210+ /// |-------------------------| // `self`
211+ /// |------| |----------| |----|
212+ /// |-------| |-------|
213+ /// ```
214+ /// would be iterated over as follows:
215+ /// ```text
216+ /// ||---|--||-|---|---|---|--|
217+ /// ```
218+ fn split (
219+ & self ,
220+ column_ranges : impl Iterator < Item = IntRange > ,
221+ ) -> impl Iterator < Item = IntRange > {
222+ /// Represents a boundary between 2 integers. Because the intervals spanning boundaries must be
223+ /// able to cover every integer, we need to be able to represent 2^128 + 1 such boundaries.
224+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
225+ enum IntBoundary {
226+ JustBefore ( u128 ) ,
227+ AfterMax ,
228+ }
229+
230+ fn unpack_intrange ( range : IntRange ) -> [ IntBoundary ; 2 ] {
231+ use IntBoundary :: * ;
232+ let ( lo, hi) = range. boundaries ( ) ;
233+ let lo = JustBefore ( lo) ;
234+ let hi = match hi. checked_add ( 1 ) {
235+ Some ( m) => JustBefore ( m) ,
236+ None => AfterMax ,
237+ } ;
238+ [ lo, hi]
239+ }
240+
241+ // The boundaries of ranges in `column_ranges` intersected with `self`.
242+ let mut boundaries: Vec < IntBoundary > = column_ranges
243+ . filter_map ( |r| self . intersection ( & r) )
244+ . map ( unpack_intrange)
245+ . flat_map ( |[ lo, hi] | [ lo, hi] )
246+ . collect ( ) ;
247+ boundaries. sort_unstable ( ) ;
248+
249+ let [ self_start, self_end] = unpack_intrange ( self . clone ( ) ) ;
250+ // Gather pairs of adjacent boundaries.
251+ let mut prev_bdy = self_start;
252+ boundaries
253+ . into_iter ( )
254+ // End with the end of the range.
255+ . chain ( once ( self_end) )
256+ // List pairs of adjacent boundaries.
257+ . map ( move |bdy| {
258+ let ret = ( prev_bdy, bdy) ;
259+ prev_bdy = bdy;
260+ ret
261+ } )
262+ // Skip duplicates.
263+ . filter ( |& ( prev_bdy, bdy) | prev_bdy != bdy)
264+ // Convert back to ranges.
265+ . map ( move |( prev_bdy, bdy) | {
266+ use IntBoundary :: * ;
267+ let range = match ( prev_bdy, bdy) {
268+ ( JustBefore ( n) , JustBefore ( m) ) if n < m => n..=( m - 1 ) ,
269+ ( JustBefore ( n) , AfterMax ) => n..=u128:: MAX ,
270+ _ => unreachable ! ( ) , // Ruled out by the sorting and filtering we did
271+ } ;
272+ IntRange { range }
273+ } )
274+ }
275+
189276 /// Only used for displaying the range properly.
190277 fn to_pat < ' tcx > ( & self , tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> Pat < ' tcx > {
191278 let ( lo, hi) = self . boundaries ( ) ;
@@ -254,18 +341,6 @@ impl IntRange {
254341 ) ;
255342 }
256343 }
257-
258- /// See `Constructor::is_covered_by`
259- fn is_covered_by ( & self , other : & Self ) -> bool {
260- if self . intersection ( other) . is_some ( ) {
261- // Constructor splitting should ensure that all intersections we encounter are actually
262- // inclusions.
263- assert ! ( self . is_subrange( other) ) ;
264- true
265- } else {
266- false
267- }
268- }
269344}
270345
271346/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
@@ -279,101 +354,6 @@ impl fmt::Debug for IntRange {
279354 }
280355}
281356
282- /// Represents a border between 2 integers. Because the intervals spanning borders must be able to
283- /// cover every integer, we need to be able to represent 2^128 + 1 such borders.
284- #[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
285- enum IntBorder {
286- JustBefore ( u128 ) ,
287- AfterMax ,
288- }
289-
290- /// A range of integers that is partitioned into disjoint subranges. This does constructor
291- /// splitting for integer ranges as explained at the top of the file.
292- ///
293- /// This is fed multiple ranges, and returns an output that covers the input, but is split so that
294- /// the only intersections between an output range and a seen range are inclusions. No output range
295- /// straddles the boundary of one of the inputs.
296- ///
297- /// The following input:
298- /// ```text
299- /// |-------------------------| // `self`
300- /// |------| |----------| |----|
301- /// |-------| |-------|
302- /// ```
303- /// would be iterated over as follows:
304- /// ```text
305- /// ||---|--||-|---|---|---|--|
306- /// ```
307- #[ derive( Debug , Clone ) ]
308- struct SplitIntRange {
309- /// The range we are splitting
310- range : IntRange ,
311- /// The borders of ranges we have seen. They are all contained within `range`. This is kept
312- /// sorted.
313- borders : Vec < IntBorder > ,
314- }
315-
316- impl SplitIntRange {
317- fn new ( range : IntRange ) -> Self {
318- SplitIntRange { range, borders : Vec :: new ( ) }
319- }
320-
321- /// Internal use
322- fn to_borders ( r : IntRange ) -> [ IntBorder ; 2 ] {
323- use IntBorder :: * ;
324- let ( lo, hi) = r. boundaries ( ) ;
325- let lo = JustBefore ( lo) ;
326- let hi = match hi. checked_add ( 1 ) {
327- Some ( m) => JustBefore ( m) ,
328- None => AfterMax ,
329- } ;
330- [ lo, hi]
331- }
332-
333- /// Add ranges relative to which we split.
334- fn split ( & mut self , ranges : impl Iterator < Item = IntRange > ) {
335- let this_range = & self . range ;
336- let included_ranges = ranges. filter_map ( |r| this_range. intersection ( & r) ) ;
337- let included_borders = included_ranges. flat_map ( |r| {
338- let borders = Self :: to_borders ( r) ;
339- once ( borders[ 0 ] ) . chain ( once ( borders[ 1 ] ) )
340- } ) ;
341- self . borders . extend ( included_borders) ;
342- self . borders . sort_unstable ( ) ;
343- }
344-
345- /// Iterate over the contained ranges.
346- fn iter ( & self ) -> impl Iterator < Item = IntRange > + Captures < ' _ > {
347- use IntBorder :: * ;
348-
349- let self_range = Self :: to_borders ( self . range . clone ( ) ) ;
350- // Start with the start of the range.
351- let mut prev_border = self_range[ 0 ] ;
352- self . borders
353- . iter ( )
354- . copied ( )
355- // End with the end of the range.
356- . chain ( once ( self_range[ 1 ] ) )
357- // List pairs of adjacent borders.
358- . map ( move |border| {
359- let ret = ( prev_border, border) ;
360- prev_border = border;
361- ret
362- } )
363- // Skip duplicates.
364- . filter ( |( prev_border, border) | prev_border != border)
365- // Finally, convert to ranges.
366- . map ( move |( prev_border, border) | {
367- let range = match ( prev_border, border) {
368- ( JustBefore ( n) , JustBefore ( m) ) if n < m => n..=( m - 1 ) ,
369- ( JustBefore ( n) , AfterMax ) => n..=u128:: MAX ,
370- _ => unreachable ! ( ) , // Ruled out by the sorting and filtering we did
371- } ;
372- IntRange { range }
373- } )
374- }
375- }
376-
377357#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
378358enum SliceKind {
379359 /// Patterns of length `n` (`[x, y]`).
@@ -733,10 +713,8 @@ impl<'tcx> Constructor<'tcx> {
733713 // Fast-track if the range is trivial. In particular, we don't do the overlapping
734714 // ranges check.
735715 IntRange ( ctor_range) if !ctor_range. is_singleton ( ) => {
736- let mut split_range = SplitIntRange :: new ( ctor_range. clone ( ) ) ;
737- let int_ranges = ctors. filter_map ( |ctor| ctor. as_int_range ( ) ) ;
738- split_range. split ( int_ranges. cloned ( ) ) ;
739- split_range. iter ( ) . map ( IntRange ) . collect ( )
716+ let int_ranges = ctors. filter_map ( |ctor| ctor. as_int_range ( ) ) . cloned ( ) ;
717+ ctor_range. split ( int_ranges) . map ( IntRange ) . collect ( )
740718 }
741719 & Slice ( Slice { kind : VarLen ( self_prefix, self_suffix) , array_len } ) => {
742720 let mut split_self = SplitVarLenSlice :: new ( self_prefix, self_suffix, array_len) ;
0 commit comments