1use std::cmp;
2use std::collections::hash_map::Entry::{Occupied, Vacant};
3
4use rustc_abi::FieldIdx;
5use rustc_ast as ast;
6use rustc_data_structures::fx::FxHashMap;
7use rustc_errors::codes::*;
8use rustc_errors::{
9 Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
10};
11use rustc_hir::def::{CtorKind, DefKind, Res};
12use rustc_hir::def_id::DefId;
13use rustc_hir::pat_util::EnumerateAndAdjustIterator;
14use rustc_hir::{
15 self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
16 PatExprKind, PatKind, expr_needs_parens,
17};
18use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
19use rustc_infer::infer::RegionVariableOrigin;
20use rustc_middle::traits::PatternOriginExpr;
21use rustc_middle::ty::{self, Ty, TypeVisitableExt};
22use rustc_middle::{bug, span_bug};
23use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
24use rustc_session::parse::feature_err;
25use rustc_span::edit_distance::find_best_match_for_name;
26use rustc_span::edition::Edition;
27use rustc_span::source_map::Spanned;
28use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym};
29use rustc_trait_selection::infer::InferCtxtExt;
30use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
31use tracing::{debug, instrument, trace};
32use ty::VariantDef;
33use ty::adjustment::{PatAdjust, PatAdjustment};
34
35use super::report_unexpected_variant_res;
36use crate::expectation::Expectation;
37use crate::gather_locals::DeclOrigin;
38use crate::{FnCtxt, errors};
39
40const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
41This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
42pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \
43this type has no compile-time size. Therefore, all accesses to trait types must be through \
44pointers. If you encounter this error you should try to avoid dereferencing the pointer.
45
46You can read more about trait objects in the Trait Objects section of the Reference: \
47https://doc.rust-lang.org/reference/types.html#trait-objects";
48
49fn is_number(text: &str) -> bool {
50 text.chars().all(|c: char| c.is_digit(10))
51}
52
53#[derive(Copy, Clone)]
57struct TopInfo<'tcx> {
58 expected: Ty<'tcx>,
60 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
64 span: Option<Span>,
87 hir_id: HirId,
89}
90
91#[derive(Copy, Clone)]
92struct PatInfo<'tcx> {
93 binding_mode: ByRef,
94 max_ref_mutbl: MutblCap,
95 top_info: TopInfo<'tcx>,
96 decl_origin: Option<DeclOrigin<'tcx>>,
97
98 current_depth: u32,
100}
101
102impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
103 fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
104 let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
109 let mut count = 0;
110
111 while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
115 cur_expr = inner;
116 count += 1;
117 }
118
119 PatternOriginExpr {
120 peeled_span: cur_expr.span,
121 peeled_count: count,
122 peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
123 }
124 });
125
126 let code = ObligationCauseCode::Pattern {
127 span: ti.span,
128 root_ty: ti.expected,
129 origin_expr: origin_expr_info,
130 };
131 self.cause(cause_span, code)
132 }
133
134 fn demand_eqtype_pat_diag(
135 &'a self,
136 cause_span: Span,
137 expected: Ty<'tcx>,
138 actual: Ty<'tcx>,
139 ti: &TopInfo<'tcx>,
140 ) -> Result<(), Diag<'a>> {
141 self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
142 .map_err(|mut diag| {
143 if let Some(expr) = ti.origin_expr {
144 self.suggest_fn_call(&mut diag, expr, expected, |output| {
145 self.can_eq(self.param_env, output, actual)
146 });
147 }
148 diag
149 })
150 }
151
152 fn demand_eqtype_pat(
153 &self,
154 cause_span: Span,
155 expected: Ty<'tcx>,
156 actual: Ty<'tcx>,
157 ti: &TopInfo<'tcx>,
158 ) -> Result<(), ErrorGuaranteed> {
159 self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit())
160 }
161}
162
163#[derive(Clone, Copy, Debug, PartialEq, Eq)]
165enum AdjustMode {
166 Peel { kind: PeelKind },
169 Pass,
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq)]
175enum PeelKind {
176 ExplicitDerefPat,
179 Implicit {
181 until_adt: Option<DefId>,
184 pat_ref_layers: usize,
187 },
188}
189
190impl AdjustMode {
191 const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
192 AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } }
193 }
194 const fn peel_all() -> AdjustMode {
195 AdjustMode::peel_until_adt(None)
196 }
197}
198
199#[derive(Clone, Copy, Debug, PartialEq, Eq)]
210enum MutblCap {
211 Not,
213
214 WeaklyNot(Option<Span>),
221
222 Mut,
224}
225
226impl MutblCap {
227 #[must_use]
228 fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
229 match self {
230 MutblCap::Not => MutblCap::Not,
231 _ => MutblCap::WeaklyNot(span),
232 }
233 }
234
235 #[must_use]
236 fn as_mutbl(self) -> Mutability {
237 match self {
238 MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
239 MutblCap::Mut => Mutability::Mut,
240 }
241 }
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq)]
250enum InheritedRefMatchRule {
251 EatOuter,
255 EatInner,
258 EatBoth {
261 consider_inherited_ref: bool,
271 },
272}
273
274#[derive(Clone, Copy, Debug)]
283struct ResolvedPat<'tcx> {
284 ty: Ty<'tcx>,
287 kind: ResolvedPatKind<'tcx>,
288}
289
290#[derive(Clone, Copy, Debug)]
291enum ResolvedPatKind<'tcx> {
292 Path { res: Res, pat_res: Res, segments: &'tcx [hir::PathSegment<'tcx>] },
293 Struct { variant: &'tcx VariantDef },
294 TupleStruct { res: Res, variant: &'tcx VariantDef },
295}
296
297impl<'tcx> ResolvedPat<'tcx> {
298 fn adjust_mode(&self) -> AdjustMode {
299 if let ResolvedPatKind::Path { res, .. } = self.kind
300 && matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
301 {
302 AdjustMode::Pass
306 } else {
307 AdjustMode::peel_until_adt(self.ty.ty_adt_def().map(|adt| adt.did()))
311 }
312 }
313}
314
315impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
316 fn downgrade_mut_inside_shared(&self) -> bool {
320 self.tcx.features().ref_pat_eat_one_layer_2024_structural()
323 }
324
325 fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule {
328 if edition.at_least_rust_2024() {
331 if self.tcx.features().ref_pat_eat_one_layer_2024() {
332 InheritedRefMatchRule::EatOuter
333 } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() {
334 InheritedRefMatchRule::EatInner
335 } else {
336 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false }
339 }
340 } else {
341 InheritedRefMatchRule::EatBoth {
342 consider_inherited_ref: self.tcx.features().ref_pat_eat_one_layer_2024()
343 || self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
344 }
345 }
346 }
347
348 fn ref_pat_matches_mut_ref(&self) -> bool {
351 self.tcx.features().ref_pat_eat_one_layer_2024()
354 || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
355 }
356
357 pub(crate) fn check_pat_top(
366 &self,
367 pat: &'tcx Pat<'tcx>,
368 expected: Ty<'tcx>,
369 span: Option<Span>,
370 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
371 decl_origin: Option<DeclOrigin<'tcx>>,
372 ) {
373 let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
374 let pat_info = PatInfo {
375 binding_mode: ByRef::No,
376 max_ref_mutbl: MutblCap::Mut,
377 top_info,
378 decl_origin,
379 current_depth: 0,
380 };
381 self.check_pat(pat, expected, pat_info);
382 }
383
384 #[instrument(level = "debug", skip(self, pat_info))]
390 fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
391 let opt_path_res = match pat.kind {
394 PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
395 Some(self.resolve_pat_path(*hir_id, *span, qpath))
396 }
397 PatKind::Struct(ref qpath, ..) => Some(self.resolve_pat_struct(pat, qpath)),
398 PatKind::TupleStruct(ref qpath, ..) => Some(self.resolve_pat_tuple_struct(pat, qpath)),
399 _ => None,
400 };
401 let adjust_mode = self.calc_adjust_mode(pat, opt_path_res);
402 let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
403 self.write_ty(pat.hir_id, ty);
404
405 if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id)
408 && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref)
409 {
410 self.register_deref_mut_bounds_if_needed(
411 pat.span,
412 pat,
413 derefed_tys.iter().filter_map(|adjust| match adjust.kind {
414 PatAdjust::OverloadedDeref => Some(adjust.source),
415 PatAdjust::BuiltinDeref => None,
416 }),
417 );
418 }
419
420 }
462
463 fn check_pat_inner(
465 &self,
466 pat: &'tcx Pat<'tcx>,
467 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
468 adjust_mode: AdjustMode,
469 expected: Ty<'tcx>,
470 pat_info: PatInfo<'tcx>,
471 ) -> Ty<'tcx> {
472 #[cfg(debug_assertions)]
473 if pat_info.binding_mode == ByRef::Yes(Mutability::Mut)
474 && pat_info.max_ref_mutbl != MutblCap::Mut
475 && self.downgrade_mut_inside_shared()
476 {
477 span_bug!(pat.span, "Pattern mutability cap violated!");
478 }
479
480 let expected = if let AdjustMode::Peel { .. } = adjust_mode
482 && pat.default_binding_modes
483 {
484 self.try_structurally_resolve_type(pat.span, expected)
485 } else {
486 expected
487 };
488 let old_pat_info = pat_info;
489 let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
490
491 match pat.kind {
492 _ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
495 && pat.default_binding_modes
496 && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
497 && self.should_peel_ref(peel_kind, expected) =>
498 {
499 debug!("inspecting {:?}", expected);
500
501 debug!("current discriminant is Ref, inserting implicit deref");
502 self.typeck_results
504 .borrow_mut()
505 .pat_adjustments_mut()
506 .entry(pat.hir_id)
507 .or_default()
508 .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
509
510 let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
511 ByRef::No |
514 ByRef::Yes(Mutability::Mut) => inner_mutability,
516 ByRef::Yes(Mutability::Not) => Mutability::Not,
519 });
520
521 let mut max_ref_mutbl = pat_info.max_ref_mutbl;
522 if self.downgrade_mut_inside_shared() {
523 binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
524 }
525 if binding_mode == ByRef::Yes(Mutability::Not) {
526 max_ref_mutbl = MutblCap::Not;
527 }
528 debug!("default binding mode is now {:?}", binding_mode);
529
530 let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info };
532 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
534 }
535 _ if self.tcx.features().deref_patterns()
538 && let AdjustMode::Peel { kind: peel_kind } = adjust_mode
539 && pat.default_binding_modes
540 && self.should_peel_smart_pointer(peel_kind, expected) =>
541 {
542 debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
543 let mut inner_ty = self.deref_pat_target(pat.span, expected);
546 let mut typeck_results = self.typeck_results.borrow_mut();
550 let mut pat_adjustments_table = typeck_results.pat_adjustments_mut();
551 let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default();
552 if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) {
559 pat_adjustments
561 .push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected });
562 } else {
563 let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected);
564 inner_ty = Ty::new_error(self.tcx, guar);
565 }
566 drop(typeck_results);
567
568 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, old_pat_info)
571 }
572 PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
573 PatKind::Never => expected,
575 PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), hir_id, .. }) => {
576 let ty = match opt_path_res.unwrap() {
577 Ok(ref pr) => {
578 self.check_pat_path(pat.hir_id, pat.span, pr, expected, &pat_info.top_info)
579 }
580 Err(guar) => Ty::new_error(self.tcx, guar),
581 };
582 self.write_ty(*hir_id, ty);
583 ty
584 }
585 PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info),
586 PatKind::Range(lhs, rhs, _) => {
587 self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info)
588 }
589 PatKind::Binding(ba, var_id, ident, sub) => {
590 self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
591 }
592 PatKind::TupleStruct(ref qpath, subpats, ddpos) => match opt_path_res.unwrap() {
593 Ok(ResolvedPat { ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) => self
594 .check_pat_tuple_struct(
595 pat, qpath, subpats, ddpos, res, ty, variant, expected, pat_info,
596 ),
597 Err(guar) => {
598 let ty_err = Ty::new_error(self.tcx, guar);
599 for subpat in subpats {
600 self.check_pat(subpat, ty_err, pat_info);
601 }
602 ty_err
603 }
604 Ok(pr) => span_bug!(pat.span, "tuple struct pattern resolved to {pr:?}"),
605 },
606 PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() {
607 Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self
608 .check_pat_struct(
609 pat,
610 fields,
611 has_rest_pat.is_some(),
612 ty,
613 variant,
614 expected,
615 pat_info,
616 ),
617 Err(guar) => {
618 let ty_err = Ty::new_error(self.tcx, guar);
619 for field in fields {
620 self.check_pat(field.pat, ty_err, pat_info);
621 }
622 ty_err
623 }
624 Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
625 },
626 PatKind::Guard(pat, cond) => {
627 self.check_pat(pat, expected, pat_info);
628 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
629 expected
630 }
631 PatKind::Or(pats) => {
632 for pat in pats {
633 self.check_pat(pat, expected, pat_info);
634 }
635 expected
636 }
637 PatKind::Tuple(elements, ddpos) => {
638 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
639 }
640 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
641 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
642 PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
643 PatKind::Slice(before, slice, after) => {
644 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
645 }
646 }
647 }
648
649 fn calc_adjust_mode(
653 &self,
654 pat: &'tcx Pat<'tcx>,
655 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
656 ) -> AdjustMode {
657 match &pat.kind {
658 PatKind::Tuple(..) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::peel_all(),
661 PatKind::Box(_) | PatKind::Deref(_) => {
665 AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat }
666 }
667 PatKind::Never => AdjustMode::peel_all(),
669 PatKind::Struct(..)
671 | PatKind::TupleStruct(..)
672 | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
673 opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
675 }
676
677 PatKind::Expr(lt) => {
682 if cfg!(debug_assertions)
685 && self.tcx.features().deref_patterns()
686 && !matches!(lt.kind, PatExprKind::Lit { .. })
687 {
688 span_bug!(
689 lt.span,
690 "FIXME(deref_patterns): adjust mode unimplemented for {:?}",
691 lt.kind
692 );
693 }
694 let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
696 if self.tcx.features().deref_patterns() {
698 let mut peeled_ty = lit_ty;
699 let mut pat_ref_layers = 0;
700 while let ty::Ref(_, inner_ty, mutbl) =
701 *self.try_structurally_resolve_type(pat.span, peeled_ty).kind()
702 {
703 debug_assert!(mutbl.is_not());
705 pat_ref_layers += 1;
706 peeled_ty = inner_ty;
707 }
708 AdjustMode::Peel {
709 kind: PeelKind::Implicit { until_adt: None, pat_ref_layers },
710 }
711 } else {
712 if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
713 }
714 }
715
716 PatKind::Ref(..)
718 | PatKind::Missing
720 | PatKind::Wild
722 | PatKind::Err(_)
724 | PatKind::Binding(..)
729 | PatKind::Or(_)
733 | PatKind::Guard(..) => AdjustMode::Pass,
735 }
736 }
737
738 fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
740 debug_assert!(expected.is_ref());
741 let pat_ref_layers = match peel_kind {
742 PeelKind::ExplicitDerefPat => 0,
743 PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
744 };
745
746 if pat_ref_layers == 0 {
749 return true;
750 }
751 debug_assert!(
752 self.tcx.features().deref_patterns(),
753 "Peeling for patterns with reference types is gated by `deref_patterns`."
754 );
755
756 let mut expected_ref_layers = 0;
762 while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
763 if mutbl.is_mut() {
764 return true;
767 }
768 expected_ref_layers += 1;
769 expected = inner_ty;
770 }
771 pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
772 }
773
774 fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
776 if let PeelKind::Implicit { until_adt, .. } = peel_kind
778 && let ty::Adt(scrutinee_adt, _) = *expected.kind()
783 && until_adt != Some(scrutinee_adt.did())
786 && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
791 && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
792 {
793 true
794 } else {
795 false
796 }
797 }
798
799 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
800 let ty = match <.kind {
801 rustc_hir::PatExprKind::Lit { lit, negated } => {
802 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
803 if *negated {
804 self.register_bound(
805 ty,
806 self.tcx.require_lang_item(LangItem::Neg, lt.span),
807 ObligationCause::dummy_with_span(lt.span),
808 );
809 }
810 ty
811 }
812 rustc_hir::PatExprKind::ConstBlock(c) => {
813 self.check_expr_const_block(c, Expectation::NoExpectation)
814 }
815 rustc_hir::PatExprKind::Path(qpath) => {
816 let (res, opt_ty, segments) =
817 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
818 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
819 }
820 };
821 self.write_ty(lt.hir_id, ty);
822 ty
823 }
824
825 fn check_pat_lit(
826 &self,
827 span: Span,
828 lt: &hir::PatExpr<'tcx>,
829 expected: Ty<'tcx>,
830 ti: &TopInfo<'tcx>,
831 ) -> Ty<'tcx> {
832 let ty = self.node_ty(lt.hir_id);
835
836 let mut pat_ty = ty;
841 if let hir::PatExprKind::Lit {
842 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
843 } = lt.kind
844 {
845 let tcx = self.tcx;
846 let expected = self.structurally_resolve_type(span, expected);
847 match *expected.kind() {
848 ty::Ref(_, inner_ty, _)
850 if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
851 {
852 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
853 pat_ty = Ty::new_imm_ref(
854 tcx,
855 tcx.lifetimes.re_static,
856 Ty::new_slice(tcx, tcx.types.u8),
857 );
858 }
859 ty::Array(..) if tcx.features().deref_patterns() => {
861 pat_ty = match *ty.kind() {
862 ty::Ref(_, inner_ty, _) => inner_ty,
863 _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
864 }
865 }
866 ty::Slice(..) if tcx.features().deref_patterns() => {
868 pat_ty = Ty::new_slice(tcx, tcx.types.u8);
869 }
870 _ => {}
872 }
873 }
874
875 if self.tcx.features().deref_patterns()
878 && let hir::PatExprKind::Lit {
879 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
880 } = lt.kind
881 && self.try_structurally_resolve_type(span, expected).is_str()
882 {
883 pat_ty = self.tcx.types.str_;
884 }
885
886 if self.tcx.features().string_deref_patterns()
887 && let hir::PatExprKind::Lit {
888 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
889 } = lt.kind
890 {
891 let tcx = self.tcx;
892 let expected = self.resolve_vars_if_possible(expected);
893 pat_ty = match expected.kind() {
894 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
895 ty::Str => Ty::new_static_str(tcx),
896 _ => pat_ty,
897 };
898 }
899
900 let cause = self.pattern_cause(ti, span);
911 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
912 err.emit();
913 }
914
915 pat_ty
916 }
917
918 fn check_pat_range(
919 &self,
920 span: Span,
921 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
922 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
923 expected: Ty<'tcx>,
924 ti: &TopInfo<'tcx>,
925 ) -> Ty<'tcx> {
926 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
927 None => None,
928 Some(expr) => {
929 let ty = self.check_pat_expr_unadjusted(expr);
930 let ty = self.try_structurally_resolve_type(expr.span, ty);
937 let fail =
938 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
939 Some((fail, ty, expr.span))
940 }
941 };
942 let mut lhs = calc_side(lhs);
943 let mut rhs = calc_side(rhs);
944
945 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
946 let guar = self.emit_err_pat_range(span, lhs, rhs);
949 return Ty::new_error(self.tcx, guar);
950 }
951
952 let demand_eqtype = |x: &mut _, y| {
955 if let Some((ref mut fail, x_ty, x_span)) = *x
956 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
957 {
958 if let Some((_, y_ty, y_span)) = y {
959 self.endpoint_has_type(&mut err, y_span, y_ty);
960 }
961 err.emit();
962 *fail = true;
963 }
964 };
965 demand_eqtype(&mut lhs, rhs);
966 demand_eqtype(&mut rhs, lhs);
967
968 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
969 return Ty::new_misc_error(self.tcx);
970 }
971
972 let ty = self.structurally_resolve_type(span, expected);
977 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
978 if let Some((ref mut fail, _, _)) = lhs {
979 *fail = true;
980 }
981 if let Some((ref mut fail, _, _)) = rhs {
982 *fail = true;
983 }
984 let guar = self.emit_err_pat_range(span, lhs, rhs);
985 return Ty::new_error(self.tcx, guar);
986 }
987 ty
988 }
989
990 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
991 if !ty.references_error() {
992 err.span_label(span, format!("this is of type `{ty}`"));
993 }
994 }
995
996 fn emit_err_pat_range(
997 &self,
998 span: Span,
999 lhs: Option<(bool, Ty<'tcx>, Span)>,
1000 rhs: Option<(bool, Ty<'tcx>, Span)>,
1001 ) -> ErrorGuaranteed {
1002 let span = match (lhs, rhs) {
1003 (Some((true, ..)), Some((true, ..))) => span,
1004 (Some((true, _, sp)), _) => sp,
1005 (_, Some((true, _, sp))) => sp,
1006 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
1007 };
1008 let mut err = struct_span_code_err!(
1009 self.dcx(),
1010 span,
1011 E0029,
1012 "only `char` and numeric types are allowed in range patterns"
1013 );
1014 let msg = |ty| {
1015 let ty = self.resolve_vars_if_possible(ty);
1016 format!("this is of type `{ty}` but it should be `char` or numeric")
1017 };
1018 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
1019 err.span_label(first_span, msg(first_ty));
1020 if let Some((_, ty, sp)) = second {
1021 let ty = self.resolve_vars_if_possible(ty);
1022 self.endpoint_has_type(&mut err, sp, ty);
1023 }
1024 };
1025 match (lhs, rhs) {
1026 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
1027 err.span_label(lhs_sp, msg(lhs_ty));
1028 err.span_label(rhs_sp, msg(rhs_ty));
1029 }
1030 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
1031 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
1032 _ => span_bug!(span, "Impossible, verified above."),
1033 }
1034 if (lhs, rhs).references_error() {
1035 err.downgrade_to_delayed_bug();
1036 }
1037 if self.tcx.sess.teach(err.code.unwrap()) {
1038 err.note(
1039 "In a match expression, only numbers and characters can be matched \
1040 against a range. This is because the compiler checks that the range \
1041 is non-empty at compile-time, and is unable to evaluate arbitrary \
1042 comparison functions. If you want to capture values of an orderable \
1043 type between two end-points, you can use a guard.",
1044 );
1045 }
1046 err.emit()
1047 }
1048
1049 fn check_pat_ident(
1050 &self,
1051 pat: &'tcx Pat<'tcx>,
1052 user_bind_annot: BindingMode,
1053 var_id: HirId,
1054 ident: Ident,
1055 sub: Option<&'tcx Pat<'tcx>>,
1056 expected: Ty<'tcx>,
1057 pat_info: PatInfo<'tcx>,
1058 ) -> Ty<'tcx> {
1059 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
1060
1061 let bm = match user_bind_annot {
1063 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
1064 if pat.span.at_least_rust_2024()
1067 && (self.tcx.features().ref_pat_eat_one_layer_2024()
1068 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
1069 {
1070 if !self.tcx.features().mut_ref() {
1071 feature_err(
1072 &self.tcx.sess,
1073 sym::mut_ref,
1074 pat.span.until(ident.span),
1075 "binding cannot be both mutable and by-reference",
1076 )
1077 .emit();
1078 }
1079
1080 BindingMode(def_br, Mutability::Mut)
1081 } else {
1082 self.add_rust_2024_migration_desugared_pat(
1084 pat_info.top_info.hir_id,
1085 pat,
1086 't', def_br_mutbl,
1088 );
1089 BindingMode(ByRef::No, Mutability::Mut)
1090 }
1091 }
1092 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
1093 BindingMode(ByRef::Yes(user_br_mutbl), _) => {
1094 if let ByRef::Yes(def_br_mutbl) = def_br {
1095 self.add_rust_2024_migration_desugared_pat(
1097 pat_info.top_info.hir_id,
1098 pat,
1099 match user_br_mutbl {
1100 Mutability::Not => 'f', Mutability::Mut => 't', },
1103 def_br_mutbl,
1104 );
1105 }
1106 user_bind_annot
1107 }
1108 };
1109
1110 if bm.0 == ByRef::Yes(Mutability::Mut)
1111 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1112 {
1113 let mut err = struct_span_code_err!(
1114 self.dcx(),
1115 ident.span,
1116 E0596,
1117 "cannot borrow as mutable inside an `&` pattern"
1118 );
1119
1120 if let Some(span) = and_pat_span {
1121 err.span_suggestion(
1122 span,
1123 "replace this `&` with `&mut`",
1124 "&mut ",
1125 Applicability::MachineApplicable,
1126 );
1127 }
1128 err.emit();
1129 }
1130
1131 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1133
1134 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1135
1136 let local_ty = self.local_ty(pat.span, pat.hir_id);
1137 let eq_ty = match bm.0 {
1138 ByRef::Yes(mutbl) => {
1139 self.new_ref_ty(pat.span, mutbl, expected)
1147 }
1148 ByRef::No => expected, };
1151
1152 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1154
1155 if var_id != pat.hir_id {
1158 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1159 }
1160
1161 if let Some(p) = sub {
1162 self.check_pat(p, expected, pat_info);
1163 }
1164
1165 local_ty
1166 }
1167
1168 fn check_binding_alt_eq_ty(
1172 &self,
1173 ba: BindingMode,
1174 span: Span,
1175 var_id: HirId,
1176 ty: Ty<'tcx>,
1177 ti: &TopInfo<'tcx>,
1178 ) {
1179 let var_ty = self.local_ty(span, var_id);
1180 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1181 let var_ty = self.resolve_vars_if_possible(var_ty);
1182 let msg = format!("first introduced with type `{var_ty}` here");
1183 err.span_label(self.tcx.hir_span(var_id), msg);
1184 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1185 matches!(
1186 n,
1187 hir::Node::Expr(hir::Expr {
1188 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1189 ..
1190 })
1191 )
1192 });
1193 let pre = if in_match { "in the same arm, " } else { "" };
1194 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1195 self.suggest_adding_missing_ref_or_removing_ref(
1196 &mut err,
1197 span,
1198 var_ty,
1199 self.resolve_vars_if_possible(ty),
1200 ba,
1201 );
1202 err.emit();
1203 }
1204 }
1205
1206 fn suggest_adding_missing_ref_or_removing_ref(
1207 &self,
1208 err: &mut Diag<'_>,
1209 span: Span,
1210 expected: Ty<'tcx>,
1211 actual: Ty<'tcx>,
1212 ba: BindingMode,
1213 ) {
1214 match (expected.kind(), actual.kind(), ba) {
1215 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1216 if self.can_eq(self.param_env, *inner_ty, actual) =>
1217 {
1218 err.span_suggestion_verbose(
1219 span.shrink_to_lo(),
1220 "consider adding `ref`",
1221 "ref ",
1222 Applicability::MaybeIncorrect,
1223 );
1224 }
1225 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1226 if self.can_eq(self.param_env, expected, *inner_ty) =>
1227 {
1228 err.span_suggestion_verbose(
1229 span.with_hi(span.lo() + BytePos(4)),
1230 "consider removing `ref`",
1231 "",
1232 Applicability::MaybeIncorrect,
1233 );
1234 }
1235 _ => (),
1236 }
1237 }
1238
1239 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1241 let tcx = self.tcx;
1242 if let PatKind::Ref(inner, mutbl) = pat.kind
1243 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1244 {
1245 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1246 debug!(?inner, ?pat, ?binding_parent);
1247
1248 let mutability = match mutbl {
1249 ast::Mutability::Mut => "mut",
1250 ast::Mutability::Not => "",
1251 };
1252
1253 let mut_var_suggestion = 'block: {
1254 if mutbl.is_not() {
1255 break 'block None;
1256 }
1257
1258 let ident_kind = match binding_parent {
1259 hir::Node::Param(_) => "parameter",
1260 hir::Node::LetStmt(_) => "variable",
1261 hir::Node::Arm(_) => "binding",
1262
1263 hir::Node::Pat(Pat { kind, .. }) => match kind {
1266 PatKind::Struct(..)
1267 | PatKind::TupleStruct(..)
1268 | PatKind::Or(..)
1269 | PatKind::Guard(..)
1270 | PatKind::Tuple(..)
1271 | PatKind::Slice(..) => "binding",
1272
1273 PatKind::Missing
1274 | PatKind::Wild
1275 | PatKind::Never
1276 | PatKind::Binding(..)
1277 | PatKind::Box(..)
1278 | PatKind::Deref(_)
1279 | PatKind::Ref(..)
1280 | PatKind::Expr(..)
1281 | PatKind::Range(..)
1282 | PatKind::Err(_) => break 'block None,
1283 },
1284
1285 _ => break 'block None,
1287 };
1288
1289 Some((
1290 pat.span,
1291 format!("to declare a mutable {ident_kind} use"),
1292 format!("mut {binding}"),
1293 ))
1294 };
1295
1296 match binding_parent {
1297 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1300 err.multipart_suggestion_verbose(
1301 format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
1302 vec![
1303 (pat.span.until(inner.span), "".to_owned()),
1304 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1305 ],
1306 Applicability::MachineApplicable
1307 );
1308
1309 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1310 err.span_note(sp, format!("{msg}: `{sugg}`"));
1311 }
1312 }
1313 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1314 for i in pat_arr.iter() {
1315 if let PatKind::Ref(the_ref, _) = i.kind
1316 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1317 {
1318 let BindingMode(_, mtblty) = mt;
1319 err.span_suggestion_verbose(
1320 i.span,
1321 format!("consider removing `&{mutability}` from the pattern"),
1322 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1323 Applicability::MaybeIncorrect,
1324 );
1325 }
1326 }
1327 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1328 err.span_note(sp, format!("{msg}: `{sugg}`"));
1329 }
1330 }
1331 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1332 err.span_suggestion_verbose(
1334 pat.span.until(inner.span),
1335 format!("consider removing `&{mutability}` from the pattern"),
1336 "",
1337 Applicability::MaybeIncorrect,
1338 );
1339
1340 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1341 err.span_note(sp, format!("{msg}: `{sugg}`"));
1342 }
1343 }
1344 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1345 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1346 }
1347 _ => {} }
1349 }
1350 }
1351
1352 fn check_dereferenceable(
1353 &self,
1354 span: Span,
1355 expected: Ty<'tcx>,
1356 inner: &Pat<'_>,
1357 ) -> Result<(), ErrorGuaranteed> {
1358 if let PatKind::Binding(..) = inner.kind
1359 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1360 && let ty::Dynamic(..) = pointee_ty.kind()
1361 {
1362 let type_str = self.ty_to_string(expected);
1365 let mut err = struct_span_code_err!(
1366 self.dcx(),
1367 span,
1368 E0033,
1369 "type `{}` cannot be dereferenced",
1370 type_str
1371 );
1372 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1373 if self.tcx.sess.teach(err.code.unwrap()) {
1374 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1375 }
1376 return Err(err.emit());
1377 }
1378 Ok(())
1379 }
1380
1381 fn resolve_pat_struct(
1382 &self,
1383 pat: &'tcx Pat<'tcx>,
1384 qpath: &hir::QPath<'tcx>,
1385 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1386 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1388 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1389 }
1390
1391 fn check_pat_struct(
1392 &self,
1393 pat: &'tcx Pat<'tcx>,
1394 fields: &'tcx [hir::PatField<'tcx>],
1395 has_rest_pat: bool,
1396 pat_ty: Ty<'tcx>,
1397 variant: &'tcx VariantDef,
1398 expected: Ty<'tcx>,
1399 pat_info: PatInfo<'tcx>,
1400 ) -> Ty<'tcx> {
1401 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1403
1404 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1406 Ok(()) => pat_ty,
1407 Err(guar) => Ty::new_error(self.tcx, guar),
1408 }
1409 }
1410
1411 fn resolve_pat_path(
1412 &self,
1413 path_id: HirId,
1414 span: Span,
1415 qpath: &'tcx hir::QPath<'_>,
1416 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1417 let tcx = self.tcx;
1418
1419 let (res, opt_ty, segments) =
1420 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1421 match res {
1422 Res::Err => {
1423 let e =
1424 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1425 self.set_tainted_by_errors(e);
1426 return Err(e);
1427 }
1428 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1429 let expected = "unit struct, unit variant or constant";
1430 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1431 return Err(e);
1432 }
1433 Res::SelfCtor(def_id) => {
1434 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1435 && adt_def.is_struct()
1436 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1437 {
1438 } else {
1440 let e = report_unexpected_variant_res(
1441 tcx,
1442 res,
1443 None,
1444 qpath,
1445 span,
1446 E0533,
1447 "unit struct",
1448 );
1449 return Err(e);
1450 }
1451 }
1452 Res::Def(
1453 DefKind::Ctor(_, CtorKind::Const)
1454 | DefKind::Const
1455 | DefKind::AssocConst
1456 | DefKind::ConstParam,
1457 _,
1458 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1460 }
1461
1462 let (pat_ty, pat_res) =
1464 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1465 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1466 }
1467
1468 fn check_pat_path(
1469 &self,
1470 pat_id_for_diag: HirId,
1471 span: Span,
1472 resolved: &ResolvedPat<'tcx>,
1473 expected: Ty<'tcx>,
1474 ti: &TopInfo<'tcx>,
1475 ) -> Ty<'tcx> {
1476 if let Err(err) =
1477 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1478 {
1479 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1480 }
1481 resolved.ty
1482 }
1483
1484 fn maybe_suggest_range_literal(
1485 &self,
1486 e: &mut Diag<'_>,
1487 opt_def_id: Option<hir::def_id::DefId>,
1488 ident: Ident,
1489 ) -> bool {
1490 match opt_def_id {
1491 Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
1492 Some(hir::Node::Item(hir::Item {
1493 kind: hir::ItemKind::Const(_, _, _, body_id),
1494 ..
1495 })) => match self.tcx.hir_node(body_id.hir_id) {
1496 hir::Node::Expr(expr) => {
1497 if hir::is_range_literal(expr) {
1498 let span = self.tcx.hir_span(body_id.hir_id);
1499 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1500 e.span_suggestion_verbose(
1501 ident.span,
1502 "you may want to move the range into the match block",
1503 snip,
1504 Applicability::MachineApplicable,
1505 );
1506 return true;
1507 }
1508 }
1509 }
1510 _ => (),
1511 },
1512 _ => (),
1513 },
1514 _ => (),
1515 }
1516 false
1517 }
1518
1519 fn emit_bad_pat_path(
1520 &self,
1521 mut e: Diag<'_>,
1522 hir_id: HirId,
1523 pat_span: Span,
1524 resolved_pat: &ResolvedPat<'tcx>,
1525 ) {
1526 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1527 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1528 };
1529
1530 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1531 e.span_label(span, format!("{} defined here", res.descr()));
1532 if let [hir::PathSegment { ident, .. }] = &*segments {
1533 e.span_label(
1534 pat_span,
1535 format!(
1536 "`{}` is interpreted as {} {}, not a new binding",
1537 ident,
1538 res.article(),
1539 res.descr(),
1540 ),
1541 );
1542 match self.tcx.parent_hir_node(hir_id) {
1543 hir::Node::PatField(..) => {
1544 e.span_suggestion_verbose(
1545 ident.span.shrink_to_hi(),
1546 "bind the struct field to a different name instead",
1547 format!(": other_{}", ident.as_str().to_lowercase()),
1548 Applicability::HasPlaceholders,
1549 );
1550 }
1551 _ => {
1552 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1553 ty::Adt(def, _) => match res {
1554 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1555 _ => (None, None),
1556 },
1557 _ => (None, None),
1558 };
1559
1560 let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) {
1561 Some(
1562 LangItem::Range
1563 | LangItem::RangeFrom
1564 | LangItem::RangeTo
1565 | LangItem::RangeFull
1566 | LangItem::RangeInclusiveStruct
1567 | LangItem::RangeToInclusive,
1568 ) => true,
1569 _ => false,
1570 };
1571 if is_range {
1572 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1573 let msg = "constants only support matching by type, \
1574 if you meant to match against a range of values, \
1575 consider using a range pattern like `min ..= max` in the match block";
1576 e.note(msg);
1577 }
1578 } else {
1579 let msg = "introduce a new binding instead";
1580 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1581 e.span_suggestion(
1582 ident.span,
1583 msg,
1584 sugg,
1585 Applicability::HasPlaceholders,
1586 );
1587 }
1588 }
1589 };
1590 }
1591 }
1592 e.emit();
1593 }
1594
1595 fn resolve_pat_tuple_struct(
1596 &self,
1597 pat: &'tcx Pat<'tcx>,
1598 qpath: &'tcx hir::QPath<'tcx>,
1599 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1600 let tcx = self.tcx;
1601 let report_unexpected_res = |res: Res| {
1602 let expected = "tuple struct or tuple variant";
1603 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1604 Err(e)
1605 };
1606
1607 let (res, opt_ty, segments) =
1609 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1610 if res == Res::Err {
1611 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1612 self.set_tainted_by_errors(e);
1613 return Err(e);
1614 }
1615
1616 let (pat_ty, res) =
1618 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1619 if !pat_ty.is_fn() {
1620 return report_unexpected_res(res);
1621 }
1622
1623 let variant = match res {
1624 Res::Err => {
1625 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1626 }
1627 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1628 return report_unexpected_res(res);
1629 }
1630 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1631 _ => bug!("unexpected pattern resolution: {:?}", res),
1632 };
1633
1634 let pat_ty = pat_ty.fn_sig(tcx).output();
1636 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1637
1638 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1639 }
1640
1641 fn check_pat_tuple_struct(
1642 &self,
1643 pat: &'tcx Pat<'tcx>,
1644 qpath: &'tcx hir::QPath<'tcx>,
1645 subpats: &'tcx [Pat<'tcx>],
1646 ddpos: hir::DotDotPos,
1647 res: Res,
1648 pat_ty: Ty<'tcx>,
1649 variant: &'tcx VariantDef,
1650 expected: Ty<'tcx>,
1651 pat_info: PatInfo<'tcx>,
1652 ) -> Ty<'tcx> {
1653 let tcx = self.tcx;
1654 let on_error = |e| {
1655 for pat in subpats {
1656 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1657 }
1658 };
1659
1660 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1662 let had_err = diag.map_err(|diag| diag.emit());
1663
1664 if subpats.len() == variant.fields.len()
1666 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1667 {
1668 let ty::Adt(_, args) = pat_ty.kind() else {
1669 bug!("unexpected pattern type {:?}", pat_ty);
1670 };
1671 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1672 let field = &variant.fields[FieldIdx::from_usize(i)];
1673 let field_ty = self.field_ty(subpat.span, field, args);
1674 self.check_pat(subpat, field_ty, pat_info);
1675
1676 self.tcx.check_stability(
1677 variant.fields[FieldIdx::from_usize(i)].did,
1678 Some(subpat.hir_id),
1679 subpat.span,
1680 None,
1681 );
1682 }
1683 if let Err(e) = had_err {
1684 on_error(e);
1685 return Ty::new_error(tcx, e);
1686 }
1687 } else {
1688 let e = self.emit_err_pat_wrong_number_of_fields(
1689 pat.span,
1690 res,
1691 qpath,
1692 subpats,
1693 &variant.fields.raw,
1694 expected,
1695 had_err,
1696 );
1697 on_error(e);
1698 return Ty::new_error(tcx, e);
1699 }
1700 pat_ty
1701 }
1702
1703 fn emit_err_pat_wrong_number_of_fields(
1704 &self,
1705 pat_span: Span,
1706 res: Res,
1707 qpath: &hir::QPath<'_>,
1708 subpats: &'tcx [Pat<'tcx>],
1709 fields: &'tcx [ty::FieldDef],
1710 expected: Ty<'tcx>,
1711 had_err: Result<(), ErrorGuaranteed>,
1712 ) -> ErrorGuaranteed {
1713 let subpats_ending = pluralize!(subpats.len());
1714 let fields_ending = pluralize!(fields.len());
1715
1716 let subpat_spans = if subpats.is_empty() {
1717 vec![pat_span]
1718 } else {
1719 subpats.iter().map(|p| p.span).collect()
1720 };
1721 let last_subpat_span = *subpat_spans.last().unwrap();
1722 let res_span = self.tcx.def_span(res.def_id());
1723 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1724 let field_def_spans = if fields.is_empty() {
1725 vec![res_span]
1726 } else {
1727 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1728 };
1729 let last_field_def_span = *field_def_spans.last().unwrap();
1730
1731 let mut err = struct_span_code_err!(
1732 self.dcx(),
1733 MultiSpan::from_spans(subpat_spans),
1734 E0023,
1735 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1736 subpats.len(),
1737 subpats_ending,
1738 res.descr(),
1739 fields.len(),
1740 fields_ending,
1741 );
1742 err.span_label(
1743 last_subpat_span,
1744 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1745 );
1746 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1747 err.span_label(qpath.span(), "");
1748 }
1749 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1750 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1751 }
1752 for span in &field_def_spans[..field_def_spans.len() - 1] {
1753 err.span_label(*span, "");
1754 }
1755 err.span_label(
1756 last_field_def_span,
1757 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1758 );
1759
1760 let missing_parentheses = match (expected.kind(), fields, had_err) {
1765 (ty::Adt(_, args), [field], Ok(())) => {
1769 let field_ty = self.field_ty(pat_span, field, args);
1770 match field_ty.kind() {
1771 ty::Tuple(fields) => fields.len() == subpats.len(),
1772 _ => false,
1773 }
1774 }
1775 _ => false,
1776 };
1777 if missing_parentheses {
1778 let (left, right) = match subpats {
1779 [] => (qpath.span().shrink_to_hi(), pat_span),
1788 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1797 };
1798 err.multipart_suggestion(
1799 "missing parentheses",
1800 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1801 Applicability::MachineApplicable,
1802 );
1803 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1804 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1805 let all_fields_span = match subpats {
1806 [] => after_fields_span,
1807 [field] => field.span,
1808 [first, .., last] => first.span.to(last.span),
1809 };
1810
1811 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1813 let first_tail_wildcard =
1814 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1815 (None, PatKind::Wild) => Some(pos),
1816 (Some(_), PatKind::Wild) => acc,
1817 _ => None,
1818 });
1819 let tail_span = match first_tail_wildcard {
1820 None => after_fields_span,
1821 Some(0) => subpats[0].span.to(after_fields_span),
1822 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1823 };
1824
1825 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1827 if !subpats.is_empty() {
1828 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1829 }
1830
1831 err.span_suggestion_verbose(
1832 after_fields_span,
1833 "use `_` to explicitly ignore each field",
1834 wildcard_sugg,
1835 Applicability::MaybeIncorrect,
1836 );
1837
1838 if fields.len() - subpats.len() > 1 || all_wildcards {
1841 if subpats.is_empty() || all_wildcards {
1842 err.span_suggestion_verbose(
1843 all_fields_span,
1844 "use `..` to ignore all fields",
1845 "..",
1846 Applicability::MaybeIncorrect,
1847 );
1848 } else {
1849 err.span_suggestion_verbose(
1850 tail_span,
1851 "use `..` to ignore the rest of the fields",
1852 ", ..",
1853 Applicability::MaybeIncorrect,
1854 );
1855 }
1856 }
1857 }
1858
1859 err.emit()
1860 }
1861
1862 fn check_pat_tuple(
1863 &self,
1864 span: Span,
1865 elements: &'tcx [Pat<'tcx>],
1866 ddpos: hir::DotDotPos,
1867 expected: Ty<'tcx>,
1868 pat_info: PatInfo<'tcx>,
1869 ) -> Ty<'tcx> {
1870 let tcx = self.tcx;
1871 let mut expected_len = elements.len();
1872 if ddpos.as_opt_usize().is_some() {
1873 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1875 expected_len = tys.len();
1876 }
1877 }
1878 let max_len = cmp::max(expected_len, elements.len());
1879
1880 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1881 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1882 let pat_ty = Ty::new_tup(tcx, element_tys);
1883 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
1884 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1887 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1888 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1889 }
1890 Ty::new_tup_from_iter(tcx, element_tys_iter)
1891 } else {
1892 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1893 self.check_pat(elem, element_tys[i], pat_info);
1894 }
1895 pat_ty
1896 }
1897 }
1898
1899 fn check_struct_pat_fields(
1900 &self,
1901 adt_ty: Ty<'tcx>,
1902 pat: &'tcx Pat<'tcx>,
1903 variant: &'tcx ty::VariantDef,
1904 fields: &'tcx [hir::PatField<'tcx>],
1905 has_rest_pat: bool,
1906 pat_info: PatInfo<'tcx>,
1907 ) -> Result<(), ErrorGuaranteed> {
1908 let tcx = self.tcx;
1909
1910 let ty::Adt(adt, args) = adt_ty.kind() else {
1911 span_bug!(pat.span, "struct pattern is not an ADT");
1912 };
1913
1914 let field_map = variant
1916 .fields
1917 .iter_enumerated()
1918 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
1919 .collect::<FxHashMap<_, _>>();
1920
1921 let mut used_fields = FxHashMap::default();
1923 let mut result = Ok(());
1924
1925 let mut inexistent_fields = vec![];
1926 for field in fields {
1928 let span = field.span;
1929 let ident = tcx.adjust_ident(field.ident, variant.def_id);
1930 let field_ty = match used_fields.entry(ident) {
1931 Occupied(occupied) => {
1932 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
1933 result = Err(guar);
1934 Ty::new_error(tcx, guar)
1935 }
1936 Vacant(vacant) => {
1937 vacant.insert(span);
1938 field_map
1939 .get(&ident)
1940 .map(|(i, f)| {
1941 self.write_field_index(field.hir_id, *i);
1942 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
1943 self.field_ty(span, f, args)
1944 })
1945 .unwrap_or_else(|| {
1946 inexistent_fields.push(field);
1947 Ty::new_misc_error(tcx)
1948 })
1949 }
1950 };
1951
1952 self.check_pat(field.pat, field_ty, pat_info);
1953 }
1954
1955 let mut unmentioned_fields = variant
1956 .fields
1957 .iter()
1958 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
1959 .filter(|(_, ident)| !used_fields.contains_key(ident))
1960 .collect::<Vec<_>>();
1961
1962 let inexistent_fields_err = if !inexistent_fields.is_empty()
1963 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
1964 {
1965 variant.has_errors()?;
1967 Some(self.error_inexistent_fields(
1968 adt.variant_descr(),
1969 &inexistent_fields,
1970 &mut unmentioned_fields,
1971 pat,
1972 variant,
1973 args,
1974 ))
1975 } else {
1976 None
1977 };
1978
1979 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
1981 if non_exhaustive && !has_rest_pat {
1982 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
1983 }
1984
1985 let mut unmentioned_err = None;
1986 if adt.is_union() {
1988 if fields.len() != 1 {
1989 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
1990 }
1991 if has_rest_pat {
1992 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
1993 }
1994 } else if !unmentioned_fields.is_empty() {
1995 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
1996 .iter()
1997 .copied()
1998 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
1999 .collect();
2000
2001 if !has_rest_pat {
2002 if accessible_unmentioned_fields.is_empty() {
2003 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
2004 } else {
2005 unmentioned_err = Some(self.error_unmentioned_fields(
2006 pat,
2007 &accessible_unmentioned_fields,
2008 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
2009 fields,
2010 ));
2011 }
2012 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
2013 self.lint_non_exhaustive_omitted_patterns(
2014 pat,
2015 &accessible_unmentioned_fields,
2016 adt_ty,
2017 )
2018 }
2019 }
2020 match (inexistent_fields_err, unmentioned_err) {
2021 (Some(i), Some(u)) => {
2022 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2023 i.delay_as_bug();
2026 u.delay_as_bug();
2027 Err(e)
2028 } else {
2029 i.emit();
2030 Err(u.emit())
2031 }
2032 }
2033 (None, Some(u)) => {
2034 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2035 u.delay_as_bug();
2036 Err(e)
2037 } else {
2038 Err(u.emit())
2039 }
2040 }
2041 (Some(err), None) => Err(err.emit()),
2042 (None, None) => {
2043 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
2044 result
2045 }
2046 }
2047 }
2048
2049 fn error_tuple_variant_index_shorthand(
2050 &self,
2051 variant: &VariantDef,
2052 pat: &'_ Pat<'_>,
2053 fields: &[hir::PatField<'_>],
2054 ) -> Result<(), ErrorGuaranteed> {
2055 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
2059 (variant.ctor_kind(), &pat.kind)
2060 {
2061 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
2062 if has_shorthand_field_name {
2063 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2064 let mut err = struct_span_code_err!(
2065 self.dcx(),
2066 pat.span,
2067 E0769,
2068 "tuple variant `{path}` written as struct variant",
2069 );
2070 err.span_suggestion_verbose(
2071 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2072 "use the tuple variant pattern syntax instead",
2073 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
2074 Applicability::MaybeIncorrect,
2075 );
2076 return Err(err.emit());
2077 }
2078 }
2079 Ok(())
2080 }
2081
2082 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
2083 let sess = self.tcx.sess;
2084 let sm = sess.source_map();
2085 let sp_brace = sm.end_point(pat.span);
2086 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
2087 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
2088
2089 struct_span_code_err!(
2090 self.dcx(),
2091 pat.span,
2092 E0638,
2093 "`..` required with {descr} marked as non-exhaustive",
2094 )
2095 .with_span_suggestion_verbose(
2096 sp_comma,
2097 "add `..` at the end of the field list to ignore all other fields",
2098 sugg,
2099 Applicability::MachineApplicable,
2100 )
2101 .emit();
2102 }
2103
2104 fn error_field_already_bound(
2105 &self,
2106 span: Span,
2107 ident: Ident,
2108 other_field: Span,
2109 ) -> ErrorGuaranteed {
2110 struct_span_code_err!(
2111 self.dcx(),
2112 span,
2113 E0025,
2114 "field `{}` bound multiple times in the pattern",
2115 ident
2116 )
2117 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2118 .with_span_label(other_field, format!("first use of `{ident}`"))
2119 .emit()
2120 }
2121
2122 fn error_inexistent_fields(
2123 &self,
2124 kind_name: &str,
2125 inexistent_fields: &[&hir::PatField<'tcx>],
2126 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2127 pat: &'tcx Pat<'tcx>,
2128 variant: &ty::VariantDef,
2129 args: ty::GenericArgsRef<'tcx>,
2130 ) -> Diag<'a> {
2131 let tcx = self.tcx;
2132 let (field_names, t, plural) = if let [field] = inexistent_fields {
2133 (format!("a field named `{}`", field.ident), "this", "")
2134 } else {
2135 (
2136 format!(
2137 "fields named {}",
2138 inexistent_fields
2139 .iter()
2140 .map(|field| format!("`{}`", field.ident))
2141 .collect::<Vec<String>>()
2142 .join(", ")
2143 ),
2144 "these",
2145 "s",
2146 )
2147 };
2148 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2149 let mut err = struct_span_code_err!(
2150 self.dcx(),
2151 spans,
2152 E0026,
2153 "{} `{}` does not have {}",
2154 kind_name,
2155 tcx.def_path_str(variant.def_id),
2156 field_names
2157 );
2158 if let Some(pat_field) = inexistent_fields.last() {
2159 err.span_label(
2160 pat_field.ident.span,
2161 format!(
2162 "{} `{}` does not have {} field{}",
2163 kind_name,
2164 tcx.def_path_str(variant.def_id),
2165 t,
2166 plural
2167 ),
2168 );
2169
2170 if let [(field_def, field)] = unmentioned_fields.as_slice()
2171 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2172 {
2173 let suggested_name =
2174 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2175 if let Some(suggested_name) = suggested_name {
2176 err.span_suggestion(
2177 pat_field.ident.span,
2178 "a field with a similar name exists",
2179 suggested_name,
2180 Applicability::MaybeIncorrect,
2181 );
2182
2183 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2189 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2191 }
2192 } else if inexistent_fields.len() == 1 {
2193 match pat_field.pat.kind {
2194 PatKind::Expr(_)
2195 if !self.may_coerce(
2196 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2197 self.field_ty(field.span, field_def, args),
2198 ) => {}
2199 _ => {
2200 err.span_suggestion_short(
2201 pat_field.ident.span,
2202 format!(
2203 "`{}` has a field named `{}`",
2204 tcx.def_path_str(variant.def_id),
2205 field.name,
2206 ),
2207 field.name,
2208 Applicability::MaybeIncorrect,
2209 );
2210 }
2211 }
2212 }
2213 }
2214 }
2215 if tcx.sess.teach(err.code.unwrap()) {
2216 err.note(
2217 "This error indicates that a struct pattern attempted to \
2218 extract a nonexistent field from a struct. Struct fields \
2219 are identified by the name used before the colon : so struct \
2220 patterns should resemble the declaration of the struct type \
2221 being matched.\n\n\
2222 If you are using shorthand field patterns but want to refer \
2223 to the struct field by a different name, you should rename \
2224 it explicitly.",
2225 );
2226 }
2227 err
2228 }
2229
2230 fn error_tuple_variant_as_struct_pat(
2231 &self,
2232 pat: &Pat<'_>,
2233 fields: &'tcx [hir::PatField<'tcx>],
2234 variant: &ty::VariantDef,
2235 ) -> Result<(), ErrorGuaranteed> {
2236 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2237 (variant.ctor_kind(), &pat.kind)
2238 {
2239 let is_tuple_struct_match = !pattern_fields.is_empty()
2240 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2241 if is_tuple_struct_match {
2242 return Ok(());
2243 }
2244
2245 variant.has_errors()?;
2247
2248 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2249 let mut err = struct_span_code_err!(
2250 self.dcx(),
2251 pat.span,
2252 E0769,
2253 "tuple variant `{}` written as struct variant",
2254 path
2255 );
2256 let (sugg, appl) = if fields.len() == variant.fields.len() {
2257 (
2258 self.get_suggested_tuple_struct_pattern(fields, variant),
2259 Applicability::MachineApplicable,
2260 )
2261 } else {
2262 (
2263 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2264 Applicability::MaybeIncorrect,
2265 )
2266 };
2267 err.span_suggestion_verbose(
2268 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2269 "use the tuple variant pattern syntax instead",
2270 format!("({sugg})"),
2271 appl,
2272 );
2273 return Err(err.emit());
2274 }
2275 Ok(())
2276 }
2277
2278 fn get_suggested_tuple_struct_pattern(
2279 &self,
2280 fields: &[hir::PatField<'_>],
2281 variant: &VariantDef,
2282 ) -> String {
2283 let variant_field_idents =
2284 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2285 fields
2286 .iter()
2287 .map(|field| {
2288 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2289 Ok(f) => {
2290 if variant_field_idents.contains(&field.ident) {
2293 String::from("_")
2294 } else {
2295 f
2296 }
2297 }
2298 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2299 }
2300 })
2301 .collect::<Vec<String>>()
2302 .join(", ")
2303 }
2304
2305 fn error_no_accessible_fields(
2321 &self,
2322 pat: &Pat<'_>,
2323 fields: &'tcx [hir::PatField<'tcx>],
2324 ) -> Diag<'a> {
2325 let mut err = self
2326 .dcx()
2327 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2328
2329 if let Some(field) = fields.last() {
2330 err.span_suggestion_verbose(
2331 field.span.shrink_to_hi(),
2332 "ignore the inaccessible and unused fields",
2333 ", ..",
2334 Applicability::MachineApplicable,
2335 );
2336 } else {
2337 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2338 qpath.span()
2339 } else {
2340 bug!("`error_no_accessible_fields` called on non-struct pattern");
2341 };
2342
2343 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2345 err.span_suggestion_verbose(
2346 span,
2347 "ignore the inaccessible and unused fields",
2348 " { .. }",
2349 Applicability::MachineApplicable,
2350 );
2351 }
2352 err
2353 }
2354
2355 fn lint_non_exhaustive_omitted_patterns(
2360 &self,
2361 pat: &Pat<'_>,
2362 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2363 ty: Ty<'tcx>,
2364 ) {
2365 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2366 const LIMIT: usize = 3;
2367 match witnesses {
2368 [] => {
2369 unreachable!(
2370 "expected an uncovered pattern, otherwise why are we emitting an error?"
2371 )
2372 }
2373 [witness] => format!("`{witness}`"),
2374 [head @ .., tail] if head.len() < LIMIT => {
2375 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2376 format!("`{}` and `{}`", head.join("`, `"), tail)
2377 }
2378 _ => {
2379 let (head, tail) = witnesses.split_at(LIMIT);
2380 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2381 format!("`{}` and {} more", head.join("`, `"), tail.len())
2382 }
2383 }
2384 }
2385 let joined_patterns = joined_uncovered_patterns(
2386 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2387 );
2388
2389 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2390 lint.primary_message("some fields are not explicitly listed");
2391 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2392 lint.help(
2393 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2394 );
2395 lint.note(format!(
2396 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2397 ));
2398 });
2399 }
2400
2401 fn error_unmentioned_fields(
2411 &self,
2412 pat: &Pat<'_>,
2413 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2414 have_inaccessible_fields: bool,
2415 fields: &'tcx [hir::PatField<'tcx>],
2416 ) -> Diag<'a> {
2417 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2418 let field_names = if let [(_, field)] = unmentioned_fields {
2419 format!("field `{field}`{inaccessible}")
2420 } else {
2421 let fields = unmentioned_fields
2422 .iter()
2423 .map(|(_, name)| format!("`{name}`"))
2424 .collect::<Vec<String>>()
2425 .join(", ");
2426 format!("fields {fields}{inaccessible}")
2427 };
2428 let mut err = struct_span_code_err!(
2429 self.dcx(),
2430 pat.span,
2431 E0027,
2432 "pattern does not mention {}",
2433 field_names
2434 );
2435 err.span_label(pat.span, format!("missing {field_names}"));
2436 let len = unmentioned_fields.len();
2437 let (prefix, postfix, sp) = match fields {
2438 [] => match &pat.kind {
2439 PatKind::Struct(path, [], None) => {
2440 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2441 }
2442 _ => return err,
2443 },
2444 [.., field] => {
2445 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2448 match &pat.kind {
2449 PatKind::Struct(..) => (", ", " }", tail),
2450 _ => return err,
2451 }
2452 }
2453 };
2454 err.span_suggestion(
2455 sp,
2456 format!(
2457 "include the missing field{} in the pattern{}",
2458 pluralize!(len),
2459 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2460 ),
2461 format!(
2462 "{}{}{}{}",
2463 prefix,
2464 unmentioned_fields
2465 .iter()
2466 .map(|(_, name)| {
2467 let field_name = name.to_string();
2468 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2469 })
2470 .collect::<Vec<_>>()
2471 .join(", "),
2472 if have_inaccessible_fields { ", .." } else { "" },
2473 postfix,
2474 ),
2475 Applicability::MachineApplicable,
2476 );
2477 err.span_suggestion(
2478 sp,
2479 format!(
2480 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2481 these = pluralize!("this", len),
2482 s = pluralize!(len),
2483 them = if len == 1 { "it" } else { "them" },
2484 ),
2485 format!(
2486 "{}{}{}{}",
2487 prefix,
2488 unmentioned_fields
2489 .iter()
2490 .map(|(_, name)| {
2491 let field_name = name.to_string();
2492 format!("{field_name}: _")
2493 })
2494 .collect::<Vec<_>>()
2495 .join(", "),
2496 if have_inaccessible_fields { ", .." } else { "" },
2497 postfix,
2498 ),
2499 Applicability::MachineApplicable,
2500 );
2501 err.span_suggestion(
2502 sp,
2503 "or always ignore missing fields here",
2504 format!("{prefix}..{postfix}"),
2505 Applicability::MachineApplicable,
2506 );
2507 err
2508 }
2509
2510 fn check_pat_box(
2511 &self,
2512 span: Span,
2513 inner: &'tcx Pat<'tcx>,
2514 expected: Ty<'tcx>,
2515 pat_info: PatInfo<'tcx>,
2516 ) -> Ty<'tcx> {
2517 let tcx = self.tcx;
2518 let (box_ty, inner_ty) = self
2519 .check_dereferenceable(span, expected, inner)
2520 .and_then(|()| {
2521 let inner_ty = self.next_ty_var(inner.span);
2524 let box_ty = Ty::new_box(tcx, inner_ty);
2525 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2526 Ok((box_ty, inner_ty))
2527 })
2528 .unwrap_or_else(|guar| {
2529 let err = Ty::new_error(tcx, guar);
2530 (err, err)
2531 });
2532 self.check_pat(inner, inner_ty, pat_info);
2533 box_ty
2534 }
2535
2536 fn check_pat_deref(
2537 &self,
2538 span: Span,
2539 inner: &'tcx Pat<'tcx>,
2540 expected: Ty<'tcx>,
2541 pat_info: PatInfo<'tcx>,
2542 ) -> Ty<'tcx> {
2543 let target_ty = self.deref_pat_target(span, expected);
2544 self.check_pat(inner, target_ty, pat_info);
2545 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2546 expected
2547 }
2548
2549 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2550 let tcx = self.tcx;
2552 self.register_bound(
2553 source_ty,
2554 tcx.require_lang_item(hir::LangItem::DerefPure, span),
2555 self.misc(span),
2556 );
2557 let target_ty = Ty::new_projection(
2559 tcx,
2560 tcx.require_lang_item(hir::LangItem::DerefTarget, span),
2561 [source_ty],
2562 );
2563 let target_ty = self.normalize(span, target_ty);
2564 self.try_structurally_resolve_type(span, target_ty)
2565 }
2566
2567 fn register_deref_mut_bounds_if_needed(
2572 &self,
2573 span: Span,
2574 inner: &'tcx Pat<'tcx>,
2575 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2576 ) {
2577 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2578 for mutably_derefed_ty in derefed_tys {
2579 self.register_bound(
2580 mutably_derefed_ty,
2581 self.tcx.require_lang_item(hir::LangItem::DerefMut, span),
2582 self.misc(span),
2583 );
2584 }
2585 }
2586 }
2587
2588 fn check_pat_ref(
2590 &self,
2591 pat: &'tcx Pat<'tcx>,
2592 inner: &'tcx Pat<'tcx>,
2593 pat_mutbl: Mutability,
2594 mut expected: Ty<'tcx>,
2595 mut pat_info: PatInfo<'tcx>,
2596 ) -> Ty<'tcx> {
2597 let tcx = self.tcx;
2598
2599 let pat_prefix_span =
2600 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2601
2602 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2603 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2604 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2609 }
2610
2611 expected = self.try_structurally_resolve_type(pat.span, expected);
2612 if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2615 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2616 InheritedRefMatchRule::EatOuter => {
2617 if pat_mutbl > inh_mut {
2619 debug_assert!(ref_pat_matches_mut_ref);
2624 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2625 }
2626
2627 pat_info.binding_mode = ByRef::No;
2628 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2629 self.check_pat(inner, expected, pat_info);
2630 return expected;
2631 }
2632 InheritedRefMatchRule::EatInner => {
2633 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2634 && pat_mutbl <= r_mutbl
2635 {
2636 debug_assert!(ref_pat_matches_mut_ref);
2643 debug_assert!(self.downgrade_mut_inside_shared());
2647 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2648 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2649 } else {
2650 if pat_mutbl > inh_mut {
2653 debug_assert!(ref_pat_matches_mut_ref);
2662 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2663 }
2664
2665 pat_info.binding_mode = ByRef::No;
2666 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2667 self.check_pat(inner, expected, pat_info);
2668 return expected;
2669 }
2670 }
2671 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2672 pat_info.binding_mode = ByRef::No;
2674
2675 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2676 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2678 self.check_pat(inner, inner_ty, pat_info);
2685 return expected;
2686 } else {
2687 }
2694 } else {
2695 if pat_mutbl > inh_mut {
2698 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2700 }
2701
2702 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2703 self.check_pat(inner, expected, pat_info);
2704 return expected;
2705 }
2706 }
2707 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2708 pat_info.binding_mode = ByRef::No;
2711 self.add_rust_2024_migration_desugared_pat(
2712 pat_info.top_info.hir_id,
2713 pat,
2714 match pat_mutbl {
2715 Mutability::Not => '&', Mutability::Mut => 't', },
2718 inh_mut,
2719 )
2720 }
2721 }
2722 }
2723
2724 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2725 Ok(()) => {
2726 debug!("check_pat_ref: expected={:?}", expected);
2733 match *expected.kind() {
2734 ty::Ref(_, r_ty, r_mutbl)
2735 if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2736 || r_mutbl == pat_mutbl =>
2737 {
2738 if r_mutbl == Mutability::Not {
2739 pat_info.max_ref_mutbl = MutblCap::Not;
2740 }
2741
2742 (expected, r_ty)
2743 }
2744
2745 _ => {
2746 let inner_ty = self.next_ty_var(inner.span);
2747 let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
2748 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2749 let err = self.demand_eqtype_pat_diag(
2750 pat.span,
2751 expected,
2752 ref_ty,
2753 &pat_info.top_info,
2754 );
2755
2756 if let Err(mut err) = err {
2759 self.borrow_pat_suggestion(&mut err, pat);
2760 err.emit();
2761 }
2762 (ref_ty, inner_ty)
2763 }
2764 }
2765 }
2766 Err(guar) => {
2767 let err = Ty::new_error(tcx, guar);
2768 (err, err)
2769 }
2770 };
2771
2772 self.check_pat(inner, inner_ty, pat_info);
2773 ref_ty
2774 }
2775
2776 fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
2778 let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
2779 Ty::new_ref(self.tcx, region, ty, mutbl)
2780 }
2781
2782 fn error_inherited_ref_mutability_mismatch(
2783 &self,
2784 pat: &'tcx Pat<'tcx>,
2785 pat_prefix_span: Option<Span>,
2786 ) -> ErrorGuaranteed {
2787 let err_msg = "mismatched types";
2788 let err = if let Some(span) = pat_prefix_span {
2789 let mut err = self.dcx().struct_span_err(span, err_msg);
2790 err.code(E0308);
2791 err.note("cannot match inherited `&` with `&mut` pattern");
2792 err.span_suggestion_verbose(
2793 span,
2794 "replace this `&mut` pattern with `&`",
2795 "&",
2796 Applicability::MachineApplicable,
2797 );
2798 err
2799 } else {
2800 self.dcx().struct_span_err(pat.span, err_msg)
2801 };
2802 err.emit()
2803 }
2804
2805 fn try_resolve_slice_ty_to_array_ty(
2806 &self,
2807 before: &'tcx [Pat<'tcx>],
2808 slice: Option<&'tcx Pat<'tcx>>,
2809 span: Span,
2810 ) -> Option<Ty<'tcx>> {
2811 if slice.is_some() {
2812 return None;
2813 }
2814
2815 let tcx = self.tcx;
2816 let len = before.len();
2817 let inner_ty = self.next_ty_var(span);
2818
2819 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2820 }
2821
2822 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2853 match decl_origin {
2854 Some(DeclOrigin::LocalDecl { els: None }) => true,
2855 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2856 }
2857 }
2858
2859 fn check_pat_slice(
2870 &self,
2871 span: Span,
2872 before: &'tcx [Pat<'tcx>],
2873 slice: Option<&'tcx Pat<'tcx>>,
2874 after: &'tcx [Pat<'tcx>],
2875 expected: Ty<'tcx>,
2876 pat_info: PatInfo<'tcx>,
2877 ) -> Ty<'tcx> {
2878 let expected = self.try_structurally_resolve_type(span, expected);
2879
2880 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
2883 if let Some(resolved_arr_ty) =
2884 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
2885 {
2886 debug!(?resolved_arr_ty);
2887 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
2888 }
2889 }
2890
2891 let expected = self.structurally_resolve_type(span, expected);
2892 debug!(?expected);
2893
2894 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
2895 ty::Array(element_ty, len) => {
2897 let min = before.len() as u64 + after.len() as u64;
2898 let (opt_slice_ty, expected) =
2899 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
2900 assert!(opt_slice_ty.is_some() || slice.is_none());
2903 (element_ty, opt_slice_ty, expected)
2904 }
2905 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
2906 _ => {
2908 let guar = expected.error_reported().err().unwrap_or_else(|| {
2909 self.error_expected_array_or_slice(span, expected, pat_info)
2910 });
2911 let err = Ty::new_error(self.tcx, guar);
2912 (err, Some(err), err)
2913 }
2914 };
2915
2916 for elt in before {
2918 self.check_pat(elt, element_ty, pat_info);
2919 }
2920 if let Some(slice) = slice {
2922 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
2923 }
2924 for elt in after {
2926 self.check_pat(elt, element_ty, pat_info);
2927 }
2928 inferred
2929 }
2930
2931 fn check_array_pat_len(
2936 &self,
2937 span: Span,
2938 element_ty: Ty<'tcx>,
2939 arr_ty: Ty<'tcx>,
2940 slice: Option<&'tcx Pat<'tcx>>,
2941 len: ty::Const<'tcx>,
2942 min_len: u64,
2943 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
2944 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
2945
2946 let guar = if let Some(len) = len {
2947 if slice.is_none() {
2949 if min_len == len {
2953 return (None, arr_ty);
2954 }
2955
2956 self.error_scrutinee_inconsistent_length(span, min_len, len)
2957 } else if let Some(pat_len) = len.checked_sub(min_len) {
2958 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
2961 } else {
2962 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
2965 }
2966 } else if slice.is_none() {
2967 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
2970 self.demand_eqtype(span, updated_arr_ty, arr_ty);
2971 return (None, updated_arr_ty);
2972 } else {
2973 self.error_scrutinee_unfixed_length(span)
2977 };
2978
2979 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
2981 }
2982
2983 fn error_scrutinee_inconsistent_length(
2984 &self,
2985 span: Span,
2986 min_len: u64,
2987 size: u64,
2988 ) -> ErrorGuaranteed {
2989 struct_span_code_err!(
2990 self.dcx(),
2991 span,
2992 E0527,
2993 "pattern requires {} element{} but array has {}",
2994 min_len,
2995 pluralize!(min_len),
2996 size,
2997 )
2998 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
2999 .emit()
3000 }
3001
3002 fn error_scrutinee_with_rest_inconsistent_length(
3003 &self,
3004 span: Span,
3005 min_len: u64,
3006 size: u64,
3007 ) -> ErrorGuaranteed {
3008 struct_span_code_err!(
3009 self.dcx(),
3010 span,
3011 E0528,
3012 "pattern requires at least {} element{} but array has {}",
3013 min_len,
3014 pluralize!(min_len),
3015 size,
3016 )
3017 .with_span_label(
3018 span,
3019 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
3020 )
3021 .emit()
3022 }
3023
3024 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
3025 struct_span_code_err!(
3026 self.dcx(),
3027 span,
3028 E0730,
3029 "cannot pattern-match on an array without a fixed length",
3030 )
3031 .emit()
3032 }
3033
3034 fn error_expected_array_or_slice(
3035 &self,
3036 span: Span,
3037 expected_ty: Ty<'tcx>,
3038 pat_info: PatInfo<'tcx>,
3039 ) -> ErrorGuaranteed {
3040 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
3041
3042 let mut slice_pat_semantics = false;
3043 let mut as_deref = None;
3044 let mut slicing = None;
3045 if let ty::Ref(_, ty, _) = expected_ty.kind()
3046 && let ty::Array(..) | ty::Slice(..) = ty.kind()
3047 {
3048 slice_pat_semantics = true;
3049 } else if self
3050 .autoderef(span, expected_ty)
3051 .silence_errors()
3052 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
3053 && let Some(span) = ti.span
3054 && let Some(_) = ti.origin_expr
3055 {
3056 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
3057 let (is_slice_or_array_or_vector, resolved_ty) =
3058 self.is_slice_or_array_or_vector(resolved_ty);
3059 match resolved_ty.kind() {
3060 ty::Adt(adt_def, _)
3061 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
3062 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
3063 {
3064 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
3066 }
3067 _ => (),
3068 }
3069
3070 let is_top_level = current_depth <= 1;
3071 if is_slice_or_array_or_vector && is_top_level {
3072 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
3073 }
3074 }
3075 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
3076 span,
3077 ty: expected_ty,
3078 slice_pat_semantics,
3079 as_deref,
3080 slicing,
3081 })
3082 }
3083
3084 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
3085 match ty.kind() {
3086 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
3087 (true, ty)
3088 }
3089 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
3090 ty::Slice(..) | ty::Array(..) => (true, ty),
3091 _ => (false, ty),
3092 }
3093 }
3094
3095 fn add_rust_2024_migration_desugared_pat(
3098 &self,
3099 pat_id: HirId,
3100 subpat: &'tcx Pat<'tcx>,
3101 final_char: char,
3102 def_br_mutbl: Mutability,
3103 ) {
3104 let from_expansion = subpat.span.from_expansion();
3106 let trimmed_span = if from_expansion {
3107 subpat.span
3109 } else {
3110 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3111 trimmed.with_ctxt(subpat.span.ctxt())
3114 };
3115
3116 let mut typeck_results = self.typeck_results.borrow_mut();
3117 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3118 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3123 primary_labels: Vec::new(),
3124 bad_modifiers: false,
3125 bad_ref_pats: false,
3126 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3127 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3128 });
3129
3130 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3131 info.bad_modifiers = true;
3132 info.suggest_eliding_modes &=
3136 user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
3137 "binding modifier"
3138 } else {
3139 info.bad_ref_pats = true;
3140 info.suggest_eliding_modes = false;
3144 "reference pattern"
3145 };
3146 let primary_label = if from_expansion {
3149 info.suggest_eliding_modes = false;
3151 "occurs within macro expansion".to_owned()
3155 } else {
3156 let dbm_str = match def_br_mutbl {
3157 Mutability::Not => "ref",
3158 Mutability::Mut => "ref mut",
3159 };
3160 format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
3161 };
3162 info.primary_labels.push((trimmed_span, primary_label));
3163 }
3164}