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;
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::hygiene::DesugaringKind;
28use rustc_span::source_map::Spanned;
29use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym};
30use rustc_trait_selection::infer::InferCtxtExt;
31use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
32use tracing::{debug, instrument, trace};
33use ty::VariantDef;
34use ty::adjustment::{PatAdjust, PatAdjustment};
35
36use super::report_unexpected_variant_res;
37use crate::expectation::Expectation;
38use crate::gather_locals::DeclOrigin;
39use crate::{FnCtxt, errors};
40
41const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
42This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
43pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \
44this type has no compile-time size. Therefore, all accesses to trait types must be through \
45pointers. If you encounter this error you should try to avoid dereferencing the pointer.
46
47You can read more about trait objects in the Trait Objects section of the Reference: \
48https://doc.rust-lang.org/reference/types.html#trait-objects";
49
50fn is_number(text: &str) -> bool {
51 text.chars().all(|c: char| c.is_digit(10))
52}
53
54#[derive(Copy, Clone)]
58struct TopInfo<'tcx> {
59 expected: Ty<'tcx>,
61 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
65 span: Option<Span>,
88 hir_id: HirId,
90}
91
92#[derive(Copy, Clone)]
93struct PatInfo<'tcx> {
94 binding_mode: ByRef,
95 max_ref_mutbl: MutblCap,
96 top_info: TopInfo<'tcx>,
97 decl_origin: Option<DeclOrigin<'tcx>>,
98
99 current_depth: u32,
101}
102
103impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
104 fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
105 let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
110 let mut count = 0;
111
112 while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
116 cur_expr = inner;
117 count += 1;
118 }
119
120 PatternOriginExpr {
121 peeled_span: cur_expr.span,
122 peeled_count: count,
123 peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
124 }
125 });
126
127 let code = ObligationCauseCode::Pattern {
128 span: ti.span,
129 root_ty: ti.expected,
130 origin_expr: origin_expr_info,
131 };
132 self.cause(cause_span, code)
133 }
134
135 fn demand_eqtype_pat_diag(
136 &'a self,
137 cause_span: Span,
138 expected: Ty<'tcx>,
139 actual: Ty<'tcx>,
140 ti: &TopInfo<'tcx>,
141 ) -> Result<(), Diag<'a>> {
142 self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
143 .map_err(|mut diag| {
144 if let Some(expr) = ti.origin_expr {
145 self.suggest_fn_call(&mut diag, expr, expected, |output| {
146 self.can_eq(self.param_env, output, actual)
147 });
148 }
149 diag
150 })
151 }
152
153 fn demand_eqtype_pat(
154 &self,
155 cause_span: Span,
156 expected: Ty<'tcx>,
157 actual: Ty<'tcx>,
158 ti: &TopInfo<'tcx>,
159 ) -> Result<(), ErrorGuaranteed> {
160 self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit())
161 }
162}
163
164#[derive(Clone, Copy, Debug, PartialEq, Eq)]
166enum AdjustMode {
167 Peel { kind: PeelKind },
170 Pass,
172}
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq)]
176enum PeelKind {
177 ExplicitDerefPat,
180 Implicit {
182 until_adt: Option<DefId>,
185 pat_ref_layers: usize,
188 },
189}
190
191impl AdjustMode {
192 const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
193 AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } }
194 }
195 const fn peel_all() -> AdjustMode {
196 AdjustMode::peel_until_adt(None)
197 }
198}
199
200#[derive(Clone, Copy, Debug, PartialEq, Eq)]
211enum MutblCap {
212 Not,
214
215 WeaklyNot(Option<Span>),
222
223 Mut,
225}
226
227impl MutblCap {
228 #[must_use]
229 fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
230 match self {
231 MutblCap::Not => MutblCap::Not,
232 _ => MutblCap::WeaklyNot(span),
233 }
234 }
235
236 #[must_use]
237 fn as_mutbl(self) -> Mutability {
238 match self {
239 MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
240 MutblCap::Mut => Mutability::Mut,
241 }
242 }
243}
244
245#[derive(Clone, Copy, Debug, PartialEq, Eq)]
251enum InheritedRefMatchRule {
252 EatOuter,
256 EatInner,
259 EatBoth {
262 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(pat, fields, has_rest_pat, ty, variant, expected, pat_info),
610 Err(guar) => {
611 let ty_err = Ty::new_error(self.tcx, guar);
612 for field in fields {
613 self.check_pat(field.pat, ty_err, pat_info);
614 }
615 ty_err
616 }
617 Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
618 },
619 PatKind::Guard(pat, cond) => {
620 self.check_pat(pat, expected, pat_info);
621 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
622 expected
623 }
624 PatKind::Or(pats) => {
625 for pat in pats {
626 self.check_pat(pat, expected, pat_info);
627 }
628 expected
629 }
630 PatKind::Tuple(elements, ddpos) => {
631 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
632 }
633 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
634 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
635 PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
636 PatKind::Slice(before, slice, after) => {
637 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
638 }
639 }
640 }
641
642 fn calc_adjust_mode(
646 &self,
647 pat: &'tcx Pat<'tcx>,
648 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
649 ) -> AdjustMode {
650 match &pat.kind {
651 PatKind::Tuple(..) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::peel_all(),
654 PatKind::Box(_) | PatKind::Deref(_) => {
658 AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat }
659 }
660 PatKind::Never => AdjustMode::peel_all(),
662 PatKind::Struct(..)
664 | PatKind::TupleStruct(..)
665 | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
666 opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
668 }
669
670 PatKind::Expr(lt) => {
675 if cfg!(debug_assertions)
678 && self.tcx.features().deref_patterns()
679 && !matches!(lt.kind, PatExprKind::Lit { .. })
680 {
681 span_bug!(
682 lt.span,
683 "FIXME(deref_patterns): adjust mode unimplemented for {:?}",
684 lt.kind
685 );
686 }
687 let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
689 if self.tcx.features().deref_patterns() {
691 let mut peeled_ty = lit_ty;
692 let mut pat_ref_layers = 0;
693 while let ty::Ref(_, inner_ty, mutbl) =
694 *self.try_structurally_resolve_type(pat.span, peeled_ty).kind()
695 {
696 debug_assert!(mutbl.is_not());
698 pat_ref_layers += 1;
699 peeled_ty = inner_ty;
700 }
701 AdjustMode::Peel {
702 kind: PeelKind::Implicit { until_adt: None, pat_ref_layers },
703 }
704 } else {
705 if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
706 }
707 }
708
709 PatKind::Ref(..)
711 | PatKind::Missing
713 | PatKind::Wild
715 | PatKind::Err(_)
717 | PatKind::Binding(..)
722 | PatKind::Or(_)
726 | PatKind::Guard(..) => AdjustMode::Pass,
728 }
729 }
730
731 fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
733 debug_assert!(expected.is_ref());
734 let pat_ref_layers = match peel_kind {
735 PeelKind::ExplicitDerefPat => 0,
736 PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
737 };
738
739 if pat_ref_layers == 0 {
742 return true;
743 }
744 debug_assert!(
745 self.tcx.features().deref_patterns(),
746 "Peeling for patterns with reference types is gated by `deref_patterns`."
747 );
748
749 let mut expected_ref_layers = 0;
755 while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
756 if mutbl.is_mut() {
757 return true;
760 }
761 expected_ref_layers += 1;
762 expected = inner_ty;
763 }
764 pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
765 }
766
767 fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
769 if let PeelKind::Implicit { until_adt, .. } = peel_kind
771 && let ty::Adt(scrutinee_adt, _) = *expected.kind()
776 && until_adt != Some(scrutinee_adt.did())
779 && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
784 && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
785 {
786 true
787 } else {
788 false
789 }
790 }
791
792 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
793 let ty = match <.kind {
794 rustc_hir::PatExprKind::Lit { lit, negated } => {
795 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
796 if *negated {
797 self.register_bound(
798 ty,
799 self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
800 ObligationCause::dummy_with_span(lt.span),
801 );
802 }
803 ty
804 }
805 rustc_hir::PatExprKind::ConstBlock(c) => {
806 self.check_expr_const_block(c, Expectation::NoExpectation)
807 }
808 rustc_hir::PatExprKind::Path(qpath) => {
809 let (res, opt_ty, segments) =
810 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
811 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
812 }
813 };
814 self.write_ty(lt.hir_id, ty);
815 ty
816 }
817
818 fn check_pat_lit(
819 &self,
820 span: Span,
821 lt: &hir::PatExpr<'tcx>,
822 expected: Ty<'tcx>,
823 ti: &TopInfo<'tcx>,
824 ) -> Ty<'tcx> {
825 let ty = self.node_ty(lt.hir_id);
828
829 let mut pat_ty = ty;
834 if let hir::PatExprKind::Lit {
835 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
836 } = lt.kind
837 {
838 let tcx = self.tcx;
839 let expected = self.structurally_resolve_type(span, expected);
840 match *expected.kind() {
841 ty::Ref(_, inner_ty, _)
843 if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
844 {
845 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
846 pat_ty = Ty::new_imm_ref(
847 tcx,
848 tcx.lifetimes.re_static,
849 Ty::new_slice(tcx, tcx.types.u8),
850 );
851 }
852 ty::Array(..) if tcx.features().deref_patterns() => {
854 pat_ty = match *ty.kind() {
855 ty::Ref(_, inner_ty, _) => inner_ty,
856 _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
857 }
858 }
859 ty::Slice(..) if tcx.features().deref_patterns() => {
861 pat_ty = Ty::new_slice(tcx, tcx.types.u8);
862 }
863 _ => {}
865 }
866 }
867
868 if self.tcx.features().deref_patterns()
871 && let hir::PatExprKind::Lit {
872 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
873 } = lt.kind
874 && self.try_structurally_resolve_type(span, expected).is_str()
875 {
876 pat_ty = self.tcx.types.str_;
877 }
878
879 if self.tcx.features().string_deref_patterns()
880 && let hir::PatExprKind::Lit {
881 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
882 } = lt.kind
883 {
884 let tcx = self.tcx;
885 let expected = self.resolve_vars_if_possible(expected);
886 pat_ty = match expected.kind() {
887 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
888 ty::Str => Ty::new_static_str(tcx),
889 _ => pat_ty,
890 };
891 }
892
893 let cause = self.pattern_cause(ti, span);
904 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
905 err.emit_unless(
906 ti.span
907 .filter(|&s| {
908 s.is_desugaring(DesugaringKind::CondTemporary)
912 })
913 .is_some(),
914 );
915 }
916
917 pat_ty
918 }
919
920 fn check_pat_range(
921 &self,
922 span: Span,
923 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
924 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
925 expected: Ty<'tcx>,
926 ti: &TopInfo<'tcx>,
927 ) -> Ty<'tcx> {
928 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
929 None => None,
930 Some(expr) => {
931 let ty = self.check_pat_expr_unadjusted(expr);
932 let ty = self.try_structurally_resolve_type(expr.span, ty);
939 let fail =
940 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
941 Some((fail, ty, expr.span))
942 }
943 };
944 let mut lhs = calc_side(lhs);
945 let mut rhs = calc_side(rhs);
946
947 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
948 let guar = self.emit_err_pat_range(span, lhs, rhs);
951 return Ty::new_error(self.tcx, guar);
952 }
953
954 let demand_eqtype = |x: &mut _, y| {
957 if let Some((ref mut fail, x_ty, x_span)) = *x
958 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
959 {
960 if let Some((_, y_ty, y_span)) = y {
961 self.endpoint_has_type(&mut err, y_span, y_ty);
962 }
963 err.emit();
964 *fail = true;
965 }
966 };
967 demand_eqtype(&mut lhs, rhs);
968 demand_eqtype(&mut rhs, lhs);
969
970 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
971 return Ty::new_misc_error(self.tcx);
972 }
973
974 let ty = self.structurally_resolve_type(span, expected);
979 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
980 if let Some((ref mut fail, _, _)) = lhs {
981 *fail = true;
982 }
983 if let Some((ref mut fail, _, _)) = rhs {
984 *fail = true;
985 }
986 let guar = self.emit_err_pat_range(span, lhs, rhs);
987 return Ty::new_error(self.tcx, guar);
988 }
989 ty
990 }
991
992 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
993 if !ty.references_error() {
994 err.span_label(span, format!("this is of type `{ty}`"));
995 }
996 }
997
998 fn emit_err_pat_range(
999 &self,
1000 span: Span,
1001 lhs: Option<(bool, Ty<'tcx>, Span)>,
1002 rhs: Option<(bool, Ty<'tcx>, Span)>,
1003 ) -> ErrorGuaranteed {
1004 let span = match (lhs, rhs) {
1005 (Some((true, ..)), Some((true, ..))) => span,
1006 (Some((true, _, sp)), _) => sp,
1007 (_, Some((true, _, sp))) => sp,
1008 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
1009 };
1010 let mut err = struct_span_code_err!(
1011 self.dcx(),
1012 span,
1013 E0029,
1014 "only `char` and numeric types are allowed in range patterns"
1015 );
1016 let msg = |ty| {
1017 let ty = self.resolve_vars_if_possible(ty);
1018 format!("this is of type `{ty}` but it should be `char` or numeric")
1019 };
1020 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
1021 err.span_label(first_span, msg(first_ty));
1022 if let Some((_, ty, sp)) = second {
1023 let ty = self.resolve_vars_if_possible(ty);
1024 self.endpoint_has_type(&mut err, sp, ty);
1025 }
1026 };
1027 match (lhs, rhs) {
1028 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
1029 err.span_label(lhs_sp, msg(lhs_ty));
1030 err.span_label(rhs_sp, msg(rhs_ty));
1031 }
1032 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
1033 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
1034 _ => span_bug!(span, "Impossible, verified above."),
1035 }
1036 if (lhs, rhs).references_error() {
1037 err.downgrade_to_delayed_bug();
1038 }
1039 if self.tcx.sess.teach(err.code.unwrap()) {
1040 err.note(
1041 "In a match expression, only numbers and characters can be matched \
1042 against a range. This is because the compiler checks that the range \
1043 is non-empty at compile-time, and is unable to evaluate arbitrary \
1044 comparison functions. If you want to capture values of an orderable \
1045 type between two end-points, you can use a guard.",
1046 );
1047 }
1048 err.emit()
1049 }
1050
1051 fn check_pat_ident(
1052 &self,
1053 pat: &'tcx Pat<'tcx>,
1054 user_bind_annot: BindingMode,
1055 var_id: HirId,
1056 ident: Ident,
1057 sub: Option<&'tcx Pat<'tcx>>,
1058 expected: Ty<'tcx>,
1059 pat_info: PatInfo<'tcx>,
1060 ) -> Ty<'tcx> {
1061 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
1062
1063 let bm = match user_bind_annot {
1065 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
1066 if pat.span.at_least_rust_2024()
1069 && (self.tcx.features().ref_pat_eat_one_layer_2024()
1070 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
1071 {
1072 if !self.tcx.features().mut_ref() {
1073 feature_err(
1074 &self.tcx.sess,
1075 sym::mut_ref,
1076 pat.span.until(ident.span),
1077 "binding cannot be both mutable and by-reference",
1078 )
1079 .emit();
1080 }
1081
1082 BindingMode(def_br, Mutability::Mut)
1083 } else {
1084 self.add_rust_2024_migration_desugared_pat(
1086 pat_info.top_info.hir_id,
1087 pat,
1088 't', def_br_mutbl,
1090 );
1091 BindingMode(ByRef::No, Mutability::Mut)
1092 }
1093 }
1094 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
1095 BindingMode(ByRef::Yes(user_br_mutbl), _) => {
1096 if let ByRef::Yes(def_br_mutbl) = def_br {
1097 self.add_rust_2024_migration_desugared_pat(
1099 pat_info.top_info.hir_id,
1100 pat,
1101 match user_br_mutbl {
1102 Mutability::Not => 'f', Mutability::Mut => 't', },
1105 def_br_mutbl,
1106 );
1107 }
1108 user_bind_annot
1109 }
1110 };
1111
1112 if bm.0 == ByRef::Yes(Mutability::Mut)
1113 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1114 {
1115 let mut err = struct_span_code_err!(
1116 self.dcx(),
1117 ident.span,
1118 E0596,
1119 "cannot borrow as mutable inside an `&` pattern"
1120 );
1121
1122 if let Some(span) = and_pat_span {
1123 err.span_suggestion(
1124 span,
1125 "replace this `&` with `&mut`",
1126 "&mut ",
1127 Applicability::MachineApplicable,
1128 );
1129 }
1130 err.emit();
1131 }
1132
1133 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1135
1136 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1137
1138 let local_ty = self.local_ty(pat.span, pat.hir_id);
1139 let eq_ty = match bm.0 {
1140 ByRef::Yes(mutbl) => {
1141 self.new_ref_ty(pat.span, mutbl, expected)
1149 }
1150 ByRef::No => expected, };
1153
1154 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1156
1157 if var_id != pat.hir_id {
1160 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1161 }
1162
1163 if let Some(p) = sub {
1164 self.check_pat(p, expected, pat_info);
1165 }
1166
1167 local_ty
1168 }
1169
1170 fn check_binding_alt_eq_ty(
1174 &self,
1175 ba: BindingMode,
1176 span: Span,
1177 var_id: HirId,
1178 ty: Ty<'tcx>,
1179 ti: &TopInfo<'tcx>,
1180 ) {
1181 let var_ty = self.local_ty(span, var_id);
1182 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1183 let var_ty = self.resolve_vars_if_possible(var_ty);
1184 let msg = format!("first introduced with type `{var_ty}` here");
1185 err.span_label(self.tcx.hir_span(var_id), msg);
1186 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1187 matches!(
1188 n,
1189 hir::Node::Expr(hir::Expr {
1190 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1191 ..
1192 })
1193 )
1194 });
1195 let pre = if in_match { "in the same arm, " } else { "" };
1196 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1197 self.suggest_adding_missing_ref_or_removing_ref(
1198 &mut err,
1199 span,
1200 var_ty,
1201 self.resolve_vars_if_possible(ty),
1202 ba,
1203 );
1204 err.emit();
1205 }
1206 }
1207
1208 fn suggest_adding_missing_ref_or_removing_ref(
1209 &self,
1210 err: &mut Diag<'_>,
1211 span: Span,
1212 expected: Ty<'tcx>,
1213 actual: Ty<'tcx>,
1214 ba: BindingMode,
1215 ) {
1216 match (expected.kind(), actual.kind(), ba) {
1217 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1218 if self.can_eq(self.param_env, *inner_ty, actual) =>
1219 {
1220 err.span_suggestion_verbose(
1221 span.shrink_to_lo(),
1222 "consider adding `ref`",
1223 "ref ",
1224 Applicability::MaybeIncorrect,
1225 );
1226 }
1227 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1228 if self.can_eq(self.param_env, expected, *inner_ty) =>
1229 {
1230 err.span_suggestion_verbose(
1231 span.with_hi(span.lo() + BytePos(4)),
1232 "consider removing `ref`",
1233 "",
1234 Applicability::MaybeIncorrect,
1235 );
1236 }
1237 _ => (),
1238 }
1239 }
1240
1241 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1243 let tcx = self.tcx;
1244 if let PatKind::Ref(inner, mutbl) = pat.kind
1245 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1246 {
1247 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1248 debug!(?inner, ?pat, ?binding_parent);
1249
1250 let mutability = match mutbl {
1251 ast::Mutability::Mut => "mut",
1252 ast::Mutability::Not => "",
1253 };
1254
1255 let mut_var_suggestion = 'block: {
1256 if mutbl.is_not() {
1257 break 'block None;
1258 }
1259
1260 let ident_kind = match binding_parent {
1261 hir::Node::Param(_) => "parameter",
1262 hir::Node::LetStmt(_) => "variable",
1263 hir::Node::Arm(_) => "binding",
1264
1265 hir::Node::Pat(Pat { kind, .. }) => match kind {
1268 PatKind::Struct(..)
1269 | PatKind::TupleStruct(..)
1270 | PatKind::Or(..)
1271 | PatKind::Guard(..)
1272 | PatKind::Tuple(..)
1273 | PatKind::Slice(..) => "binding",
1274
1275 PatKind::Missing
1276 | PatKind::Wild
1277 | PatKind::Never
1278 | PatKind::Binding(..)
1279 | PatKind::Box(..)
1280 | PatKind::Deref(_)
1281 | PatKind::Ref(..)
1282 | PatKind::Expr(..)
1283 | PatKind::Range(..)
1284 | PatKind::Err(_) => break 'block None,
1285 },
1286
1287 _ => break 'block None,
1289 };
1290
1291 Some((
1292 pat.span,
1293 format!("to declare a mutable {ident_kind} use"),
1294 format!("mut {binding}"),
1295 ))
1296 };
1297
1298 match binding_parent {
1299 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1302 err.multipart_suggestion_verbose(
1303 format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
1304 vec![
1305 (pat.span.until(inner.span), "".to_owned()),
1306 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1307 ],
1308 Applicability::MachineApplicable
1309 );
1310
1311 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1312 err.span_note(sp, format!("{msg}: `{sugg}`"));
1313 }
1314 }
1315 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1316 for i in pat_arr.iter() {
1317 if let PatKind::Ref(the_ref, _) = i.kind
1318 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1319 {
1320 let BindingMode(_, mtblty) = mt;
1321 err.span_suggestion_verbose(
1322 i.span,
1323 format!("consider removing `&{mutability}` from the pattern"),
1324 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1325 Applicability::MaybeIncorrect,
1326 );
1327 }
1328 }
1329 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1330 err.span_note(sp, format!("{msg}: `{sugg}`"));
1331 }
1332 }
1333 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1334 err.span_suggestion_verbose(
1336 pat.span.until(inner.span),
1337 format!("consider removing `&{mutability}` from the pattern"),
1338 "",
1339 Applicability::MaybeIncorrect,
1340 );
1341
1342 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1343 err.span_note(sp, format!("{msg}: `{sugg}`"));
1344 }
1345 }
1346 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1347 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1348 }
1349 _ => {} }
1351 }
1352 }
1353
1354 fn check_dereferenceable(
1355 &self,
1356 span: Span,
1357 expected: Ty<'tcx>,
1358 inner: &Pat<'_>,
1359 ) -> Result<(), ErrorGuaranteed> {
1360 if let PatKind::Binding(..) = inner.kind
1361 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1362 && let ty::Dynamic(..) = pointee_ty.kind()
1363 {
1364 let type_str = self.ty_to_string(expected);
1367 let mut err = struct_span_code_err!(
1368 self.dcx(),
1369 span,
1370 E0033,
1371 "type `{}` cannot be dereferenced",
1372 type_str
1373 );
1374 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1375 if self.tcx.sess.teach(err.code.unwrap()) {
1376 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1377 }
1378 return Err(err.emit());
1379 }
1380 Ok(())
1381 }
1382
1383 fn resolve_pat_struct(
1384 &self,
1385 pat: &'tcx Pat<'tcx>,
1386 qpath: &hir::QPath<'tcx>,
1387 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1388 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1390 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1391 }
1392
1393 fn check_pat_struct(
1394 &self,
1395 pat: &'tcx Pat<'tcx>,
1396 fields: &'tcx [hir::PatField<'tcx>],
1397 has_rest_pat: bool,
1398 pat_ty: Ty<'tcx>,
1399 variant: &'tcx VariantDef,
1400 expected: Ty<'tcx>,
1401 pat_info: PatInfo<'tcx>,
1402 ) -> Ty<'tcx> {
1403 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1405
1406 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1408 Ok(()) => pat_ty,
1409 Err(guar) => Ty::new_error(self.tcx, guar),
1410 }
1411 }
1412
1413 fn resolve_pat_path(
1414 &self,
1415 path_id: HirId,
1416 span: Span,
1417 qpath: &'tcx hir::QPath<'_>,
1418 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1419 let tcx = self.tcx;
1420
1421 let (res, opt_ty, segments) =
1422 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1423 match res {
1424 Res::Err => {
1425 let e =
1426 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1427 self.set_tainted_by_errors(e);
1428 return Err(e);
1429 }
1430 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1431 let expected = "unit struct, unit variant or constant";
1432 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1433 return Err(e);
1434 }
1435 Res::SelfCtor(def_id) => {
1436 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1437 && adt_def.is_struct()
1438 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1439 {
1440 } else {
1442 let e = report_unexpected_variant_res(
1443 tcx,
1444 res,
1445 None,
1446 qpath,
1447 span,
1448 E0533,
1449 "unit struct",
1450 );
1451 return Err(e);
1452 }
1453 }
1454 Res::Def(
1455 DefKind::Ctor(_, CtorKind::Const)
1456 | DefKind::Const
1457 | DefKind::AssocConst
1458 | DefKind::ConstParam,
1459 _,
1460 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1462 }
1463
1464 let (pat_ty, pat_res) =
1466 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1467 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1468 }
1469
1470 fn check_pat_path(
1471 &self,
1472 pat_id_for_diag: HirId,
1473 span: Span,
1474 resolved: &ResolvedPat<'tcx>,
1475 expected: Ty<'tcx>,
1476 ti: &TopInfo<'tcx>,
1477 ) -> Ty<'tcx> {
1478 if let Err(err) =
1479 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1480 {
1481 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1482 }
1483 resolved.ty
1484 }
1485
1486 fn maybe_suggest_range_literal(
1487 &self,
1488 e: &mut Diag<'_>,
1489 opt_def_id: Option<hir::def_id::DefId>,
1490 ident: Ident,
1491 ) -> bool {
1492 match opt_def_id {
1493 Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
1494 Some(hir::Node::Item(hir::Item {
1495 kind: hir::ItemKind::Const(_, _, _, body_id),
1496 ..
1497 })) => match self.tcx.hir_node(body_id.hir_id) {
1498 hir::Node::Expr(expr) => {
1499 if hir::is_range_literal(expr) {
1500 let span = self.tcx.hir_span(body_id.hir_id);
1501 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1502 e.span_suggestion_verbose(
1503 ident.span,
1504 "you may want to move the range into the match block",
1505 snip,
1506 Applicability::MachineApplicable,
1507 );
1508 return true;
1509 }
1510 }
1511 }
1512 _ => (),
1513 },
1514 _ => (),
1515 },
1516 _ => (),
1517 }
1518 false
1519 }
1520
1521 fn emit_bad_pat_path(
1522 &self,
1523 mut e: Diag<'_>,
1524 hir_id: HirId,
1525 pat_span: Span,
1526 resolved_pat: &ResolvedPat<'tcx>,
1527 ) {
1528 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1529 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1530 };
1531
1532 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1533 e.span_label(span, format!("{} defined here", res.descr()));
1534 if let [hir::PathSegment { ident, .. }] = &*segments {
1535 e.span_label(
1536 pat_span,
1537 format!(
1538 "`{}` is interpreted as {} {}, not a new binding",
1539 ident,
1540 res.article(),
1541 res.descr(),
1542 ),
1543 );
1544 match self.tcx.parent_hir_node(hir_id) {
1545 hir::Node::PatField(..) => {
1546 e.span_suggestion_verbose(
1547 ident.span.shrink_to_hi(),
1548 "bind the struct field to a different name instead",
1549 format!(": other_{}", ident.as_str().to_lowercase()),
1550 Applicability::HasPlaceholders,
1551 );
1552 }
1553 _ => {
1554 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1555 ty::Adt(def, _) => match res {
1556 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1557 _ => (None, None),
1558 },
1559 _ => (None, None),
1560 };
1561
1562 let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) {
1563 Some(
1564 LangItem::Range
1565 | LangItem::RangeFrom
1566 | LangItem::RangeTo
1567 | LangItem::RangeFull
1568 | LangItem::RangeInclusiveStruct
1569 | LangItem::RangeToInclusive,
1570 ) => true,
1571 _ => false,
1572 };
1573 if is_range {
1574 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1575 let msg = "constants only support matching by type, \
1576 if you meant to match against a range of values, \
1577 consider using a range pattern like `min ..= max` in the match block";
1578 e.note(msg);
1579 }
1580 } else {
1581 let msg = "introduce a new binding instead";
1582 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1583 e.span_suggestion(
1584 ident.span,
1585 msg,
1586 sugg,
1587 Applicability::HasPlaceholders,
1588 );
1589 }
1590 }
1591 };
1592 }
1593 }
1594 e.emit();
1595 }
1596
1597 fn resolve_pat_tuple_struct(
1598 &self,
1599 pat: &'tcx Pat<'tcx>,
1600 qpath: &'tcx hir::QPath<'tcx>,
1601 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1602 let tcx = self.tcx;
1603 let report_unexpected_res = |res: Res| {
1604 let expected = "tuple struct or tuple variant";
1605 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1606 Err(e)
1607 };
1608
1609 let (res, opt_ty, segments) =
1611 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1612 if res == Res::Err {
1613 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1614 self.set_tainted_by_errors(e);
1615 return Err(e);
1616 }
1617
1618 let (pat_ty, res) =
1620 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1621 if !pat_ty.is_fn() {
1622 return report_unexpected_res(res);
1623 }
1624
1625 let variant = match res {
1626 Res::Err => {
1627 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1628 }
1629 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1630 return report_unexpected_res(res);
1631 }
1632 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1633 _ => bug!("unexpected pattern resolution: {:?}", res),
1634 };
1635
1636 let pat_ty = pat_ty.fn_sig(tcx).output();
1638 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1639
1640 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1641 }
1642
1643 fn check_pat_tuple_struct(
1644 &self,
1645 pat: &'tcx Pat<'tcx>,
1646 qpath: &'tcx hir::QPath<'tcx>,
1647 subpats: &'tcx [Pat<'tcx>],
1648 ddpos: hir::DotDotPos,
1649 res: Res,
1650 pat_ty: Ty<'tcx>,
1651 variant: &'tcx VariantDef,
1652 expected: Ty<'tcx>,
1653 pat_info: PatInfo<'tcx>,
1654 ) -> Ty<'tcx> {
1655 let tcx = self.tcx;
1656 let on_error = |e| {
1657 for pat in subpats {
1658 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1659 }
1660 };
1661
1662 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1664 let had_err = diag.map_err(|diag| diag.emit());
1665
1666 if subpats.len() == variant.fields.len()
1668 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1669 {
1670 let ty::Adt(_, args) = pat_ty.kind() else {
1671 bug!("unexpected pattern type {:?}", pat_ty);
1672 };
1673 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1674 let field = &variant.fields[FieldIdx::from_usize(i)];
1675 let field_ty = self.field_ty(subpat.span, field, args);
1676 self.check_pat(subpat, field_ty, pat_info);
1677
1678 self.tcx.check_stability(
1679 variant.fields[FieldIdx::from_usize(i)].did,
1680 Some(subpat.hir_id),
1681 subpat.span,
1682 None,
1683 );
1684 }
1685 if let Err(e) = had_err {
1686 on_error(e);
1687 return Ty::new_error(tcx, e);
1688 }
1689 } else {
1690 let e = self.emit_err_pat_wrong_number_of_fields(
1691 pat.span,
1692 res,
1693 qpath,
1694 subpats,
1695 &variant.fields.raw,
1696 expected,
1697 had_err,
1698 );
1699 on_error(e);
1700 return Ty::new_error(tcx, e);
1701 }
1702 pat_ty
1703 }
1704
1705 fn emit_err_pat_wrong_number_of_fields(
1706 &self,
1707 pat_span: Span,
1708 res: Res,
1709 qpath: &hir::QPath<'_>,
1710 subpats: &'tcx [Pat<'tcx>],
1711 fields: &'tcx [ty::FieldDef],
1712 expected: Ty<'tcx>,
1713 had_err: Result<(), ErrorGuaranteed>,
1714 ) -> ErrorGuaranteed {
1715 let subpats_ending = pluralize!(subpats.len());
1716 let fields_ending = pluralize!(fields.len());
1717
1718 let subpat_spans = if subpats.is_empty() {
1719 vec![pat_span]
1720 } else {
1721 subpats.iter().map(|p| p.span).collect()
1722 };
1723 let last_subpat_span = *subpat_spans.last().unwrap();
1724 let res_span = self.tcx.def_span(res.def_id());
1725 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1726 let field_def_spans = if fields.is_empty() {
1727 vec![res_span]
1728 } else {
1729 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1730 };
1731 let last_field_def_span = *field_def_spans.last().unwrap();
1732
1733 let mut err = struct_span_code_err!(
1734 self.dcx(),
1735 MultiSpan::from_spans(subpat_spans),
1736 E0023,
1737 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1738 subpats.len(),
1739 subpats_ending,
1740 res.descr(),
1741 fields.len(),
1742 fields_ending,
1743 );
1744 err.span_label(
1745 last_subpat_span,
1746 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1747 );
1748 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1749 err.span_label(qpath.span(), "");
1750 }
1751 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1752 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1753 }
1754 for span in &field_def_spans[..field_def_spans.len() - 1] {
1755 err.span_label(*span, "");
1756 }
1757 err.span_label(
1758 last_field_def_span,
1759 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1760 );
1761
1762 let missing_parentheses = match (expected.kind(), fields, had_err) {
1767 (ty::Adt(_, args), [field], Ok(())) => {
1771 let field_ty = self.field_ty(pat_span, field, args);
1772 match field_ty.kind() {
1773 ty::Tuple(fields) => fields.len() == subpats.len(),
1774 _ => false,
1775 }
1776 }
1777 _ => false,
1778 };
1779 if missing_parentheses {
1780 let (left, right) = match subpats {
1781 [] => (qpath.span().shrink_to_hi(), pat_span),
1790 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1799 };
1800 err.multipart_suggestion(
1801 "missing parentheses",
1802 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1803 Applicability::MachineApplicable,
1804 );
1805 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1806 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1807 let all_fields_span = match subpats {
1808 [] => after_fields_span,
1809 [field] => field.span,
1810 [first, .., last] => first.span.to(last.span),
1811 };
1812
1813 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1815 let first_tail_wildcard =
1816 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1817 (None, PatKind::Wild) => Some(pos),
1818 (Some(_), PatKind::Wild) => acc,
1819 _ => None,
1820 });
1821 let tail_span = match first_tail_wildcard {
1822 None => after_fields_span,
1823 Some(0) => subpats[0].span.to(after_fields_span),
1824 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1825 };
1826
1827 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1829 if !subpats.is_empty() {
1830 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1831 }
1832
1833 err.span_suggestion_verbose(
1834 after_fields_span,
1835 "use `_` to explicitly ignore each field",
1836 wildcard_sugg,
1837 Applicability::MaybeIncorrect,
1838 );
1839
1840 if fields.len() - subpats.len() > 1 || all_wildcards {
1843 if subpats.is_empty() || all_wildcards {
1844 err.span_suggestion_verbose(
1845 all_fields_span,
1846 "use `..` to ignore all fields",
1847 "..",
1848 Applicability::MaybeIncorrect,
1849 );
1850 } else {
1851 err.span_suggestion_verbose(
1852 tail_span,
1853 "use `..` to ignore the rest of the fields",
1854 ", ..",
1855 Applicability::MaybeIncorrect,
1856 );
1857 }
1858 }
1859 }
1860
1861 err.emit()
1862 }
1863
1864 fn check_pat_tuple(
1865 &self,
1866 span: Span,
1867 elements: &'tcx [Pat<'tcx>],
1868 ddpos: hir::DotDotPos,
1869 expected: Ty<'tcx>,
1870 pat_info: PatInfo<'tcx>,
1871 ) -> Ty<'tcx> {
1872 let tcx = self.tcx;
1873 let mut expected_len = elements.len();
1874 if ddpos.as_opt_usize().is_some() {
1875 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1877 expected_len = tys.len();
1878 }
1879 }
1880 let max_len = cmp::max(expected_len, elements.len());
1881
1882 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1883 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1884 let pat_ty = Ty::new_tup(tcx, element_tys);
1885 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
1886 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1889 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1890 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1891 }
1892 Ty::new_tup_from_iter(tcx, element_tys_iter)
1893 } else {
1894 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1895 self.check_pat(elem, element_tys[i], pat_info);
1896 }
1897 pat_ty
1898 }
1899 }
1900
1901 fn check_struct_pat_fields(
1902 &self,
1903 adt_ty: Ty<'tcx>,
1904 pat: &'tcx Pat<'tcx>,
1905 variant: &'tcx ty::VariantDef,
1906 fields: &'tcx [hir::PatField<'tcx>],
1907 has_rest_pat: bool,
1908 pat_info: PatInfo<'tcx>,
1909 ) -> Result<(), ErrorGuaranteed> {
1910 let tcx = self.tcx;
1911
1912 let ty::Adt(adt, args) = adt_ty.kind() else {
1913 span_bug!(pat.span, "struct pattern is not an ADT");
1914 };
1915
1916 let field_map = variant
1918 .fields
1919 .iter_enumerated()
1920 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
1921 .collect::<FxHashMap<_, _>>();
1922
1923 let mut used_fields = FxHashMap::default();
1925 let mut result = Ok(());
1926
1927 let mut inexistent_fields = vec![];
1928 for field in fields {
1930 let span = field.span;
1931 let ident = tcx.adjust_ident(field.ident, variant.def_id);
1932 let field_ty = match used_fields.entry(ident) {
1933 Occupied(occupied) => {
1934 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
1935 result = Err(guar);
1936 Ty::new_error(tcx, guar)
1937 }
1938 Vacant(vacant) => {
1939 vacant.insert(span);
1940 field_map
1941 .get(&ident)
1942 .map(|(i, f)| {
1943 self.write_field_index(field.hir_id, *i);
1944 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
1945 self.field_ty(span, f, args)
1946 })
1947 .unwrap_or_else(|| {
1948 inexistent_fields.push(field);
1949 Ty::new_misc_error(tcx)
1950 })
1951 }
1952 };
1953
1954 self.check_pat(field.pat, field_ty, pat_info);
1955 }
1956
1957 let mut unmentioned_fields = variant
1958 .fields
1959 .iter()
1960 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
1961 .filter(|(_, ident)| !used_fields.contains_key(ident))
1962 .collect::<Vec<_>>();
1963
1964 let inexistent_fields_err = if !inexistent_fields.is_empty()
1965 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
1966 {
1967 variant.has_errors()?;
1969 Some(self.error_inexistent_fields(
1970 adt.variant_descr(),
1971 &inexistent_fields,
1972 &mut unmentioned_fields,
1973 pat,
1974 variant,
1975 args,
1976 ))
1977 } else {
1978 None
1979 };
1980
1981 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
1983 if non_exhaustive && !has_rest_pat {
1984 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
1985 }
1986
1987 let mut unmentioned_err = None;
1988 if adt.is_union() {
1990 if fields.len() != 1 {
1991 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
1992 }
1993 if has_rest_pat {
1994 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
1995 }
1996 } else if !unmentioned_fields.is_empty() {
1997 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
1998 .iter()
1999 .copied()
2000 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
2001 .collect();
2002
2003 if !has_rest_pat {
2004 if accessible_unmentioned_fields.is_empty() {
2005 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
2006 } else {
2007 unmentioned_err = Some(self.error_unmentioned_fields(
2008 pat,
2009 &accessible_unmentioned_fields,
2010 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
2011 fields,
2012 ));
2013 }
2014 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
2015 self.lint_non_exhaustive_omitted_patterns(
2016 pat,
2017 &accessible_unmentioned_fields,
2018 adt_ty,
2019 )
2020 }
2021 }
2022 match (inexistent_fields_err, unmentioned_err) {
2023 (Some(i), Some(u)) => {
2024 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2025 i.delay_as_bug();
2028 u.delay_as_bug();
2029 Err(e)
2030 } else {
2031 i.emit();
2032 Err(u.emit())
2033 }
2034 }
2035 (None, Some(u)) => {
2036 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2037 u.delay_as_bug();
2038 Err(e)
2039 } else {
2040 Err(u.emit())
2041 }
2042 }
2043 (Some(err), None) => Err(err.emit()),
2044 (None, None) => {
2045 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
2046 result
2047 }
2048 }
2049 }
2050
2051 fn error_tuple_variant_index_shorthand(
2052 &self,
2053 variant: &VariantDef,
2054 pat: &'_ Pat<'_>,
2055 fields: &[hir::PatField<'_>],
2056 ) -> Result<(), ErrorGuaranteed> {
2057 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
2061 (variant.ctor_kind(), &pat.kind)
2062 {
2063 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
2064 if has_shorthand_field_name {
2065 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2066 let mut err = struct_span_code_err!(
2067 self.dcx(),
2068 pat.span,
2069 E0769,
2070 "tuple variant `{path}` written as struct variant",
2071 );
2072 err.span_suggestion_verbose(
2073 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2074 "use the tuple variant pattern syntax instead",
2075 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
2076 Applicability::MaybeIncorrect,
2077 );
2078 return Err(err.emit());
2079 }
2080 }
2081 Ok(())
2082 }
2083
2084 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
2085 let sess = self.tcx.sess;
2086 let sm = sess.source_map();
2087 let sp_brace = sm.end_point(pat.span);
2088 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
2089 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
2090
2091 struct_span_code_err!(
2092 self.dcx(),
2093 pat.span,
2094 E0638,
2095 "`..` required with {descr} marked as non-exhaustive",
2096 )
2097 .with_span_suggestion_verbose(
2098 sp_comma,
2099 "add `..` at the end of the field list to ignore all other fields",
2100 sugg,
2101 Applicability::MachineApplicable,
2102 )
2103 .emit();
2104 }
2105
2106 fn error_field_already_bound(
2107 &self,
2108 span: Span,
2109 ident: Ident,
2110 other_field: Span,
2111 ) -> ErrorGuaranteed {
2112 struct_span_code_err!(
2113 self.dcx(),
2114 span,
2115 E0025,
2116 "field `{}` bound multiple times in the pattern",
2117 ident
2118 )
2119 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2120 .with_span_label(other_field, format!("first use of `{ident}`"))
2121 .emit()
2122 }
2123
2124 fn error_inexistent_fields(
2125 &self,
2126 kind_name: &str,
2127 inexistent_fields: &[&hir::PatField<'tcx>],
2128 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2129 pat: &'tcx Pat<'tcx>,
2130 variant: &ty::VariantDef,
2131 args: ty::GenericArgsRef<'tcx>,
2132 ) -> Diag<'a> {
2133 let tcx = self.tcx;
2134 let (field_names, t, plural) = if let [field] = inexistent_fields {
2135 (format!("a field named `{}`", field.ident), "this", "")
2136 } else {
2137 (
2138 format!(
2139 "fields named {}",
2140 inexistent_fields
2141 .iter()
2142 .map(|field| format!("`{}`", field.ident))
2143 .collect::<Vec<String>>()
2144 .join(", ")
2145 ),
2146 "these",
2147 "s",
2148 )
2149 };
2150 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2151 let mut err = struct_span_code_err!(
2152 self.dcx(),
2153 spans,
2154 E0026,
2155 "{} `{}` does not have {}",
2156 kind_name,
2157 tcx.def_path_str(variant.def_id),
2158 field_names
2159 );
2160 if let Some(pat_field) = inexistent_fields.last() {
2161 err.span_label(
2162 pat_field.ident.span,
2163 format!(
2164 "{} `{}` does not have {} field{}",
2165 kind_name,
2166 tcx.def_path_str(variant.def_id),
2167 t,
2168 plural
2169 ),
2170 );
2171
2172 if let [(field_def, field)] = unmentioned_fields.as_slice()
2173 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2174 {
2175 let suggested_name =
2176 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2177 if let Some(suggested_name) = suggested_name {
2178 err.span_suggestion(
2179 pat_field.ident.span,
2180 "a field with a similar name exists",
2181 suggested_name,
2182 Applicability::MaybeIncorrect,
2183 );
2184
2185 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2191 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2193 }
2194 } else if inexistent_fields.len() == 1 {
2195 match pat_field.pat.kind {
2196 PatKind::Expr(_)
2197 if !self.may_coerce(
2198 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2199 self.field_ty(field.span, field_def, args),
2200 ) => {}
2201 _ => {
2202 err.span_suggestion_short(
2203 pat_field.ident.span,
2204 format!(
2205 "`{}` has a field named `{}`",
2206 tcx.def_path_str(variant.def_id),
2207 field.name,
2208 ),
2209 field.name,
2210 Applicability::MaybeIncorrect,
2211 );
2212 }
2213 }
2214 }
2215 }
2216 }
2217 if tcx.sess.teach(err.code.unwrap()) {
2218 err.note(
2219 "This error indicates that a struct pattern attempted to \
2220 extract a nonexistent field from a struct. Struct fields \
2221 are identified by the name used before the colon : so struct \
2222 patterns should resemble the declaration of the struct type \
2223 being matched.\n\n\
2224 If you are using shorthand field patterns but want to refer \
2225 to the struct field by a different name, you should rename \
2226 it explicitly.",
2227 );
2228 }
2229 err
2230 }
2231
2232 fn error_tuple_variant_as_struct_pat(
2233 &self,
2234 pat: &Pat<'_>,
2235 fields: &'tcx [hir::PatField<'tcx>],
2236 variant: &ty::VariantDef,
2237 ) -> Result<(), ErrorGuaranteed> {
2238 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2239 (variant.ctor_kind(), &pat.kind)
2240 {
2241 let is_tuple_struct_match = !pattern_fields.is_empty()
2242 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2243 if is_tuple_struct_match {
2244 return Ok(());
2245 }
2246
2247 variant.has_errors()?;
2249
2250 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2251 let mut err = struct_span_code_err!(
2252 self.dcx(),
2253 pat.span,
2254 E0769,
2255 "tuple variant `{}` written as struct variant",
2256 path
2257 );
2258 let (sugg, appl) = if fields.len() == variant.fields.len() {
2259 (
2260 self.get_suggested_tuple_struct_pattern(fields, variant),
2261 Applicability::MachineApplicable,
2262 )
2263 } else {
2264 (
2265 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2266 Applicability::MaybeIncorrect,
2267 )
2268 };
2269 err.span_suggestion_verbose(
2270 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2271 "use the tuple variant pattern syntax instead",
2272 format!("({sugg})"),
2273 appl,
2274 );
2275 return Err(err.emit());
2276 }
2277 Ok(())
2278 }
2279
2280 fn get_suggested_tuple_struct_pattern(
2281 &self,
2282 fields: &[hir::PatField<'_>],
2283 variant: &VariantDef,
2284 ) -> String {
2285 let variant_field_idents =
2286 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2287 fields
2288 .iter()
2289 .map(|field| {
2290 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2291 Ok(f) => {
2292 if variant_field_idents.contains(&field.ident) {
2295 String::from("_")
2296 } else {
2297 f
2298 }
2299 }
2300 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2301 }
2302 })
2303 .collect::<Vec<String>>()
2304 .join(", ")
2305 }
2306
2307 fn error_no_accessible_fields(
2323 &self,
2324 pat: &Pat<'_>,
2325 fields: &'tcx [hir::PatField<'tcx>],
2326 ) -> Diag<'a> {
2327 let mut err = self
2328 .dcx()
2329 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2330
2331 if let Some(field) = fields.last() {
2332 err.span_suggestion_verbose(
2333 field.span.shrink_to_hi(),
2334 "ignore the inaccessible and unused fields",
2335 ", ..",
2336 Applicability::MachineApplicable,
2337 );
2338 } else {
2339 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2340 qpath.span()
2341 } else {
2342 bug!("`error_no_accessible_fields` called on non-struct pattern");
2343 };
2344
2345 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2347 err.span_suggestion_verbose(
2348 span,
2349 "ignore the inaccessible and unused fields",
2350 " { .. }",
2351 Applicability::MachineApplicable,
2352 );
2353 }
2354 err
2355 }
2356
2357 fn lint_non_exhaustive_omitted_patterns(
2362 &self,
2363 pat: &Pat<'_>,
2364 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2365 ty: Ty<'tcx>,
2366 ) {
2367 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2368 const LIMIT: usize = 3;
2369 match witnesses {
2370 [] => {
2371 unreachable!(
2372 "expected an uncovered pattern, otherwise why are we emitting an error?"
2373 )
2374 }
2375 [witness] => format!("`{witness}`"),
2376 [head @ .., tail] if head.len() < LIMIT => {
2377 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2378 format!("`{}` and `{}`", head.join("`, `"), tail)
2379 }
2380 _ => {
2381 let (head, tail) = witnesses.split_at(LIMIT);
2382 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2383 format!("`{}` and {} more", head.join("`, `"), tail.len())
2384 }
2385 }
2386 }
2387 let joined_patterns = joined_uncovered_patterns(
2388 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2389 );
2390
2391 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2392 lint.primary_message("some fields are not explicitly listed");
2393 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2394 lint.help(
2395 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2396 );
2397 lint.note(format!(
2398 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2399 ));
2400 });
2401 }
2402
2403 fn error_unmentioned_fields(
2413 &self,
2414 pat: &Pat<'_>,
2415 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2416 have_inaccessible_fields: bool,
2417 fields: &'tcx [hir::PatField<'tcx>],
2418 ) -> Diag<'a> {
2419 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2420 let field_names = if let [(_, field)] = unmentioned_fields {
2421 format!("field `{field}`{inaccessible}")
2422 } else {
2423 let fields = unmentioned_fields
2424 .iter()
2425 .map(|(_, name)| format!("`{name}`"))
2426 .collect::<Vec<String>>()
2427 .join(", ");
2428 format!("fields {fields}{inaccessible}")
2429 };
2430 let mut err = struct_span_code_err!(
2431 self.dcx(),
2432 pat.span,
2433 E0027,
2434 "pattern does not mention {}",
2435 field_names
2436 );
2437 err.span_label(pat.span, format!("missing {field_names}"));
2438 let len = unmentioned_fields.len();
2439 let (prefix, postfix, sp) = match fields {
2440 [] => match &pat.kind {
2441 PatKind::Struct(path, [], false) => {
2442 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2443 }
2444 _ => return err,
2445 },
2446 [.., field] => {
2447 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2450 match &pat.kind {
2451 PatKind::Struct(..) => (", ", " }", tail),
2452 _ => return err,
2453 }
2454 }
2455 };
2456 err.span_suggestion(
2457 sp,
2458 format!(
2459 "include the missing field{} in the pattern{}",
2460 pluralize!(len),
2461 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2462 ),
2463 format!(
2464 "{}{}{}{}",
2465 prefix,
2466 unmentioned_fields
2467 .iter()
2468 .map(|(_, name)| {
2469 let field_name = name.to_string();
2470 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2471 })
2472 .collect::<Vec<_>>()
2473 .join(", "),
2474 if have_inaccessible_fields { ", .." } else { "" },
2475 postfix,
2476 ),
2477 Applicability::MachineApplicable,
2478 );
2479 err.span_suggestion(
2480 sp,
2481 format!(
2482 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2483 these = pluralize!("this", len),
2484 s = pluralize!(len),
2485 them = if len == 1 { "it" } else { "them" },
2486 ),
2487 format!(
2488 "{}{}{}{}",
2489 prefix,
2490 unmentioned_fields
2491 .iter()
2492 .map(|(_, name)| {
2493 let field_name = name.to_string();
2494 format!("{field_name}: _")
2495 })
2496 .collect::<Vec<_>>()
2497 .join(", "),
2498 if have_inaccessible_fields { ", .." } else { "" },
2499 postfix,
2500 ),
2501 Applicability::MachineApplicable,
2502 );
2503 err.span_suggestion(
2504 sp,
2505 "or always ignore missing fields here",
2506 format!("{prefix}..{postfix}"),
2507 Applicability::MachineApplicable,
2508 );
2509 err
2510 }
2511
2512 fn check_pat_box(
2513 &self,
2514 span: Span,
2515 inner: &'tcx Pat<'tcx>,
2516 expected: Ty<'tcx>,
2517 pat_info: PatInfo<'tcx>,
2518 ) -> Ty<'tcx> {
2519 let tcx = self.tcx;
2520 let (box_ty, inner_ty) = self
2521 .check_dereferenceable(span, expected, inner)
2522 .and_then(|()| {
2523 let inner_ty = self.next_ty_var(inner.span);
2526 let box_ty = Ty::new_box(tcx, inner_ty);
2527 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2528 Ok((box_ty, inner_ty))
2529 })
2530 .unwrap_or_else(|guar| {
2531 let err = Ty::new_error(tcx, guar);
2532 (err, err)
2533 });
2534 self.check_pat(inner, inner_ty, pat_info);
2535 box_ty
2536 }
2537
2538 fn check_pat_deref(
2539 &self,
2540 span: Span,
2541 inner: &'tcx Pat<'tcx>,
2542 expected: Ty<'tcx>,
2543 pat_info: PatInfo<'tcx>,
2544 ) -> Ty<'tcx> {
2545 let target_ty = self.deref_pat_target(span, expected);
2546 self.check_pat(inner, target_ty, pat_info);
2547 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2548 expected
2549 }
2550
2551 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2552 let tcx = self.tcx;
2554 self.register_bound(
2555 source_ty,
2556 tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
2557 self.misc(span),
2558 );
2559 let target_ty = Ty::new_projection(
2561 tcx,
2562 tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
2563 [source_ty],
2564 );
2565 let target_ty = self.normalize(span, target_ty);
2566 self.try_structurally_resolve_type(span, target_ty)
2567 }
2568
2569 fn register_deref_mut_bounds_if_needed(
2574 &self,
2575 span: Span,
2576 inner: &'tcx Pat<'tcx>,
2577 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2578 ) {
2579 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2580 for mutably_derefed_ty in derefed_tys {
2581 self.register_bound(
2582 mutably_derefed_ty,
2583 self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
2584 self.misc(span),
2585 );
2586 }
2587 }
2588 }
2589
2590 fn check_pat_ref(
2592 &self,
2593 pat: &'tcx Pat<'tcx>,
2594 inner: &'tcx Pat<'tcx>,
2595 pat_mutbl: Mutability,
2596 mut expected: Ty<'tcx>,
2597 mut pat_info: PatInfo<'tcx>,
2598 ) -> Ty<'tcx> {
2599 let tcx = self.tcx;
2600
2601 let pat_prefix_span =
2602 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2603
2604 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2605 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2606 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2611 }
2612
2613 expected = self.try_structurally_resolve_type(pat.span, expected);
2614 if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2617 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2618 InheritedRefMatchRule::EatOuter => {
2619 if pat_mutbl > inh_mut {
2621 debug_assert!(ref_pat_matches_mut_ref);
2626 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2627 }
2628
2629 pat_info.binding_mode = ByRef::No;
2630 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2631 self.check_pat(inner, expected, pat_info);
2632 return expected;
2633 }
2634 InheritedRefMatchRule::EatInner => {
2635 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2636 && pat_mutbl <= r_mutbl
2637 {
2638 debug_assert!(ref_pat_matches_mut_ref);
2645 debug_assert!(self.downgrade_mut_inside_shared());
2649 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2650 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2651 } else {
2652 if pat_mutbl > inh_mut {
2655 debug_assert!(ref_pat_matches_mut_ref);
2664 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2665 }
2666
2667 pat_info.binding_mode = ByRef::No;
2668 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2669 self.check_pat(inner, expected, pat_info);
2670 return expected;
2671 }
2672 }
2673 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2674 pat_info.binding_mode = ByRef::No;
2676
2677 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2678 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2680 self.check_pat(inner, inner_ty, pat_info);
2687 return expected;
2688 } else {
2689 }
2696 } else {
2697 if pat_mutbl > inh_mut {
2700 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2702 }
2703
2704 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2705 self.check_pat(inner, expected, pat_info);
2706 return expected;
2707 }
2708 }
2709 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2710 pat_info.binding_mode = ByRef::No;
2713 self.add_rust_2024_migration_desugared_pat(
2714 pat_info.top_info.hir_id,
2715 pat,
2716 match pat_mutbl {
2717 Mutability::Not => '&', Mutability::Mut => 't', },
2720 inh_mut,
2721 )
2722 }
2723 }
2724 }
2725
2726 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2727 Ok(()) => {
2728 debug!("check_pat_ref: expected={:?}", expected);
2735 match *expected.kind() {
2736 ty::Ref(_, r_ty, r_mutbl)
2737 if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2738 || r_mutbl == pat_mutbl =>
2739 {
2740 if r_mutbl == Mutability::Not {
2741 pat_info.max_ref_mutbl = MutblCap::Not;
2742 }
2743
2744 (expected, r_ty)
2745 }
2746
2747 _ => {
2748 let inner_ty = self.next_ty_var(inner.span);
2749 let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
2750 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2751 let err = self.demand_eqtype_pat_diag(
2752 pat.span,
2753 expected,
2754 ref_ty,
2755 &pat_info.top_info,
2756 );
2757
2758 if let Err(mut err) = err {
2761 self.borrow_pat_suggestion(&mut err, pat);
2762 err.emit();
2763 }
2764 (ref_ty, inner_ty)
2765 }
2766 }
2767 }
2768 Err(guar) => {
2769 let err = Ty::new_error(tcx, guar);
2770 (err, err)
2771 }
2772 };
2773
2774 self.check_pat(inner, inner_ty, pat_info);
2775 ref_ty
2776 }
2777
2778 fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
2780 let region = self.next_region_var(infer::PatternRegion(span));
2781 Ty::new_ref(self.tcx, region, ty, mutbl)
2782 }
2783
2784 fn error_inherited_ref_mutability_mismatch(
2785 &self,
2786 pat: &'tcx Pat<'tcx>,
2787 pat_prefix_span: Option<Span>,
2788 ) -> ErrorGuaranteed {
2789 let err_msg = "mismatched types";
2790 let err = if let Some(span) = pat_prefix_span {
2791 let mut err = self.dcx().struct_span_err(span, err_msg);
2792 err.code(E0308);
2793 err.note("cannot match inherited `&` with `&mut` pattern");
2794 err.span_suggestion_verbose(
2795 span,
2796 "replace this `&mut` pattern with `&`",
2797 "&",
2798 Applicability::MachineApplicable,
2799 );
2800 err
2801 } else {
2802 self.dcx().struct_span_err(pat.span, err_msg)
2803 };
2804 err.emit()
2805 }
2806
2807 fn try_resolve_slice_ty_to_array_ty(
2808 &self,
2809 before: &'tcx [Pat<'tcx>],
2810 slice: Option<&'tcx Pat<'tcx>>,
2811 span: Span,
2812 ) -> Option<Ty<'tcx>> {
2813 if slice.is_some() {
2814 return None;
2815 }
2816
2817 let tcx = self.tcx;
2818 let len = before.len();
2819 let inner_ty = self.next_ty_var(span);
2820
2821 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2822 }
2823
2824 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2855 match decl_origin {
2856 Some(DeclOrigin::LocalDecl { els: None }) => true,
2857 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2858 }
2859 }
2860
2861 fn check_pat_slice(
2872 &self,
2873 span: Span,
2874 before: &'tcx [Pat<'tcx>],
2875 slice: Option<&'tcx Pat<'tcx>>,
2876 after: &'tcx [Pat<'tcx>],
2877 expected: Ty<'tcx>,
2878 pat_info: PatInfo<'tcx>,
2879 ) -> Ty<'tcx> {
2880 let expected = self.try_structurally_resolve_type(span, expected);
2881
2882 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
2885 if let Some(resolved_arr_ty) =
2886 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
2887 {
2888 debug!(?resolved_arr_ty);
2889 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
2890 }
2891 }
2892
2893 let expected = self.structurally_resolve_type(span, expected);
2894 debug!(?expected);
2895
2896 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
2897 ty::Array(element_ty, len) => {
2899 let min = before.len() as u64 + after.len() as u64;
2900 let (opt_slice_ty, expected) =
2901 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
2902 assert!(opt_slice_ty.is_some() || slice.is_none());
2905 (element_ty, opt_slice_ty, expected)
2906 }
2907 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
2908 _ => {
2910 let guar = expected.error_reported().err().unwrap_or_else(|| {
2911 self.error_expected_array_or_slice(span, expected, pat_info)
2912 });
2913 let err = Ty::new_error(self.tcx, guar);
2914 (err, Some(err), err)
2915 }
2916 };
2917
2918 for elt in before {
2920 self.check_pat(elt, element_ty, pat_info);
2921 }
2922 if let Some(slice) = slice {
2924 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
2925 }
2926 for elt in after {
2928 self.check_pat(elt, element_ty, pat_info);
2929 }
2930 inferred
2931 }
2932
2933 fn check_array_pat_len(
2938 &self,
2939 span: Span,
2940 element_ty: Ty<'tcx>,
2941 arr_ty: Ty<'tcx>,
2942 slice: Option<&'tcx Pat<'tcx>>,
2943 len: ty::Const<'tcx>,
2944 min_len: u64,
2945 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
2946 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
2947
2948 let guar = if let Some(len) = len {
2949 if slice.is_none() {
2951 if min_len == len {
2955 return (None, arr_ty);
2956 }
2957
2958 self.error_scrutinee_inconsistent_length(span, min_len, len)
2959 } else if let Some(pat_len) = len.checked_sub(min_len) {
2960 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
2963 } else {
2964 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
2967 }
2968 } else if slice.is_none() {
2969 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
2972 self.demand_eqtype(span, updated_arr_ty, arr_ty);
2973 return (None, updated_arr_ty);
2974 } else {
2975 self.error_scrutinee_unfixed_length(span)
2979 };
2980
2981 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
2983 }
2984
2985 fn error_scrutinee_inconsistent_length(
2986 &self,
2987 span: Span,
2988 min_len: u64,
2989 size: u64,
2990 ) -> ErrorGuaranteed {
2991 struct_span_code_err!(
2992 self.dcx(),
2993 span,
2994 E0527,
2995 "pattern requires {} element{} but array has {}",
2996 min_len,
2997 pluralize!(min_len),
2998 size,
2999 )
3000 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
3001 .emit()
3002 }
3003
3004 fn error_scrutinee_with_rest_inconsistent_length(
3005 &self,
3006 span: Span,
3007 min_len: u64,
3008 size: u64,
3009 ) -> ErrorGuaranteed {
3010 struct_span_code_err!(
3011 self.dcx(),
3012 span,
3013 E0528,
3014 "pattern requires at least {} element{} but array has {}",
3015 min_len,
3016 pluralize!(min_len),
3017 size,
3018 )
3019 .with_span_label(
3020 span,
3021 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
3022 )
3023 .emit()
3024 }
3025
3026 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
3027 struct_span_code_err!(
3028 self.dcx(),
3029 span,
3030 E0730,
3031 "cannot pattern-match on an array without a fixed length",
3032 )
3033 .emit()
3034 }
3035
3036 fn error_expected_array_or_slice(
3037 &self,
3038 span: Span,
3039 expected_ty: Ty<'tcx>,
3040 pat_info: PatInfo<'tcx>,
3041 ) -> ErrorGuaranteed {
3042 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
3043
3044 let mut slice_pat_semantics = false;
3045 let mut as_deref = None;
3046 let mut slicing = None;
3047 if let ty::Ref(_, ty, _) = expected_ty.kind()
3048 && let ty::Array(..) | ty::Slice(..) = ty.kind()
3049 {
3050 slice_pat_semantics = true;
3051 } else if self
3052 .autoderef(span, expected_ty)
3053 .silence_errors()
3054 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
3055 && let Some(span) = ti.span
3056 && let Some(_) = ti.origin_expr
3057 {
3058 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
3059 let (is_slice_or_array_or_vector, resolved_ty) =
3060 self.is_slice_or_array_or_vector(resolved_ty);
3061 match resolved_ty.kind() {
3062 ty::Adt(adt_def, _)
3063 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
3064 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
3065 {
3066 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
3068 }
3069 _ => (),
3070 }
3071
3072 let is_top_level = current_depth <= 1;
3073 if is_slice_or_array_or_vector && is_top_level {
3074 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
3075 }
3076 }
3077 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
3078 span,
3079 ty: expected_ty,
3080 slice_pat_semantics,
3081 as_deref,
3082 slicing,
3083 })
3084 }
3085
3086 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
3087 match ty.kind() {
3088 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
3089 (true, ty)
3090 }
3091 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
3092 ty::Slice(..) | ty::Array(..) => (true, ty),
3093 _ => (false, ty),
3094 }
3095 }
3096
3097 fn add_rust_2024_migration_desugared_pat(
3100 &self,
3101 pat_id: HirId,
3102 subpat: &'tcx Pat<'tcx>,
3103 final_char: char,
3104 def_br_mutbl: Mutability,
3105 ) {
3106 let from_expansion = subpat.span.from_expansion();
3108 let trimmed_span = if from_expansion {
3109 subpat.span
3111 } else {
3112 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3113 trimmed.with_ctxt(subpat.span.ctxt())
3116 };
3117
3118 let mut typeck_results = self.typeck_results.borrow_mut();
3119 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3120 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3125 primary_labels: Vec::new(),
3126 bad_modifiers: false,
3127 bad_ref_pats: false,
3128 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3129 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3130 });
3131
3132 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3133 info.bad_modifiers = true;
3134 info.suggest_eliding_modes &=
3138 user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
3139 "binding modifier"
3140 } else {
3141 info.bad_ref_pats = true;
3142 info.suggest_eliding_modes = false;
3146 "reference pattern"
3147 };
3148 let primary_label = if from_expansion {
3151 info.suggest_eliding_modes = false;
3153 "occurs within macro expansion".to_owned()
3157 } else {
3158 let dbm_str = match def_br_mutbl {
3159 Mutability::Not => "ref",
3160 Mutability::Mut => "ref mut",
3161 };
3162 format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
3163 };
3164 info.primary_labels.push((trimmed_span, primary_label));
3165 }
3166}