@@ -27,7 +27,7 @@ use rustc_middle::ty::CanonicalUserTypeAnnotation;
2727use rustc_middle:: ty:: TypeVisitableExt ;
2828use rustc_middle:: ty:: { self , AdtDef , Region , Ty , TyCtxt , UserType } ;
2929use rustc_middle:: ty:: { GenericArg , GenericArgsRef } ;
30- use rustc_span:: { Span , Symbol } ;
30+ use rustc_span:: { ErrorGuaranteed , Span , Symbol } ;
3131use rustc_target:: abi:: FieldIdx ;
3232
3333use std:: cmp:: Ordering ;
@@ -85,127 +85,126 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
8585 )
8686 }
8787
88- fn lower_range_expr (
88+ fn lower_pattern_range_endpoint (
8989 & mut self ,
90- expr : & ' tcx hir:: Expr < ' tcx > ,
91- ) -> ( PatKind < ' tcx > , Option < Ascription < ' tcx > > ) {
92- match self . lower_lit ( expr) {
93- PatKind :: AscribeUserType { ascription, subpattern : box Pat { kind, .. } } => {
94- ( kind, Some ( ascription) )
90+ expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
91+ ) -> Result < ( Option < mir:: Const < ' tcx > > , Option < Ascription < ' tcx > > ) , ErrorGuaranteed > {
92+ match expr {
93+ None => Ok ( ( None , None ) ) ,
94+ Some ( expr) => {
95+ let ( kind, ascr) = match self . lower_lit ( expr) {
96+ PatKind :: AscribeUserType { ascription, subpattern : box Pat { kind, .. } } => {
97+ ( kind, Some ( ascription) )
98+ }
99+ kind => ( kind, None ) ,
100+ } ;
101+ let value = if let PatKind :: Constant { value } = kind {
102+ value
103+ } else {
104+ let msg = format ! (
105+ "found bad range pattern endpoint `{expr:?}` outside of error recovery"
106+ ) ;
107+ return Err ( self . tcx . sess . delay_span_bug ( expr. span , msg) ) ;
108+ } ;
109+ Ok ( ( Some ( value) , ascr) )
95110 }
96- kind => ( kind, None ) ,
97111 }
98112 }
99113
100114 fn lower_pattern_range (
101115 & mut self ,
102- ty : Ty < ' tcx > ,
103- lo : mir:: Const < ' tcx > ,
104- hi : mir:: Const < ' tcx > ,
116+ lo_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
117+ hi_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
105118 end : RangeEnd ,
119+ ty : Ty < ' tcx > ,
106120 span : Span ,
107- lo_expr : Option < & hir:: Expr < ' tcx > > ,
108- hi_expr : Option < & hir:: Expr < ' tcx > > ,
109- ) -> PatKind < ' tcx > {
121+ ) -> Result < PatKind < ' tcx > , ErrorGuaranteed > {
122+ if lo_expr. is_none ( ) && hi_expr. is_none ( ) {
123+ let msg = format ! ( "found twice-open range pattern (`..`) outside of error recovery" ) ;
124+ return Err ( self . tcx . sess . delay_span_bug ( span, msg) ) ;
125+ }
126+
127+ let ( lo, lo_ascr) = self . lower_pattern_range_endpoint ( lo_expr) ?;
128+ let ( hi, hi_ascr) = self . lower_pattern_range_endpoint ( hi_expr) ?;
129+
130+ let lo = lo. unwrap_or_else ( || {
131+ // Unwrap is ok because the type is known to be numeric.
132+ let lo = ty. numeric_min_val ( self . tcx ) . unwrap ( ) ;
133+ mir:: Const :: from_ty_const ( lo, self . tcx )
134+ } ) ;
135+ let hi = hi. unwrap_or_else ( || {
136+ // Unwrap is ok because the type is known to be numeric.
137+ let hi = ty. numeric_max_val ( self . tcx ) . unwrap ( ) ;
138+ mir:: Const :: from_ty_const ( hi, self . tcx )
139+ } ) ;
110140 assert_eq ! ( lo. ty( ) , ty) ;
111141 assert_eq ! ( hi. ty( ) , ty) ;
142+
112143 let cmp = compare_const_vals ( self . tcx , lo, hi, self . param_env ) ;
113- let max = || {
114- self . tcx
115- . layout_of ( self . param_env . with_reveal_all_normalized ( self . tcx ) . and ( ty) )
116- . ok ( )
117- . unwrap ( )
118- . size
119- . unsigned_int_max ( )
120- } ;
121- match ( end, cmp) {
144+ let mut kind = match ( end, cmp) {
122145 // `x..y` where `x < y`.
123146 // Non-empty because the range includes at least `x`.
124147 ( RangeEnd :: Excluded , Some ( Ordering :: Less ) ) => {
125148 PatKind :: Range ( Box :: new ( PatRange { lo, hi, end } ) )
126149 }
127- // `x..y` where `x >= y`. The range is empty => error.
128- ( RangeEnd :: Excluded , _) => {
129- let mut lower_overflow = false ;
130- let mut higher_overflow = false ;
131- if let Some ( hir:: Expr { kind : hir:: ExprKind :: Lit ( lit) , .. } ) = lo_expr
132- && let rustc_ast:: ast:: LitKind :: Int ( val, _) = lit. node
133- {
134- if lo. eval_bits ( self . tcx , self . param_env ) != val {
135- lower_overflow = true ;
136- self . tcx . sess . emit_err ( LiteralOutOfRange { span : lit. span , ty, max : max ( ) } ) ;
137- }
138- }
139- if let Some ( hir:: Expr { kind : hir:: ExprKind :: Lit ( lit) , .. } ) = hi_expr
140- && let rustc_ast:: ast:: LitKind :: Int ( val, _) = lit. node
141- {
142- if hi. eval_bits ( self . tcx , self . param_env ) != val {
143- higher_overflow = true ;
144- self . tcx . sess . emit_err ( LiteralOutOfRange { span : lit. span , ty, max : max ( ) } ) ;
145- }
146- }
147- if !lower_overflow && !higher_overflow {
148- self . tcx . sess . emit_err ( LowerRangeBoundMustBeLessThanUpper { span } ) ;
149- }
150- PatKind :: Wild
151- }
152150 // `x..=y` where `x == y`.
153151 ( RangeEnd :: Included , Some ( Ordering :: Equal ) ) => PatKind :: Constant { value : lo } ,
154152 // `x..=y` where `x < y`.
155153 ( RangeEnd :: Included , Some ( Ordering :: Less ) ) => {
156154 PatKind :: Range ( Box :: new ( PatRange { lo, hi, end } ) )
157155 }
158- // `x..=y` where `x > y` hence the range is empty => error.
159- ( RangeEnd :: Included , _) => {
160- let mut lower_overflow = false ;
161- let mut higher_overflow = false ;
156+ // `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error.
157+ _ => {
158+ let max = || {
159+ self . tcx
160+ . layout_of ( self . param_env . with_reveal_all_normalized ( self . tcx ) . and ( ty) )
161+ . ok ( )
162+ . unwrap ( )
163+ . size
164+ . unsigned_int_max ( )
165+ } ;
166+ // Emit a different message if there was overflow.
162167 if let Some ( hir:: Expr { kind : hir:: ExprKind :: Lit ( lit) , .. } ) = lo_expr
163168 && let rustc_ast:: ast:: LitKind :: Int ( val, _) = lit. node
164169 {
165170 if lo. eval_bits ( self . tcx , self . param_env ) != val {
166- lower_overflow = true ;
167- self . tcx . sess . emit_err ( LiteralOutOfRange { span : lit. span , ty, max : max ( ) } ) ;
171+ return Err ( self . tcx . sess . emit_err ( LiteralOutOfRange { span : lit. span , ty, max : max ( ) } ) ) ;
168172 }
169173 }
170174 if let Some ( hir:: Expr { kind : hir:: ExprKind :: Lit ( lit) , .. } ) = hi_expr
171175 && let rustc_ast:: ast:: LitKind :: Int ( val, _) = lit. node
172176 {
173177 if hi. eval_bits ( self . tcx , self . param_env ) != val {
174- higher_overflow = true ;
175- self . tcx . sess . emit_err ( LiteralOutOfRange { span : lit. span , ty, max : max ( ) } ) ;
178+ return Err ( self . tcx . sess . emit_err ( LiteralOutOfRange { span : lit. span , ty, max : max ( ) } ) ) ;
176179 }
177180 }
178- if !lower_overflow && !higher_overflow {
179- self . tcx . sess . emit_err ( LowerRangeBoundMustBeLessThanOrEqualToUpper {
180- span,
181- teach : self . tcx . sess . teach ( & error_code ! ( E0030 ) ) . then_some ( ( ) ) ,
182- } ) ;
183- }
184- PatKind :: Wild
181+ let e = match end {
182+ RangeEnd :: Included => {
183+ self . tcx . sess . emit_err ( LowerRangeBoundMustBeLessThanOrEqualToUpper {
184+ span,
185+ teach : self . tcx . sess . teach ( & error_code ! ( E0030 ) ) . then_some ( ( ) ) ,
186+ } )
187+ }
188+ RangeEnd :: Excluded => {
189+ self . tcx . sess . emit_err ( LowerRangeBoundMustBeLessThanUpper { span } )
190+ }
191+ } ;
192+ return Err ( e) ;
185193 }
186- }
187- }
194+ } ;
188195
189- fn normalize_range_pattern_ends (
190- & self ,
191- ty : Ty < ' tcx > ,
192- lo : Option < & PatKind < ' tcx > > ,
193- hi : Option < & PatKind < ' tcx > > ,
194- ) -> Option < ( mir:: Const < ' tcx > , mir:: Const < ' tcx > ) > {
195- match ( lo, hi) {
196- ( Some ( PatKind :: Constant { value : lo } ) , Some ( PatKind :: Constant { value : hi } ) ) => {
197- Some ( ( * lo, * hi) )
198- }
199- ( Some ( PatKind :: Constant { value : lo } ) , None ) => {
200- let hi = ty. numeric_max_val ( self . tcx ) ?;
201- Some ( ( * lo, mir:: Const :: from_ty_const ( hi, self . tcx ) ) )
202- }
203- ( None , Some ( PatKind :: Constant { value : hi } ) ) => {
204- let lo = ty. numeric_min_val ( self . tcx ) ?;
205- Some ( ( mir:: Const :: from_ty_const ( lo, self . tcx ) , * hi) )
196+ // If we are handling a range with associated constants (e.g.
197+ // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
198+ // constants somewhere. Have them on the range pattern.
199+ for ascr in [ lo_ascr, hi_ascr] {
200+ if let Some ( ascription) = ascr {
201+ kind = PatKind :: AscribeUserType {
202+ ascription,
203+ subpattern : Box :: new ( Pat { span, ty, kind } ) ,
204+ } ;
206205 }
207- _ => None ,
208206 }
207+ Ok ( kind)
209208 }
210209
211210 #[ instrument( skip( self ) , level = "debug" ) ]
@@ -220,37 +219,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
220219
221220 hir:: PatKind :: Range ( ref lo_expr, ref hi_expr, end) => {
222221 let ( lo_expr, hi_expr) = ( lo_expr. as_deref ( ) , hi_expr. as_deref ( ) ) ;
223- let lo_span = lo_expr. map_or ( pat. span , |e| e. span ) ;
224- let lo = lo_expr. map ( |e| self . lower_range_expr ( e) ) ;
225- let hi = hi_expr. map ( |e| self . lower_range_expr ( e) ) ;
226-
227- let ( lp, hp) = ( lo. as_ref ( ) . map ( |( x, _) | x) , hi. as_ref ( ) . map ( |( x, _) | x) ) ;
228- let mut kind = match self . normalize_range_pattern_ends ( ty, lp, hp) {
229- Some ( ( lc, hc) ) => {
230- self . lower_pattern_range ( ty, lc, hc, end, lo_span, lo_expr, hi_expr)
231- }
232- None => {
233- let msg = format ! (
234- "found bad range pattern `{:?}` outside of error recovery" ,
235- ( & lo, & hi) ,
236- ) ;
237- self . tcx . sess . delay_span_bug ( pat. span , msg) ;
238- PatKind :: Wild
239- }
240- } ;
241-
242- // If we are handling a range with associated constants (e.g.
243- // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
244- // constants somewhere. Have them on the range pattern.
245- for end in & [ lo, hi] {
246- if let Some ( ( _, Some ( ascription) ) ) = end {
247- let subpattern = Box :: new ( Pat { span : pat. span , ty, kind } ) ;
248- kind =
249- PatKind :: AscribeUserType { ascription : ascription. clone ( ) , subpattern } ;
250- }
251- }
252-
253- kind
222+ let span = lo_expr. map_or ( span, |e| e. span ) ;
223+ // FIXME?: returning `_` can cause inaccurate "unreachable" warnings. This can be
224+ // fixed by returning `PatKind::Const(ConstKind::Error(...))` if #115937 gets
225+ // merged.
226+ self . lower_pattern_range ( lo_expr, hi_expr, end, ty, span) . unwrap_or ( PatKind :: Wild )
254227 }
255228
256229 hir:: PatKind :: Path ( ref qpath) => {
0 commit comments