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