@@ -103,7 +103,7 @@ enum MaybeInfiniteInt {
103103    NegInfinity , 
104104    /// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite`. 
105105Finite ( u128 ) , 
106-     /// The integer after `u128::MAX`. Used when we switch  to exclusive ranges in `IntRange::split` . 
106+     /// The integer after `u128::MAX`. We need it  to represent `x..=u128::MAX` as an exclusive range . 
107107JustAfterMax , 
108108    PosInfinity , 
109109} 
@@ -142,8 +142,11 @@ impl MaybeInfiniteInt {
142142            PatRangeBoundary :: PosInfinity  => PosInfinity , 
143143        } 
144144    } 
145+ 
145146    /// Used only for diagnostics. 
146- /// This could change from finite to infinite if we got `usize::MAX+1` after range splitting. 
147+ /// Note: it is possible to get `isize/usize::MAX+1` here, as explained in the doc for 
148+ /// [`IntRange::split`]. This cannot be represented as a `Const`, so we represent it with 
149+ /// `PosInfinity`. 
147150fn  to_diagnostic_pat_range_bdy < ' tcx > ( 
148151        self , 
149152        ty :  Ty < ' tcx > , 
@@ -170,19 +173,18 @@ impl MaybeInfiniteInt {
170173        } 
171174    } 
172175
173-     fn  is_finite ( self )  -> bool  { 
174-         matches ! ( self ,  Finite ( _) ) 
175-     } 
176+     /// Note: this will not turn a finite value into an infinite one or vice-versa. 
176177fn  minus_one ( self )  -> Self  { 
177178        match  self  { 
178179            Finite ( n)  => match  n. checked_sub ( 1 )  { 
179180                Some ( m)  => Finite ( m) , 
180-                 None  => NegInfinity , 
181+                 None  => bug ! ( ) , 
181182            } , 
182183            JustAfterMax  => Finite ( u128:: MAX ) , 
183184            x => x, 
184185        } 
185186    } 
187+     /// Note: this will not turn a finite value into an infinite one or vice-versa. 
186188fn  plus_one ( self )  -> Self  { 
187189        match  self  { 
188190            Finite ( n)  => match  n. checked_add ( 1 )  { 
@@ -195,18 +197,15 @@ impl MaybeInfiniteInt {
195197    } 
196198} 
197199
198- /// An inclusive  interval, used for precise integer exhaustiveness checking. `IntRange`s always 
200+ /// An exclusive  interval, used for precise integer exhaustiveness checking. `IntRange`s always 
199201/// store a contiguous range. 
200202/// 
201203/// `IntRange` is never used to encode an empty range or a "range" that wraps around the (offset) 
202- /// space: i.e., `range.lo <= range.hi`. 
203- /// 
204- /// Note: the range can be `NegInfinity..=NegInfinity` or `PosInfinity..=PosInfinity` to represent 
205- /// the values before `isize::MIN` and after `isize::MAX`/`usize::MAX`. 
204+ /// space: i.e., `range.lo < range.hi`. 
206205#[ derive( Clone ,  Copy ,  PartialEq ,  Eq ) ]  
207206pub ( crate )  struct  IntRange  { 
208-     lo :  MaybeInfiniteInt , 
209-     hi :  MaybeInfiniteInt , 
207+     lo :  MaybeInfiniteInt ,   // Must not be `PosInfinity`. 
208+     hi :  MaybeInfiniteInt ,   // Must not be `NegInfinity`. 
210209} 
211210
212211impl  IntRange  { 
@@ -217,23 +216,23 @@ impl IntRange {
217216
218217    /// Best effort; will not know that e.g. `255u8..` is a singleton. 
219218fn  is_singleton ( & self )  -> bool  { 
220-         self . lo  == self . hi  &&  self . lo . is_finite ( ) 
219+         self . lo . plus_one ( )  == self . hi 
221220    } 
222221
223222    #[ inline]  
224223    fn  from_bits < ' tcx > ( tcx :  TyCtxt < ' tcx > ,  ty :  Ty < ' tcx > ,  bits :  u128 )  -> IntRange  { 
225224        let  x = MaybeInfiniteInt :: new_finite ( tcx,  ty,  bits) ; 
226-         IntRange  {  lo :  x,  hi :  x } 
225+         IntRange  {  lo :  x,  hi :  x. plus_one ( )  } 
227226    } 
228227
229228    #[ inline]  
230229    fn  from_range ( lo :  MaybeInfiniteInt ,  mut  hi :  MaybeInfiniteInt ,  end :  RangeEnd )  -> IntRange  { 
231-         if  end == RangeEnd :: Excluded  { 
232-             hi = hi. minus_one ( ) ; 
230+         if  end == RangeEnd :: Included  { 
231+             hi = hi. plus_one ( ) ; 
233232        } 
234-         if  lo > hi { 
233+         if  lo >=  hi { 
235234            // This should have been caught earlier by E0030. 
236-             bug ! ( "malformed range pattern: {lo:?}..= {hi:?}" ) ; 
235+             bug ! ( "malformed range pattern: {lo:?}..{hi:?}" ) ; 
237236        } 
238237        IntRange  {  lo,  hi } 
239238    } 
@@ -243,7 +242,7 @@ impl IntRange {
243242    } 
244243
245244    fn  intersection ( & self ,  other :  & Self )  -> Option < Self >  { 
246-         if  self . lo  <=  other. hi  && other. lo  <=  self . hi  { 
245+         if  self . lo  < other. hi  && other. lo  < self . hi  { 
247246            Some ( IntRange  {  lo :  max ( self . lo ,  other. lo ) ,  hi :  min ( self . hi ,  other. hi )  } ) 
248247        }  else  { 
249248            None 
@@ -262,8 +261,7 @@ impl IntRange {
262261        // `true` in the following cases: 
263262        // 1 -------          // 1       ------- 
264263        // 2       --------   // 2 ------- 
265-         ( ( self . lo  == other. hi  && self . lo . is_finite ( ) ) 
266-             || ( self . hi  == other. lo  && self . hi . is_finite ( ) ) ) 
264+         ( ( self . lo . plus_one ( )  == other. hi )  || ( other. lo . plus_one ( )  == self . hi ) ) 
267265            && !self . is_singleton ( ) 
268266            && !other. is_singleton ( ) 
269267    } 
@@ -295,38 +293,45 @@ impl IntRange {
295293/// ``` 
296294/// where each sequence of dashes is an output range, and dashes outside parentheses are marked 
297295/// as `Presence::Missing`. 
296+ /// 
297+ /// ## `isize`/`usize` 
298+ /// 
299+ /// Whereas a wildcard of type `i32` stands for the range `i32::MIN..=i32::MAX`, a `usize` 
300+ /// wildcard stands for `0..PosInfinity` and a `isize` wildcard stands for 
301+ /// `NegInfinity..PosInfinity`. In other words, as far as `IntRange` is concerned, there are 
302+ /// values before `isize::MIN` and after `usize::MAX`/`isize::MAX`. 
303+ /// This is to avoid e.g. `0..(u32::MAX as usize)` from being exhaustive on one architecture and 
304+ /// not others. See discussions around the `precise_pointer_size_matching` feature for more 
305+ /// details. 
306+ /// 
307+ /// These infinities affect splitting subtly: it is possible to get `NegInfinity..0` and 
308+ /// `usize::MAX+1..PosInfinity` in the output. Diagnostics must be careful to handle these 
309+ /// fictitious ranges sensibly. 
298310fn  split ( 
299311        & self , 
300312        column_ranges :  impl  Iterator < Item  = IntRange > , 
301313    )  -> impl  Iterator < Item  = ( Presence ,  IntRange ) >  { 
302-         // Make the range into an exclusive range. 
303-         fn  unpack_intrange ( range :  IntRange )  -> [ MaybeInfiniteInt ;  2 ]  { 
304-             [ range. lo ,  range. hi . plus_one ( ) ] 
305-         } 
306- 
307314        // The boundaries of ranges in `column_ranges` intersected with `self`. 
308315        // We do parenthesis matching for input ranges. A boundary counts as +1 if it starts 
309316        // a range and -1 if it ends it. When the count is > 0 between two boundaries, we 
310317        // are within an input range. 
311318        let  mut  boundaries:  Vec < ( MaybeInfiniteInt ,  isize ) >  = column_ranges
312319            . filter_map ( |r| self . intersection ( & r) ) 
313-             . map ( unpack_intrange) 
314-             . flat_map ( |[ lo,  hi] | [ ( lo,  1 ) ,  ( hi,  -1 ) ] ) 
320+             . flat_map ( |r| [ ( r. lo ,  1 ) ,  ( r. hi ,  -1 ) ] ) 
315321            . collect ( ) ; 
316322        // We sort by boundary, and for each boundary we sort the "closing parentheses" first. The 
317323        // order of +1/-1 for a same boundary value is actually irrelevant, because we only look at 
318324        // the accumulated count between distinct boundary values. 
319325        boundaries. sort_unstable ( ) ; 
320326
321-         let  [ self_start,  self_end]  = unpack_intrange ( * self ) ; 
322327        // Accumulate parenthesis counts. 
323328        let  mut  paren_counter = 0isize ; 
324329        // Gather pairs of adjacent boundaries. 
325-         let  mut  prev_bdy = self_start ; 
330+         let  mut  prev_bdy = self . lo ; 
326331        boundaries
327332            . into_iter ( ) 
328333            // End with the end of the range. The count is ignored. 
329-             . chain ( once ( ( self_end ,  0 ) ) ) 
334+             . chain ( once ( ( self . hi ,  0 ) ) ) 
330335            // List pairs of adjacent boundaries and the count between them. 
331336            . map ( move  |( bdy,  delta) | { 
332337                // `delta` affects the count as we cross `bdy`, so the relevant count between 
@@ -342,21 +347,22 @@ impl IntRange {
342347            . map ( move  |( prev_bdy,  paren_count,  bdy) | { 
343348                use  Presence :: * ; 
344349                let  presence = if  paren_count > 0  {  Seen  }  else  {  Unseen  } ; 
345-                 // Turn back into an inclusive range. 
346-                 let  range = IntRange :: from_range ( prev_bdy,  bdy,  RangeEnd :: Excluded ) ; 
350+                 let  range = IntRange  {  lo :  prev_bdy,  hi :  bdy } ; 
347351                ( presence,  range) 
348352            } ) 
349353    } 
350354
351-     /// Whether the range denotes the values before `isize::MIN` or the values  after 
352- /// `usize::MAX`/`isize::MAX`. 
355+     /// Whether the range denotes the fictitious  values before `isize::MIN` or after 
356+ /// `usize::MAX`/`isize::MAX` (see doc of [`IntRange::split`] for why these exist) . 
353357pub ( crate )  fn  is_beyond_boundaries < ' tcx > ( & self ,  ty :  Ty < ' tcx > ,  tcx :  TyCtxt < ' tcx > )  -> bool  { 
354-         // First check if we are usize/isize to avoid unnecessary `to_diagnostic_pat_range_bdy`. 
355358        ty. is_ptr_sized_integral ( )  && !tcx. features ( ) . precise_pointer_size_matching  && { 
359+             // The two invalid ranges are `NegInfinity..isize::MIN` (represented as 
360+             // `NegInfinity..0`), and `{u,i}size::MAX+1..PosInfinity`. `to_diagnostic_pat_range_bdy` 
361+             // converts `MAX+1` to `PosInfinity`, and we couldn't have `PosInfinity` in `self.lo` 
362+             // otherwise. 
356363            let  lo = self . lo . to_diagnostic_pat_range_bdy ( ty,  tcx) ; 
357-             let  hi = self . hi . to_diagnostic_pat_range_bdy ( ty,  tcx) ; 
358364            matches ! ( lo,  PatRangeBoundary :: PosInfinity ) 
359-                 || matches ! ( hi,  PatRangeBoundary :: NegInfinity ) 
365+                 || matches ! ( self . hi,  MaybeInfiniteInt :: Finite ( 0 ) ) 
360366        } 
361367    } 
362368    /// Only used for displaying the range. 
@@ -368,28 +374,27 @@ impl IntRange {
368374            let  value = lo. as_finite ( ) . unwrap ( ) ; 
369375            PatKind :: Constant  {  value } 
370376        }  else  { 
377+             // We convert to an inclusive range for diagnostics. 
378+             let  mut  end = RangeEnd :: Included ; 
371379            let  mut  lo = self . lo . to_diagnostic_pat_range_bdy ( ty,  tcx) ; 
372-             let  mut  hi = self . hi . to_diagnostic_pat_range_bdy ( ty,  tcx) ; 
373-             let  end = if  hi. is_finite ( )  { 
374-                 RangeEnd :: Included 
375-             }  else  { 
376-                 // `0..=` isn't a valid pattern. 
377-                 RangeEnd :: Excluded 
378-             } ; 
379-             if  matches ! ( hi,  PatRangeBoundary :: NegInfinity )  { 
380-                 // The range denotes the values before `isize::MIN`. 
381-                 let  c = ty. numeric_min_val ( tcx) . unwrap ( ) ; 
382-                 let  value = mir:: Const :: from_ty_const ( c,  tcx) ; 
383-                 hi = PatRangeBoundary :: Finite ( value) ; 
384-             } 
385380            if  matches ! ( lo,  PatRangeBoundary :: PosInfinity )  { 
386-                 // The range denotes the values after `usize::MAX`/`isize::MAX`. 
387-                 // We represent this as `usize::MAX..` which is slightly incorrect but probably 
388-                 // clear enough. 
381+                 // The only reason to get `PosInfinity` here is the special case where 
382+                 // `to_diagnostic_pat_range_bdy` found `{u,i}size::MAX+1`. So the range denotes the 
383+                 // fictitious values after `{u,i}size::MAX` (see [`IntRange::split`] for why we do 
384+                 // this). We show this to the user as `usize::MAX..` which is slightly incorrect but 
385+                 // probably clear enough. 
389386                let  c = ty. numeric_max_val ( tcx) . unwrap ( ) ; 
390387                let  value = mir:: Const :: from_ty_const ( c,  tcx) ; 
391388                lo = PatRangeBoundary :: Finite ( value) ; 
392389            } 
390+             let  hi = if  matches ! ( self . hi,  MaybeInfiniteInt :: Finite ( 0 ) )  { 
391+                 // The range encodes `..ty::MIN`, so we can't convert it to an inclusive range. 
392+                 end = RangeEnd :: Excluded ; 
393+                 self . hi 
394+             }  else  { 
395+                 self . hi . minus_one ( ) 
396+             } ; 
397+             let  hi = hi. to_diagnostic_pat_range_bdy ( ty,  tcx) ; 
393398            PatKind :: Range ( Box :: new ( PatRange  {  lo,  hi,  end,  ty } ) ) 
394399        } ; 
395400
@@ -449,7 +454,7 @@ impl fmt::Debug for IntRange {
449454        if  let  Finite ( lo)  = self . lo  { 
450455            write ! ( f,  "{lo}" ) ?; 
451456        } 
452-         write ! ( f,  "{}" ,  RangeEnd :: Included ) ?; 
457+         write ! ( f,  "{}" ,  RangeEnd :: Excluded ) ?; 
453458        if  let  Finite ( hi)  = self . hi  { 
454459            write ! ( f,  "{hi}" ) ?; 
455460        } 
0 commit comments