]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/thir/pattern/mod.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_mir_build / src / thir / pattern / mod.rs
CommitLineData
9fa01778 1//! Validation of patterns/matches.
c30ab7b3 2
0531ce1d 3mod check_match;
e74abb32 4mod const_to_pat;
fc512014
XL
5mod deconstruct_pat;
6mod usefulness;
0531ce1d 7
0531ce1d
XL
8pub(crate) use self::check_match::check_match;
9
3dfed10e 10use crate::thir::util::UserAnnotatedTyHelpers;
0531ce1d 11
dfeec247
XL
12use rustc_errors::struct_span_err;
13use rustc_hir as hir;
17df50a5 14use rustc_hir::def::{CtorOf, DefKind, Res};
dfeec247
XL
15use rustc_hir::pat_util::EnumerateAndAdjustIterator;
16use rustc_hir::RangeEnd;
e74abb32 17use rustc_index::vec::Idx;
923072b8
FG
18use rustc_middle::mir::interpret::{
19 ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
20};
21use rustc_middle::mir::{self, UserTypeProjection};
ba9703b0 22use rustc_middle::mir::{BorrowKind, Field, Mutability};
923072b8 23use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
ba9703b0 24use rustc_middle::ty::subst::{GenericArg, SubstsRef};
923072b8 25use rustc_middle::ty::CanonicalUserTypeAnnotation;
94222f64 26use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
17df50a5 27use rustc_span::{Span, Symbol};
c30ab7b3 28
0531ce1d 29use std::cmp::Ordering;
c30ab7b3
SL
30
31#[derive(Clone, Debug)]
923072b8 32pub(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
39pub(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 47pub(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 63impl<'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 608impl<'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 618pub(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 626pub(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
636impl<'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
643impl<'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
649impl<'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 655macro_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
667ClonePatternFoldableImpls! { <'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 674impl<'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 680impl<'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 694impl<'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 752pub(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}