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, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
19};
20use rustc_middle::ty::layout::IntegerExt;
21use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
22use rustc_middle::{bug, span_bug};
23use rustc_span::def_id::LocalDefId;
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<'a, 'tcx> {
32 tcx: TyCtxt<'tcx>,
33 typing_env: ty::TypingEnv<'tcx>,
34 typeck_results: &'a ty::TypeckResults<'tcx>,
35
36 rust_2024_migration: Option<PatMigration<'a>>,
38}
39
40pub(super) fn pat_from_hir<'a, 'tcx>(
41 tcx: TyCtxt<'tcx>,
42 typing_env: ty::TypingEnv<'tcx>,
43 typeck_results: &'a ty::TypeckResults<'tcx>,
44 pat: &'tcx hir::Pat<'tcx>,
45) -> Box<Pat<'tcx>> {
46 let mut pcx = PatCtxt {
47 tcx,
48 typing_env,
49 typeck_results,
50 rust_2024_migration: typeck_results
51 .rust_2024_migration_desugared_pats()
52 .get(pat.hir_id)
53 .map(PatMigration::new),
54 };
55 let result = pcx.lower_pattern(pat);
56 debug!("pat_from_hir({:?}) = {:?}", pat, result);
57 if let Some(m) = pcx.rust_2024_migration {
58 m.emit(tcx, pat.hir_id);
59 }
60 result
61}
62
63impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
64 fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
65 let adjustments: &[Ty<'tcx>] =
66 self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
67
68 let mut opt_old_mode_span = None;
70 if let Some(s) = &mut self.rust_2024_migration
71 && !adjustments.is_empty()
72 {
73 opt_old_mode_span = s.visit_implicit_derefs(pat.span, adjustments);
74 }
75
76 let unadjusted_pat = match pat.kind {
96 hir::PatKind::Ref(inner, _)
97 if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
98 {
99 self.lower_pattern(inner)
100 }
101 _ => self.lower_pattern_unadjusted(pat),
102 };
103
104 let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
105 debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
106 Box::new(Pat {
107 span: thir_pat.span,
108 ty: *ref_ty,
109 kind: PatKind::Deref { subpattern: thir_pat },
110 })
111 });
112
113 if let Some(s) = &mut self.rust_2024_migration
114 && !adjustments.is_empty()
115 {
116 s.leave_ref(opt_old_mode_span);
117 }
118
119 adjusted_pat
120 }
121
122 fn lower_pattern_range_endpoint(
123 &mut self,
124 expr: Option<&'tcx hir::PatExpr<'tcx>>,
125 ascriptions: &mut Vec<Ascription<'tcx>>,
127 inline_consts: &mut Vec<LocalDefId>,
128 ) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
129 let Some(expr) = expr else { return Ok(None) };
130
131 let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr);
134
135 loop {
137 match kind {
138 PatKind::AscribeUserType { ascription, subpattern } => {
139 ascriptions.push(ascription);
140 kind = subpattern.kind;
141 }
142 PatKind::ExpandedConstant { is_inline, def_id, subpattern } => {
143 if is_inline {
144 inline_consts.extend(def_id.as_local());
145 }
146 kind = subpattern.kind;
147 }
148 _ => break,
149 }
150 }
151
152 let PatKind::Constant { value } = kind else {
154 let msg =
155 format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
156 return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
157 };
158
159 Ok(Some(PatRangeBoundary::Finite(value)))
160 }
161
162 fn error_on_literal_overflow(
168 &self,
169 expr: Option<&'tcx hir::PatExpr<'tcx>>,
170 ty: Ty<'tcx>,
171 ) -> Result<(), ErrorGuaranteed> {
172 use rustc_ast::ast::LitKind;
173
174 let Some(expr) = expr else {
175 return Ok(());
176 };
177 let span = expr.span;
178
179 let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
183 return Ok(());
184 };
185 let LitKind::Int(lit_val, _) = lit.node else {
186 return Ok(());
187 };
188 let (min, max): (i128, u128) = match ty.kind() {
189 ty::Int(ity) => {
190 let size = Integer::from_int_ty(&self.tcx, *ity).size();
191 (size.signed_int_min(), size.signed_int_max() as u128)
192 }
193 ty::Uint(uty) => {
194 let size = Integer::from_uint_ty(&self.tcx, *uty).size();
195 (0, size.unsigned_int_max())
196 }
197 _ => {
198 return Ok(());
199 }
200 };
201 if (negated && lit_val > max + 1) || (!negated && lit_val > max) {
204 return Err(self.tcx.dcx().emit_err(LiteralOutOfRange { span, ty, min, max }));
205 }
206 Ok(())
207 }
208
209 fn lower_pattern_range(
210 &mut self,
211 lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
212 hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
213 end: RangeEnd,
214 ty: Ty<'tcx>,
215 span: Span,
216 ) -> Result<PatKind<'tcx>, ErrorGuaranteed> {
217 if lo_expr.is_none() && hi_expr.is_none() {
218 let msg = "found twice-open range pattern (`..`) outside of error recovery";
219 self.tcx.dcx().span_bug(span, msg);
220 }
221
222 let mut ascriptions = vec![];
224 let mut inline_consts = vec![];
225
226 let mut lower_endpoint =
227 |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts);
228
229 let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
230 let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
231
232 let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
233 let mut kind = PatKind::Range(Arc::new(PatRange { lo, hi, end, ty }));
234 match (end, cmp) {
235 (RangeEnd::Excluded, Some(Ordering::Less)) => {}
237 (RangeEnd::Included, Some(Ordering::Less)) => {}
239 (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
241 kind = PatKind::Constant { value: lo.as_finite().unwrap() };
242 }
243 (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
245 (RangeEnd::Included, Some(Ordering::Equal)) if !hi.is_finite() => {}
248 _ => {
250 self.error_on_literal_overflow(lo_expr, ty)?;
252 self.error_on_literal_overflow(hi_expr, ty)?;
253 let e = match end {
254 RangeEnd::Included => {
255 self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
256 span,
257 teach: self.tcx.sess.teach(E0030),
258 })
259 }
260 RangeEnd::Excluded => {
261 self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanUpper { span })
262 }
263 };
264 return Err(e);
265 }
266 }
267
268 for ascription in ascriptions {
272 kind = PatKind::AscribeUserType {
273 ascription,
274 subpattern: Box::new(Pat { span, ty, kind }),
275 };
276 }
277 for def in inline_consts {
278 kind = PatKind::ExpandedConstant {
279 def_id: def.to_def_id(),
280 is_inline: true,
281 subpattern: Box::new(Pat { span, ty, kind }),
282 };
283 }
284 Ok(kind)
285 }
286
287 #[instrument(skip(self), level = "debug")]
288 fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
289 let mut ty = self.typeck_results.node_type(pat.hir_id);
290 let mut span = pat.span;
291
292 let kind = match pat.kind {
293 hir::PatKind::Wild => PatKind::Wild,
294
295 hir::PatKind::Never => PatKind::Never,
296
297 hir::PatKind::Expr(value) => self.lower_pat_expr(value),
298
299 hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
300 let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
301 self.lower_pattern_range(lo_expr, hi_expr, end, ty, span)
302 .unwrap_or_else(PatKind::Error)
303 }
304
305 hir::PatKind::Deref(subpattern) => {
306 let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
307 let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
308 PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability }
309 }
310 hir::PatKind::Ref(subpattern, _) => {
311 let opt_old_mode_span =
313 self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
314 let subpattern = self.lower_pattern(subpattern);
315 if let Some(s) = &mut self.rust_2024_migration {
316 s.leave_ref(opt_old_mode_span);
317 }
318 PatKind::Deref { subpattern }
319 }
320 hir::PatKind::Box(subpattern) => {
321 PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
322 }
323
324 hir::PatKind::Slice(prefix, slice, suffix) => {
325 self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
326 }
327
328 hir::PatKind::Tuple(pats, ddpos) => {
329 let ty::Tuple(tys) = ty.kind() else {
330 span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty);
331 };
332 let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
333 PatKind::Leaf { subpatterns }
334 }
335
336 hir::PatKind::Binding(explicit_ba, id, ident, sub) => {
337 if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
338 span = span.with_hi(ident_span.hi());
339 }
340
341 let mode = *self
342 .typeck_results
343 .pat_binding_modes()
344 .get(pat.hir_id)
345 .expect("missing binding mode");
346
347 if let Some(s) = &mut self.rust_2024_migration {
348 s.visit_binding(pat.span, mode, explicit_ba, ident);
349 }
350
351 let var_ty = ty;
354 if let hir::ByRef::Yes(_) = mode.0 {
355 if let ty::Ref(_, rty, _) = ty.kind() {
356 ty = *rty;
357 } else {
358 bug!("`ref {}` has wrong type {}", ident, ty);
359 }
360 };
361
362 PatKind::Binding {
363 mode,
364 name: ident.name,
365 var: LocalVarId(id),
366 ty: var_ty,
367 subpattern: self.lower_opt_pattern(sub),
368 is_primary: id == pat.hir_id,
369 }
370 }
371
372 hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => {
373 let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
374 let ty::Adt(adt_def, _) = ty.kind() else {
375 span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty);
376 };
377 let variant_def = adt_def.variant_of_res(res);
378 let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
379 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
380 }
381
382 hir::PatKind::Struct(ref qpath, fields, _) => {
383 let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
384 let subpatterns = fields
385 .iter()
386 .map(|field| FieldPat {
387 field: self.typeck_results.field_index(field.hir_id),
388 pattern: *self.lower_pattern(field.pat),
389 })
390 .collect();
391
392 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
393 }
394
395 hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
396
397 hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
399
400 hir::PatKind::Err(guar) => PatKind::Error(guar),
401 };
402
403 Box::new(Pat { span, ty, kind })
404 }
405
406 fn lower_tuple_subpats(
407 &mut self,
408 pats: &'tcx [hir::Pat<'tcx>],
409 expected_len: usize,
410 gap_pos: hir::DotDotPos,
411 ) -> Vec<FieldPat<'tcx>> {
412 pats.iter()
413 .enumerate_and_adjust(expected_len, gap_pos)
414 .map(|(i, subpattern)| FieldPat {
415 field: FieldIdx::new(i),
416 pattern: *self.lower_pattern(subpattern),
417 })
418 .collect()
419 }
420
421 fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Pat<'tcx>]> {
422 pats.iter().map(|p| *self.lower_pattern(p)).collect()
423 }
424
425 fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
426 pat.map(|p| self.lower_pattern(p))
427 }
428
429 fn slice_or_array_pattern(
430 &mut self,
431 span: Span,
432 ty: Ty<'tcx>,
433 prefix: &'tcx [hir::Pat<'tcx>],
434 slice: Option<&'tcx hir::Pat<'tcx>>,
435 suffix: &'tcx [hir::Pat<'tcx>],
436 ) -> PatKind<'tcx> {
437 let prefix = self.lower_patterns(prefix);
438 let slice = self.lower_opt_pattern(slice);
439 let suffix = self.lower_patterns(suffix);
440 match ty.kind() {
441 ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
443 ty::Array(_, len) => {
445 let len = len
446 .try_to_target_usize(self.tcx)
447 .expect("expected len of array pat to be definite");
448 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
449 PatKind::Array { prefix, slice, suffix }
450 }
451 _ => span_bug!(span, "bad slice pattern type {:?}", ty),
452 }
453 }
454
455 fn lower_variant_or_leaf(
456 &mut self,
457 res: Res,
458 hir_id: hir::HirId,
459 span: Span,
460 ty: Ty<'tcx>,
461 subpatterns: Vec<FieldPat<'tcx>>,
462 ) -> PatKind<'tcx> {
463 let res = match res {
464 Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
465 let variant_id = self.tcx.parent(variant_ctor_id);
466 Res::Def(DefKind::Variant, variant_id)
467 }
468 res => res,
469 };
470
471 let mut kind = match res {
472 Res::Def(DefKind::Variant, variant_id) => {
473 let enum_id = self.tcx.parent(variant_id);
474 let adt_def = self.tcx.adt_def(enum_id);
475 if adt_def.is_enum() {
476 let args = match ty.kind() {
477 ty::Adt(_, args) | ty::FnDef(_, args) => args,
478 ty::Error(e) => {
479 return PatKind::Error(*e);
481 }
482 _ => bug!("inappropriate type for def: {:?}", ty),
483 };
484 PatKind::Variant {
485 adt_def,
486 args,
487 variant_index: adt_def.variant_index_with_id(variant_id),
488 subpatterns,
489 }
490 } else {
491 PatKind::Leaf { subpatterns }
492 }
493 }
494
495 Res::Def(
496 DefKind::Struct
497 | DefKind::Ctor(CtorOf::Struct, ..)
498 | DefKind::Union
499 | DefKind::TyAlias
500 | DefKind::AssocTy,
501 _,
502 )
503 | Res::SelfTyParam { .. }
504 | Res::SelfTyAlias { .. }
505 | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
506 _ => {
507 let e = match res {
508 Res::Def(DefKind::ConstParam, def_id) => {
509 let const_span = self.tcx.def_span(def_id);
510 self.tcx.dcx().emit_err(ConstParamInPattern { span, const_span })
511 }
512 Res::Def(DefKind::Static { .. }, def_id) => {
513 let static_span = self.tcx.def_span(def_id);
514 self.tcx.dcx().emit_err(StaticInPattern { span, static_span })
515 }
516 _ => self.tcx.dcx().emit_err(NonConstPath { span }),
517 };
518 PatKind::Error(e)
519 }
520 };
521
522 if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) {
523 debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
524 let annotation = CanonicalUserTypeAnnotation {
525 user_ty: Box::new(user_ty),
526 span,
527 inferred_ty: self.typeck_results.node_type(hir_id),
528 };
529 kind = PatKind::AscribeUserType {
530 subpattern: Box::new(Pat { span, ty, kind }),
531 ascription: Ascription { annotation, variance: ty::Covariant },
532 };
533 }
534
535 kind
536 }
537
538 fn user_args_applied_to_ty_of_hir_id(
539 &self,
540 hir_id: hir::HirId,
541 ) -> Option<ty::CanonicalUserType<'tcx>> {
542 crate::thir::util::user_args_applied_to_ty_of_hir_id(self.tcx, self.typeck_results, hir_id)
543 }
544
545 #[instrument(skip(self), level = "debug")]
549 fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
550 let ty = self.typeck_results.node_type(id);
551 let res = self.typeck_results.qpath_res(qpath, id);
552
553 let (def_id, user_ty) = match res {
554 Res::Def(DefKind::Const, def_id) => (def_id, None),
555 Res::Def(DefKind::AssocConst, def_id) => {
556 (def_id, self.typeck_results.user_provided_types().get(id))
557 }
558
559 _ => {
560 let kind = self.lower_variant_or_leaf(res, id, span, ty, vec![]);
563 return Box::new(Pat { span, ty, kind });
564 }
565 };
566
567 let args = self.typeck_results.node_args(id);
569 let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
570 let subpattern = self.const_to_pat(c, ty, id, span);
571
572 let mut pattern = {
576 let kind = PatKind::ExpandedConstant { subpattern, def_id, is_inline: false };
577 Box::new(Pat { span, ty, kind })
578 };
579
580 if let Some(&user_ty) = user_ty {
583 let annotation = CanonicalUserTypeAnnotation {
584 user_ty: Box::new(user_ty),
585 span,
586 inferred_ty: self.typeck_results.node_type(id),
587 };
588 let kind = PatKind::AscribeUserType {
589 subpattern: pattern,
590 ascription: Ascription {
591 annotation,
592 variance: ty::Contravariant,
595 },
596 };
597 pattern = Box::new(Pat { span, kind, ty });
598 }
599
600 pattern
601 }
602
603 fn lower_inline_const(
605 &mut self,
606 block: &'tcx hir::ConstBlock,
607 id: hir::HirId,
608 span: Span,
609 ) -> PatKind<'tcx> {
610 let tcx = self.tcx;
611 let def_id = block.def_id;
612 let ty = tcx.typeck(def_id).node_type(block.hir_id);
613
614 let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
615 let parent_args =
616 tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
617 let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
618
619 debug_assert!(!args.has_free_regions());
620
621 let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
622 let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
623
624 PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
627 }
628
629 fn lower_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
634 let (lit, neg) = match &expr.kind {
635 hir::PatExprKind::Path(qpath) => {
636 return self.lower_path(qpath, expr.hir_id, expr.span).kind;
637 }
638 hir::PatExprKind::ConstBlock(anon_const) => {
639 return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
640 }
641 hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
642 };
643
644 let ct_ty = self.typeck_results.node_type(expr.hir_id);
645 let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
646 let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
647 self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
648 }
649}