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