]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | //! Validation of patterns/matches. |
c30ab7b3 | 2 | |
0531ce1d | 3 | mod check_match; |
e74abb32 | 4 | mod const_to_pat; |
9c376795 | 5 | pub(crate) mod deconstruct_pat; |
fc512014 | 6 | mod usefulness; |
0531ce1d | 7 | |
0531ce1d | 8 | pub(crate) use self::check_match::check_match; |
9c376795 | 9 | pub(crate) use self::usefulness::MatchCheckCtxt; |
0531ce1d | 10 | |
9c376795 | 11 | use crate::errors::*; |
3dfed10e | 12 | use crate::thir::util::UserAnnotatedTyHelpers; |
0531ce1d | 13 | |
9c376795 | 14 | use rustc_errors::error_code; |
dfeec247 | 15 | use rustc_hir as hir; |
17df50a5 | 16 | use rustc_hir::def::{CtorOf, DefKind, Res}; |
dfeec247 XL |
17 | use rustc_hir::pat_util::EnumerateAndAdjustIterator; |
18 | use rustc_hir::RangeEnd; | |
e74abb32 | 19 | use rustc_index::vec::Idx; |
923072b8 FG |
20 | use rustc_middle::mir::interpret::{ |
21 | ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar, | |
22 | }; | |
23 | use rustc_middle::mir::{self, UserTypeProjection}; | |
353b0b11 | 24 | use rustc_middle::mir::{BorrowKind, Mutability}; |
923072b8 | 25 | use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; |
ba9703b0 | 26 | use rustc_middle::ty::subst::{GenericArg, SubstsRef}; |
923072b8 | 27 | use rustc_middle::ty::CanonicalUserTypeAnnotation; |
353b0b11 | 28 | use rustc_middle::ty::{self, AdtDef, ConstKind, Region, Ty, TyCtxt, UserType}; |
17df50a5 | 29 | use rustc_span::{Span, Symbol}; |
353b0b11 | 30 | use rustc_target::abi::FieldIdx; |
c30ab7b3 | 31 | |
0531ce1d | 32 | use std::cmp::Ordering; |
c30ab7b3 | 33 | |
f2b60f7d FG |
34 | struct PatCtxt<'a, 'tcx> { |
35 | tcx: TyCtxt<'tcx>, | |
36 | param_env: ty::ParamEnv<'tcx>, | |
37 | typeck_results: &'a ty::TypeckResults<'tcx>, | |
c30ab7b3 SL |
38 | } |
39 | ||
f2b60f7d | 40 | pub(super) fn pat_from_hir<'a, 'tcx>( |
17df50a5 XL |
41 | tcx: TyCtxt<'tcx>, |
42 | param_env: ty::ParamEnv<'tcx>, | |
43 | typeck_results: &'a ty::TypeckResults<'tcx>, | |
44 | pat: &'tcx hir::Pat<'tcx>, | |
f2b60f7d | 45 | ) -> Box<Pat<'tcx>> { |
353b0b11 | 46 | let mut pcx = PatCtxt { tcx, param_env, typeck_results }; |
17df50a5 | 47 | let result = pcx.lower_pattern(pat); |
17df50a5 XL |
48 | debug!("pat_from_hir({:?}) = {:?}", pat, result); |
49 | result | |
c30ab7b3 SL |
50 | } |
51 | ||
e74abb32 | 52 | impl<'a, 'tcx> PatCtxt<'a, 'tcx> { |
f2b60f7d | 53 | fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { |
ea8adc8c XL |
54 | // When implicit dereferences have been inserted in this pattern, the unadjusted lowered |
55 | // pattern has the type that results *after* dereferencing. For example, in this code: | |
56 | // | |
57 | // ``` | |
58 | // match &&Some(0i32) { | |
59 | // Some(n) => { ... }, | |
60 | // _ => { ... }, | |
61 | // } | |
62 | // ``` | |
63 | // | |
64 | // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is | |
2b03887a | 65 | // determined in rustc_hir_analysis::check::match). The adjustments would be |
ea8adc8c XL |
66 | // |
67 | // `vec![&&Option<i32>, &Option<i32>]`. | |
68 | // | |
3dfed10e | 69 | // Applying the adjustments, we want to instead output `&&Some(n)` (as a THIR pattern). So |
e74abb32 | 70 | // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the |
ea8adc8c XL |
71 | // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted |
72 | // gets the least-dereferenced type). | |
73 | let unadjusted_pat = self.lower_pattern_unadjusted(pat); | |
3dfed10e | 74 | self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( |
dfeec247 | 75 | unadjusted_pat, |
f2b60f7d | 76 | |pat: Box<_>, ref_ty| { |
dfeec247 | 77 | debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); |
f2b60f7d | 78 | Box::new(Pat { |
dfeec247 | 79 | span: pat.span, |
5099ac24 | 80 | ty: *ref_ty, |
f2b60f7d FG |
81 | kind: PatKind::Deref { subpattern: pat }, |
82 | }) | |
dfeec247 XL |
83 | }, |
84 | ) | |
ea8adc8c XL |
85 | } |
86 | ||
9fa01778 XL |
87 | fn lower_range_expr( |
88 | &mut self, | |
dfeec247 | 89 | expr: &'tcx hir::Expr<'tcx>, |
e74abb32 | 90 | ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) { |
9fa01778 | 91 | match self.lower_lit(expr) { |
f2b60f7d | 92 | PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { |
dfeec247 XL |
93 | (kind, Some(ascription)) |
94 | } | |
9fa01778 XL |
95 | kind => (kind, None), |
96 | } | |
97 | } | |
98 | ||
dfeec247 XL |
99 | fn lower_pattern_range( |
100 | &mut self, | |
101 | ty: Ty<'tcx>, | |
923072b8 FG |
102 | lo: mir::ConstantKind<'tcx>, |
103 | hi: mir::ConstantKind<'tcx>, | |
dfeec247 XL |
104 | end: RangeEnd, |
105 | span: Span, | |
9c376795 FG |
106 | lo_expr: Option<&hir::Expr<'tcx>>, |
107 | hi_expr: Option<&hir::Expr<'tcx>>, | |
dfeec247 | 108 | ) -> PatKind<'tcx> { |
5099ac24 FG |
109 | assert_eq!(lo.ty(), ty); |
110 | assert_eq!(hi.ty(), ty); | |
923072b8 | 111 | let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env); |
9c376795 FG |
112 | let max = || { |
113 | self.tcx | |
114 | .layout_of(self.param_env.with_reveal_all_normalized(self.tcx).and(ty)) | |
115 | .ok() | |
116 | .unwrap() | |
117 | .size | |
118 | .unsigned_int_max() | |
119 | }; | |
dfeec247 XL |
120 | match (end, cmp) { |
121 | // `x..y` where `x < y`. | |
122 | // Non-empty because the range includes at least `x`. | |
f2b60f7d FG |
123 | (RangeEnd::Excluded, Some(Ordering::Less)) => { |
124 | PatKind::Range(Box::new(PatRange { lo, hi, end })) | |
125 | } | |
dfeec247 XL |
126 | // `x..y` where `x >= y`. The range is empty => error. |
127 | (RangeEnd::Excluded, _) => { | |
9c376795 FG |
128 | let mut lower_overflow = false; |
129 | let mut higher_overflow = false; | |
130 | if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr | |
131 | && let rustc_ast::ast::LitKind::Int(val, _) = lit.node | |
132 | { | |
133 | if lo.eval_bits(self.tcx, self.param_env, ty) != val { | |
134 | lower_overflow = true; | |
135 | self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); | |
136 | } | |
137 | } | |
138 | if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr | |
139 | && let rustc_ast::ast::LitKind::Int(val, _) = lit.node | |
140 | { | |
141 | if hi.eval_bits(self.tcx, self.param_env, ty) != val { | |
142 | higher_overflow = true; | |
143 | self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); | |
144 | } | |
145 | } | |
146 | if !lower_overflow && !higher_overflow { | |
147 | self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }); | |
148 | } | |
dfeec247 XL |
149 | PatKind::Wild |
150 | } | |
151 | // `x..=y` where `x == y`. | |
152 | (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo }, | |
153 | // `x..=y` where `x < y`. | |
f2b60f7d FG |
154 | (RangeEnd::Included, Some(Ordering::Less)) => { |
155 | PatKind::Range(Box::new(PatRange { lo, hi, end })) | |
156 | } | |
dfeec247 XL |
157 | // `x..=y` where `x > y` hence the range is empty => error. |
158 | (RangeEnd::Included, _) => { | |
9c376795 FG |
159 | let mut lower_overflow = false; |
160 | let mut higher_overflow = false; | |
161 | if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr | |
162 | && let rustc_ast::ast::LitKind::Int(val, _) = lit.node | |
163 | { | |
164 | if lo.eval_bits(self.tcx, self.param_env, ty) != val { | |
165 | lower_overflow = true; | |
166 | self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); | |
167 | } | |
168 | } | |
169 | if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr | |
170 | && let rustc_ast::ast::LitKind::Int(val, _) = lit.node | |
171 | { | |
172 | if hi.eval_bits(self.tcx, self.param_env, ty) != val { | |
173 | higher_overflow = true; | |
174 | self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); | |
175 | } | |
176 | } | |
177 | if !lower_overflow && !higher_overflow { | |
178 | self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { | |
179 | span, | |
9ffffee4 | 180 | teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), |
9c376795 | 181 | }); |
dfeec247 | 182 | } |
dfeec247 XL |
183 | PatKind::Wild |
184 | } | |
185 | } | |
186 | } | |
187 | ||
188 | fn normalize_range_pattern_ends( | |
189 | &self, | |
190 | ty: Ty<'tcx>, | |
191 | lo: Option<&PatKind<'tcx>>, | |
192 | hi: Option<&PatKind<'tcx>>, | |
923072b8 | 193 | ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> { |
dfeec247 XL |
194 | match (lo, hi) { |
195 | (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { | |
5099ac24 | 196 | Some((*lo, *hi)) |
dfeec247 XL |
197 | } |
198 | (Some(PatKind::Constant { value: lo }), None) => { | |
923072b8 FG |
199 | let hi = ty.numeric_max_val(self.tcx)?; |
200 | Some((*lo, mir::ConstantKind::from_const(hi, self.tcx))) | |
dfeec247 XL |
201 | } |
202 | (None, Some(PatKind::Constant { value: hi })) => { | |
923072b8 FG |
203 | let lo = ty.numeric_min_val(self.tcx)?; |
204 | Some((mir::ConstantKind::from_const(lo, self.tcx), *hi)) | |
dfeec247 XL |
205 | } |
206 | _ => None, | |
207 | } | |
208 | } | |
209 | ||
2b03887a | 210 | #[instrument(skip(self), level = "debug")] |
f2b60f7d | 211 | fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { |
3dfed10e | 212 | let mut ty = self.typeck_results.node_type(pat.hir_id); |
f2b60f7d | 213 | let mut span = pat.span; |
dfeec247 | 214 | |
e74abb32 XL |
215 | let kind = match pat.kind { |
216 | hir::PatKind::Wild => PatKind::Wild, | |
c30ab7b3 | 217 | |
5e7ed085 | 218 | hir::PatKind::Lit(value) => self.lower_lit(value), |
c30ab7b3 | 219 | |
e74abb32 | 220 | hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { |
dfeec247 XL |
221 | let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); |
222 | let lo_span = lo_expr.map_or(pat.span, |e| e.span); | |
223 | let lo = lo_expr.map(|e| self.lower_range_expr(e)); | |
224 | let hi = hi_expr.map(|e| self.lower_range_expr(e)); | |
225 | ||
487cf647 | 226 | let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x)); |
dfeec247 | 227 | let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) { |
9c376795 FG |
228 | Some((lc, hc)) => { |
229 | self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr) | |
230 | } | |
dfeec247 XL |
231 | None => { |
232 | let msg = &format!( | |
233 | "found bad range pattern `{:?}` outside of error recovery", | |
234 | (&lo, &hi), | |
0731742a | 235 | ); |
dfeec247 | 236 | self.tcx.sess.delay_span_bug(pat.span, msg); |
e74abb32 | 237 | PatKind::Wild |
dfeec247 | 238 | } |
9fa01778 XL |
239 | }; |
240 | ||
241 | // If we are handling a range with associated constants (e.g. | |
242 | // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated | |
243 | // constants somewhere. Have them on the range pattern. | |
dfeec247 XL |
244 | for end in &[lo, hi] { |
245 | if let Some((_, Some(ascription))) = end { | |
f2b60f7d | 246 | let subpattern = Box::new(Pat { span: pat.span, ty, kind }); |
923072b8 FG |
247 | kind = |
248 | PatKind::AscribeUserType { ascription: ascription.clone(), subpattern }; | |
0731742a | 249 | } |
c30ab7b3 | 250 | } |
9fa01778 XL |
251 | |
252 | kind | |
c30ab7b3 SL |
253 | } |
254 | ||
e74abb32 | 255 | hir::PatKind::Path(ref qpath) => { |
0531ce1d | 256 | return self.lower_path(qpath, pat.hir_id, pat.span); |
c30ab7b3 SL |
257 | } |
258 | ||
dfeec247 | 259 | hir::PatKind::Ref(ref subpattern, _) | hir::PatKind::Box(ref subpattern) => { |
e74abb32 | 260 | PatKind::Deref { subpattern: self.lower_pattern(subpattern) } |
c30ab7b3 SL |
261 | } |
262 | ||
e74abb32 | 263 | hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => { |
dfeec247 | 264 | self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix) |
c30ab7b3 SL |
265 | } |
266 | ||
dfeec247 | 267 | hir::PatKind::Tuple(ref pats, ddpos) => { |
5e7ed085 FG |
268 | let ty::Tuple(ref tys) = ty.kind() else { |
269 | span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty); | |
dfeec247 XL |
270 | }; |
271 | let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos); | |
272 | PatKind::Leaf { subpatterns } | |
c30ab7b3 SL |
273 | } |
274 | ||
e74abb32 | 275 | hir::PatKind::Binding(_, id, ident, ref sub) => { |
f2b60f7d FG |
276 | if let Some(ident_span) = ident.span.find_ancestor_inside(span) { |
277 | span = span.with_hi(ident_span.hi()); | |
278 | } | |
279 | ||
3dfed10e XL |
280 | let bm = *self |
281 | .typeck_results | |
282 | .pat_binding_modes() | |
283 | .get(pat.hir_id) | |
284 | .expect("missing binding mode"); | |
c30ab7b3 | 285 | let (mutability, mode) = match bm { |
dfeec247 XL |
286 | ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), |
287 | ty::BindByReference(hir::Mutability::Mut) => ( | |
288 | Mutability::Not, | |
289 | BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }), | |
290 | ), | |
291 | ty::BindByReference(hir::Mutability::Not) => { | |
292 | (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) | |
293 | } | |
c30ab7b3 SL |
294 | }; |
295 | ||
296 | // A ref x pattern is the same node used for x, and as such it has | |
297 | // x's type, which is &T, where we want T (the type being matched). | |
dfeec247 | 298 | let var_ty = ty; |
3b2f2976 | 299 | if let ty::BindByReference(_) = bm { |
1b1a35ee | 300 | if let ty::Ref(_, rty, _) = ty.kind() { |
5099ac24 | 301 | ty = *rty; |
c30ab7b3 | 302 | } else { |
8faf50e0 | 303 | bug!("`ref {}` has wrong type {}", ident, ty); |
c30ab7b3 | 304 | } |
dfeec247 | 305 | }; |
c30ab7b3 | 306 | |
e74abb32 | 307 | PatKind::Binding { |
3b2f2976 XL |
308 | mutability, |
309 | mode, | |
8faf50e0 | 310 | name: ident.name, |
923072b8 | 311 | var: LocalVarId(id), |
c30ab7b3 SL |
312 | ty: var_ty, |
313 | subpattern: self.lower_opt_pattern(sub), | |
f9f354fc | 314 | is_primary: id == pat.hir_id, |
c30ab7b3 SL |
315 | } |
316 | } | |
317 | ||
dfeec247 | 318 | hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => { |
3dfed10e | 319 | let res = self.typeck_results.qpath_res(qpath, pat.hir_id); |
5e7ed085 FG |
320 | let ty::Adt(adt_def, _) = ty.kind() else { |
321 | span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty); | |
c30ab7b3 | 322 | }; |
48663c56 | 323 | let variant_def = adt_def.variant_of_res(res); |
dfeec247 | 324 | let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); |
48663c56 | 325 | self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) |
c30ab7b3 SL |
326 | } |
327 | ||
e74abb32 | 328 | hir::PatKind::Struct(ref qpath, ref fields, _) => { |
3dfed10e | 329 | let res = self.typeck_results.qpath_res(qpath, pat.hir_id); |
dfeec247 XL |
330 | let subpatterns = fields |
331 | .iter() | |
332 | .map(|field| FieldPat { | |
353b0b11 | 333 | field: self.typeck_results.field_index(field.hir_id), |
dfeec247 XL |
334 | pattern: self.lower_pattern(&field.pat), |
335 | }) | |
336 | .collect(); | |
c30ab7b3 | 337 | |
48663c56 | 338 | self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) |
c30ab7b3 | 339 | } |
e1599b0c | 340 | |
dfeec247 | 341 | hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, |
c30ab7b3 SL |
342 | }; |
343 | ||
f2b60f7d | 344 | Box::new(Pat { span, ty, kind }) |
c30ab7b3 SL |
345 | } |
346 | ||
dfeec247 XL |
347 | fn lower_tuple_subpats( |
348 | &mut self, | |
136023e0 | 349 | pats: &'tcx [hir::Pat<'tcx>], |
dfeec247 | 350 | expected_len: usize, |
f2b60f7d | 351 | gap_pos: hir::DotDotPos, |
dfeec247 XL |
352 | ) -> Vec<FieldPat<'tcx>> { |
353 | pats.iter() | |
354 | .enumerate_and_adjust(expected_len, gap_pos) | |
355 | .map(|(i, subpattern)| FieldPat { | |
353b0b11 | 356 | field: FieldIdx::new(i), |
dfeec247 XL |
357 | pattern: self.lower_pattern(subpattern), |
358 | }) | |
359 | .collect() | |
c30ab7b3 SL |
360 | } |
361 | ||
f2b60f7d | 362 | fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> { |
dfeec247 | 363 | pats.iter().map(|p| self.lower_pattern(p)).collect() |
c30ab7b3 SL |
364 | } |
365 | ||
f2b60f7d FG |
366 | fn lower_opt_pattern( |
367 | &mut self, | |
368 | pat: &'tcx Option<&'tcx hir::Pat<'tcx>>, | |
369 | ) -> Option<Box<Pat<'tcx>>> { | |
487cf647 | 370 | pat.map(|p| self.lower_pattern(p)) |
c30ab7b3 SL |
371 | } |
372 | ||
373 | fn slice_or_array_pattern( | |
374 | &mut self, | |
375 | span: Span, | |
376 | ty: Ty<'tcx>, | |
136023e0 | 377 | prefix: &'tcx [hir::Pat<'tcx>], |
dfeec247 | 378 | slice: &'tcx Option<&'tcx hir::Pat<'tcx>>, |
136023e0 | 379 | suffix: &'tcx [hir::Pat<'tcx>], |
dfeec247 | 380 | ) -> PatKind<'tcx> { |
c30ab7b3 SL |
381 | let prefix = self.lower_patterns(prefix); |
382 | let slice = self.lower_opt_pattern(slice); | |
383 | let suffix = self.lower_patterns(suffix); | |
1b1a35ee | 384 | match ty.kind() { |
dfeec247 XL |
385 | // Matching a slice, `[T]`. |
386 | ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, | |
387 | // Fixed-length array, `[T; len]`. | |
b7449926 | 388 | ty::Array(_, len) => { |
9ffffee4 | 389 | let len = len.eval_target_usize(self.tcx, self.param_env); |
ea8adc8c | 390 | assert!(len >= prefix.len() as u64 + suffix.len() as u64); |
dfeec247 | 391 | PatKind::Array { prefix, slice, suffix } |
c30ab7b3 | 392 | } |
dfeec247 | 393 | _ => span_bug!(span, "bad slice pattern type {:?}", ty), |
c30ab7b3 SL |
394 | } |
395 | } | |
396 | ||
397 | fn lower_variant_or_leaf( | |
398 | &mut self, | |
48663c56 | 399 | res: Res, |
0bf4aa26 | 400 | hir_id: hir::HirId, |
0531ce1d | 401 | span: Span, |
32a655c1 | 402 | ty: Ty<'tcx>, |
e74abb32 XL |
403 | subpatterns: Vec<FieldPat<'tcx>>, |
404 | ) -> PatKind<'tcx> { | |
48663c56 XL |
405 | let res = match res { |
406 | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { | |
04454e1e | 407 | let variant_id = self.tcx.parent(variant_ctor_id); |
48663c56 | 408 | Res::Def(DefKind::Variant, variant_id) |
dfeec247 | 409 | } |
48663c56 | 410 | res => res, |
532ac7d7 XL |
411 | }; |
412 | ||
48663c56 XL |
413 | let mut kind = match res { |
414 | Res::Def(DefKind::Variant, variant_id) => { | |
04454e1e | 415 | let enum_id = self.tcx.parent(variant_id); |
7cac9316 | 416 | let adt_def = self.tcx.adt_def(enum_id); |
ff7c6d11 | 417 | if adt_def.is_enum() { |
1b1a35ee | 418 | let substs = match ty.kind() { |
dfeec247 | 419 | ty::Adt(_, substs) | ty::FnDef(_, substs) => substs, |
f035d41b | 420 | ty::Error(_) => { |
dfeec247 | 421 | // Avoid ICE (#50585) |
e74abb32 | 422 | return PatKind::Wild; |
8faf50e0 | 423 | } |
532ac7d7 | 424 | _ => bug!("inappropriate type for def: {:?}", ty), |
32a655c1 | 425 | }; |
e74abb32 | 426 | PatKind::Variant { |
3b2f2976 XL |
427 | adt_def, |
428 | substs, | |
c30ab7b3 | 429 | variant_index: adt_def.variant_index_with_id(variant_id), |
3b2f2976 | 430 | subpatterns, |
c30ab7b3 SL |
431 | } |
432 | } else { | |
e74abb32 | 433 | PatKind::Leaf { subpatterns } |
c30ab7b3 SL |
434 | } |
435 | } | |
436 | ||
ba9703b0 XL |
437 | Res::Def( |
438 | DefKind::Struct | |
439 | | DefKind::Ctor(CtorOf::Struct, ..) | |
440 | | DefKind::Union | |
441 | | DefKind::TyAlias | |
442 | | DefKind::AssocTy, | |
443 | _, | |
444 | ) | |
2b03887a FG |
445 | | Res::SelfTyParam { .. } |
446 | | Res::SelfTyAlias { .. } | |
dfeec247 | 447 | | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, |
0531ce1d | 448 | _ => { |
353b0b11 FG |
449 | match res { |
450 | Res::Def(DefKind::ConstParam, _) => { | |
451 | self.tcx.sess.emit_err(ConstParamInPattern { span }) | |
452 | } | |
453 | Res::Def(DefKind::Static(_), _) => { | |
454 | self.tcx.sess.emit_err(StaticInPattern { span }) | |
455 | } | |
456 | _ => self.tcx.sess.emit_err(NonConstPath { span }), | |
ba9703b0 | 457 | }; |
e74abb32 | 458 | PatKind::Wild |
0531ce1d | 459 | } |
0bf4aa26 XL |
460 | }; |
461 | ||
462 | if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { | |
0731742a | 463 | debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); |
923072b8 | 464 | let annotation = CanonicalUserTypeAnnotation { |
f2b60f7d | 465 | user_ty: Box::new(user_ty), |
923072b8 FG |
466 | span, |
467 | inferred_ty: self.typeck_results.node_type(hir_id), | |
468 | }; | |
e74abb32 | 469 | kind = PatKind::AscribeUserType { |
f2b60f7d | 470 | subpattern: Box::new(Pat { span, ty, kind }), |
923072b8 | 471 | ascription: Ascription { annotation, variance: ty::Variance::Covariant }, |
0bf4aa26 | 472 | }; |
c30ab7b3 | 473 | } |
0bf4aa26 XL |
474 | |
475 | kind | |
c30ab7b3 | 476 | } |
32a655c1 | 477 | |
0531ce1d XL |
478 | /// Takes a HIR Path. If the path is a constant, evaluates it and feeds |
479 | /// it to `const_to_pat`. Any other path (like enum variants without fields) | |
9fa01778 | 480 | /// is converted to the corresponding pattern via `lower_variant_or_leaf`. |
923072b8 | 481 | #[instrument(skip(self), level = "debug")] |
f2b60f7d | 482 | fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> { |
3dfed10e XL |
483 | let ty = self.typeck_results.node_type(id); |
484 | let res = self.typeck_results.qpath_res(qpath, id); | |
f9f354fc | 485 | |
f2b60f7d | 486 | let pat_from_kind = |kind| Box::new(Pat { span, ty, kind }); |
f9f354fc XL |
487 | |
488 | let (def_id, is_associated_const) = match res { | |
489 | Res::Def(DefKind::Const, def_id) => (def_id, false), | |
490 | Res::Def(DefKind::AssocConst, def_id) => (def_id, true), | |
491 | ||
492 | _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])), | |
2c00a5a8 | 493 | }; |
dfeec247 | 494 | |
f9f354fc XL |
495 | // Use `Reveal::All` here because patterns are always monomorphic even if their function |
496 | // isn't. | |
3dfed10e | 497 | let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx); |
f2b60f7d FG |
498 | // N.B. There is no guarantee that substs collected in typeck results are fully normalized, |
499 | // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE | |
500 | // if given unnormalized types. | |
501 | let substs = self | |
502 | .tcx | |
503 | .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_substs(id)); | |
f9f354fc XL |
504 | let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) { |
505 | Ok(Some(i)) => i, | |
506 | Ok(None) => { | |
136023e0 XL |
507 | // It should be assoc consts if there's no error but we cannot resolve it. |
508 | debug_assert!(is_associated_const); | |
509 | ||
353b0b11 | 510 | self.tcx.sess.emit_err(AssocConstInPattern { span }); |
f9f354fc XL |
511 | |
512 | return pat_from_kind(PatKind::Wild); | |
513 | } | |
514 | ||
515 | Err(_) => { | |
9c376795 | 516 | self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); |
f9f354fc | 517 | return pat_from_kind(PatKind::Wild); |
32a655c1 | 518 | } |
32a655c1 SL |
519 | }; |
520 | ||
f9f354fc XL |
521 | // `mir_const_qualif` must be called with the `DefId` of the item where the const is |
522 | // defined, not where it is declared. The difference is significant for associated | |
523 | // constants. | |
524 | let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq; | |
525 | debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation); | |
526 | ||
527 | match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) { | |
923072b8 FG |
528 | Ok(literal) => { |
529 | let const_ = mir::ConstantKind::Val(literal, ty); | |
5099ac24 | 530 | let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation); |
f9f354fc XL |
531 | |
532 | if !is_associated_const { | |
533 | return pattern; | |
534 | } | |
535 | ||
3dfed10e | 536 | let user_provided_types = self.typeck_results().user_provided_types(); |
923072b8 FG |
537 | if let Some(&user_ty) = user_provided_types.get(id) { |
538 | let annotation = CanonicalUserTypeAnnotation { | |
f2b60f7d | 539 | user_ty: Box::new(user_ty), |
923072b8 FG |
540 | span, |
541 | inferred_ty: self.typeck_results().node_type(id), | |
542 | }; | |
f2b60f7d | 543 | Box::new(Pat { |
f9f354fc | 544 | span, |
f2b60f7d | 545 | kind: PatKind::AscribeUserType { |
f9f354fc XL |
546 | subpattern: pattern, |
547 | ascription: Ascription { | |
923072b8 | 548 | annotation, |
f9f354fc XL |
549 | /// Note that use `Contravariant` here. See the |
550 | /// `variance` field documentation for details. | |
551 | variance: ty::Variance::Contravariant, | |
f9f354fc | 552 | }, |
f2b60f7d | 553 | }, |
5099ac24 | 554 | ty: const_.ty(), |
f2b60f7d | 555 | }) |
f9f354fc XL |
556 | } else { |
557 | pattern | |
558 | } | |
559 | } | |
3dfed10e XL |
560 | Err(ErrorHandled::TooGeneric) => { |
561 | // While `Reported | Linted` cases will have diagnostics emitted already | |
562 | // it is not true for TooGeneric case, so we need to give user more information. | |
9c376795 | 563 | self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); |
3dfed10e XL |
564 | pat_from_kind(PatKind::Wild) |
565 | } | |
f9f354fc | 566 | Err(_) => { |
9c376795 | 567 | self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); |
f9f354fc XL |
568 | pat_from_kind(PatKind::Wild) |
569 | } | |
570 | } | |
32a655c1 SL |
571 | } |
572 | ||
a2a8927a XL |
573 | /// Converts inline const patterns. |
574 | fn lower_inline_const( | |
575 | &mut self, | |
576 | anon_const: &'tcx hir::AnonConst, | |
577 | id: hir::HirId, | |
578 | span: Span, | |
579 | ) -> PatKind<'tcx> { | |
487cf647 | 580 | let value = mir::ConstantKind::from_inline_const(self.tcx, anon_const.def_id); |
a2a8927a XL |
581 | |
582 | // Evaluate early like we do in `lower_path`. | |
583 | let value = value.eval(self.tcx, self.param_env); | |
584 | ||
923072b8 | 585 | match value { |
f2b60f7d FG |
586 | mir::ConstantKind::Ty(c) => match c.kind() { |
587 | ConstKind::Param(_) => { | |
353b0b11 | 588 | self.tcx.sess.emit_err(ConstParamInPattern { span }); |
f2b60f7d | 589 | return PatKind::Wild; |
923072b8 | 590 | } |
487cf647 FG |
591 | ConstKind::Error(_) => { |
592 | return PatKind::Wild; | |
593 | } | |
f2b60f7d FG |
594 | _ => bug!("Expected ConstKind::Param"), |
595 | }, | |
596 | mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind, | |
597 | mir::ConstantKind::Unevaluated(..) => { | |
598 | // If we land here it means the const can't be evaluated because it's `TooGeneric`. | |
9c376795 | 599 | self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); |
f2b60f7d | 600 | return PatKind::Wild; |
a2a8927a | 601 | } |
a2a8927a | 602 | } |
a2a8927a XL |
603 | } |
604 | ||
0531ce1d | 605 | /// Converts literals, paths and negation of literals to patterns. |
9fa01778 XL |
606 | /// The special case for negation exists to allow things like `-128_i8` |
607 | /// which would overflow if we tried to evaluate `128_i8` and then negate | |
0531ce1d | 608 | /// afterwards. |
dfeec247 | 609 | fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { |
a2a8927a XL |
610 | let (lit, neg) = match expr.kind { |
611 | hir::ExprKind::Path(ref qpath) => { | |
f2b60f7d | 612 | return self.lower_path(qpath, expr.hir_id, expr.span).kind; |
32a655c1 | 613 | } |
a2a8927a XL |
614 | hir::ExprKind::ConstBlock(ref anon_const) => { |
615 | return self.lower_inline_const(anon_const, expr.hir_id, expr.span); | |
616 | } | |
617 | hir::ExprKind::Lit(ref lit) => (lit, false), | |
618 | hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { | |
5e7ed085 FG |
619 | let hir::ExprKind::Lit(ref lit) = expr.kind else { |
620 | span_bug!(expr.span, "not a literal: {:?}", expr); | |
a2a8927a XL |
621 | }; |
622 | (lit, true) | |
623 | } | |
624 | _ => span_bug!(expr.span, "not a literal: {:?}", expr), | |
625 | }; | |
626 | ||
627 | let lit_input = | |
628 | LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; | |
923072b8 | 629 | match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) { |
f2b60f7d | 630 | Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, |
487cf647 | 631 | Err(LitToConstError::Reported(_)) => PatKind::Wild, |
a2a8927a | 632 | Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), |
32a655c1 SL |
633 | } |
634 | } | |
416331ca XL |
635 | } |
636 | ||
dfeec247 | 637 | impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> { |
dc9dc135 | 638 | fn tcx(&self) -> TyCtxt<'tcx> { |
0bf4aa26 XL |
639 | self.tcx |
640 | } | |
641 | ||
3dfed10e XL |
642 | fn typeck_results(&self) -> &ty::TypeckResults<'tcx> { |
643 | self.typeck_results | |
0bf4aa26 XL |
644 | } |
645 | } | |
646 | ||
f2b60f7d | 647 | trait PatternFoldable<'tcx>: Sized { |
c30ab7b3 SL |
648 | fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
649 | self.super_fold_with(folder) | |
650 | } | |
651 | ||
652 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self; | |
653 | } | |
654 | ||
f2b60f7d | 655 | trait PatternFolder<'tcx>: Sized { |
e74abb32 | 656 | fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> { |
c30ab7b3 SL |
657 | pattern.super_fold_with(self) |
658 | } | |
659 | ||
e74abb32 | 660 | fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> { |
c30ab7b3 SL |
661 | kind.super_fold_with(self) |
662 | } | |
663 | } | |
664 | ||
c30ab7b3 SL |
665 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> { |
666 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
667 | let content: T = (**self).fold_with(folder); | |
94222f64 | 668 | Box::new(content) |
c30ab7b3 SL |
669 | } |
670 | } | |
671 | ||
672 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> { | |
673 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
674 | self.iter().map(|t| t.fold_with(folder)).collect() | |
675 | } | |
676 | } | |
677 | ||
f2b60f7d FG |
678 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> { |
679 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
680 | self.iter().map(|t| t.fold_with(folder)).collect() | |
681 | } | |
682 | } | |
683 | ||
c30ab7b3 | 684 | impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> { |
dfeec247 | 685 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
c30ab7b3 SL |
686 | self.as_ref().map(|t| t.fold_with(folder)) |
687 | } | |
688 | } | |
689 | ||
923072b8 | 690 | macro_rules! ClonePatternFoldableImpls { |
476ff2be | 691 | (<$lt_tcx:tt> $($ty:ty),+) => { |
c30ab7b3 | 692 | $( |
476ff2be SL |
693 | impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty { |
694 | fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self { | |
695 | Clone::clone(self) | |
c30ab7b3 SL |
696 | } |
697 | } | |
698 | )+ | |
699 | } | |
700 | } | |
701 | ||
923072b8 | 702 | ClonePatternFoldableImpls! { <'tcx> |
353b0b11 | 703 | Span, FieldIdx, Mutability, Symbol, LocalVarId, usize, |
5e7ed085 | 704 | Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>, |
e74abb32 | 705 | SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>, |
923072b8 | 706 | UserTypeProjection, CanonicalUserTypeAnnotation<'tcx> |
476ff2be | 707 | } |
c30ab7b3 | 708 | |
e74abb32 | 709 | impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> { |
c30ab7b3 | 710 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
dfeec247 | 711 | FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) } |
c30ab7b3 SL |
712 | } |
713 | } | |
714 | ||
e74abb32 | 715 | impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> { |
c30ab7b3 SL |
716 | fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
717 | folder.fold_pattern(self) | |
718 | } | |
719 | ||
720 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
e74abb32 | 721 | Pat { |
c30ab7b3 SL |
722 | ty: self.ty.fold_with(folder), |
723 | span: self.span.fold_with(folder), | |
dfeec247 | 724 | kind: self.kind.fold_with(folder), |
c30ab7b3 SL |
725 | } |
726 | } | |
727 | } | |
728 | ||
e74abb32 | 729 | impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { |
c30ab7b3 SL |
730 | fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { |
731 | folder.fold_pattern_kind(self) | |
732 | } | |
733 | ||
734 | fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { | |
735 | match *self { | |
e74abb32 XL |
736 | PatKind::Wild => PatKind::Wild, |
737 | PatKind::AscribeUserType { | |
b7449926 | 738 | ref subpattern, |
923072b8 | 739 | ascription: Ascription { ref annotation, variance }, |
e74abb32 | 740 | } => PatKind::AscribeUserType { |
b7449926 | 741 | subpattern: subpattern.fold_with(folder), |
923072b8 | 742 | ascription: Ascription { annotation: annotation.fold_with(folder), variance }, |
b7449926 | 743 | }, |
f9f354fc | 744 | PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => { |
dfeec247 XL |
745 | PatKind::Binding { |
746 | mutability: mutability.fold_with(folder), | |
747 | name: name.fold_with(folder), | |
748 | mode: mode.fold_with(folder), | |
749 | var: var.fold_with(folder), | |
750 | ty: ty.fold_with(folder), | |
751 | subpattern: subpattern.fold_with(folder), | |
f9f354fc | 752 | is_primary, |
dfeec247 XL |
753 | } |
754 | } | |
755 | PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { | |
756 | PatKind::Variant { | |
757 | adt_def: adt_def.fold_with(folder), | |
758 | substs: substs.fold_with(folder), | |
759 | variant_index, | |
760 | subpatterns: subpatterns.fold_with(folder), | |
761 | } | |
762 | } | |
763 | PatKind::Leaf { ref subpatterns } => { | |
764 | PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) } | |
765 | } | |
766 | PatKind::Deref { ref subpattern } => { | |
767 | PatKind::Deref { subpattern: subpattern.fold_with(folder) } | |
768 | } | |
769 | PatKind::Constant { value } => PatKind::Constant { value }, | |
f2b60f7d | 770 | PatKind::Range(ref range) => PatKind::Range(range.clone()), |
dfeec247 | 771 | PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { |
c30ab7b3 SL |
772 | prefix: prefix.fold_with(folder), |
773 | slice: slice.fold_with(folder), | |
dfeec247 | 774 | suffix: suffix.fold_with(folder), |
c30ab7b3 | 775 | }, |
dfeec247 | 776 | PatKind::Array { ref prefix, ref slice, ref suffix } => PatKind::Array { |
c30ab7b3 SL |
777 | prefix: prefix.fold_with(folder), |
778 | slice: slice.fold_with(folder), | |
dfeec247 | 779 | suffix: suffix.fold_with(folder), |
c30ab7b3 | 780 | }, |
e74abb32 | 781 | PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) }, |
c30ab7b3 SL |
782 | } |
783 | } | |
784 | } | |
0531ce1d | 785 | |
04454e1e | 786 | #[instrument(skip(tcx), level = "debug")] |
923072b8 | 787 | pub(crate) fn compare_const_vals<'tcx>( |
dc9dc135 | 788 | tcx: TyCtxt<'tcx>, |
923072b8 FG |
789 | a: mir::ConstantKind<'tcx>, |
790 | b: mir::ConstantKind<'tcx>, | |
416331ca | 791 | param_env: ty::ParamEnv<'tcx>, |
0531ce1d | 792 | ) -> Option<Ordering> { |
923072b8 FG |
793 | assert_eq!(a.ty(), b.ty()); |
794 | ||
795 | let ty = a.ty(); | |
796 | ||
797 | // This code is hot when compiling matches with many ranges. So we | |
798 | // special-case extraction of evaluated scalars for speed, for types where | |
799 | // raw data comparisons are appropriate. E.g. `unicode-normalization` has | |
800 | // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared | |
801 | // in this way. | |
802 | match ty.kind() { | |
803 | ty::Float(_) | ty::Int(_) => {} // require special handling, see below | |
804 | _ => match (a, b) { | |
805 | ( | |
806 | mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty), | |
807 | mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty), | |
808 | ) => return Some(a.cmp(&b)), | |
809 | _ => {} | |
810 | }, | |
811 | } | |
812 | ||
813 | let a = a.eval_bits(tcx, param_env, ty); | |
814 | let b = b.eval_bits(tcx, param_env, ty); | |
815 | ||
816 | use rustc_apfloat::Float; | |
817 | match *ty.kind() { | |
818 | ty::Float(ty::FloatTy::F32) => { | |
819 | let a = rustc_apfloat::ieee::Single::from_bits(a); | |
820 | let b = rustc_apfloat::ieee::Single::from_bits(b); | |
821 | a.partial_cmp(&b) | |
822 | } | |
823 | ty::Float(ty::FloatTy::F64) => { | |
824 | let a = rustc_apfloat::ieee::Double::from_bits(a); | |
825 | let b = rustc_apfloat::ieee::Double::from_bits(b); | |
826 | a.partial_cmp(&b) | |
827 | } | |
828 | ty::Int(ity) => { | |
829 | use rustc_middle::ty::layout::IntegerExt; | |
830 | let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size(); | |
831 | let a = size.sign_extend(a); | |
832 | let b = size.sign_extend(b); | |
833 | Some((a as i128).cmp(&(b as i128))) | |
834 | } | |
835 | _ => Some(a.cmp(&b)), | |
0531ce1d XL |
836 | } |
837 | } |