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(pat, fields, has_rest_pat, ty, variant, expected, pat_info),
609 Err(guar) => {
610 let ty_err = Ty::new_error(self.tcx, guar);
611 for field in fields {
612 self.check_pat(field.pat, ty_err, pat_info);
613 }
614 ty_err
615 }
616 Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
617 },
618 PatKind::Guard(pat, cond) => {
619 self.check_pat(pat, expected, pat_info);
620 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
621 expected
622 }
623 PatKind::Or(pats) => {
624 for pat in pats {
625 self.check_pat(pat, expected, pat_info);
626 }
627 expected
628 }
629 PatKind::Tuple(elements, ddpos) => {
630 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
631 }
632 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
633 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
634 PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
635 PatKind::Slice(before, slice, after) => {
636 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
637 }
638 }
639 }
640
641 fn calc_adjust_mode(
645 &self,
646 pat: &'tcx Pat<'tcx>,
647 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
648 ) -> AdjustMode {
649 match &pat.kind {
650 PatKind::Tuple(..) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::peel_all(),
653 PatKind::Box(_) | PatKind::Deref(_) => {
657 AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat }
658 }
659 PatKind::Never => AdjustMode::peel_all(),
661 PatKind::Struct(..)
663 | PatKind::TupleStruct(..)
664 | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
665 opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
667 }
668
669 PatKind::Expr(lt) => {
674 if cfg!(debug_assertions)
677 && self.tcx.features().deref_patterns()
678 && !matches!(lt.kind, PatExprKind::Lit { .. })
679 {
680 span_bug!(
681 lt.span,
682 "FIXME(deref_patterns): adjust mode unimplemented for {:?}",
683 lt.kind
684 );
685 }
686 let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
688 if self.tcx.features().deref_patterns() {
690 let mut peeled_ty = lit_ty;
691 let mut pat_ref_layers = 0;
692 while let ty::Ref(_, inner_ty, mutbl) =
693 *self.try_structurally_resolve_type(pat.span, peeled_ty).kind()
694 {
695 debug_assert!(mutbl.is_not());
697 pat_ref_layers += 1;
698 peeled_ty = inner_ty;
699 }
700 AdjustMode::Peel {
701 kind: PeelKind::Implicit { until_adt: None, pat_ref_layers },
702 }
703 } else {
704 if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
705 }
706 }
707
708 PatKind::Ref(..)
710 | PatKind::Missing
712 | PatKind::Wild
714 | PatKind::Err(_)
716 | PatKind::Binding(..)
721 | PatKind::Or(_)
725 | PatKind::Guard(..) => AdjustMode::Pass,
727 }
728 }
729
730 fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
732 debug_assert!(expected.is_ref());
733 let pat_ref_layers = match peel_kind {
734 PeelKind::ExplicitDerefPat => 0,
735 PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
736 };
737
738 if pat_ref_layers == 0 {
741 return true;
742 }
743 debug_assert!(
744 self.tcx.features().deref_patterns(),
745 "Peeling for patterns with reference types is gated by `deref_patterns`."
746 );
747
748 let mut expected_ref_layers = 0;
754 while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
755 if mutbl.is_mut() {
756 return true;
759 }
760 expected_ref_layers += 1;
761 expected = inner_ty;
762 }
763 pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
764 }
765
766 fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
768 if let PeelKind::Implicit { until_adt, .. } = peel_kind
770 && let ty::Adt(scrutinee_adt, _) = *expected.kind()
775 && until_adt != Some(scrutinee_adt.did())
778 && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
783 && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
784 {
785 true
786 } else {
787 false
788 }
789 }
790
791 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
792 let ty = match <.kind {
793 rustc_hir::PatExprKind::Lit { lit, negated } => {
794 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
795 if *negated {
796 self.register_bound(
797 ty,
798 self.tcx.require_lang_item(LangItem::Neg, lt.span),
799 ObligationCause::dummy_with_span(lt.span),
800 );
801 }
802 ty
803 }
804 rustc_hir::PatExprKind::ConstBlock(c) => {
805 self.check_expr_const_block(c, Expectation::NoExpectation)
806 }
807 rustc_hir::PatExprKind::Path(qpath) => {
808 let (res, opt_ty, segments) =
809 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
810 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
811 }
812 };
813 self.write_ty(lt.hir_id, ty);
814 ty
815 }
816
817 fn check_pat_lit(
818 &self,
819 span: Span,
820 lt: &hir::PatExpr<'tcx>,
821 expected: Ty<'tcx>,
822 ti: &TopInfo<'tcx>,
823 ) -> Ty<'tcx> {
824 let ty = self.node_ty(lt.hir_id);
827
828 let mut pat_ty = ty;
833 if let hir::PatExprKind::Lit {
834 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
835 } = lt.kind
836 {
837 let tcx = self.tcx;
838 let expected = self.structurally_resolve_type(span, expected);
839 match *expected.kind() {
840 ty::Ref(_, inner_ty, _)
842 if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
843 {
844 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
845 pat_ty = Ty::new_imm_ref(
846 tcx,
847 tcx.lifetimes.re_static,
848 Ty::new_slice(tcx, tcx.types.u8),
849 );
850 }
851 ty::Array(..) if tcx.features().deref_patterns() => {
853 pat_ty = match *ty.kind() {
854 ty::Ref(_, inner_ty, _) => inner_ty,
855 _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
856 }
857 }
858 ty::Slice(..) if tcx.features().deref_patterns() => {
860 pat_ty = Ty::new_slice(tcx, tcx.types.u8);
861 }
862 _ => {}
864 }
865 }
866
867 if self.tcx.features().deref_patterns()
870 && let hir::PatExprKind::Lit {
871 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
872 } = lt.kind
873 && self.try_structurally_resolve_type(span, expected).is_str()
874 {
875 pat_ty = self.tcx.types.str_;
876 }
877
878 if self.tcx.features().string_deref_patterns()
879 && let hir::PatExprKind::Lit {
880 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
881 } = lt.kind
882 {
883 let tcx = self.tcx;
884 let expected = self.resolve_vars_if_possible(expected);
885 pat_ty = match expected.kind() {
886 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
887 ty::Str => Ty::new_static_str(tcx),
888 _ => pat_ty,
889 };
890 }
891
892 let cause = self.pattern_cause(ti, span);
903 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
904 err.emit();
905 }
906
907 pat_ty
908 }
909
910 fn check_pat_range(
911 &self,
912 span: Span,
913 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
914 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
915 expected: Ty<'tcx>,
916 ti: &TopInfo<'tcx>,
917 ) -> Ty<'tcx> {
918 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
919 None => None,
920 Some(expr) => {
921 let ty = self.check_pat_expr_unadjusted(expr);
922 let ty = self.try_structurally_resolve_type(expr.span, ty);
929 let fail =
930 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
931 Some((fail, ty, expr.span))
932 }
933 };
934 let mut lhs = calc_side(lhs);
935 let mut rhs = calc_side(rhs);
936
937 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
938 let guar = self.emit_err_pat_range(span, lhs, rhs);
941 return Ty::new_error(self.tcx, guar);
942 }
943
944 let demand_eqtype = |x: &mut _, y| {
947 if let Some((ref mut fail, x_ty, x_span)) = *x
948 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
949 {
950 if let Some((_, y_ty, y_span)) = y {
951 self.endpoint_has_type(&mut err, y_span, y_ty);
952 }
953 err.emit();
954 *fail = true;
955 }
956 };
957 demand_eqtype(&mut lhs, rhs);
958 demand_eqtype(&mut rhs, lhs);
959
960 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
961 return Ty::new_misc_error(self.tcx);
962 }
963
964 let ty = self.structurally_resolve_type(span, expected);
969 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
970 if let Some((ref mut fail, _, _)) = lhs {
971 *fail = true;
972 }
973 if let Some((ref mut fail, _, _)) = rhs {
974 *fail = true;
975 }
976 let guar = self.emit_err_pat_range(span, lhs, rhs);
977 return Ty::new_error(self.tcx, guar);
978 }
979 ty
980 }
981
982 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
983 if !ty.references_error() {
984 err.span_label(span, format!("this is of type `{ty}`"));
985 }
986 }
987
988 fn emit_err_pat_range(
989 &self,
990 span: Span,
991 lhs: Option<(bool, Ty<'tcx>, Span)>,
992 rhs: Option<(bool, Ty<'tcx>, Span)>,
993 ) -> ErrorGuaranteed {
994 let span = match (lhs, rhs) {
995 (Some((true, ..)), Some((true, ..))) => span,
996 (Some((true, _, sp)), _) => sp,
997 (_, Some((true, _, sp))) => sp,
998 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
999 };
1000 let mut err = struct_span_code_err!(
1001 self.dcx(),
1002 span,
1003 E0029,
1004 "only `char` and numeric types are allowed in range patterns"
1005 );
1006 let msg = |ty| {
1007 let ty = self.resolve_vars_if_possible(ty);
1008 format!("this is of type `{ty}` but it should be `char` or numeric")
1009 };
1010 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
1011 err.span_label(first_span, msg(first_ty));
1012 if let Some((_, ty, sp)) = second {
1013 let ty = self.resolve_vars_if_possible(ty);
1014 self.endpoint_has_type(&mut err, sp, ty);
1015 }
1016 };
1017 match (lhs, rhs) {
1018 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
1019 err.span_label(lhs_sp, msg(lhs_ty));
1020 err.span_label(rhs_sp, msg(rhs_ty));
1021 }
1022 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
1023 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
1024 _ => span_bug!(span, "Impossible, verified above."),
1025 }
1026 if (lhs, rhs).references_error() {
1027 err.downgrade_to_delayed_bug();
1028 }
1029 if self.tcx.sess.teach(err.code.unwrap()) {
1030 err.note(
1031 "In a match expression, only numbers and characters can be matched \
1032 against a range. This is because the compiler checks that the range \
1033 is non-empty at compile-time, and is unable to evaluate arbitrary \
1034 comparison functions. If you want to capture values of an orderable \
1035 type between two end-points, you can use a guard.",
1036 );
1037 }
1038 err.emit()
1039 }
1040
1041 fn check_pat_ident(
1042 &self,
1043 pat: &'tcx Pat<'tcx>,
1044 user_bind_annot: BindingMode,
1045 var_id: HirId,
1046 ident: Ident,
1047 sub: Option<&'tcx Pat<'tcx>>,
1048 expected: Ty<'tcx>,
1049 pat_info: PatInfo<'tcx>,
1050 ) -> Ty<'tcx> {
1051 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
1052
1053 let bm = match user_bind_annot {
1055 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
1056 if pat.span.at_least_rust_2024()
1059 && (self.tcx.features().ref_pat_eat_one_layer_2024()
1060 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
1061 {
1062 if !self.tcx.features().mut_ref() {
1063 feature_err(
1064 &self.tcx.sess,
1065 sym::mut_ref,
1066 pat.span.until(ident.span),
1067 "binding cannot be both mutable and by-reference",
1068 )
1069 .emit();
1070 }
1071
1072 BindingMode(def_br, Mutability::Mut)
1073 } else {
1074 self.add_rust_2024_migration_desugared_pat(
1076 pat_info.top_info.hir_id,
1077 pat,
1078 't', def_br_mutbl,
1080 );
1081 BindingMode(ByRef::No, Mutability::Mut)
1082 }
1083 }
1084 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
1085 BindingMode(ByRef::Yes(user_br_mutbl), _) => {
1086 if let ByRef::Yes(def_br_mutbl) = def_br {
1087 self.add_rust_2024_migration_desugared_pat(
1089 pat_info.top_info.hir_id,
1090 pat,
1091 match user_br_mutbl {
1092 Mutability::Not => 'f', Mutability::Mut => 't', },
1095 def_br_mutbl,
1096 );
1097 }
1098 user_bind_annot
1099 }
1100 };
1101
1102 if bm.0 == ByRef::Yes(Mutability::Mut)
1103 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1104 {
1105 let mut err = struct_span_code_err!(
1106 self.dcx(),
1107 ident.span,
1108 E0596,
1109 "cannot borrow as mutable inside an `&` pattern"
1110 );
1111
1112 if let Some(span) = and_pat_span {
1113 err.span_suggestion(
1114 span,
1115 "replace this `&` with `&mut`",
1116 "&mut ",
1117 Applicability::MachineApplicable,
1118 );
1119 }
1120 err.emit();
1121 }
1122
1123 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1125
1126 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1127
1128 let local_ty = self.local_ty(pat.span, pat.hir_id);
1129 let eq_ty = match bm.0 {
1130 ByRef::Yes(mutbl) => {
1131 self.new_ref_ty(pat.span, mutbl, expected)
1139 }
1140 ByRef::No => expected, };
1143
1144 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1146
1147 if var_id != pat.hir_id {
1150 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1151 }
1152
1153 if let Some(p) = sub {
1154 self.check_pat(p, expected, pat_info);
1155 }
1156
1157 local_ty
1158 }
1159
1160 fn check_binding_alt_eq_ty(
1164 &self,
1165 ba: BindingMode,
1166 span: Span,
1167 var_id: HirId,
1168 ty: Ty<'tcx>,
1169 ti: &TopInfo<'tcx>,
1170 ) {
1171 let var_ty = self.local_ty(span, var_id);
1172 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1173 let var_ty = self.resolve_vars_if_possible(var_ty);
1174 let msg = format!("first introduced with type `{var_ty}` here");
1175 err.span_label(self.tcx.hir_span(var_id), msg);
1176 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1177 matches!(
1178 n,
1179 hir::Node::Expr(hir::Expr {
1180 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1181 ..
1182 })
1183 )
1184 });
1185 let pre = if in_match { "in the same arm, " } else { "" };
1186 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1187 self.suggest_adding_missing_ref_or_removing_ref(
1188 &mut err,
1189 span,
1190 var_ty,
1191 self.resolve_vars_if_possible(ty),
1192 ba,
1193 );
1194 err.emit();
1195 }
1196 }
1197
1198 fn suggest_adding_missing_ref_or_removing_ref(
1199 &self,
1200 err: &mut Diag<'_>,
1201 span: Span,
1202 expected: Ty<'tcx>,
1203 actual: Ty<'tcx>,
1204 ba: BindingMode,
1205 ) {
1206 match (expected.kind(), actual.kind(), ba) {
1207 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1208 if self.can_eq(self.param_env, *inner_ty, actual) =>
1209 {
1210 err.span_suggestion_verbose(
1211 span.shrink_to_lo(),
1212 "consider adding `ref`",
1213 "ref ",
1214 Applicability::MaybeIncorrect,
1215 );
1216 }
1217 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1218 if self.can_eq(self.param_env, expected, *inner_ty) =>
1219 {
1220 err.span_suggestion_verbose(
1221 span.with_hi(span.lo() + BytePos(4)),
1222 "consider removing `ref`",
1223 "",
1224 Applicability::MaybeIncorrect,
1225 );
1226 }
1227 _ => (),
1228 }
1229 }
1230
1231 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1233 let tcx = self.tcx;
1234 if let PatKind::Ref(inner, mutbl) = pat.kind
1235 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1236 {
1237 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1238 debug!(?inner, ?pat, ?binding_parent);
1239
1240 let mutability = match mutbl {
1241 ast::Mutability::Mut => "mut",
1242 ast::Mutability::Not => "",
1243 };
1244
1245 let mut_var_suggestion = 'block: {
1246 if mutbl.is_not() {
1247 break 'block None;
1248 }
1249
1250 let ident_kind = match binding_parent {
1251 hir::Node::Param(_) => "parameter",
1252 hir::Node::LetStmt(_) => "variable",
1253 hir::Node::Arm(_) => "binding",
1254
1255 hir::Node::Pat(Pat { kind, .. }) => match kind {
1258 PatKind::Struct(..)
1259 | PatKind::TupleStruct(..)
1260 | PatKind::Or(..)
1261 | PatKind::Guard(..)
1262 | PatKind::Tuple(..)
1263 | PatKind::Slice(..) => "binding",
1264
1265 PatKind::Missing
1266 | PatKind::Wild
1267 | PatKind::Never
1268 | PatKind::Binding(..)
1269 | PatKind::Box(..)
1270 | PatKind::Deref(_)
1271 | PatKind::Ref(..)
1272 | PatKind::Expr(..)
1273 | PatKind::Range(..)
1274 | PatKind::Err(_) => break 'block None,
1275 },
1276
1277 _ => break 'block None,
1279 };
1280
1281 Some((
1282 pat.span,
1283 format!("to declare a mutable {ident_kind} use"),
1284 format!("mut {binding}"),
1285 ))
1286 };
1287
1288 match binding_parent {
1289 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1292 err.multipart_suggestion_verbose(
1293 format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
1294 vec![
1295 (pat.span.until(inner.span), "".to_owned()),
1296 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1297 ],
1298 Applicability::MachineApplicable
1299 );
1300
1301 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1302 err.span_note(sp, format!("{msg}: `{sugg}`"));
1303 }
1304 }
1305 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1306 for i in pat_arr.iter() {
1307 if let PatKind::Ref(the_ref, _) = i.kind
1308 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1309 {
1310 let BindingMode(_, mtblty) = mt;
1311 err.span_suggestion_verbose(
1312 i.span,
1313 format!("consider removing `&{mutability}` from the pattern"),
1314 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1315 Applicability::MaybeIncorrect,
1316 );
1317 }
1318 }
1319 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1320 err.span_note(sp, format!("{msg}: `{sugg}`"));
1321 }
1322 }
1323 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1324 err.span_suggestion_verbose(
1326 pat.span.until(inner.span),
1327 format!("consider removing `&{mutability}` from the pattern"),
1328 "",
1329 Applicability::MaybeIncorrect,
1330 );
1331
1332 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1333 err.span_note(sp, format!("{msg}: `{sugg}`"));
1334 }
1335 }
1336 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1337 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1338 }
1339 _ => {} }
1341 }
1342 }
1343
1344 fn check_dereferenceable(
1345 &self,
1346 span: Span,
1347 expected: Ty<'tcx>,
1348 inner: &Pat<'_>,
1349 ) -> Result<(), ErrorGuaranteed> {
1350 if let PatKind::Binding(..) = inner.kind
1351 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1352 && let ty::Dynamic(..) = pointee_ty.kind()
1353 {
1354 let type_str = self.ty_to_string(expected);
1357 let mut err = struct_span_code_err!(
1358 self.dcx(),
1359 span,
1360 E0033,
1361 "type `{}` cannot be dereferenced",
1362 type_str
1363 );
1364 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1365 if self.tcx.sess.teach(err.code.unwrap()) {
1366 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1367 }
1368 return Err(err.emit());
1369 }
1370 Ok(())
1371 }
1372
1373 fn resolve_pat_struct(
1374 &self,
1375 pat: &'tcx Pat<'tcx>,
1376 qpath: &hir::QPath<'tcx>,
1377 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1378 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1380 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1381 }
1382
1383 fn check_pat_struct(
1384 &self,
1385 pat: &'tcx Pat<'tcx>,
1386 fields: &'tcx [hir::PatField<'tcx>],
1387 has_rest_pat: bool,
1388 pat_ty: Ty<'tcx>,
1389 variant: &'tcx VariantDef,
1390 expected: Ty<'tcx>,
1391 pat_info: PatInfo<'tcx>,
1392 ) -> Ty<'tcx> {
1393 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1395
1396 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1398 Ok(()) => pat_ty,
1399 Err(guar) => Ty::new_error(self.tcx, guar),
1400 }
1401 }
1402
1403 fn resolve_pat_path(
1404 &self,
1405 path_id: HirId,
1406 span: Span,
1407 qpath: &'tcx hir::QPath<'_>,
1408 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1409 let tcx = self.tcx;
1410
1411 let (res, opt_ty, segments) =
1412 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1413 match res {
1414 Res::Err => {
1415 let e =
1416 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1417 self.set_tainted_by_errors(e);
1418 return Err(e);
1419 }
1420 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1421 let expected = "unit struct, unit variant or constant";
1422 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1423 return Err(e);
1424 }
1425 Res::SelfCtor(def_id) => {
1426 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1427 && adt_def.is_struct()
1428 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1429 {
1430 } else {
1432 let e = report_unexpected_variant_res(
1433 tcx,
1434 res,
1435 None,
1436 qpath,
1437 span,
1438 E0533,
1439 "unit struct",
1440 );
1441 return Err(e);
1442 }
1443 }
1444 Res::Def(
1445 DefKind::Ctor(_, CtorKind::Const)
1446 | DefKind::Const
1447 | DefKind::AssocConst
1448 | DefKind::ConstParam,
1449 _,
1450 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1452 }
1453
1454 let (pat_ty, pat_res) =
1456 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1457 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1458 }
1459
1460 fn check_pat_path(
1461 &self,
1462 pat_id_for_diag: HirId,
1463 span: Span,
1464 resolved: &ResolvedPat<'tcx>,
1465 expected: Ty<'tcx>,
1466 ti: &TopInfo<'tcx>,
1467 ) -> Ty<'tcx> {
1468 if let Err(err) =
1469 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1470 {
1471 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1472 }
1473 resolved.ty
1474 }
1475
1476 fn maybe_suggest_range_literal(
1477 &self,
1478 e: &mut Diag<'_>,
1479 opt_def_id: Option<hir::def_id::DefId>,
1480 ident: Ident,
1481 ) -> bool {
1482 match opt_def_id {
1483 Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
1484 Some(hir::Node::Item(hir::Item {
1485 kind: hir::ItemKind::Const(_, _, _, body_id),
1486 ..
1487 })) => match self.tcx.hir_node(body_id.hir_id) {
1488 hir::Node::Expr(expr) => {
1489 if hir::is_range_literal(expr) {
1490 let span = self.tcx.hir_span(body_id.hir_id);
1491 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1492 e.span_suggestion_verbose(
1493 ident.span,
1494 "you may want to move the range into the match block",
1495 snip,
1496 Applicability::MachineApplicable,
1497 );
1498 return true;
1499 }
1500 }
1501 }
1502 _ => (),
1503 },
1504 _ => (),
1505 },
1506 _ => (),
1507 }
1508 false
1509 }
1510
1511 fn emit_bad_pat_path(
1512 &self,
1513 mut e: Diag<'_>,
1514 hir_id: HirId,
1515 pat_span: Span,
1516 resolved_pat: &ResolvedPat<'tcx>,
1517 ) {
1518 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1519 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1520 };
1521
1522 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1523 e.span_label(span, format!("{} defined here", res.descr()));
1524 if let [hir::PathSegment { ident, .. }] = &*segments {
1525 e.span_label(
1526 pat_span,
1527 format!(
1528 "`{}` is interpreted as {} {}, not a new binding",
1529 ident,
1530 res.article(),
1531 res.descr(),
1532 ),
1533 );
1534 match self.tcx.parent_hir_node(hir_id) {
1535 hir::Node::PatField(..) => {
1536 e.span_suggestion_verbose(
1537 ident.span.shrink_to_hi(),
1538 "bind the struct field to a different name instead",
1539 format!(": other_{}", ident.as_str().to_lowercase()),
1540 Applicability::HasPlaceholders,
1541 );
1542 }
1543 _ => {
1544 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1545 ty::Adt(def, _) => match res {
1546 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1547 _ => (None, None),
1548 },
1549 _ => (None, None),
1550 };
1551
1552 let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) {
1553 Some(
1554 LangItem::Range
1555 | LangItem::RangeFrom
1556 | LangItem::RangeTo
1557 | LangItem::RangeFull
1558 | LangItem::RangeInclusiveStruct
1559 | LangItem::RangeToInclusive,
1560 ) => true,
1561 _ => false,
1562 };
1563 if is_range {
1564 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1565 let msg = "constants only support matching by type, \
1566 if you meant to match against a range of values, \
1567 consider using a range pattern like `min ..= max` in the match block";
1568 e.note(msg);
1569 }
1570 } else {
1571 let msg = "introduce a new binding instead";
1572 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1573 e.span_suggestion(
1574 ident.span,
1575 msg,
1576 sugg,
1577 Applicability::HasPlaceholders,
1578 );
1579 }
1580 }
1581 };
1582 }
1583 }
1584 e.emit();
1585 }
1586
1587 fn resolve_pat_tuple_struct(
1588 &self,
1589 pat: &'tcx Pat<'tcx>,
1590 qpath: &'tcx hir::QPath<'tcx>,
1591 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1592 let tcx = self.tcx;
1593 let report_unexpected_res = |res: Res| {
1594 let expected = "tuple struct or tuple variant";
1595 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1596 Err(e)
1597 };
1598
1599 let (res, opt_ty, segments) =
1601 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1602 if res == Res::Err {
1603 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1604 self.set_tainted_by_errors(e);
1605 return Err(e);
1606 }
1607
1608 let (pat_ty, res) =
1610 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1611 if !pat_ty.is_fn() {
1612 return report_unexpected_res(res);
1613 }
1614
1615 let variant = match res {
1616 Res::Err => {
1617 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1618 }
1619 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1620 return report_unexpected_res(res);
1621 }
1622 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1623 _ => bug!("unexpected pattern resolution: {:?}", res),
1624 };
1625
1626 let pat_ty = pat_ty.fn_sig(tcx).output();
1628 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1629
1630 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1631 }
1632
1633 fn check_pat_tuple_struct(
1634 &self,
1635 pat: &'tcx Pat<'tcx>,
1636 qpath: &'tcx hir::QPath<'tcx>,
1637 subpats: &'tcx [Pat<'tcx>],
1638 ddpos: hir::DotDotPos,
1639 res: Res,
1640 pat_ty: Ty<'tcx>,
1641 variant: &'tcx VariantDef,
1642 expected: Ty<'tcx>,
1643 pat_info: PatInfo<'tcx>,
1644 ) -> Ty<'tcx> {
1645 let tcx = self.tcx;
1646 let on_error = |e| {
1647 for pat in subpats {
1648 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1649 }
1650 };
1651
1652 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1654 let had_err = diag.map_err(|diag| diag.emit());
1655
1656 if subpats.len() == variant.fields.len()
1658 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1659 {
1660 let ty::Adt(_, args) = pat_ty.kind() else {
1661 bug!("unexpected pattern type {:?}", pat_ty);
1662 };
1663 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1664 let field = &variant.fields[FieldIdx::from_usize(i)];
1665 let field_ty = self.field_ty(subpat.span, field, args);
1666 self.check_pat(subpat, field_ty, pat_info);
1667
1668 self.tcx.check_stability(
1669 variant.fields[FieldIdx::from_usize(i)].did,
1670 Some(subpat.hir_id),
1671 subpat.span,
1672 None,
1673 );
1674 }
1675 if let Err(e) = had_err {
1676 on_error(e);
1677 return Ty::new_error(tcx, e);
1678 }
1679 } else {
1680 let e = self.emit_err_pat_wrong_number_of_fields(
1681 pat.span,
1682 res,
1683 qpath,
1684 subpats,
1685 &variant.fields.raw,
1686 expected,
1687 had_err,
1688 );
1689 on_error(e);
1690 return Ty::new_error(tcx, e);
1691 }
1692 pat_ty
1693 }
1694
1695 fn emit_err_pat_wrong_number_of_fields(
1696 &self,
1697 pat_span: Span,
1698 res: Res,
1699 qpath: &hir::QPath<'_>,
1700 subpats: &'tcx [Pat<'tcx>],
1701 fields: &'tcx [ty::FieldDef],
1702 expected: Ty<'tcx>,
1703 had_err: Result<(), ErrorGuaranteed>,
1704 ) -> ErrorGuaranteed {
1705 let subpats_ending = pluralize!(subpats.len());
1706 let fields_ending = pluralize!(fields.len());
1707
1708 let subpat_spans = if subpats.is_empty() {
1709 vec![pat_span]
1710 } else {
1711 subpats.iter().map(|p| p.span).collect()
1712 };
1713 let last_subpat_span = *subpat_spans.last().unwrap();
1714 let res_span = self.tcx.def_span(res.def_id());
1715 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1716 let field_def_spans = if fields.is_empty() {
1717 vec![res_span]
1718 } else {
1719 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1720 };
1721 let last_field_def_span = *field_def_spans.last().unwrap();
1722
1723 let mut err = struct_span_code_err!(
1724 self.dcx(),
1725 MultiSpan::from_spans(subpat_spans),
1726 E0023,
1727 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1728 subpats.len(),
1729 subpats_ending,
1730 res.descr(),
1731 fields.len(),
1732 fields_ending,
1733 );
1734 err.span_label(
1735 last_subpat_span,
1736 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1737 );
1738 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1739 err.span_label(qpath.span(), "");
1740 }
1741 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1742 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1743 }
1744 for span in &field_def_spans[..field_def_spans.len() - 1] {
1745 err.span_label(*span, "");
1746 }
1747 err.span_label(
1748 last_field_def_span,
1749 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1750 );
1751
1752 let missing_parentheses = match (expected.kind(), fields, had_err) {
1757 (ty::Adt(_, args), [field], Ok(())) => {
1761 let field_ty = self.field_ty(pat_span, field, args);
1762 match field_ty.kind() {
1763 ty::Tuple(fields) => fields.len() == subpats.len(),
1764 _ => false,
1765 }
1766 }
1767 _ => false,
1768 };
1769 if missing_parentheses {
1770 let (left, right) = match subpats {
1771 [] => (qpath.span().shrink_to_hi(), pat_span),
1780 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1789 };
1790 err.multipart_suggestion(
1791 "missing parentheses",
1792 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1793 Applicability::MachineApplicable,
1794 );
1795 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1796 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1797 let all_fields_span = match subpats {
1798 [] => after_fields_span,
1799 [field] => field.span,
1800 [first, .., last] => first.span.to(last.span),
1801 };
1802
1803 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1805 let first_tail_wildcard =
1806 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1807 (None, PatKind::Wild) => Some(pos),
1808 (Some(_), PatKind::Wild) => acc,
1809 _ => None,
1810 });
1811 let tail_span = match first_tail_wildcard {
1812 None => after_fields_span,
1813 Some(0) => subpats[0].span.to(after_fields_span),
1814 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1815 };
1816
1817 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1819 if !subpats.is_empty() {
1820 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1821 }
1822
1823 err.span_suggestion_verbose(
1824 after_fields_span,
1825 "use `_` to explicitly ignore each field",
1826 wildcard_sugg,
1827 Applicability::MaybeIncorrect,
1828 );
1829
1830 if fields.len() - subpats.len() > 1 || all_wildcards {
1833 if subpats.is_empty() || all_wildcards {
1834 err.span_suggestion_verbose(
1835 all_fields_span,
1836 "use `..` to ignore all fields",
1837 "..",
1838 Applicability::MaybeIncorrect,
1839 );
1840 } else {
1841 err.span_suggestion_verbose(
1842 tail_span,
1843 "use `..` to ignore the rest of the fields",
1844 ", ..",
1845 Applicability::MaybeIncorrect,
1846 );
1847 }
1848 }
1849 }
1850
1851 err.emit()
1852 }
1853
1854 fn check_pat_tuple(
1855 &self,
1856 span: Span,
1857 elements: &'tcx [Pat<'tcx>],
1858 ddpos: hir::DotDotPos,
1859 expected: Ty<'tcx>,
1860 pat_info: PatInfo<'tcx>,
1861 ) -> Ty<'tcx> {
1862 let tcx = self.tcx;
1863 let mut expected_len = elements.len();
1864 if ddpos.as_opt_usize().is_some() {
1865 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1867 expected_len = tys.len();
1868 }
1869 }
1870 let max_len = cmp::max(expected_len, elements.len());
1871
1872 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1873 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1874 let pat_ty = Ty::new_tup(tcx, element_tys);
1875 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
1876 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1879 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1880 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1881 }
1882 Ty::new_tup_from_iter(tcx, element_tys_iter)
1883 } else {
1884 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1885 self.check_pat(elem, element_tys[i], pat_info);
1886 }
1887 pat_ty
1888 }
1889 }
1890
1891 fn check_struct_pat_fields(
1892 &self,
1893 adt_ty: Ty<'tcx>,
1894 pat: &'tcx Pat<'tcx>,
1895 variant: &'tcx ty::VariantDef,
1896 fields: &'tcx [hir::PatField<'tcx>],
1897 has_rest_pat: bool,
1898 pat_info: PatInfo<'tcx>,
1899 ) -> Result<(), ErrorGuaranteed> {
1900 let tcx = self.tcx;
1901
1902 let ty::Adt(adt, args) = adt_ty.kind() else {
1903 span_bug!(pat.span, "struct pattern is not an ADT");
1904 };
1905
1906 let field_map = variant
1908 .fields
1909 .iter_enumerated()
1910 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
1911 .collect::<FxHashMap<_, _>>();
1912
1913 let mut used_fields = FxHashMap::default();
1915 let mut result = Ok(());
1916
1917 let mut inexistent_fields = vec![];
1918 for field in fields {
1920 let span = field.span;
1921 let ident = tcx.adjust_ident(field.ident, variant.def_id);
1922 let field_ty = match used_fields.entry(ident) {
1923 Occupied(occupied) => {
1924 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
1925 result = Err(guar);
1926 Ty::new_error(tcx, guar)
1927 }
1928 Vacant(vacant) => {
1929 vacant.insert(span);
1930 field_map
1931 .get(&ident)
1932 .map(|(i, f)| {
1933 self.write_field_index(field.hir_id, *i);
1934 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
1935 self.field_ty(span, f, args)
1936 })
1937 .unwrap_or_else(|| {
1938 inexistent_fields.push(field);
1939 Ty::new_misc_error(tcx)
1940 })
1941 }
1942 };
1943
1944 self.check_pat(field.pat, field_ty, pat_info);
1945 }
1946
1947 let mut unmentioned_fields = variant
1948 .fields
1949 .iter()
1950 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
1951 .filter(|(_, ident)| !used_fields.contains_key(ident))
1952 .collect::<Vec<_>>();
1953
1954 let inexistent_fields_err = if !inexistent_fields.is_empty()
1955 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
1956 {
1957 variant.has_errors()?;
1959 Some(self.error_inexistent_fields(
1960 adt.variant_descr(),
1961 &inexistent_fields,
1962 &mut unmentioned_fields,
1963 pat,
1964 variant,
1965 args,
1966 ))
1967 } else {
1968 None
1969 };
1970
1971 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
1973 if non_exhaustive && !has_rest_pat {
1974 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
1975 }
1976
1977 let mut unmentioned_err = None;
1978 if adt.is_union() {
1980 if fields.len() != 1 {
1981 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
1982 }
1983 if has_rest_pat {
1984 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
1985 }
1986 } else if !unmentioned_fields.is_empty() {
1987 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
1988 .iter()
1989 .copied()
1990 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
1991 .collect();
1992
1993 if !has_rest_pat {
1994 if accessible_unmentioned_fields.is_empty() {
1995 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
1996 } else {
1997 unmentioned_err = Some(self.error_unmentioned_fields(
1998 pat,
1999 &accessible_unmentioned_fields,
2000 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
2001 fields,
2002 ));
2003 }
2004 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
2005 self.lint_non_exhaustive_omitted_patterns(
2006 pat,
2007 &accessible_unmentioned_fields,
2008 adt_ty,
2009 )
2010 }
2011 }
2012 match (inexistent_fields_err, unmentioned_err) {
2013 (Some(i), Some(u)) => {
2014 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2015 i.delay_as_bug();
2018 u.delay_as_bug();
2019 Err(e)
2020 } else {
2021 i.emit();
2022 Err(u.emit())
2023 }
2024 }
2025 (None, Some(u)) => {
2026 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2027 u.delay_as_bug();
2028 Err(e)
2029 } else {
2030 Err(u.emit())
2031 }
2032 }
2033 (Some(err), None) => Err(err.emit()),
2034 (None, None) => {
2035 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
2036 result
2037 }
2038 }
2039 }
2040
2041 fn error_tuple_variant_index_shorthand(
2042 &self,
2043 variant: &VariantDef,
2044 pat: &'_ Pat<'_>,
2045 fields: &[hir::PatField<'_>],
2046 ) -> Result<(), ErrorGuaranteed> {
2047 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
2051 (variant.ctor_kind(), &pat.kind)
2052 {
2053 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
2054 if has_shorthand_field_name {
2055 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2056 let mut err = struct_span_code_err!(
2057 self.dcx(),
2058 pat.span,
2059 E0769,
2060 "tuple variant `{path}` written as struct variant",
2061 );
2062 err.span_suggestion_verbose(
2063 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2064 "use the tuple variant pattern syntax instead",
2065 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
2066 Applicability::MaybeIncorrect,
2067 );
2068 return Err(err.emit());
2069 }
2070 }
2071 Ok(())
2072 }
2073
2074 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
2075 let sess = self.tcx.sess;
2076 let sm = sess.source_map();
2077 let sp_brace = sm.end_point(pat.span);
2078 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
2079 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
2080
2081 struct_span_code_err!(
2082 self.dcx(),
2083 pat.span,
2084 E0638,
2085 "`..` required with {descr} marked as non-exhaustive",
2086 )
2087 .with_span_suggestion_verbose(
2088 sp_comma,
2089 "add `..` at the end of the field list to ignore all other fields",
2090 sugg,
2091 Applicability::MachineApplicable,
2092 )
2093 .emit();
2094 }
2095
2096 fn error_field_already_bound(
2097 &self,
2098 span: Span,
2099 ident: Ident,
2100 other_field: Span,
2101 ) -> ErrorGuaranteed {
2102 struct_span_code_err!(
2103 self.dcx(),
2104 span,
2105 E0025,
2106 "field `{}` bound multiple times in the pattern",
2107 ident
2108 )
2109 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2110 .with_span_label(other_field, format!("first use of `{ident}`"))
2111 .emit()
2112 }
2113
2114 fn error_inexistent_fields(
2115 &self,
2116 kind_name: &str,
2117 inexistent_fields: &[&hir::PatField<'tcx>],
2118 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2119 pat: &'tcx Pat<'tcx>,
2120 variant: &ty::VariantDef,
2121 args: ty::GenericArgsRef<'tcx>,
2122 ) -> Diag<'a> {
2123 let tcx = self.tcx;
2124 let (field_names, t, plural) = if let [field] = inexistent_fields {
2125 (format!("a field named `{}`", field.ident), "this", "")
2126 } else {
2127 (
2128 format!(
2129 "fields named {}",
2130 inexistent_fields
2131 .iter()
2132 .map(|field| format!("`{}`", field.ident))
2133 .collect::<Vec<String>>()
2134 .join(", ")
2135 ),
2136 "these",
2137 "s",
2138 )
2139 };
2140 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2141 let mut err = struct_span_code_err!(
2142 self.dcx(),
2143 spans,
2144 E0026,
2145 "{} `{}` does not have {}",
2146 kind_name,
2147 tcx.def_path_str(variant.def_id),
2148 field_names
2149 );
2150 if let Some(pat_field) = inexistent_fields.last() {
2151 err.span_label(
2152 pat_field.ident.span,
2153 format!(
2154 "{} `{}` does not have {} field{}",
2155 kind_name,
2156 tcx.def_path_str(variant.def_id),
2157 t,
2158 plural
2159 ),
2160 );
2161
2162 if let [(field_def, field)] = unmentioned_fields.as_slice()
2163 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2164 {
2165 let suggested_name =
2166 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2167 if let Some(suggested_name) = suggested_name {
2168 err.span_suggestion(
2169 pat_field.ident.span,
2170 "a field with a similar name exists",
2171 suggested_name,
2172 Applicability::MaybeIncorrect,
2173 );
2174
2175 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2181 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2183 }
2184 } else if inexistent_fields.len() == 1 {
2185 match pat_field.pat.kind {
2186 PatKind::Expr(_)
2187 if !self.may_coerce(
2188 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2189 self.field_ty(field.span, field_def, args),
2190 ) => {}
2191 _ => {
2192 err.span_suggestion_short(
2193 pat_field.ident.span,
2194 format!(
2195 "`{}` has a field named `{}`",
2196 tcx.def_path_str(variant.def_id),
2197 field.name,
2198 ),
2199 field.name,
2200 Applicability::MaybeIncorrect,
2201 );
2202 }
2203 }
2204 }
2205 }
2206 }
2207 if tcx.sess.teach(err.code.unwrap()) {
2208 err.note(
2209 "This error indicates that a struct pattern attempted to \
2210 extract a nonexistent field from a struct. Struct fields \
2211 are identified by the name used before the colon : so struct \
2212 patterns should resemble the declaration of the struct type \
2213 being matched.\n\n\
2214 If you are using shorthand field patterns but want to refer \
2215 to the struct field by a different name, you should rename \
2216 it explicitly.",
2217 );
2218 }
2219 err
2220 }
2221
2222 fn error_tuple_variant_as_struct_pat(
2223 &self,
2224 pat: &Pat<'_>,
2225 fields: &'tcx [hir::PatField<'tcx>],
2226 variant: &ty::VariantDef,
2227 ) -> Result<(), ErrorGuaranteed> {
2228 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2229 (variant.ctor_kind(), &pat.kind)
2230 {
2231 let is_tuple_struct_match = !pattern_fields.is_empty()
2232 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2233 if is_tuple_struct_match {
2234 return Ok(());
2235 }
2236
2237 variant.has_errors()?;
2239
2240 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2241 let mut err = struct_span_code_err!(
2242 self.dcx(),
2243 pat.span,
2244 E0769,
2245 "tuple variant `{}` written as struct variant",
2246 path
2247 );
2248 let (sugg, appl) = if fields.len() == variant.fields.len() {
2249 (
2250 self.get_suggested_tuple_struct_pattern(fields, variant),
2251 Applicability::MachineApplicable,
2252 )
2253 } else {
2254 (
2255 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2256 Applicability::MaybeIncorrect,
2257 )
2258 };
2259 err.span_suggestion_verbose(
2260 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2261 "use the tuple variant pattern syntax instead",
2262 format!("({sugg})"),
2263 appl,
2264 );
2265 return Err(err.emit());
2266 }
2267 Ok(())
2268 }
2269
2270 fn get_suggested_tuple_struct_pattern(
2271 &self,
2272 fields: &[hir::PatField<'_>],
2273 variant: &VariantDef,
2274 ) -> String {
2275 let variant_field_idents =
2276 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2277 fields
2278 .iter()
2279 .map(|field| {
2280 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2281 Ok(f) => {
2282 if variant_field_idents.contains(&field.ident) {
2285 String::from("_")
2286 } else {
2287 f
2288 }
2289 }
2290 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2291 }
2292 })
2293 .collect::<Vec<String>>()
2294 .join(", ")
2295 }
2296
2297 fn error_no_accessible_fields(
2313 &self,
2314 pat: &Pat<'_>,
2315 fields: &'tcx [hir::PatField<'tcx>],
2316 ) -> Diag<'a> {
2317 let mut err = self
2318 .dcx()
2319 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2320
2321 if let Some(field) = fields.last() {
2322 err.span_suggestion_verbose(
2323 field.span.shrink_to_hi(),
2324 "ignore the inaccessible and unused fields",
2325 ", ..",
2326 Applicability::MachineApplicable,
2327 );
2328 } else {
2329 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2330 qpath.span()
2331 } else {
2332 bug!("`error_no_accessible_fields` called on non-struct pattern");
2333 };
2334
2335 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2337 err.span_suggestion_verbose(
2338 span,
2339 "ignore the inaccessible and unused fields",
2340 " { .. }",
2341 Applicability::MachineApplicable,
2342 );
2343 }
2344 err
2345 }
2346
2347 fn lint_non_exhaustive_omitted_patterns(
2352 &self,
2353 pat: &Pat<'_>,
2354 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2355 ty: Ty<'tcx>,
2356 ) {
2357 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2358 const LIMIT: usize = 3;
2359 match witnesses {
2360 [] => {
2361 unreachable!(
2362 "expected an uncovered pattern, otherwise why are we emitting an error?"
2363 )
2364 }
2365 [witness] => format!("`{witness}`"),
2366 [head @ .., tail] if head.len() < LIMIT => {
2367 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2368 format!("`{}` and `{}`", head.join("`, `"), tail)
2369 }
2370 _ => {
2371 let (head, tail) = witnesses.split_at(LIMIT);
2372 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2373 format!("`{}` and {} more", head.join("`, `"), tail.len())
2374 }
2375 }
2376 }
2377 let joined_patterns = joined_uncovered_patterns(
2378 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2379 );
2380
2381 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2382 lint.primary_message("some fields are not explicitly listed");
2383 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2384 lint.help(
2385 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2386 );
2387 lint.note(format!(
2388 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2389 ));
2390 });
2391 }
2392
2393 fn error_unmentioned_fields(
2403 &self,
2404 pat: &Pat<'_>,
2405 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2406 have_inaccessible_fields: bool,
2407 fields: &'tcx [hir::PatField<'tcx>],
2408 ) -> Diag<'a> {
2409 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2410 let field_names = if let [(_, field)] = unmentioned_fields {
2411 format!("field `{field}`{inaccessible}")
2412 } else {
2413 let fields = unmentioned_fields
2414 .iter()
2415 .map(|(_, name)| format!("`{name}`"))
2416 .collect::<Vec<String>>()
2417 .join(", ");
2418 format!("fields {fields}{inaccessible}")
2419 };
2420 let mut err = struct_span_code_err!(
2421 self.dcx(),
2422 pat.span,
2423 E0027,
2424 "pattern does not mention {}",
2425 field_names
2426 );
2427 err.span_label(pat.span, format!("missing {field_names}"));
2428 let len = unmentioned_fields.len();
2429 let (prefix, postfix, sp) = match fields {
2430 [] => match &pat.kind {
2431 PatKind::Struct(path, [], false) => {
2432 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2433 }
2434 _ => return err,
2435 },
2436 [.., field] => {
2437 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2440 match &pat.kind {
2441 PatKind::Struct(..) => (", ", " }", tail),
2442 _ => return err,
2443 }
2444 }
2445 };
2446 err.span_suggestion(
2447 sp,
2448 format!(
2449 "include the missing field{} in the pattern{}",
2450 pluralize!(len),
2451 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2452 ),
2453 format!(
2454 "{}{}{}{}",
2455 prefix,
2456 unmentioned_fields
2457 .iter()
2458 .map(|(_, name)| {
2459 let field_name = name.to_string();
2460 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2461 })
2462 .collect::<Vec<_>>()
2463 .join(", "),
2464 if have_inaccessible_fields { ", .." } else { "" },
2465 postfix,
2466 ),
2467 Applicability::MachineApplicable,
2468 );
2469 err.span_suggestion(
2470 sp,
2471 format!(
2472 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2473 these = pluralize!("this", len),
2474 s = pluralize!(len),
2475 them = if len == 1 { "it" } else { "them" },
2476 ),
2477 format!(
2478 "{}{}{}{}",
2479 prefix,
2480 unmentioned_fields
2481 .iter()
2482 .map(|(_, name)| {
2483 let field_name = name.to_string();
2484 format!("{field_name}: _")
2485 })
2486 .collect::<Vec<_>>()
2487 .join(", "),
2488 if have_inaccessible_fields { ", .." } else { "" },
2489 postfix,
2490 ),
2491 Applicability::MachineApplicable,
2492 );
2493 err.span_suggestion(
2494 sp,
2495 "or always ignore missing fields here",
2496 format!("{prefix}..{postfix}"),
2497 Applicability::MachineApplicable,
2498 );
2499 err
2500 }
2501
2502 fn check_pat_box(
2503 &self,
2504 span: Span,
2505 inner: &'tcx Pat<'tcx>,
2506 expected: Ty<'tcx>,
2507 pat_info: PatInfo<'tcx>,
2508 ) -> Ty<'tcx> {
2509 let tcx = self.tcx;
2510 let (box_ty, inner_ty) = self
2511 .check_dereferenceable(span, expected, inner)
2512 .and_then(|()| {
2513 let inner_ty = self.next_ty_var(inner.span);
2516 let box_ty = Ty::new_box(tcx, inner_ty);
2517 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2518 Ok((box_ty, inner_ty))
2519 })
2520 .unwrap_or_else(|guar| {
2521 let err = Ty::new_error(tcx, guar);
2522 (err, err)
2523 });
2524 self.check_pat(inner, inner_ty, pat_info);
2525 box_ty
2526 }
2527
2528 fn check_pat_deref(
2529 &self,
2530 span: Span,
2531 inner: &'tcx Pat<'tcx>,
2532 expected: Ty<'tcx>,
2533 pat_info: PatInfo<'tcx>,
2534 ) -> Ty<'tcx> {
2535 let target_ty = self.deref_pat_target(span, expected);
2536 self.check_pat(inner, target_ty, pat_info);
2537 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2538 expected
2539 }
2540
2541 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2542 let tcx = self.tcx;
2544 self.register_bound(
2545 source_ty,
2546 tcx.require_lang_item(hir::LangItem::DerefPure, span),
2547 self.misc(span),
2548 );
2549 let target_ty = Ty::new_projection(
2551 tcx,
2552 tcx.require_lang_item(hir::LangItem::DerefTarget, span),
2553 [source_ty],
2554 );
2555 let target_ty = self.normalize(span, target_ty);
2556 self.try_structurally_resolve_type(span, target_ty)
2557 }
2558
2559 fn register_deref_mut_bounds_if_needed(
2564 &self,
2565 span: Span,
2566 inner: &'tcx Pat<'tcx>,
2567 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2568 ) {
2569 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2570 for mutably_derefed_ty in derefed_tys {
2571 self.register_bound(
2572 mutably_derefed_ty,
2573 self.tcx.require_lang_item(hir::LangItem::DerefMut, span),
2574 self.misc(span),
2575 );
2576 }
2577 }
2578 }
2579
2580 fn check_pat_ref(
2582 &self,
2583 pat: &'tcx Pat<'tcx>,
2584 inner: &'tcx Pat<'tcx>,
2585 pat_mutbl: Mutability,
2586 mut expected: Ty<'tcx>,
2587 mut pat_info: PatInfo<'tcx>,
2588 ) -> Ty<'tcx> {
2589 let tcx = self.tcx;
2590
2591 let pat_prefix_span =
2592 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2593
2594 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2595 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2596 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2601 }
2602
2603 expected = self.try_structurally_resolve_type(pat.span, expected);
2604 if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2607 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2608 InheritedRefMatchRule::EatOuter => {
2609 if pat_mutbl > inh_mut {
2611 debug_assert!(ref_pat_matches_mut_ref);
2616 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2617 }
2618
2619 pat_info.binding_mode = ByRef::No;
2620 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2621 self.check_pat(inner, expected, pat_info);
2622 return expected;
2623 }
2624 InheritedRefMatchRule::EatInner => {
2625 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2626 && pat_mutbl <= r_mutbl
2627 {
2628 debug_assert!(ref_pat_matches_mut_ref);
2635 debug_assert!(self.downgrade_mut_inside_shared());
2639 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2640 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2641 } else {
2642 if pat_mutbl > inh_mut {
2645 debug_assert!(ref_pat_matches_mut_ref);
2654 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2655 }
2656
2657 pat_info.binding_mode = ByRef::No;
2658 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2659 self.check_pat(inner, expected, pat_info);
2660 return expected;
2661 }
2662 }
2663 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2664 pat_info.binding_mode = ByRef::No;
2666
2667 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2668 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2670 self.check_pat(inner, inner_ty, pat_info);
2677 return expected;
2678 } else {
2679 }
2686 } else {
2687 if pat_mutbl > inh_mut {
2690 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2692 }
2693
2694 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2695 self.check_pat(inner, expected, pat_info);
2696 return expected;
2697 }
2698 }
2699 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2700 pat_info.binding_mode = ByRef::No;
2703 self.add_rust_2024_migration_desugared_pat(
2704 pat_info.top_info.hir_id,
2705 pat,
2706 match pat_mutbl {
2707 Mutability::Not => '&', Mutability::Mut => 't', },
2710 inh_mut,
2711 )
2712 }
2713 }
2714 }
2715
2716 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2717 Ok(()) => {
2718 debug!("check_pat_ref: expected={:?}", expected);
2725 match *expected.kind() {
2726 ty::Ref(_, r_ty, r_mutbl)
2727 if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2728 || r_mutbl == pat_mutbl =>
2729 {
2730 if r_mutbl == Mutability::Not {
2731 pat_info.max_ref_mutbl = MutblCap::Not;
2732 }
2733
2734 (expected, r_ty)
2735 }
2736
2737 _ => {
2738 let inner_ty = self.next_ty_var(inner.span);
2739 let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
2740 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2741 let err = self.demand_eqtype_pat_diag(
2742 pat.span,
2743 expected,
2744 ref_ty,
2745 &pat_info.top_info,
2746 );
2747
2748 if let Err(mut err) = err {
2751 self.borrow_pat_suggestion(&mut err, pat);
2752 err.emit();
2753 }
2754 (ref_ty, inner_ty)
2755 }
2756 }
2757 }
2758 Err(guar) => {
2759 let err = Ty::new_error(tcx, guar);
2760 (err, err)
2761 }
2762 };
2763
2764 self.check_pat(inner, inner_ty, pat_info);
2765 ref_ty
2766 }
2767
2768 fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
2770 let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
2771 Ty::new_ref(self.tcx, region, ty, mutbl)
2772 }
2773
2774 fn error_inherited_ref_mutability_mismatch(
2775 &self,
2776 pat: &'tcx Pat<'tcx>,
2777 pat_prefix_span: Option<Span>,
2778 ) -> ErrorGuaranteed {
2779 let err_msg = "mismatched types";
2780 let err = if let Some(span) = pat_prefix_span {
2781 let mut err = self.dcx().struct_span_err(span, err_msg);
2782 err.code(E0308);
2783 err.note("cannot match inherited `&` with `&mut` pattern");
2784 err.span_suggestion_verbose(
2785 span,
2786 "replace this `&mut` pattern with `&`",
2787 "&",
2788 Applicability::MachineApplicable,
2789 );
2790 err
2791 } else {
2792 self.dcx().struct_span_err(pat.span, err_msg)
2793 };
2794 err.emit()
2795 }
2796
2797 fn try_resolve_slice_ty_to_array_ty(
2798 &self,
2799 before: &'tcx [Pat<'tcx>],
2800 slice: Option<&'tcx Pat<'tcx>>,
2801 span: Span,
2802 ) -> Option<Ty<'tcx>> {
2803 if slice.is_some() {
2804 return None;
2805 }
2806
2807 let tcx = self.tcx;
2808 let len = before.len();
2809 let inner_ty = self.next_ty_var(span);
2810
2811 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2812 }
2813
2814 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2845 match decl_origin {
2846 Some(DeclOrigin::LocalDecl { els: None }) => true,
2847 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2848 }
2849 }
2850
2851 fn check_pat_slice(
2862 &self,
2863 span: Span,
2864 before: &'tcx [Pat<'tcx>],
2865 slice: Option<&'tcx Pat<'tcx>>,
2866 after: &'tcx [Pat<'tcx>],
2867 expected: Ty<'tcx>,
2868 pat_info: PatInfo<'tcx>,
2869 ) -> Ty<'tcx> {
2870 let expected = self.try_structurally_resolve_type(span, expected);
2871
2872 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
2875 if let Some(resolved_arr_ty) =
2876 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
2877 {
2878 debug!(?resolved_arr_ty);
2879 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
2880 }
2881 }
2882
2883 let expected = self.structurally_resolve_type(span, expected);
2884 debug!(?expected);
2885
2886 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
2887 ty::Array(element_ty, len) => {
2889 let min = before.len() as u64 + after.len() as u64;
2890 let (opt_slice_ty, expected) =
2891 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
2892 assert!(opt_slice_ty.is_some() || slice.is_none());
2895 (element_ty, opt_slice_ty, expected)
2896 }
2897 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
2898 _ => {
2900 let guar = expected.error_reported().err().unwrap_or_else(|| {
2901 self.error_expected_array_or_slice(span, expected, pat_info)
2902 });
2903 let err = Ty::new_error(self.tcx, guar);
2904 (err, Some(err), err)
2905 }
2906 };
2907
2908 for elt in before {
2910 self.check_pat(elt, element_ty, pat_info);
2911 }
2912 if let Some(slice) = slice {
2914 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
2915 }
2916 for elt in after {
2918 self.check_pat(elt, element_ty, pat_info);
2919 }
2920 inferred
2921 }
2922
2923 fn check_array_pat_len(
2928 &self,
2929 span: Span,
2930 element_ty: Ty<'tcx>,
2931 arr_ty: Ty<'tcx>,
2932 slice: Option<&'tcx Pat<'tcx>>,
2933 len: ty::Const<'tcx>,
2934 min_len: u64,
2935 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
2936 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
2937
2938 let guar = if let Some(len) = len {
2939 if slice.is_none() {
2941 if min_len == len {
2945 return (None, arr_ty);
2946 }
2947
2948 self.error_scrutinee_inconsistent_length(span, min_len, len)
2949 } else if let Some(pat_len) = len.checked_sub(min_len) {
2950 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
2953 } else {
2954 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
2957 }
2958 } else if slice.is_none() {
2959 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
2962 self.demand_eqtype(span, updated_arr_ty, arr_ty);
2963 return (None, updated_arr_ty);
2964 } else {
2965 self.error_scrutinee_unfixed_length(span)
2969 };
2970
2971 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
2973 }
2974
2975 fn error_scrutinee_inconsistent_length(
2976 &self,
2977 span: Span,
2978 min_len: u64,
2979 size: u64,
2980 ) -> ErrorGuaranteed {
2981 struct_span_code_err!(
2982 self.dcx(),
2983 span,
2984 E0527,
2985 "pattern requires {} element{} but array has {}",
2986 min_len,
2987 pluralize!(min_len),
2988 size,
2989 )
2990 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
2991 .emit()
2992 }
2993
2994 fn error_scrutinee_with_rest_inconsistent_length(
2995 &self,
2996 span: Span,
2997 min_len: u64,
2998 size: u64,
2999 ) -> ErrorGuaranteed {
3000 struct_span_code_err!(
3001 self.dcx(),
3002 span,
3003 E0528,
3004 "pattern requires at least {} element{} but array has {}",
3005 min_len,
3006 pluralize!(min_len),
3007 size,
3008 )
3009 .with_span_label(
3010 span,
3011 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
3012 )
3013 .emit()
3014 }
3015
3016 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
3017 struct_span_code_err!(
3018 self.dcx(),
3019 span,
3020 E0730,
3021 "cannot pattern-match on an array without a fixed length",
3022 )
3023 .emit()
3024 }
3025
3026 fn error_expected_array_or_slice(
3027 &self,
3028 span: Span,
3029 expected_ty: Ty<'tcx>,
3030 pat_info: PatInfo<'tcx>,
3031 ) -> ErrorGuaranteed {
3032 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
3033
3034 let mut slice_pat_semantics = false;
3035 let mut as_deref = None;
3036 let mut slicing = None;
3037 if let ty::Ref(_, ty, _) = expected_ty.kind()
3038 && let ty::Array(..) | ty::Slice(..) = ty.kind()
3039 {
3040 slice_pat_semantics = true;
3041 } else if self
3042 .autoderef(span, expected_ty)
3043 .silence_errors()
3044 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
3045 && let Some(span) = ti.span
3046 && let Some(_) = ti.origin_expr
3047 {
3048 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
3049 let (is_slice_or_array_or_vector, resolved_ty) =
3050 self.is_slice_or_array_or_vector(resolved_ty);
3051 match resolved_ty.kind() {
3052 ty::Adt(adt_def, _)
3053 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
3054 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
3055 {
3056 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
3058 }
3059 _ => (),
3060 }
3061
3062 let is_top_level = current_depth <= 1;
3063 if is_slice_or_array_or_vector && is_top_level {
3064 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
3065 }
3066 }
3067 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
3068 span,
3069 ty: expected_ty,
3070 slice_pat_semantics,
3071 as_deref,
3072 slicing,
3073 })
3074 }
3075
3076 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
3077 match ty.kind() {
3078 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
3079 (true, ty)
3080 }
3081 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
3082 ty::Slice(..) | ty::Array(..) => (true, ty),
3083 _ => (false, ty),
3084 }
3085 }
3086
3087 fn add_rust_2024_migration_desugared_pat(
3090 &self,
3091 pat_id: HirId,
3092 subpat: &'tcx Pat<'tcx>,
3093 final_char: char,
3094 def_br_mutbl: Mutability,
3095 ) {
3096 let from_expansion = subpat.span.from_expansion();
3098 let trimmed_span = if from_expansion {
3099 subpat.span
3101 } else {
3102 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3103 trimmed.with_ctxt(subpat.span.ctxt())
3106 };
3107
3108 let mut typeck_results = self.typeck_results.borrow_mut();
3109 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3110 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3115 primary_labels: Vec::new(),
3116 bad_modifiers: false,
3117 bad_ref_pats: false,
3118 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3119 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3120 });
3121
3122 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3123 info.bad_modifiers = true;
3124 info.suggest_eliding_modes &=
3128 user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
3129 "binding modifier"
3130 } else {
3131 info.bad_ref_pats = true;
3132 info.suggest_eliding_modes = false;
3136 "reference pattern"
3137 };
3138 let primary_label = if from_expansion {
3141 info.suggest_eliding_modes = false;
3143 "occurs within macro expansion".to_owned()
3147 } else {
3148 let dbm_str = match def_br_mutbl {
3149 Mutability::Not => "ref",
3150 Mutability::Mut => "ref mut",
3151 };
3152 format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
3153 };
3154 info.primary_labels.push((trimmed_span, primary_label));
3155 }
3156}