]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/thir/pattern/mod.rs
Update upstream source from tag 'upstream/1.70.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;
9c376795 5pub(crate) mod deconstruct_pat;
fc512014 6mod usefulness;
0531ce1d 7
0531ce1d 8pub(crate) use self::check_match::check_match;
9c376795 9pub(crate) use self::usefulness::MatchCheckCtxt;
0531ce1d 10
9c376795 11use crate::errors::*;
3dfed10e 12use crate::thir::util::UserAnnotatedTyHelpers;
0531ce1d 13
9c376795 14use rustc_errors::error_code;
dfeec247 15use rustc_hir as hir;
17df50a5 16use rustc_hir::def::{CtorOf, DefKind, Res};
dfeec247
XL
17use rustc_hir::pat_util::EnumerateAndAdjustIterator;
18use rustc_hir::RangeEnd;
e74abb32 19use rustc_index::vec::Idx;
923072b8
FG
20use rustc_middle::mir::interpret::{
21 ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
22};
23use rustc_middle::mir::{self, UserTypeProjection};
353b0b11 24use rustc_middle::mir::{BorrowKind, Mutability};
923072b8 25use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
ba9703b0 26use rustc_middle::ty::subst::{GenericArg, SubstsRef};
923072b8 27use rustc_middle::ty::CanonicalUserTypeAnnotation;
353b0b11 28use rustc_middle::ty::{self, AdtDef, ConstKind, Region, Ty, TyCtxt, UserType};
17df50a5 29use rustc_span::{Span, Symbol};
353b0b11 30use rustc_target::abi::FieldIdx;
c30ab7b3 31
0531ce1d 32use std::cmp::Ordering;
c30ab7b3 33
f2b60f7d
FG
34struct 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 40pub(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 52impl<'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 637impl<'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 647trait 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 655trait 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
665impl<'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
672impl<'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
678impl<'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 684impl<'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 690macro_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 702ClonePatternFoldableImpls! { <'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 709impl<'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 715impl<'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 729impl<'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 787pub(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}