rustc_mir_build/thir/pattern/
mod.rs

1//! Validation of patterns/matches.
2
3mod check_match;
4mod const_to_pat;
5
6use std::cmp::Ordering;
7use std::sync::Arc;
8
9use rustc_abi::{FieldIdx, Integer};
10use rustc_errors::MultiSpan;
11use rustc_errors::codes::*;
12use rustc_hir::def::{CtorOf, DefKind, Res};
13use rustc_hir::pat_util::EnumerateAndAdjustIterator;
14use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
15use rustc_index::Idx;
16use rustc_lint as lint;
17use rustc_middle::mir::interpret::LitToConstInput;
18use rustc_middle::thir::{
19    Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
20};
21use rustc_middle::ty::layout::IntegerExt;
22use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
23use rustc_middle::{bug, span_bug};
24use rustc_span::def_id::LocalDefId;
25use rustc_span::{ErrorGuaranteed, Span};
26use tracing::{debug, instrument};
27
28pub(crate) use self::check_match::check_match;
29use crate::errors::*;
30use crate::fluent_generated as fluent;
31
32struct PatCtxt<'a, 'tcx> {
33    tcx: TyCtxt<'tcx>,
34    typing_env: ty::TypingEnv<'tcx>,
35    typeck_results: &'a ty::TypeckResults<'tcx>,
36
37    /// Used by the Rust 2024 migration lint.
38    rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
39}
40
41pub(super) fn pat_from_hir<'a, 'tcx>(
42    tcx: TyCtxt<'tcx>,
43    typing_env: ty::TypingEnv<'tcx>,
44    typeck_results: &'a ty::TypeckResults<'tcx>,
45    pat: &'tcx hir::Pat<'tcx>,
46) -> Box<Pat<'tcx>> {
47    let migration_info = typeck_results.rust_2024_migration_desugared_pats().get(pat.hir_id);
48    let mut pcx = PatCtxt {
49        tcx,
50        typing_env,
51        typeck_results,
52        rust_2024_migration_suggestion: migration_info.and_then(|info| {
53            Some(Rust2024IncompatiblePatSugg {
54                suggest_eliding_modes: info.suggest_eliding_modes,
55                suggestion: Vec::new(),
56                ref_pattern_count: 0,
57                binding_mode_count: 0,
58                default_mode_span: None,
59                default_mode_labels: Default::default(),
60            })
61        }),
62    };
63    let result = pcx.lower_pattern(pat);
64    debug!("pat_from_hir({:?}) = {:?}", pat, result);
65    if let Some(info) = migration_info
66        && let Some(sugg) = pcx.rust_2024_migration_suggestion
67    {
68        let mut spans =
69            MultiSpan::from_spans(info.primary_labels.iter().map(|(span, _)| *span).collect());
70        for (span, label) in &info.primary_labels {
71            spans.push_span_label(*span, label.clone());
72        }
73        // If a relevant span is from at least edition 2024, this is a hard error.
74        let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
75        if is_hard_error {
76            let mut err =
77                tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
78            if let Some(lint_info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
79                // provide the same reference link as the lint
80                err.note(format!("for more information, see {}", lint_info.reference));
81            }
82            err.arg("bad_modifiers", info.bad_modifiers);
83            err.arg("bad_ref_pats", info.bad_ref_pats);
84            err.arg("is_hard_error", true);
85            err.subdiagnostic(sugg);
86            err.emit();
87        } else {
88            tcx.emit_node_span_lint(
89                lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
90                pat.hir_id,
91                spans,
92                Rust2024IncompatiblePat {
93                    sugg,
94                    bad_modifiers: info.bad_modifiers,
95                    bad_ref_pats: info.bad_ref_pats,
96                    is_hard_error,
97                },
98            );
99        }
100    }
101    result
102}
103
104impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
105    fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
106        let adjustments: &[Ty<'tcx>] =
107            self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
108
109        let mut opt_old_mode_span = None;
110        if let Some(s) = &mut self.rust_2024_migration_suggestion
111            && !adjustments.is_empty()
112        {
113            let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
114                let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
115                    span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
116                };
117                mutbl
118            });
119
120            if !s.suggest_eliding_modes {
121                let suggestion_str: String =
122                    implicit_deref_mutbls.clone().map(|mutbl| mutbl.ref_prefix_str()).collect();
123                s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
124                s.ref_pattern_count += adjustments.len();
125            }
126
127            // Remember if this changed the default binding mode, in case we want to label it.
128            let min_mutbl = implicit_deref_mutbls.min().unwrap();
129            if s.default_mode_span.is_none_or(|(_, old_mutbl)| min_mutbl < old_mutbl) {
130                opt_old_mode_span = Some(s.default_mode_span);
131                s.default_mode_span = Some((pat.span, min_mutbl));
132            }
133        };
134
135        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
136        // pattern has the type that results *after* dereferencing. For example, in this code:
137        //
138        // ```
139        // match &&Some(0i32) {
140        //     Some(n) => { ... },
141        //     _ => { ... },
142        // }
143        // ```
144        //
145        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
146        // determined in rustc_hir_analysis::check::match). The adjustments would be
147        //
148        // `vec![&&Option<i32>, &Option<i32>]`.
149        //
150        // Applying the adjustments, we want to instead output `&&Some(n)` (as a THIR pattern). So
151        // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
152        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
153        // gets the least-dereferenced type).
154        let unadjusted_pat = match pat.kind {
155            hir::PatKind::Ref(inner, _)
156                if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
157            {
158                self.lower_pattern(inner)
159            }
160            _ => self.lower_pattern_unadjusted(pat),
161        };
162
163        let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
164            debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
165            Box::new(Pat {
166                span: thir_pat.span,
167                ty: *ref_ty,
168                kind: PatKind::Deref { subpattern: thir_pat },
169            })
170        });
171
172        if let Some(s) = &mut self.rust_2024_migration_suggestion
173            && let Some(old_mode_span) = opt_old_mode_span
174        {
175            s.default_mode_span = old_mode_span;
176        }
177
178        adjusted_pat
179    }
180
181    fn lower_pattern_range_endpoint(
182        &mut self,
183        expr: Option<&'tcx hir::PatExpr<'tcx>>,
184        // Out-parameters collecting extra data to be reapplied by the caller
185        ascriptions: &mut Vec<Ascription<'tcx>>,
186        inline_consts: &mut Vec<LocalDefId>,
187    ) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
188        let Some(expr) = expr else { return Ok(None) };
189
190        // Lower the endpoint into a temporary `PatKind` that will then be
191        // deconstructed to obtain the constant value and other data.
192        let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr);
193
194        // Unpeel any ascription or inline-const wrapper nodes.
195        loop {
196            match kind {
197                PatKind::AscribeUserType { ascription, subpattern } => {
198                    ascriptions.push(ascription);
199                    kind = subpattern.kind;
200                }
201                PatKind::ExpandedConstant { is_inline, def_id, subpattern } => {
202                    if is_inline {
203                        inline_consts.extend(def_id.as_local());
204                    }
205                    kind = subpattern.kind;
206                }
207                _ => break,
208            }
209        }
210
211        // The unpeeled kind should now be a constant, giving us the endpoint value.
212        let PatKind::Constant { value } = kind else {
213            let msg =
214                format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
215            return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
216        };
217
218        Ok(Some(PatRangeBoundary::Finite(value)))
219    }
220
221    /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we
222    /// encounter a range pattern like `-130i8..2`: if we believe `eval_bits`, this looks like a
223    /// range where the endpoints are in the wrong order. To avoid a confusing error message, we
224    /// check for overflow then.
225    /// This is only called when the range is already known to be malformed.
226    fn error_on_literal_overflow(
227        &self,
228        expr: Option<&'tcx hir::PatExpr<'tcx>>,
229        ty: Ty<'tcx>,
230    ) -> Result<(), ErrorGuaranteed> {
231        use rustc_ast::ast::LitKind;
232
233        let Some(expr) = expr else {
234            return Ok(());
235        };
236        let span = expr.span;
237
238        // We need to inspect the original expression, because if we only inspect the output of
239        // `eval_bits`, an overflowed value has already been wrapped around.
240        // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint.
241        let hir::PatExprKind::Lit { lit, negated } = expr.kind else {
242            return Ok(());
243        };
244        let LitKind::Int(lit_val, _) = lit.node else {
245            return Ok(());
246        };
247        let (min, max): (i128, u128) = match ty.kind() {
248            ty::Int(ity) => {
249                let size = Integer::from_int_ty(&self.tcx, *ity).size();
250                (size.signed_int_min(), size.signed_int_max() as u128)
251            }
252            ty::Uint(uty) => {
253                let size = Integer::from_uint_ty(&self.tcx, *uty).size();
254                (0, size.unsigned_int_max())
255            }
256            _ => {
257                return Ok(());
258            }
259        };
260        // Detect literal value out of range `[min, max]` inclusive, avoiding use of `-min` to
261        // prevent overflow/panic.
262        if (negated && lit_val > max + 1) || (!negated && lit_val > max) {
263            return Err(self.tcx.dcx().emit_err(LiteralOutOfRange { span, ty, min, max }));
264        }
265        Ok(())
266    }
267
268    fn lower_pattern_range(
269        &mut self,
270        lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
271        hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
272        end: RangeEnd,
273        ty: Ty<'tcx>,
274        span: Span,
275    ) -> Result<PatKind<'tcx>, ErrorGuaranteed> {
276        if lo_expr.is_none() && hi_expr.is_none() {
277            let msg = "found twice-open range pattern (`..`) outside of error recovery";
278            self.tcx.dcx().span_bug(span, msg);
279        }
280
281        // Collect extra data while lowering the endpoints, to be reapplied later.
282        let mut ascriptions = vec![];
283        let mut inline_consts = vec![];
284
285        let mut lower_endpoint =
286            |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts);
287
288        let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
289        let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
290
291        let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
292        let mut kind = PatKind::Range(Arc::new(PatRange { lo, hi, end, ty }));
293        match (end, cmp) {
294            // `x..y` where `x < y`.
295            (RangeEnd::Excluded, Some(Ordering::Less)) => {}
296            // `x..=y` where `x < y`.
297            (RangeEnd::Included, Some(Ordering::Less)) => {}
298            // `x..=y` where `x == y` and `x` and `y` are finite.
299            (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
300                kind = PatKind::Constant { value: lo.as_finite().unwrap() };
301            }
302            // `..=x` where `x == ty::MIN`.
303            (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
304            // `x..` where `x == ty::MAX` (yes, `x..` gives `RangeEnd::Included` since it is meant
305            // to include `ty::MAX`).
306            (RangeEnd::Included, Some(Ordering::Equal)) if !hi.is_finite() => {}
307            // `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error.
308            _ => {
309                // Emit a more appropriate message if there was overflow.
310                self.error_on_literal_overflow(lo_expr, ty)?;
311                self.error_on_literal_overflow(hi_expr, ty)?;
312                let e = match end {
313                    RangeEnd::Included => {
314                        self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
315                            span,
316                            teach: self.tcx.sess.teach(E0030),
317                        })
318                    }
319                    RangeEnd::Excluded => {
320                        self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanUpper { span })
321                    }
322                };
323                return Err(e);
324            }
325        }
326
327        // If we are handling a range with associated constants (e.g.
328        // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
329        // constants somewhere. Have them on the range pattern.
330        for ascription in ascriptions {
331            kind = PatKind::AscribeUserType {
332                ascription,
333                subpattern: Box::new(Pat { span, ty, kind }),
334            };
335        }
336        for def in inline_consts {
337            kind = PatKind::ExpandedConstant {
338                def_id: def.to_def_id(),
339                is_inline: true,
340                subpattern: Box::new(Pat { span, ty, kind }),
341            };
342        }
343        Ok(kind)
344    }
345
346    #[instrument(skip(self), level = "debug")]
347    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
348        let mut ty = self.typeck_results.node_type(pat.hir_id);
349        let mut span = pat.span;
350
351        let kind = match pat.kind {
352            hir::PatKind::Wild => PatKind::Wild,
353
354            hir::PatKind::Never => PatKind::Never,
355
356            hir::PatKind::Expr(value) => self.lower_pat_expr(value),
357
358            hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
359                let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
360                self.lower_pattern_range(lo_expr, hi_expr, end, ty, span)
361                    .unwrap_or_else(PatKind::Error)
362            }
363
364            hir::PatKind::Deref(subpattern) => {
365                let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
366                let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
367                PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability }
368            }
369            hir::PatKind::Ref(subpattern, _) => {
370                // Track the default binding mode for the Rust 2024 migration suggestion.
371                let old_mode_span = self.rust_2024_migration_suggestion.as_mut().and_then(|s| {
372                    if let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span {
373                        // If this eats a by-ref default binding mode, label the binding mode.
374                        s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
375                    }
376                    s.default_mode_span.take()
377                });
378                let subpattern = self.lower_pattern(subpattern);
379                if let Some(s) = &mut self.rust_2024_migration_suggestion {
380                    s.default_mode_span = old_mode_span;
381                }
382                PatKind::Deref { subpattern }
383            }
384            hir::PatKind::Box(subpattern) => {
385                PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
386            }
387
388            hir::PatKind::Slice(prefix, slice, suffix) => {
389                self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
390            }
391
392            hir::PatKind::Tuple(pats, ddpos) => {
393                let ty::Tuple(tys) = ty.kind() else {
394                    span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty);
395                };
396                let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
397                PatKind::Leaf { subpatterns }
398            }
399
400            hir::PatKind::Binding(explicit_ba, id, ident, sub) => {
401                if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
402                    span = span.with_hi(ident_span.hi());
403                }
404
405                let mode = *self
406                    .typeck_results
407                    .pat_binding_modes()
408                    .get(pat.hir_id)
409                    .expect("missing binding mode");
410
411                if let Some(s) = &mut self.rust_2024_migration_suggestion {
412                    if explicit_ba != hir::BindingMode::NONE
413                        && let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span
414                    {
415                        // If this overrides a by-ref default binding mode, label the binding mode.
416                        s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
417                        // If our suggestion is to elide redundnt modes, this will be one of them.
418                        if s.suggest_eliding_modes {
419                            s.suggestion.push((pat.span.with_hi(ident.span.lo()), String::new()));
420                            s.binding_mode_count += 1;
421                        }
422                    }
423                    if !s.suggest_eliding_modes
424                        && explicit_ba.0 == ByRef::No
425                        && let ByRef::Yes(mutbl) = mode.0
426                    {
427                        let sugg_str = match mutbl {
428                            Mutability::Not => "ref ",
429                            Mutability::Mut => "ref mut ",
430                        };
431                        s.suggestion.push((
432                            pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
433                            sugg_str.to_owned(),
434                        ));
435                        s.binding_mode_count += 1;
436                    }
437                }
438
439                // A ref x pattern is the same node used for x, and as such it has
440                // x's type, which is &T, where we want T (the type being matched).
441                let var_ty = ty;
442                if let hir::ByRef::Yes(_) = mode.0 {
443                    if let ty::Ref(_, rty, _) = ty.kind() {
444                        ty = *rty;
445                    } else {
446                        bug!("`ref {}` has wrong type {}", ident, ty);
447                    }
448                };
449
450                PatKind::Binding {
451                    mode,
452                    name: ident.name,
453                    var: LocalVarId(id),
454                    ty: var_ty,
455                    subpattern: self.lower_opt_pattern(sub),
456                    is_primary: id == pat.hir_id,
457                }
458            }
459
460            hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => {
461                let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
462                let ty::Adt(adt_def, _) = ty.kind() else {
463                    span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty);
464                };
465                let variant_def = adt_def.variant_of_res(res);
466                let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
467                self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
468            }
469
470            hir::PatKind::Struct(ref qpath, fields, _) => {
471                let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
472                let subpatterns = fields
473                    .iter()
474                    .map(|field| FieldPat {
475                        field: self.typeck_results.field_index(field.hir_id),
476                        pattern: *self.lower_pattern(field.pat),
477                    })
478                    .collect();
479
480                self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
481            }
482
483            hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
484
485            // FIXME(guard_patterns): implement guard pattern lowering
486            hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
487
488            hir::PatKind::Err(guar) => PatKind::Error(guar),
489        };
490
491        Box::new(Pat { span, ty, kind })
492    }
493
494    fn lower_tuple_subpats(
495        &mut self,
496        pats: &'tcx [hir::Pat<'tcx>],
497        expected_len: usize,
498        gap_pos: hir::DotDotPos,
499    ) -> Vec<FieldPat<'tcx>> {
500        pats.iter()
501            .enumerate_and_adjust(expected_len, gap_pos)
502            .map(|(i, subpattern)| FieldPat {
503                field: FieldIdx::new(i),
504                pattern: *self.lower_pattern(subpattern),
505            })
506            .collect()
507    }
508
509    fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Pat<'tcx>]> {
510        pats.iter().map(|p| *self.lower_pattern(p)).collect()
511    }
512
513    fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
514        pat.map(|p| self.lower_pattern(p))
515    }
516
517    fn slice_or_array_pattern(
518        &mut self,
519        span: Span,
520        ty: Ty<'tcx>,
521        prefix: &'tcx [hir::Pat<'tcx>],
522        slice: Option<&'tcx hir::Pat<'tcx>>,
523        suffix: &'tcx [hir::Pat<'tcx>],
524    ) -> PatKind<'tcx> {
525        let prefix = self.lower_patterns(prefix);
526        let slice = self.lower_opt_pattern(slice);
527        let suffix = self.lower_patterns(suffix);
528        match ty.kind() {
529            // Matching a slice, `[T]`.
530            ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
531            // Fixed-length array, `[T; len]`.
532            ty::Array(_, len) => {
533                let len = len
534                    .try_to_target_usize(self.tcx)
535                    .expect("expected len of array pat to be definite");
536                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
537                PatKind::Array { prefix, slice, suffix }
538            }
539            _ => span_bug!(span, "bad slice pattern type {:?}", ty),
540        }
541    }
542
543    fn lower_variant_or_leaf(
544        &mut self,
545        res: Res,
546        hir_id: hir::HirId,
547        span: Span,
548        ty: Ty<'tcx>,
549        subpatterns: Vec<FieldPat<'tcx>>,
550    ) -> PatKind<'tcx> {
551        let res = match res {
552            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
553                let variant_id = self.tcx.parent(variant_ctor_id);
554                Res::Def(DefKind::Variant, variant_id)
555            }
556            res => res,
557        };
558
559        let mut kind = match res {
560            Res::Def(DefKind::Variant, variant_id) => {
561                let enum_id = self.tcx.parent(variant_id);
562                let adt_def = self.tcx.adt_def(enum_id);
563                if adt_def.is_enum() {
564                    let args = match ty.kind() {
565                        ty::Adt(_, args) | ty::FnDef(_, args) => args,
566                        ty::Error(e) => {
567                            // Avoid ICE (#50585)
568                            return PatKind::Error(*e);
569                        }
570                        _ => bug!("inappropriate type for def: {:?}", ty),
571                    };
572                    PatKind::Variant {
573                        adt_def,
574                        args,
575                        variant_index: adt_def.variant_index_with_id(variant_id),
576                        subpatterns,
577                    }
578                } else {
579                    PatKind::Leaf { subpatterns }
580                }
581            }
582
583            Res::Def(
584                DefKind::Struct
585                | DefKind::Ctor(CtorOf::Struct, ..)
586                | DefKind::Union
587                | DefKind::TyAlias
588                | DefKind::AssocTy,
589                _,
590            )
591            | Res::SelfTyParam { .. }
592            | Res::SelfTyAlias { .. }
593            | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
594            _ => {
595                let e = match res {
596                    Res::Def(DefKind::ConstParam, def_id) => {
597                        let const_span = self.tcx.def_span(def_id);
598                        self.tcx.dcx().emit_err(ConstParamInPattern { span, const_span })
599                    }
600                    Res::Def(DefKind::Static { .. }, def_id) => {
601                        let static_span = self.tcx.def_span(def_id);
602                        self.tcx.dcx().emit_err(StaticInPattern { span, static_span })
603                    }
604                    _ => self.tcx.dcx().emit_err(NonConstPath { span }),
605                };
606                PatKind::Error(e)
607            }
608        };
609
610        if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) {
611            debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
612            let annotation = CanonicalUserTypeAnnotation {
613                user_ty: Box::new(user_ty),
614                span,
615                inferred_ty: self.typeck_results.node_type(hir_id),
616            };
617            kind = PatKind::AscribeUserType {
618                subpattern: Box::new(Pat { span, ty, kind }),
619                ascription: Ascription { annotation, variance: ty::Covariant },
620            };
621        }
622
623        kind
624    }
625
626    fn user_args_applied_to_ty_of_hir_id(
627        &self,
628        hir_id: hir::HirId,
629    ) -> Option<ty::CanonicalUserType<'tcx>> {
630        crate::thir::util::user_args_applied_to_ty_of_hir_id(self.typeck_results, hir_id)
631    }
632
633    /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
634    /// it to `const_to_pat`. Any other path (like enum variants without fields)
635    /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
636    #[instrument(skip(self), level = "debug")]
637    fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
638        let ty = self.typeck_results.node_type(id);
639        let res = self.typeck_results.qpath_res(qpath, id);
640
641        let (def_id, user_ty) = match res {
642            Res::Def(DefKind::Const, def_id) => (def_id, None),
643            Res::Def(DefKind::AssocConst, def_id) => {
644                (def_id, self.typeck_results.user_provided_types().get(id))
645            }
646
647            _ => {
648                // The path isn't the name of a constant, so it must actually
649                // be a unit struct or unit variant (e.g. `Option::None`).
650                let kind = self.lower_variant_or_leaf(res, id, span, ty, vec![]);
651                return Box::new(Pat { span, ty, kind });
652            }
653        };
654
655        // Lower the named constant to a THIR pattern.
656        let args = self.typeck_results.node_args(id);
657        let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
658        let subpattern = self.const_to_pat(c, ty, id, span);
659
660        // Wrap the pattern in a marker node to indicate that it is the result
661        // of lowering a named constant. This marker is used for improved
662        // diagnostics in some situations, but has no effect at runtime.
663        let mut pattern = {
664            let kind = PatKind::ExpandedConstant { subpattern, def_id, is_inline: false };
665            Box::new(Pat { span, ty, kind })
666        };
667
668        // If this is an associated constant with an explicit user-written
669        // type, add an ascription node (e.g. `<Foo<'a> as MyTrait>::CONST`).
670        if let Some(&user_ty) = user_ty {
671            let annotation = CanonicalUserTypeAnnotation {
672                user_ty: Box::new(user_ty),
673                span,
674                inferred_ty: self.typeck_results.node_type(id),
675            };
676            let kind = PatKind::AscribeUserType {
677                subpattern: pattern,
678                ascription: Ascription {
679                    annotation,
680                    // Note that we use `Contravariant` here. See the
681                    // `variance` field documentation for details.
682                    variance: ty::Contravariant,
683                },
684            };
685            pattern = Box::new(Pat { span, kind, ty });
686        }
687
688        pattern
689    }
690
691    /// Lowers an inline const block (e.g. `const { 1 + 1 }`) to a pattern.
692    fn lower_inline_const(
693        &mut self,
694        block: &'tcx hir::ConstBlock,
695        id: hir::HirId,
696        span: Span,
697    ) -> PatKind<'tcx> {
698        let tcx = self.tcx;
699        let def_id = block.def_id;
700        let ty = tcx.typeck(def_id).node_type(block.hir_id);
701
702        let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
703        let parent_args =
704            tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
705        let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
706
707        debug_assert!(!args.has_free_regions());
708
709        let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
710        let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
711
712        // Wrap the pattern in a marker node to indicate that it is the result
713        // of lowering an inline const block.
714        PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
715    }
716
717    /// Lowers the kinds of "expression" that can appear in a HIR pattern:
718    /// - Paths (e.g. `FOO`, `foo::BAR`, `Option::None`)
719    /// - Inline const blocks (e.g. `const { 1 + 1 }`)
720    /// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
721    fn lower_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
722        let (lit, neg) = match &expr.kind {
723            hir::PatExprKind::Path(qpath) => {
724                return self.lower_path(qpath, expr.hir_id, expr.span).kind;
725            }
726            hir::PatExprKind::ConstBlock(anon_const) => {
727                return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
728            }
729            hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
730        };
731
732        let ct_ty = self.typeck_results.node_type(expr.hir_id);
733        let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
734        let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
735        self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
736    }
737}