1mod check_match;
4mod const_to_pat;
5mod migration;
6
7use std::cmp::Ordering;
8use std::sync::Arc;
9
10use rustc_abi::{FieldIdx, Integer};
11use rustc_errors::codes::*;
12use rustc_hir::def::{CtorOf, DefKind, Res};
13use rustc_hir::pat_util::EnumerateAndAdjustIterator;
14use rustc_hir::{self as hir, RangeEnd};
15use rustc_index::Idx;
16use rustc_middle::mir::interpret::LitToConstInput;
17use rustc_middle::thir::{
18 Ascription, DerefPatBorrowMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
19};
20use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
21use rustc_middle::ty::layout::IntegerExt;
22use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
23use rustc_middle::{bug, span_bug};
24use rustc_span::{ErrorGuaranteed, Span};
25use tracing::{debug, instrument};
26
27pub(crate) use self::check_match::check_match;
28use self::migration::PatMigration;
29use crate::errors::*;
30
31struct PatCtxt<'tcx> {
33 tcx: TyCtxt<'tcx>,
34 typing_env: ty::TypingEnv<'tcx>,
35 typeck_results: &'tcx ty::TypeckResults<'tcx>,
36
37 rust_2024_migration: Option<PatMigration<'tcx>>,
39}
40
41pub(super) fn pat_from_hir<'tcx>(
42 tcx: TyCtxt<'tcx>,
43 typing_env: ty::TypingEnv<'tcx>,
44 typeck_results: &'tcx ty::TypeckResults<'tcx>,
45 pat: &'tcx hir::Pat<'tcx>,
46) -> Box<Pat<'tcx>> {
47 let mut pcx = PatCtxt {
48 tcx,
49 typing_env,
50 typeck_results,
51 rust_2024_migration: typeck_results
52 .rust_2024_migration_desugared_pats()
53 .get(pat.hir_id)
54 .map(PatMigration::new),
55 };
56 let result = pcx.lower_pattern(pat);
57 debug!("pat_from_hir({:?}) = {:?}", pat, result);
58 if let Some(m) = pcx.rust_2024_migration {
59 m.emit(tcx, pat.hir_id);
60 }
61 result
62}
63
64impl<'tcx> PatCtxt<'tcx> {
65 fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
66 let adjustments: &[PatAdjustment<'tcx>] =
67 self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
68
69 let mut opt_old_mode_span = None;
73 if let Some(s) = &mut self.rust_2024_migration
74 && adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref)
75 {
76 opt_old_mode_span = s.visit_implicit_derefs(pat.span, adjustments);
77 }
78
79 let unadjusted_pat = match pat.kind {
99 hir::PatKind::Ref(inner, _, _)
100 if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
101 {
102 self.lower_pattern(inner)
103 }
104 _ => self.lower_pattern_unadjusted(pat),
105 };
106
107 let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, adjust| {
108 debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust);
109 let span = thir_pat.span;
110 let kind = match adjust.kind {
111 PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat },
112 PatAdjust::OverloadedDeref => {
113 let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat);
114 PatKind::DerefPattern { subpattern: thir_pat, borrow }
115 }
116 PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat },
117 };
118 Box::new(Pat { span, ty: adjust.source, kind })
119 });
120
121 if let Some(s) = &mut self.rust_2024_migration
122 && adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref)
123 {
124 s.leave_ref(opt_old_mode_span);
125 }
126
127 adjusted_pat
128 }
129
130 fn lower_pattern_range_endpoint(
131 &mut self,
132 expr: Option<&'tcx hir::PatExpr<'tcx>>,
133 ascriptions: &mut Vec<Ascription<'tcx>>,
135 ) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
136 let Some(expr) = expr else { return Ok(None) };
137
138 let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr, None);
141
142 loop {
144 match kind {
145 PatKind::AscribeUserType { ascription, subpattern } => {
146 ascriptions.push(ascription);
147 kind = subpattern.kind;
148 }
149 PatKind::ExpandedConstant { def_id: _, subpattern } => {
150 kind = subpattern.kind;
154 }
155 _ => break,
156 }
157 }
158
159 let PatKind::Constant { value } = kind else {
161 let msg =
162 format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
163 return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
164 };
165 Ok(Some(PatRangeBoundary::Finite(value.valtree)))
166 }
167
168 fn error_on_literal_overflow(
174 &self,
175 expr: Option<&'tcx hir::PatExpr<'tcx>>,
176 ty: Ty<'tcx>,
177 ) -> Result<(), ErrorGuaranteed> {
178 use rustc_ast::ast::LitKind;
179
180 let Some(expr) = expr else {
181 return Ok(());
182 };
183 let span = expr.span;
184
185 let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
189 return Ok(());
190 };
191 let LitKind::Int(lit_val, _) = lit.node else {
192 return Ok(());
193 };
194 let (min, max): (i128, u128) = match ty.kind() {
195 ty::Int(ity) => {
196 let size = Integer::from_int_ty(&self.tcx, *ity).size();
197 (size.signed_int_min(), size.signed_int_max() as u128)
198 }
199 ty::Uint(uty) => {
200 let size = Integer::from_uint_ty(&self.tcx, *uty).size();
201 (0, size.unsigned_int_max())
202 }
203 _ => {
204 return Ok(());
205 }
206 };
207 if (negated && lit_val > max + 1) || (!negated && lit_val > max) {
210 return Err(self.tcx.dcx().emit_err(LiteralOutOfRange { span, ty, min, max }));
211 }
212 Ok(())
213 }
214
215 fn lower_pattern_range(
216 &mut self,
217 lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
218 hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
219 end: RangeEnd,
220 ty: Ty<'tcx>,
221 span: Span,
222 ) -> Result<PatKind<'tcx>, ErrorGuaranteed> {
223 if lo_expr.is_none() && hi_expr.is_none() {
224 let msg = "found twice-open range pattern (`..`) outside of error recovery";
225 self.tcx.dcx().span_bug(span, msg);
226 }
227
228 let mut ascriptions = vec![];
230 let mut lower_endpoint = |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions);
231
232 let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
233 let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
234
235 let cmp = lo.compare_with(hi, ty, self.tcx);
236 let mut kind = PatKind::Range(Arc::new(PatRange { lo, hi, end, ty }));
237 match (end, cmp) {
238 (RangeEnd::Excluded, Some(Ordering::Less)) => {}
240 (RangeEnd::Included, Some(Ordering::Less)) => {}
242 (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
244 let value = ty::Value { ty, valtree: lo.as_finite().unwrap() };
245 kind = PatKind::Constant { value };
246 }
247 (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
249 (RangeEnd::Included, Some(Ordering::Equal)) if !hi.is_finite() => {}
252 _ => {
254 self.error_on_literal_overflow(lo_expr, ty)?;
256 self.error_on_literal_overflow(hi_expr, ty)?;
257 let e = match end {
258 RangeEnd::Included => {
259 self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
260 span,
261 teach: self.tcx.sess.teach(E0030),
262 })
263 }
264 RangeEnd::Excluded if lo_expr.is_none() => {
265 self.tcx.dcx().emit_err(UpperRangeBoundCannotBeMin { span })
266 }
267 RangeEnd::Excluded => {
268 self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanUpper { span })
269 }
270 };
271 return Err(e);
272 }
273 }
274
275 for ascription in ascriptions {
279 let subpattern = Box::new(Pat { span, ty, kind });
280 kind = PatKind::AscribeUserType { ascription, subpattern };
281 }
282 Ok(kind)
288 }
289
290 #[instrument(skip(self), level = "debug")]
291 fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
292 let mut ty = self.typeck_results.node_type(pat.hir_id);
293 let mut span = pat.span;
294
295 let kind = match pat.kind {
296 hir::PatKind::Missing => PatKind::Missing,
297
298 hir::PatKind::Wild => PatKind::Wild,
299
300 hir::PatKind::Never => PatKind::Never,
301
302 hir::PatKind::Expr(value) => self.lower_pat_expr(value, Some(ty)),
303
304 hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
305 let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
306 self.lower_pattern_range(lo_expr, hi_expr, end, ty, span)
307 .unwrap_or_else(PatKind::Error)
308 }
309
310 hir::PatKind::Deref(subpattern) => {
311 let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern);
312 PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow }
313 }
314 hir::PatKind::Ref(subpattern, _, _) => {
315 let opt_old_mode_span =
317 self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
318 let subpattern = self.lower_pattern(subpattern);
319 if let Some(s) = &mut self.rust_2024_migration {
320 s.leave_ref(opt_old_mode_span);
321 }
322 PatKind::Deref { subpattern }
323 }
324 hir::PatKind::Box(subpattern) => PatKind::DerefPattern {
325 subpattern: self.lower_pattern(subpattern),
326 borrow: DerefPatBorrowMode::Box,
327 },
328
329 hir::PatKind::Slice(prefix, slice, suffix) => {
330 self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
331 }
332
333 hir::PatKind::Tuple(pats, ddpos) => {
334 let ty::Tuple(tys) = ty.kind() else {
335 span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty);
336 };
337 let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
338 PatKind::Leaf { subpatterns }
339 }
340
341 hir::PatKind::Binding(explicit_ba, id, ident, sub) => {
342 if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
343 span = span.with_hi(ident_span.hi());
344 }
345
346 let mode = *self
347 .typeck_results
348 .pat_binding_modes()
349 .get(pat.hir_id)
350 .expect("missing binding mode");
351
352 if let Some(s) = &mut self.rust_2024_migration {
353 s.visit_binding(pat.span, mode, explicit_ba, ident);
354 }
355
356 let var_ty = ty;
359 if let hir::ByRef::Yes(pinnedness, _) = mode.0 {
360 match pinnedness {
361 hir::Pinnedness::Pinned
362 if let Some(pty) = ty.pinned_ty()
363 && let &ty::Ref(_, rty, _) = pty.kind() =>
364 {
365 ty = rty;
366 }
367 hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => {
368 ty = rty;
369 }
370 _ => bug!("`ref {}` has wrong type {}", ident, ty),
371 }
372 };
373
374 PatKind::Binding {
375 mode,
376 name: ident.name,
377 var: LocalVarId(id),
378 ty: var_ty,
379 subpattern: self.lower_opt_pattern(sub),
380 is_primary: id == pat.hir_id,
381 is_shorthand: false,
382 }
383 }
384
385 hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => {
386 let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
387 let ty::Adt(adt_def, _) = ty.kind() else {
388 span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty);
389 };
390 let variant_def = adt_def.variant_of_res(res);
391 let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
392 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
393 }
394
395 hir::PatKind::Struct(ref qpath, fields, _) => {
396 let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
397 let subpatterns = fields
398 .iter()
399 .map(|field| {
400 let mut pattern = *self.lower_pattern(field.pat);
401 if let PatKind::Binding { ref mut is_shorthand, .. } = pattern.kind {
402 *is_shorthand = field.is_shorthand;
403 }
404 let field = self.typeck_results.field_index(field.hir_id);
405 FieldPat { field, pattern }
406 })
407 .collect();
408
409 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
410 }
411
412 hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
413
414 hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
416
417 hir::PatKind::Err(guar) => PatKind::Error(guar),
418 };
419
420 Box::new(Pat { span, ty, kind })
421 }
422
423 fn lower_tuple_subpats(
424 &mut self,
425 pats: &'tcx [hir::Pat<'tcx>],
426 expected_len: usize,
427 gap_pos: hir::DotDotPos,
428 ) -> Vec<FieldPat<'tcx>> {
429 pats.iter()
430 .enumerate_and_adjust(expected_len, gap_pos)
431 .map(|(i, subpattern)| FieldPat {
432 field: FieldIdx::new(i),
433 pattern: *self.lower_pattern(subpattern),
434 })
435 .collect()
436 }
437
438 fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Pat<'tcx>]> {
439 pats.iter().map(|p| *self.lower_pattern(p)).collect()
440 }
441
442 fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
443 pat.map(|p| self.lower_pattern(p))
444 }
445
446 fn slice_or_array_pattern(
447 &mut self,
448 span: Span,
449 ty: Ty<'tcx>,
450 prefix: &'tcx [hir::Pat<'tcx>],
451 slice: Option<&'tcx hir::Pat<'tcx>>,
452 suffix: &'tcx [hir::Pat<'tcx>],
453 ) -> PatKind<'tcx> {
454 let prefix = self.lower_patterns(prefix);
455 let slice = self.lower_opt_pattern(slice);
456 let suffix = self.lower_patterns(suffix);
457 match ty.kind() {
458 ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
460 ty::Array(_, len) => {
462 let len = len
463 .try_to_target_usize(self.tcx)
464 .expect("expected len of array pat to be definite");
465 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
466 PatKind::Array { prefix, slice, suffix }
467 }
468 _ => span_bug!(span, "bad slice pattern type {:?}", ty),
469 }
470 }
471
472 fn lower_variant_or_leaf(
473 &mut self,
474 res: Res,
475 hir_id: hir::HirId,
476 span: Span,
477 ty: Ty<'tcx>,
478 subpatterns: Vec<FieldPat<'tcx>>,
479 ) -> PatKind<'tcx> {
480 let res = match res {
481 Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
482 let variant_id = self.tcx.parent(variant_ctor_id);
483 Res::Def(DefKind::Variant, variant_id)
484 }
485 res => res,
486 };
487
488 let mut kind = match res {
489 Res::Def(DefKind::Variant, variant_id) => {
490 let enum_id = self.tcx.parent(variant_id);
491 let adt_def = self.tcx.adt_def(enum_id);
492 if adt_def.is_enum() {
493 let args = match ty.kind() {
494 ty::Adt(_, args) | ty::FnDef(_, args) => args,
495 ty::Error(e) => {
496 return PatKind::Error(*e);
498 }
499 _ => bug!("inappropriate type for def: {:?}", ty),
500 };
501 PatKind::Variant {
502 adt_def,
503 args,
504 variant_index: adt_def.variant_index_with_id(variant_id),
505 subpatterns,
506 }
507 } else {
508 PatKind::Leaf { subpatterns }
509 }
510 }
511
512 Res::Def(
513 DefKind::Struct
514 | DefKind::Ctor(CtorOf::Struct, ..)
515 | DefKind::Union
516 | DefKind::TyAlias
517 | DefKind::AssocTy,
518 _,
519 )
520 | Res::SelfTyParam { .. }
521 | Res::SelfTyAlias { .. }
522 | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
523 _ => {
524 let e = match res {
525 Res::Def(DefKind::ConstParam, def_id) => {
526 let const_span = self.tcx.def_span(def_id);
527 self.tcx.dcx().emit_err(ConstParamInPattern { span, const_span })
528 }
529 Res::Def(DefKind::Static { .. }, def_id) => {
530 let static_span = self.tcx.def_span(def_id);
531 self.tcx.dcx().emit_err(StaticInPattern { span, static_span })
532 }
533 _ => self.tcx.dcx().emit_err(NonConstPath { span }),
534 };
535 PatKind::Error(e)
536 }
537 };
538
539 if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) {
540 debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
541 let annotation = CanonicalUserTypeAnnotation {
542 user_ty: Box::new(user_ty),
543 span,
544 inferred_ty: self.typeck_results.node_type(hir_id),
545 };
546 kind = PatKind::AscribeUserType {
547 subpattern: Box::new(Pat { span, ty, kind }),
548 ascription: Ascription { annotation, variance: ty::Covariant },
549 };
550 }
551
552 kind
553 }
554
555 fn user_args_applied_to_ty_of_hir_id(
556 &self,
557 hir_id: hir::HirId,
558 ) -> Option<ty::CanonicalUserType<'tcx>> {
559 crate::thir::util::user_args_applied_to_ty_of_hir_id(self.tcx, self.typeck_results, hir_id)
560 }
561
562 #[instrument(skip(self), level = "debug")]
566 fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
567 let ty = self.typeck_results.node_type(id);
568 let res = self.typeck_results.qpath_res(qpath, id);
569
570 let (def_id, user_ty) = match res {
571 Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
572 (def_id, self.typeck_results.user_provided_types().get(id))
573 }
574
575 _ => {
576 let kind = self.lower_variant_or_leaf(res, id, span, ty, vec![]);
579 return Box::new(Pat { span, ty, kind });
580 }
581 };
582
583 let args = self.typeck_results.node_args(id);
585 let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
588 let mut pattern = self.const_to_pat(c, ty, id, span);
589
590 if let Some(&user_ty) = user_ty {
593 let annotation = CanonicalUserTypeAnnotation {
594 user_ty: Box::new(user_ty),
595 span,
596 inferred_ty: self.typeck_results.node_type(id),
597 };
598 let kind = PatKind::AscribeUserType {
599 subpattern: pattern,
600 ascription: Ascription {
601 annotation,
602 variance: ty::Contravariant,
605 },
606 };
607 pattern = Box::new(Pat { span, kind, ty });
608 }
609
610 pattern
611 }
612
613 fn lower_pat_expr(
617 &mut self,
618 expr: &'tcx hir::PatExpr<'tcx>,
619 pat_ty: Option<Ty<'tcx>>,
620 ) -> PatKind<'tcx> {
621 match &expr.kind {
622 hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind,
623 hir::PatExprKind::Lit { lit, negated } => {
624 let ct_ty = match pat_ty {
630 Some(pat_ty) => pat_ty,
631 None => self.typeck_results.node_type(expr.hir_id),
632 };
633 let lit_input = LitToConstInput { lit: lit.node, ty: ct_ty, neg: *negated };
634 let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
635 self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
636 }
637 }
638 }
639}