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, Pinnedness, 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_pinnedness: PinnednessCap,
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 PinnednessCap {
252 Not,
254 Pinned,
256}
257
258#[derive(Clone, Copy, Debug, PartialEq, Eq)]
264enum InheritedRefMatchRule {
265 EatOuter,
269 EatInner,
272 EatBoth {
275 consider_inherited_ref: bool,
286 },
287}
288
289#[derive(Clone, Copy, Debug)]
298struct ResolvedPat<'tcx> {
299 ty: Ty<'tcx>,
302 kind: ResolvedPatKind<'tcx>,
303}
304
305#[derive(Clone, Copy, Debug)]
306enum ResolvedPatKind<'tcx> {
307 Path { res: Res, pat_res: Res, segments: &'tcx [hir::PathSegment<'tcx>] },
308 Struct { variant: &'tcx VariantDef },
309 TupleStruct { res: Res, variant: &'tcx VariantDef },
310}
311
312impl<'tcx> ResolvedPat<'tcx> {
313 fn adjust_mode(&self) -> AdjustMode {
314 if let ResolvedPatKind::Path { res, .. } = self.kind
315 && matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
316 {
317 AdjustMode::Pass
321 } else {
322 AdjustMode::peel_until_adt(self.ty.ty_adt_def().map(|adt| adt.did()))
326 }
327 }
328}
329
330impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
331 fn downgrade_mut_inside_shared(&self) -> bool {
335 self.tcx.features().ref_pat_eat_one_layer_2024_structural()
338 }
339
340 fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule {
343 if edition.at_least_rust_2024() {
346 if self.tcx.features().ref_pat_eat_one_layer_2024() {
347 InheritedRefMatchRule::EatOuter
348 } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() {
349 InheritedRefMatchRule::EatInner
350 } else {
351 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false }
354 }
355 } else {
356 InheritedRefMatchRule::EatBoth {
357 consider_inherited_ref: self.tcx.features().ref_pat_eat_one_layer_2024()
358 || self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
359 }
360 }
361 }
362
363 fn ref_pat_matches_mut_ref(&self) -> bool {
366 self.tcx.features().ref_pat_eat_one_layer_2024()
369 || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
370 }
371
372 pub(crate) fn check_pat_top(
381 &self,
382 pat: &'tcx Pat<'tcx>,
383 expected: Ty<'tcx>,
384 span: Option<Span>,
385 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
386 decl_origin: Option<DeclOrigin<'tcx>>,
387 ) {
388 let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
389 let pat_info = PatInfo {
390 binding_mode: ByRef::No,
391 max_pinnedness: PinnednessCap::Not,
392 max_ref_mutbl: MutblCap::Mut,
393 top_info,
394 decl_origin,
395 current_depth: 0,
396 };
397 self.check_pat(pat, expected, pat_info);
398 }
399
400 #[instrument(level = "debug", skip(self, pat_info))]
406 fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
407 let opt_path_res = match pat.kind {
410 PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
411 Some(self.resolve_pat_path(*hir_id, *span, qpath))
412 }
413 PatKind::Struct(ref qpath, ..) => Some(self.resolve_pat_struct(pat, qpath)),
414 PatKind::TupleStruct(ref qpath, ..) => Some(self.resolve_pat_tuple_struct(pat, qpath)),
415 _ => None,
416 };
417 let adjust_mode = self.calc_adjust_mode(pat, opt_path_res);
418 let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
419 self.write_ty(pat.hir_id, ty);
420
421 if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id)
424 && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref)
425 {
426 self.register_deref_mut_bounds_if_needed(
427 pat.span,
428 pat,
429 derefed_tys.iter().filter_map(|adjust| match adjust.kind {
430 PatAdjust::OverloadedDeref => Some(adjust.source),
431 PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None,
432 }),
433 );
434 }
435
436 }
478
479 fn check_pat_inner(
481 &self,
482 pat: &'tcx Pat<'tcx>,
483 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
484 adjust_mode: AdjustMode,
485 expected: Ty<'tcx>,
486 pat_info: PatInfo<'tcx>,
487 ) -> Ty<'tcx> {
488 #[cfg(debug_assertions)]
489 if matches!(pat_info.binding_mode, ByRef::Yes(_, Mutability::Mut))
490 && pat_info.max_ref_mutbl != MutblCap::Mut
491 && self.downgrade_mut_inside_shared()
492 {
493 span_bug!(pat.span, "Pattern mutability cap violated!");
494 }
495
496 let expected = if let AdjustMode::Peel { .. } = adjust_mode
498 && pat.default_binding_modes
499 {
500 self.try_structurally_resolve_type(pat.span, expected)
501 } else {
502 expected
503 };
504 let old_pat_info = pat_info;
505 let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
506
507 match pat.kind {
508 _ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
511 && pat.default_binding_modes
512 && let &ty::Ref(_, inner_ty, inner_mutability) = expected.kind()
513 && self.should_peel_ref(peel_kind, expected) =>
514 {
515 debug!("inspecting {:?}", expected);
516
517 debug!("current discriminant is Ref, inserting implicit deref");
518 self.typeck_results
520 .borrow_mut()
521 .pat_adjustments_mut()
522 .entry(pat.hir_id)
523 .or_default()
524 .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
525
526 let new_pat_info =
528 self.adjust_pat_info(Pinnedness::Not, inner_mutability, old_pat_info);
529
530 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
532 }
533 _ if self.tcx.features().pin_ergonomics()
536 && let AdjustMode::Peel { kind: peel_kind } = adjust_mode
537 && pat.default_binding_modes
538 && self.should_peel_smart_pointer(peel_kind, expected)
539 && let Some(pinned_ty) = expected.pinned_ty()
540 && let &ty::Ref(_, inner_ty, inner_mutability) = pinned_ty.kind() =>
544 {
545 debug!("scrutinee ty {expected:?} is a pinned reference, inserting pin deref");
546
547 if let Some(adt) = inner_ty.ty_adt_def()
550 && !adt.is_pin_project()
551 && !adt.is_pin()
552 {
553 let def_span: Option<Span> = self.tcx.hir_span_if_local(adt.did());
554 let sugg_span = def_span.map(|span| span.shrink_to_lo());
555 self.dcx().emit_err(crate::errors::ProjectOnNonPinProjectType {
556 span: pat.span,
557 def_span,
558 sugg_span,
559 });
560 }
561
562 let new_pat_info =
564 self.adjust_pat_info(Pinnedness::Pinned, inner_mutability, old_pat_info);
565
566 self.check_deref_pattern(
567 pat,
568 opt_path_res,
569 adjust_mode,
570 expected,
571 inner_ty,
572 PatAdjust::PinDeref,
573 new_pat_info,
574 )
575 }
576 _ if self.tcx.features().deref_patterns()
579 && let AdjustMode::Peel { kind: peel_kind } = adjust_mode
580 && pat.default_binding_modes
581 && self.should_peel_smart_pointer(peel_kind, expected) =>
582 {
583 debug!("scrutinee ty {expected:?} is a smart pointer, inserting pin deref");
584
585 let inner_ty = self.deref_pat_target(pat.span, expected);
588 self.check_deref_pattern(
592 pat,
593 opt_path_res,
594 adjust_mode,
595 expected,
596 inner_ty,
597 PatAdjust::OverloadedDeref,
598 old_pat_info,
599 )
600 }
601 PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
602 PatKind::Never => expected,
604 PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), hir_id, .. }) => {
605 let ty = match opt_path_res.unwrap() {
606 Ok(ref pr) => {
607 self.check_pat_path(pat.hir_id, pat.span, pr, expected, &pat_info.top_info)
608 }
609 Err(guar) => Ty::new_error(self.tcx, guar),
610 };
611 self.write_ty(*hir_id, ty);
612 ty
613 }
614 PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info),
615 PatKind::Range(lhs, rhs, _) => {
616 self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info)
617 }
618 PatKind::Binding(ba, var_id, ident, sub) => {
619 self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
620 }
621 PatKind::TupleStruct(ref qpath, subpats, ddpos) => match opt_path_res.unwrap() {
622 Ok(ResolvedPat { ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) => self
623 .check_pat_tuple_struct(
624 pat, qpath, subpats, ddpos, res, ty, variant, expected, pat_info,
625 ),
626 Err(guar) => {
627 let ty_err = Ty::new_error(self.tcx, guar);
628 for subpat in subpats {
629 self.check_pat(subpat, ty_err, pat_info);
630 }
631 ty_err
632 }
633 Ok(pr) => span_bug!(pat.span, "tuple struct pattern resolved to {pr:?}"),
634 },
635 PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() {
636 Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self
637 .check_pat_struct(
638 pat,
639 fields,
640 has_rest_pat.is_some(),
641 ty,
642 variant,
643 expected,
644 pat_info,
645 ),
646 Err(guar) => {
647 let ty_err = Ty::new_error(self.tcx, guar);
648 for field in fields {
649 self.check_pat(field.pat, ty_err, pat_info);
650 }
651 ty_err
652 }
653 Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
654 },
655 PatKind::Guard(pat, cond) => {
656 self.check_pat(pat, expected, pat_info);
657 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
658 expected
659 }
660 PatKind::Or(pats) => {
661 for pat in pats {
662 self.check_pat(pat, expected, pat_info);
663 }
664 expected
665 }
666 PatKind::Tuple(elements, ddpos) => {
667 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
668 }
669 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
670 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
671 PatKind::Ref(inner, pinned, mutbl) => {
672 self.check_pat_ref(pat, inner, pinned, mutbl, expected, pat_info)
673 }
674 PatKind::Slice(before, slice, after) => {
675 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
676 }
677 }
678 }
679
680 fn adjust_pat_info(
681 &self,
682 inner_pinnedness: Pinnedness,
683 inner_mutability: Mutability,
684 pat_info: PatInfo<'tcx>,
685 ) -> PatInfo<'tcx> {
686 let mut binding_mode = match pat_info.binding_mode {
687 ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
691 ByRef::Yes(pinnedness, mutability) => {
692 let pinnedness = match pinnedness {
693 Pinnedness::Not => inner_pinnedness,
695 Pinnedness::Pinned => Pinnedness::Pinned,
701 };
702
703 let mutability = match mutability {
704 Mutability::Mut => inner_mutability,
706 Mutability::Not => Mutability::Not,
709 };
710 ByRef::Yes(pinnedness, mutability)
711 }
712 };
713
714 let PatInfo { mut max_ref_mutbl, mut max_pinnedness, .. } = pat_info;
715 if self.downgrade_mut_inside_shared() {
716 binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
717 }
718 match binding_mode {
719 ByRef::Yes(_, Mutability::Not) => max_ref_mutbl = MutblCap::Not,
720 ByRef::Yes(Pinnedness::Pinned, _) => max_pinnedness = PinnednessCap::Pinned,
721 _ => {}
722 }
723 debug!("default binding mode is now {:?}", binding_mode);
724 PatInfo { binding_mode, max_pinnedness, max_ref_mutbl, ..pat_info }
725 }
726
727 fn check_deref_pattern(
728 &self,
729 pat: &'tcx Pat<'tcx>,
730 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
731 adjust_mode: AdjustMode,
732 expected: Ty<'tcx>,
733 mut inner_ty: Ty<'tcx>,
734 pat_adjust_kind: PatAdjust,
735 pat_info: PatInfo<'tcx>,
736 ) -> Ty<'tcx> {
737 debug_assert!(
738 !matches!(pat_adjust_kind, PatAdjust::BuiltinDeref),
739 "unexpected deref pattern for builtin reference type {expected:?}",
740 );
741
742 let mut typeck_results = self.typeck_results.borrow_mut();
743 let mut pat_adjustments_table = typeck_results.pat_adjustments_mut();
744 let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default();
745 if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) {
752 pat_adjustments.push(PatAdjustment { kind: pat_adjust_kind, source: expected });
754 } else {
755 let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected);
756 inner_ty = Ty::new_error(self.tcx, guar);
757 }
758 drop(typeck_results);
759
760 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, pat_info)
763 }
764
765 fn calc_adjust_mode(
769 &self,
770 pat: &'tcx Pat<'tcx>,
771 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
772 ) -> AdjustMode {
773 match &pat.kind {
774 PatKind::Tuple(..) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::peel_all(),
777 PatKind::Box(_) | PatKind::Deref(_) => {
781 AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat }
782 }
783 PatKind::Never => AdjustMode::peel_all(),
785 PatKind::Struct(..)
787 | PatKind::TupleStruct(..)
788 | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
789 opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
791 }
792
793 PatKind::Expr(lt) => {
798 if cfg!(debug_assertions)
801 && self.tcx.features().deref_patterns()
802 && !matches!(lt.kind, PatExprKind::Lit { .. })
803 {
804 span_bug!(
805 lt.span,
806 "FIXME(deref_patterns): adjust mode unimplemented for {:?}",
807 lt.kind
808 );
809 }
810 let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
812 if self.tcx.features().deref_patterns() {
814 let mut peeled_ty = lit_ty;
815 let mut pat_ref_layers = 0;
816 while let ty::Ref(_, inner_ty, mutbl) =
817 *self.try_structurally_resolve_type(pat.span, peeled_ty).kind()
818 {
819 debug_assert!(mutbl.is_not());
821 pat_ref_layers += 1;
822 peeled_ty = inner_ty;
823 }
824 AdjustMode::Peel {
825 kind: PeelKind::Implicit { until_adt: None, pat_ref_layers },
826 }
827 } else {
828 if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
829 }
830 }
831
832 PatKind::Ref(..)
834 | PatKind::Missing
836 | PatKind::Wild
838 | PatKind::Err(_)
840 | PatKind::Binding(..)
845 | PatKind::Or(_)
849 | PatKind::Guard(..) => AdjustMode::Pass,
851 }
852 }
853
854 fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
856 debug_assert!(expected.is_ref());
857 let pat_ref_layers = match peel_kind {
858 PeelKind::ExplicitDerefPat => 0,
859 PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
860 };
861
862 if pat_ref_layers == 0 {
865 return true;
866 }
867 debug_assert!(
868 self.tcx.features().deref_patterns(),
869 "Peeling for patterns with reference types is gated by `deref_patterns`."
870 );
871
872 let mut expected_ref_layers = 0;
878 while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
879 if mutbl.is_mut() {
880 return true;
883 }
884 expected_ref_layers += 1;
885 expected = inner_ty;
886 }
887 pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
888 }
889
890 fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
892 if let PeelKind::Implicit { until_adt, .. } = peel_kind
894 && let ty::Adt(scrutinee_adt, _) = *expected.kind()
899 && until_adt != Some(scrutinee_adt.did())
902 && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
907 && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
908 {
909 true
910 } else {
911 false
912 }
913 }
914
915 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
916 let ty = match <.kind {
917 rustc_hir::PatExprKind::Lit { lit, negated } => {
918 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
919 if *negated {
920 self.register_bound(
921 ty,
922 self.tcx.require_lang_item(LangItem::Neg, lt.span),
923 ObligationCause::dummy_with_span(lt.span),
924 );
925 }
926 ty
927 }
928 rustc_hir::PatExprKind::Path(qpath) => {
929 let (res, opt_ty, segments) =
930 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
931 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
932 }
933 };
934 self.write_ty(lt.hir_id, ty);
935 ty
936 }
937
938 fn check_pat_lit(
939 &self,
940 span: Span,
941 lt: &hir::PatExpr<'tcx>,
942 expected: Ty<'tcx>,
943 ti: &TopInfo<'tcx>,
944 ) -> Ty<'tcx> {
945 let ty = self.node_ty(lt.hir_id);
948
949 let mut pat_ty = ty;
954 if let hir::PatExprKind::Lit {
955 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
956 } = lt.kind
957 {
958 let tcx = self.tcx;
959 let expected = self.structurally_resolve_type(span, expected);
960 match *expected.kind() {
961 ty::Ref(_, inner_ty, _)
963 if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
964 {
965 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
966 pat_ty = Ty::new_imm_ref(
967 tcx,
968 tcx.lifetimes.re_static,
969 Ty::new_slice(tcx, tcx.types.u8),
970 );
971 }
972 ty::Array(..) if tcx.features().deref_patterns() => {
974 pat_ty = match *ty.kind() {
975 ty::Ref(_, inner_ty, _) => inner_ty,
976 _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
977 }
978 }
979 ty::Slice(..) if tcx.features().deref_patterns() => {
981 pat_ty = Ty::new_slice(tcx, tcx.types.u8);
982 }
983 _ => {}
985 }
986 }
987
988 if self.tcx.features().deref_patterns()
991 && let hir::PatExprKind::Lit {
992 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
993 } = lt.kind
994 && self.try_structurally_resolve_type(span, expected).is_str()
995 {
996 pat_ty = self.tcx.types.str_;
997 }
998
999 let cause = self.pattern_cause(ti, span);
1010 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
1011 err.emit();
1012 }
1013
1014 pat_ty
1015 }
1016
1017 fn check_pat_range(
1018 &self,
1019 span: Span,
1020 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
1021 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
1022 expected: Ty<'tcx>,
1023 ti: &TopInfo<'tcx>,
1024 ) -> Ty<'tcx> {
1025 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
1026 None => None,
1027 Some(expr) => {
1028 let ty = self.check_pat_expr_unadjusted(expr);
1029 let ty = self.try_structurally_resolve_type(expr.span, ty);
1036 let fail =
1037 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
1038 Some((fail, ty, expr.span))
1039 }
1040 };
1041 let mut lhs = calc_side(lhs);
1042 let mut rhs = calc_side(rhs);
1043
1044 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
1045 let guar = self.emit_err_pat_range(span, lhs, rhs);
1048 return Ty::new_error(self.tcx, guar);
1049 }
1050
1051 let demand_eqtype = |x: &mut _, y| {
1054 if let Some((ref mut fail, x_ty, x_span)) = *x
1055 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
1056 {
1057 if let Some((_, y_ty, y_span)) = y {
1058 self.endpoint_has_type(&mut err, y_span, y_ty);
1059 }
1060 err.emit();
1061 *fail = true;
1062 }
1063 };
1064 demand_eqtype(&mut lhs, rhs);
1065 demand_eqtype(&mut rhs, lhs);
1066
1067 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
1068 return Ty::new_misc_error(self.tcx);
1069 }
1070
1071 let ty = self.structurally_resolve_type(span, expected);
1076 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
1077 if let Some((ref mut fail, _, _)) = lhs {
1078 *fail = true;
1079 }
1080 if let Some((ref mut fail, _, _)) = rhs {
1081 *fail = true;
1082 }
1083 let guar = self.emit_err_pat_range(span, lhs, rhs);
1084 return Ty::new_error(self.tcx, guar);
1085 }
1086 ty
1087 }
1088
1089 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
1090 if !ty.references_error() {
1091 err.span_label(span, format!("this is of type `{ty}`"));
1092 }
1093 }
1094
1095 fn emit_err_pat_range(
1096 &self,
1097 span: Span,
1098 lhs: Option<(bool, Ty<'tcx>, Span)>,
1099 rhs: Option<(bool, Ty<'tcx>, Span)>,
1100 ) -> ErrorGuaranteed {
1101 let span = match (lhs, rhs) {
1102 (Some((true, ..)), Some((true, ..))) => span,
1103 (Some((true, _, sp)), _) => sp,
1104 (_, Some((true, _, sp))) => sp,
1105 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
1106 };
1107 let mut err = struct_span_code_err!(
1108 self.dcx(),
1109 span,
1110 E0029,
1111 "only `char` and numeric types are allowed in range patterns"
1112 );
1113 let msg = |ty| {
1114 let ty = self.resolve_vars_if_possible(ty);
1115 format!("this is of type `{ty}` but it should be `char` or numeric")
1116 };
1117 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
1118 err.span_label(first_span, msg(first_ty));
1119 if let Some((_, ty, sp)) = second {
1120 let ty = self.resolve_vars_if_possible(ty);
1121 self.endpoint_has_type(&mut err, sp, ty);
1122 }
1123 };
1124 match (lhs, rhs) {
1125 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
1126 err.span_label(lhs_sp, msg(lhs_ty));
1127 err.span_label(rhs_sp, msg(rhs_ty));
1128 }
1129 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
1130 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
1131 _ => span_bug!(span, "Impossible, verified above."),
1132 }
1133 if (lhs, rhs).references_error() {
1134 err.downgrade_to_delayed_bug();
1135 }
1136 if self.tcx.sess.teach(err.code.unwrap()) {
1137 err.note(
1138 "In a match expression, only numbers and characters can be matched \
1139 against a range. This is because the compiler checks that the range \
1140 is non-empty at compile-time, and is unable to evaluate arbitrary \
1141 comparison functions. If you want to capture values of an orderable \
1142 type between two end-points, you can use a guard.",
1143 );
1144 }
1145 err.emit()
1146 }
1147
1148 fn check_pat_ident(
1149 &self,
1150 pat: &'tcx Pat<'tcx>,
1151 user_bind_annot: BindingMode,
1152 var_id: HirId,
1153 ident: Ident,
1154 sub: Option<&'tcx Pat<'tcx>>,
1155 expected: Ty<'tcx>,
1156 pat_info: PatInfo<'tcx>,
1157 ) -> Ty<'tcx> {
1158 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
1159
1160 let bm = match user_bind_annot {
1162 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(_, def_br_mutbl) = def_br => {
1163 if pat.span.at_least_rust_2024()
1166 && (self.tcx.features().ref_pat_eat_one_layer_2024()
1167 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
1168 {
1169 if !self.tcx.features().mut_ref() {
1170 feature_err(
1171 self.tcx.sess,
1172 sym::mut_ref,
1173 pat.span.until(ident.span),
1174 "binding cannot be both mutable and by-reference",
1175 )
1176 .emit();
1177 }
1178
1179 BindingMode(def_br, Mutability::Mut)
1180 } else {
1181 self.add_rust_2024_migration_desugared_pat(
1183 pat_info.top_info.hir_id,
1184 pat,
1185 't', def_br_mutbl,
1187 );
1188 BindingMode(ByRef::No, Mutability::Mut)
1189 }
1190 }
1191 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
1192 BindingMode(ByRef::Yes(_, user_br_mutbl), _) => {
1193 if let ByRef::Yes(_, def_br_mutbl) = def_br {
1194 self.add_rust_2024_migration_desugared_pat(
1196 pat_info.top_info.hir_id,
1197 pat,
1198 match user_br_mutbl {
1199 Mutability::Not => 'f', Mutability::Mut => 't', },
1202 def_br_mutbl,
1203 );
1204 }
1205 user_bind_annot
1206 }
1207 };
1208
1209 if pat_info.max_pinnedness == PinnednessCap::Pinned
1212 && matches!(bm.0, ByRef::Yes(Pinnedness::Not, _))
1213 {
1214 self.register_bound(
1215 expected,
1216 self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
1217 self.misc(pat.span),
1218 )
1219 }
1220
1221 if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
1222 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1223 {
1224 let mut err = struct_span_code_err!(
1225 self.dcx(),
1226 ident.span,
1227 E0596,
1228 "cannot borrow as mutable inside an `&` pattern"
1229 );
1230
1231 if let Some(span) = and_pat_span {
1232 err.span_suggestion(
1233 span,
1234 "replace this `&` with `&mut`",
1235 "&mut ",
1236 Applicability::MachineApplicable,
1237 );
1238 }
1239 err.emit();
1240 }
1241
1242 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1244
1245 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1246
1247 let local_ty = self.local_ty(pat.span, pat.hir_id);
1248 let eq_ty = match bm.0 {
1249 ByRef::Yes(pinnedness, mutbl) => {
1250 self.new_ref_ty(pat.span, pinnedness, mutbl, expected)
1262 }
1263 ByRef::No => expected, };
1266
1267 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1269
1270 if var_id != pat.hir_id {
1273 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1274 }
1275
1276 if let Some(p) = sub {
1277 self.check_pat(p, expected, pat_info);
1278 }
1279
1280 local_ty
1281 }
1282
1283 fn check_binding_alt_eq_ty(
1287 &self,
1288 ba: BindingMode,
1289 span: Span,
1290 var_id: HirId,
1291 ty: Ty<'tcx>,
1292 ti: &TopInfo<'tcx>,
1293 ) {
1294 let var_ty = self.local_ty(span, var_id);
1295 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1296 let var_ty = self.resolve_vars_if_possible(var_ty);
1297 let msg = format!("first introduced with type `{var_ty}` here");
1298 err.span_label(self.tcx.hir_span(var_id), msg);
1299 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1300 matches!(
1301 n,
1302 hir::Node::Expr(hir::Expr {
1303 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1304 ..
1305 })
1306 )
1307 });
1308 let pre = if in_match { "in the same arm, " } else { "" };
1309 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1310 self.suggest_adding_missing_ref_or_removing_ref(
1311 &mut err,
1312 span,
1313 var_ty,
1314 self.resolve_vars_if_possible(ty),
1315 ba,
1316 );
1317 err.emit();
1318 }
1319 }
1320
1321 fn suggest_adding_missing_ref_or_removing_ref(
1322 &self,
1323 err: &mut Diag<'_>,
1324 span: Span,
1325 expected: Ty<'tcx>,
1326 actual: Ty<'tcx>,
1327 ba: BindingMode,
1328 ) {
1329 match (expected.kind(), actual.kind(), ba) {
1330 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1331 if self.can_eq(self.param_env, *inner_ty, actual) =>
1332 {
1333 err.span_suggestion_verbose(
1334 span.shrink_to_lo(),
1335 "consider adding `ref`",
1336 "ref ",
1337 Applicability::MaybeIncorrect,
1338 );
1339 }
1340 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1341 if self.can_eq(self.param_env, expected, *inner_ty) =>
1342 {
1343 err.span_suggestion_verbose(
1344 span.with_hi(span.lo() + BytePos(4)),
1345 "consider removing `ref`",
1346 "",
1347 Applicability::MaybeIncorrect,
1348 );
1349 }
1350 _ => (),
1351 }
1352 }
1353
1354 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1357 let tcx = self.tcx;
1358 if let PatKind::Ref(inner, pinned, mutbl) = pat.kind
1359 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1360 {
1361 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1362 debug!(?inner, ?pat, ?binding_parent);
1363
1364 let pin_and_mut = pinned.prefix_str(mutbl).trim_end();
1365
1366 let mut_var_suggestion = 'block: {
1367 if mutbl.is_not() {
1368 break 'block None;
1369 }
1370
1371 let ident_kind = match binding_parent {
1372 hir::Node::Param(_) => "parameter",
1373 hir::Node::LetStmt(_) => "variable",
1374 hir::Node::Arm(_) => "binding",
1375
1376 hir::Node::Pat(Pat { kind, .. }) => match kind {
1379 PatKind::Struct(..)
1380 | PatKind::TupleStruct(..)
1381 | PatKind::Or(..)
1382 | PatKind::Guard(..)
1383 | PatKind::Tuple(..)
1384 | PatKind::Slice(..) => "binding",
1385
1386 PatKind::Missing
1387 | PatKind::Wild
1388 | PatKind::Never
1389 | PatKind::Binding(..)
1390 | PatKind::Box(..)
1391 | PatKind::Deref(_)
1392 | PatKind::Ref(..)
1393 | PatKind::Expr(..)
1394 | PatKind::Range(..)
1395 | PatKind::Err(_) => break 'block None,
1396 },
1397
1398 _ => break 'block None,
1400 };
1401
1402 Some((
1403 pat.span,
1404 format!("to declare a mutable {ident_kind} use"),
1405 format!("mut {binding}"),
1406 ))
1407 };
1408
1409 match binding_parent {
1410 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1413 err.multipart_suggestion_verbose(
1414 format!("to take parameter `{binding}` by reference, move `&{pin_and_mut}` to the type"),
1415 vec![
1416 (pat.span.until(inner.span), "".to_owned()),
1417 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1418 ],
1419 Applicability::MachineApplicable
1420 );
1421
1422 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1423 err.span_note(sp, format!("{msg}: `{sugg}`"));
1424 }
1425 }
1426 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1427 for i in pat_arr.iter() {
1428 if let PatKind::Ref(the_ref, _, _) = i.kind
1429 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1430 {
1431 let BindingMode(_, mtblty) = mt;
1432 err.span_suggestion_verbose(
1433 i.span,
1434 format!("consider removing `&{pin_and_mut}` from the pattern"),
1435 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1436 Applicability::MaybeIncorrect,
1437 );
1438 }
1439 }
1440 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1441 err.span_note(sp, format!("{msg}: `{sugg}`"));
1442 }
1443 }
1444 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1445 err.span_suggestion_verbose(
1447 pat.span.until(inner.span),
1448 format!("consider removing `&{pin_and_mut}` from the pattern"),
1449 "",
1450 Applicability::MaybeIncorrect,
1451 );
1452
1453 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1454 err.span_note(sp, format!("{msg}: `{sugg}`"));
1455 }
1456 }
1457 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1458 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1459 }
1460 _ => {} }
1462 }
1463 }
1464
1465 fn check_dereferenceable(
1466 &self,
1467 span: Span,
1468 expected: Ty<'tcx>,
1469 inner: &Pat<'_>,
1470 ) -> Result<(), ErrorGuaranteed> {
1471 if let PatKind::Binding(..) = inner.kind
1472 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1473 && let ty::Dynamic(..) = pointee_ty.kind()
1474 {
1475 let type_str = self.ty_to_string(expected);
1478 let mut err = struct_span_code_err!(
1479 self.dcx(),
1480 span,
1481 E0033,
1482 "type `{}` cannot be dereferenced",
1483 type_str
1484 );
1485 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1486 if self.tcx.sess.teach(err.code.unwrap()) {
1487 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1488 }
1489 return Err(err.emit());
1490 }
1491 Ok(())
1492 }
1493
1494 fn resolve_pat_struct(
1495 &self,
1496 pat: &'tcx Pat<'tcx>,
1497 qpath: &hir::QPath<'tcx>,
1498 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1499 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1501 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1502 }
1503
1504 fn check_pat_struct(
1505 &self,
1506 pat: &'tcx Pat<'tcx>,
1507 fields: &'tcx [hir::PatField<'tcx>],
1508 has_rest_pat: bool,
1509 pat_ty: Ty<'tcx>,
1510 variant: &'tcx VariantDef,
1511 expected: Ty<'tcx>,
1512 pat_info: PatInfo<'tcx>,
1513 ) -> Ty<'tcx> {
1514 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1516
1517 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1519 Ok(()) => pat_ty,
1520 Err(guar) => Ty::new_error(self.tcx, guar),
1521 }
1522 }
1523
1524 fn resolve_pat_path(
1525 &self,
1526 path_id: HirId,
1527 span: Span,
1528 qpath: &'tcx hir::QPath<'_>,
1529 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1530 let tcx = self.tcx;
1531
1532 let (res, opt_ty, segments) =
1533 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1534 match res {
1535 Res::Err => {
1536 let e =
1537 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1538 self.set_tainted_by_errors(e);
1539 return Err(e);
1540 }
1541 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1542 let expected = "unit struct, unit variant or constant";
1543 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1544 return Err(e);
1545 }
1546 Res::SelfCtor(def_id) => {
1547 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1548 && adt_def.is_struct()
1549 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1550 {
1551 } else {
1553 let e = report_unexpected_variant_res(
1554 tcx,
1555 res,
1556 None,
1557 qpath,
1558 span,
1559 E0533,
1560 "unit struct",
1561 );
1562 return Err(e);
1563 }
1564 }
1565 Res::Def(
1566 DefKind::Ctor(_, CtorKind::Const)
1567 | DefKind::Const
1568 | DefKind::AssocConst
1569 | DefKind::ConstParam,
1570 _,
1571 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1573 }
1574
1575 let (pat_ty, pat_res) =
1577 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1578 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1579 }
1580
1581 fn check_pat_path(
1582 &self,
1583 pat_id_for_diag: HirId,
1584 span: Span,
1585 resolved: &ResolvedPat<'tcx>,
1586 expected: Ty<'tcx>,
1587 ti: &TopInfo<'tcx>,
1588 ) -> Ty<'tcx> {
1589 if let Err(err) =
1590 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1591 {
1592 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1593 }
1594 resolved.ty
1595 }
1596
1597 fn maybe_suggest_range_literal(
1598 &self,
1599 e: &mut Diag<'_>,
1600 opt_def_id: Option<hir::def_id::DefId>,
1601 ident: Ident,
1602 ) -> bool {
1603 if let Some(def_id) = opt_def_id
1604 && let Some(hir::Node::Item(hir::Item {
1605 kind: hir::ItemKind::Const(_, _, _, ct_rhs),
1606 ..
1607 })) = self.tcx.hir_get_if_local(def_id)
1608 && let hir::Node::Expr(expr) = self.tcx.hir_node(ct_rhs.hir_id())
1609 && hir::is_range_literal(expr)
1610 {
1611 let span = self.tcx.hir_span(ct_rhs.hir_id());
1612 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1613 e.span_suggestion_verbose(
1614 ident.span,
1615 "you may want to move the range into the match block",
1616 snip,
1617 Applicability::MachineApplicable,
1618 );
1619 return true;
1620 }
1621 }
1622 false
1623 }
1624
1625 fn emit_bad_pat_path(
1626 &self,
1627 mut e: Diag<'_>,
1628 hir_id: HirId,
1629 pat_span: Span,
1630 resolved_pat: &ResolvedPat<'tcx>,
1631 ) {
1632 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1633 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1634 };
1635
1636 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1637 e.span_label(span, format!("{} defined here", res.descr()));
1638 if let [hir::PathSegment { ident, .. }] = segments {
1639 e.span_label(
1640 pat_span,
1641 format!(
1642 "`{}` is interpreted as {} {}, not a new binding",
1643 ident,
1644 res.article(),
1645 res.descr(),
1646 ),
1647 );
1648 match self.tcx.parent_hir_node(hir_id) {
1649 hir::Node::PatField(..) => {
1650 e.span_suggestion_verbose(
1651 ident.span.shrink_to_hi(),
1652 "bind the struct field to a different name instead",
1653 format!(": other_{}", ident.as_str().to_lowercase()),
1654 Applicability::HasPlaceholders,
1655 );
1656 }
1657 _ => {
1658 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1659 ty::Adt(def, _) => match res {
1660 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1661 _ => (None, None),
1662 },
1663 _ => (None, None),
1664 };
1665
1666 let is_range = matches!(
1667 type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
1668 Some(
1669 LangItem::Range
1670 | LangItem::RangeFrom
1671 | LangItem::RangeTo
1672 | LangItem::RangeFull
1673 | LangItem::RangeInclusiveStruct
1674 | LangItem::RangeToInclusive,
1675 )
1676 );
1677 if is_range {
1678 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1679 let msg = "constants only support matching by type, \
1680 if you meant to match against a range of values, \
1681 consider using a range pattern like `min ..= max` in the match block";
1682 e.note(msg);
1683 }
1684 } else {
1685 let msg = "introduce a new binding instead";
1686 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1687 e.span_suggestion(
1688 ident.span,
1689 msg,
1690 sugg,
1691 Applicability::HasPlaceholders,
1692 );
1693 }
1694 }
1695 };
1696 }
1697 }
1698 e.emit();
1699 }
1700
1701 fn resolve_pat_tuple_struct(
1702 &self,
1703 pat: &'tcx Pat<'tcx>,
1704 qpath: &'tcx hir::QPath<'tcx>,
1705 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1706 let tcx = self.tcx;
1707 let report_unexpected_res = |res: Res| {
1708 let expected = "tuple struct or tuple variant";
1709 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1710 Err(e)
1711 };
1712
1713 let (res, opt_ty, segments) =
1715 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1716 if res == Res::Err {
1717 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1718 self.set_tainted_by_errors(e);
1719 return Err(e);
1720 }
1721
1722 let (pat_ty, res) =
1724 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1725 if !pat_ty.is_fn() {
1726 return report_unexpected_res(res);
1727 }
1728
1729 let variant = match res {
1730 Res::Err => {
1731 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1732 }
1733 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1734 return report_unexpected_res(res);
1735 }
1736 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1737 _ => bug!("unexpected pattern resolution: {:?}", res),
1738 };
1739
1740 let pat_ty = pat_ty.fn_sig(tcx).output();
1742 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1743
1744 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1745 }
1746
1747 fn check_pat_tuple_struct(
1748 &self,
1749 pat: &'tcx Pat<'tcx>,
1750 qpath: &'tcx hir::QPath<'tcx>,
1751 subpats: &'tcx [Pat<'tcx>],
1752 ddpos: hir::DotDotPos,
1753 res: Res,
1754 pat_ty: Ty<'tcx>,
1755 variant: &'tcx VariantDef,
1756 expected: Ty<'tcx>,
1757 pat_info: PatInfo<'tcx>,
1758 ) -> Ty<'tcx> {
1759 let tcx = self.tcx;
1760 let on_error = |e| {
1761 for pat in subpats {
1762 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1763 }
1764 };
1765
1766 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1768 let had_err = diag.map_err(|diag| diag.emit());
1769
1770 if subpats.len() == variant.fields.len()
1772 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1773 {
1774 let ty::Adt(_, args) = pat_ty.kind() else {
1775 bug!("unexpected pattern type {:?}", pat_ty);
1776 };
1777 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1778 let field = &variant.fields[FieldIdx::from_usize(i)];
1779 let field_ty = self.field_ty(subpat.span, field, args);
1780 self.check_pat(subpat, field_ty, pat_info);
1781
1782 self.tcx.check_stability(
1783 variant.fields[FieldIdx::from_usize(i)].did,
1784 Some(subpat.hir_id),
1785 subpat.span,
1786 None,
1787 );
1788 }
1789 if let Err(e) = had_err {
1790 on_error(e);
1791 return Ty::new_error(tcx, e);
1792 }
1793 } else {
1794 let e = self.emit_err_pat_wrong_number_of_fields(
1795 pat.span,
1796 res,
1797 qpath,
1798 subpats,
1799 &variant.fields.raw,
1800 expected,
1801 had_err,
1802 );
1803 on_error(e);
1804 return Ty::new_error(tcx, e);
1805 }
1806 pat_ty
1807 }
1808
1809 fn emit_err_pat_wrong_number_of_fields(
1810 &self,
1811 pat_span: Span,
1812 res: Res,
1813 qpath: &hir::QPath<'_>,
1814 subpats: &'tcx [Pat<'tcx>],
1815 fields: &'tcx [ty::FieldDef],
1816 expected: Ty<'tcx>,
1817 had_err: Result<(), ErrorGuaranteed>,
1818 ) -> ErrorGuaranteed {
1819 let subpats_ending = pluralize!(subpats.len());
1820 let fields_ending = pluralize!(fields.len());
1821
1822 let subpat_spans = if subpats.is_empty() {
1823 vec![pat_span]
1824 } else {
1825 subpats.iter().map(|p| p.span).collect()
1826 };
1827 let last_subpat_span = *subpat_spans.last().unwrap();
1828 let res_span = self.tcx.def_span(res.def_id());
1829 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1830 let field_def_spans = if fields.is_empty() {
1831 vec![res_span]
1832 } else {
1833 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1834 };
1835 let last_field_def_span = *field_def_spans.last().unwrap();
1836
1837 let mut err = struct_span_code_err!(
1838 self.dcx(),
1839 MultiSpan::from_spans(subpat_spans),
1840 E0023,
1841 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1842 subpats.len(),
1843 subpats_ending,
1844 res.descr(),
1845 fields.len(),
1846 fields_ending,
1847 );
1848 err.span_label(
1849 last_subpat_span,
1850 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1851 );
1852 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1853 err.span_label(qpath.span(), "");
1854 }
1855 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1856 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1857 }
1858 for span in &field_def_spans[..field_def_spans.len() - 1] {
1859 err.span_label(*span, "");
1860 }
1861 err.span_label(
1862 last_field_def_span,
1863 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1864 );
1865
1866 let missing_parentheses = match (expected.kind(), fields, had_err) {
1871 (ty::Adt(_, args), [field], Ok(())) => {
1875 let field_ty = self.field_ty(pat_span, field, args);
1876 match field_ty.kind() {
1877 ty::Tuple(fields) => fields.len() == subpats.len(),
1878 _ => false,
1879 }
1880 }
1881 _ => false,
1882 };
1883 if missing_parentheses {
1884 let (left, right) = match subpats {
1885 [] => (qpath.span().shrink_to_hi(), pat_span),
1894 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1903 };
1904 err.multipart_suggestion(
1905 "missing parentheses",
1906 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1907 Applicability::MachineApplicable,
1908 );
1909 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1910 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1911 let all_fields_span = match subpats {
1912 [] => after_fields_span,
1913 [field] => field.span,
1914 [first, .., last] => first.span.to(last.span),
1915 };
1916
1917 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1919 let first_tail_wildcard =
1920 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1921 (None, PatKind::Wild) => Some(pos),
1922 (Some(_), PatKind::Wild) => acc,
1923 _ => None,
1924 });
1925 let tail_span = match first_tail_wildcard {
1926 None => after_fields_span,
1927 Some(0) => subpats[0].span.to(after_fields_span),
1928 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1929 };
1930
1931 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1933 if !subpats.is_empty() {
1934 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1935 }
1936
1937 err.span_suggestion_verbose(
1938 after_fields_span,
1939 "use `_` to explicitly ignore each field",
1940 wildcard_sugg,
1941 Applicability::MaybeIncorrect,
1942 );
1943
1944 if fields.len() - subpats.len() > 1 || all_wildcards {
1947 if subpats.is_empty() || all_wildcards {
1948 err.span_suggestion_verbose(
1949 all_fields_span,
1950 "use `..` to ignore all fields",
1951 "..",
1952 Applicability::MaybeIncorrect,
1953 );
1954 } else {
1955 err.span_suggestion_verbose(
1956 tail_span,
1957 "use `..` to ignore the rest of the fields",
1958 ", ..",
1959 Applicability::MaybeIncorrect,
1960 );
1961 }
1962 }
1963 }
1964
1965 err.emit()
1966 }
1967
1968 fn check_pat_tuple(
1969 &self,
1970 span: Span,
1971 elements: &'tcx [Pat<'tcx>],
1972 ddpos: hir::DotDotPos,
1973 expected: Ty<'tcx>,
1974 pat_info: PatInfo<'tcx>,
1975 ) -> Ty<'tcx> {
1976 let tcx = self.tcx;
1977 let mut expected_len = elements.len();
1978 if ddpos.as_opt_usize().is_some() {
1979 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1981 expected_len = tys.len();
1982 }
1983 }
1984 let max_len = cmp::max(expected_len, elements.len());
1985
1986 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1987 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1988 let pat_ty = Ty::new_tup(tcx, element_tys);
1989 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
1990 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1993 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1994 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1995 }
1996 Ty::new_tup_from_iter(tcx, element_tys_iter)
1997 } else {
1998 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1999 self.check_pat(elem, element_tys[i], pat_info);
2000 }
2001 pat_ty
2002 }
2003 }
2004
2005 fn check_struct_pat_fields(
2006 &self,
2007 adt_ty: Ty<'tcx>,
2008 pat: &'tcx Pat<'tcx>,
2009 variant: &'tcx ty::VariantDef,
2010 fields: &'tcx [hir::PatField<'tcx>],
2011 has_rest_pat: bool,
2012 pat_info: PatInfo<'tcx>,
2013 ) -> Result<(), ErrorGuaranteed> {
2014 let tcx = self.tcx;
2015
2016 let ty::Adt(adt, args) = adt_ty.kind() else {
2017 span_bug!(pat.span, "struct pattern is not an ADT");
2018 };
2019
2020 let field_map = variant
2022 .fields
2023 .iter_enumerated()
2024 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
2025 .collect::<FxHashMap<_, _>>();
2026
2027 let mut used_fields = FxHashMap::default();
2029 let mut result = Ok(());
2030
2031 let mut inexistent_fields = vec![];
2032 for field in fields {
2034 let span = field.span;
2035 let ident = tcx.adjust_ident(field.ident, variant.def_id);
2036 let field_ty = match used_fields.entry(ident) {
2037 Occupied(occupied) => {
2038 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
2039 result = Err(guar);
2040 Ty::new_error(tcx, guar)
2041 }
2042 Vacant(vacant) => {
2043 vacant.insert(span);
2044 field_map
2045 .get(&ident)
2046 .map(|(i, f)| {
2047 self.write_field_index(field.hir_id, *i);
2048 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
2049 self.field_ty(span, f, args)
2050 })
2051 .unwrap_or_else(|| {
2052 inexistent_fields.push(field);
2053 Ty::new_misc_error(tcx)
2054 })
2055 }
2056 };
2057
2058 self.check_pat(field.pat, field_ty, pat_info);
2059 }
2060
2061 let mut unmentioned_fields = variant
2062 .fields
2063 .iter()
2064 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
2065 .filter(|(_, ident)| !used_fields.contains_key(ident))
2066 .collect::<Vec<_>>();
2067
2068 let inexistent_fields_err = if !inexistent_fields.is_empty()
2069 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
2070 {
2071 variant.has_errors()?;
2073 Some(self.error_inexistent_fields(
2074 adt.variant_descr(),
2075 &inexistent_fields,
2076 &mut unmentioned_fields,
2077 pat,
2078 variant,
2079 args,
2080 ))
2081 } else {
2082 None
2083 };
2084
2085 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
2087 if non_exhaustive && !has_rest_pat {
2088 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
2089 }
2090
2091 let mut unmentioned_err = None;
2092 if adt.is_union() {
2094 if fields.len() != 1 {
2095 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
2096 }
2097 if has_rest_pat {
2098 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
2099 }
2100 } else if !unmentioned_fields.is_empty() {
2101 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
2102 .iter()
2103 .copied()
2104 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
2105 .collect();
2106
2107 if !has_rest_pat {
2108 if accessible_unmentioned_fields.is_empty() {
2109 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
2110 } else {
2111 unmentioned_err = Some(self.error_unmentioned_fields(
2112 pat,
2113 &accessible_unmentioned_fields,
2114 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
2115 fields,
2116 ));
2117 }
2118 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
2119 self.lint_non_exhaustive_omitted_patterns(
2120 pat,
2121 &accessible_unmentioned_fields,
2122 adt_ty,
2123 )
2124 }
2125 }
2126 match (inexistent_fields_err, unmentioned_err) {
2127 (Some(i), Some(u)) => {
2128 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2129 i.delay_as_bug();
2132 u.delay_as_bug();
2133 Err(e)
2134 } else {
2135 i.emit();
2136 Err(u.emit())
2137 }
2138 }
2139 (None, Some(u)) => {
2140 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2141 u.delay_as_bug();
2142 Err(e)
2143 } else {
2144 Err(u.emit())
2145 }
2146 }
2147 (Some(err), None) => Err(err.emit()),
2148 (None, None) => {
2149 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
2150 result
2151 }
2152 }
2153 }
2154
2155 fn error_tuple_variant_index_shorthand(
2156 &self,
2157 variant: &VariantDef,
2158 pat: &'_ Pat<'_>,
2159 fields: &[hir::PatField<'_>],
2160 ) -> Result<(), ErrorGuaranteed> {
2161 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
2165 (variant.ctor_kind(), &pat.kind)
2166 {
2167 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
2168 if has_shorthand_field_name {
2169 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2170 let mut err = struct_span_code_err!(
2171 self.dcx(),
2172 pat.span,
2173 E0769,
2174 "tuple variant `{path}` written as struct variant",
2175 );
2176 err.span_suggestion_verbose(
2177 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2178 "use the tuple variant pattern syntax instead",
2179 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
2180 Applicability::MaybeIncorrect,
2181 );
2182 return Err(err.emit());
2183 }
2184 }
2185 Ok(())
2186 }
2187
2188 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
2189 let sess = self.tcx.sess;
2190 let sm = sess.source_map();
2191 let sp_brace = sm.end_point(pat.span);
2192 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
2193 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
2194
2195 struct_span_code_err!(
2196 self.dcx(),
2197 pat.span,
2198 E0638,
2199 "`..` required with {descr} marked as non-exhaustive",
2200 )
2201 .with_span_suggestion_verbose(
2202 sp_comma,
2203 "add `..` at the end of the field list to ignore all other fields",
2204 sugg,
2205 Applicability::MachineApplicable,
2206 )
2207 .emit();
2208 }
2209
2210 fn error_field_already_bound(
2211 &self,
2212 span: Span,
2213 ident: Ident,
2214 other_field: Span,
2215 ) -> ErrorGuaranteed {
2216 struct_span_code_err!(
2217 self.dcx(),
2218 span,
2219 E0025,
2220 "field `{}` bound multiple times in the pattern",
2221 ident
2222 )
2223 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2224 .with_span_label(other_field, format!("first use of `{ident}`"))
2225 .emit()
2226 }
2227
2228 fn error_inexistent_fields(
2229 &self,
2230 kind_name: &str,
2231 inexistent_fields: &[&hir::PatField<'tcx>],
2232 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2233 pat: &'tcx Pat<'tcx>,
2234 variant: &ty::VariantDef,
2235 args: ty::GenericArgsRef<'tcx>,
2236 ) -> Diag<'a> {
2237 let tcx = self.tcx;
2238 let (field_names, t, plural) = if let [field] = inexistent_fields {
2239 (format!("a field named `{}`", field.ident), "this", "")
2240 } else {
2241 (
2242 format!(
2243 "fields named {}",
2244 inexistent_fields
2245 .iter()
2246 .map(|field| format!("`{}`", field.ident))
2247 .collect::<Vec<String>>()
2248 .join(", ")
2249 ),
2250 "these",
2251 "s",
2252 )
2253 };
2254 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2255 let mut err = struct_span_code_err!(
2256 self.dcx(),
2257 spans,
2258 E0026,
2259 "{} `{}` does not have {}",
2260 kind_name,
2261 tcx.def_path_str(variant.def_id),
2262 field_names
2263 );
2264 if let Some(pat_field) = inexistent_fields.last() {
2265 err.span_label(
2266 pat_field.ident.span,
2267 format!(
2268 "{} `{}` does not have {} field{}",
2269 kind_name,
2270 tcx.def_path_str(variant.def_id),
2271 t,
2272 plural
2273 ),
2274 );
2275
2276 if let [(field_def, field)] = unmentioned_fields.as_slice()
2277 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2278 {
2279 let suggested_name =
2280 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2281 if let Some(suggested_name) = suggested_name {
2282 err.span_suggestion_verbose(
2283 pat_field.ident.span,
2284 "a field with a similar name exists",
2285 suggested_name,
2286 Applicability::MaybeIncorrect,
2287 );
2288
2289 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2295 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2297 }
2298 } else if inexistent_fields.len() == 1 {
2299 match pat_field.pat.kind {
2300 PatKind::Expr(_)
2301 if !self.may_coerce(
2302 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2303 self.field_ty(field.span, field_def, args),
2304 ) => {}
2305 _ => {
2306 err.span_suggestion_short(
2307 pat_field.ident.span,
2308 format!(
2309 "`{}` has a field named `{}`",
2310 tcx.def_path_str(variant.def_id),
2311 field.name,
2312 ),
2313 field.name,
2314 Applicability::MaybeIncorrect,
2315 );
2316 }
2317 }
2318 }
2319 }
2320 }
2321 if tcx.sess.teach(err.code.unwrap()) {
2322 err.note(
2323 "This error indicates that a struct pattern attempted to \
2324 extract a nonexistent field from a struct. Struct fields \
2325 are identified by the name used before the colon : so struct \
2326 patterns should resemble the declaration of the struct type \
2327 being matched.\n\n\
2328 If you are using shorthand field patterns but want to refer \
2329 to the struct field by a different name, you should rename \
2330 it explicitly.",
2331 );
2332 }
2333 err
2334 }
2335
2336 fn error_tuple_variant_as_struct_pat(
2337 &self,
2338 pat: &Pat<'_>,
2339 fields: &'tcx [hir::PatField<'tcx>],
2340 variant: &ty::VariantDef,
2341 ) -> Result<(), ErrorGuaranteed> {
2342 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2343 (variant.ctor_kind(), &pat.kind)
2344 {
2345 let is_tuple_struct_match = !pattern_fields.is_empty()
2346 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2347 if is_tuple_struct_match {
2348 return Ok(());
2349 }
2350
2351 variant.has_errors()?;
2353
2354 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2355 let mut err = struct_span_code_err!(
2356 self.dcx(),
2357 pat.span,
2358 E0769,
2359 "tuple variant `{}` written as struct variant",
2360 path
2361 );
2362 let (sugg, appl) = if fields.len() == variant.fields.len() {
2363 (
2364 self.get_suggested_tuple_struct_pattern(fields, variant),
2365 Applicability::MachineApplicable,
2366 )
2367 } else {
2368 (
2369 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2370 Applicability::MaybeIncorrect,
2371 )
2372 };
2373 err.span_suggestion_verbose(
2374 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2375 "use the tuple variant pattern syntax instead",
2376 format!("({sugg})"),
2377 appl,
2378 );
2379 return Err(err.emit());
2380 }
2381 Ok(())
2382 }
2383
2384 fn get_suggested_tuple_struct_pattern(
2385 &self,
2386 fields: &[hir::PatField<'_>],
2387 variant: &VariantDef,
2388 ) -> String {
2389 let variant_field_idents =
2390 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2391 fields
2392 .iter()
2393 .map(|field| {
2394 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2395 Ok(f) => {
2396 if variant_field_idents.contains(&field.ident) {
2399 String::from("_")
2400 } else {
2401 f
2402 }
2403 }
2404 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2405 }
2406 })
2407 .collect::<Vec<String>>()
2408 .join(", ")
2409 }
2410
2411 fn error_no_accessible_fields(
2427 &self,
2428 pat: &Pat<'_>,
2429 fields: &'tcx [hir::PatField<'tcx>],
2430 ) -> Diag<'a> {
2431 let mut err = self
2432 .dcx()
2433 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2434
2435 if let Some(field) = fields.last() {
2436 err.span_suggestion_verbose(
2437 field.span.shrink_to_hi(),
2438 "ignore the inaccessible and unused fields",
2439 ", ..",
2440 Applicability::MachineApplicable,
2441 );
2442 } else {
2443 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2444 qpath.span()
2445 } else {
2446 bug!("`error_no_accessible_fields` called on non-struct pattern");
2447 };
2448
2449 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2451 err.span_suggestion_verbose(
2452 span,
2453 "ignore the inaccessible and unused fields",
2454 " { .. }",
2455 Applicability::MachineApplicable,
2456 );
2457 }
2458 err
2459 }
2460
2461 fn lint_non_exhaustive_omitted_patterns(
2466 &self,
2467 pat: &Pat<'_>,
2468 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2469 ty: Ty<'tcx>,
2470 ) {
2471 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2472 const LIMIT: usize = 3;
2473 match witnesses {
2474 [] => {
2475 unreachable!(
2476 "expected an uncovered pattern, otherwise why are we emitting an error?"
2477 )
2478 }
2479 [witness] => format!("`{witness}`"),
2480 [head @ .., tail] if head.len() < LIMIT => {
2481 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2482 format!("`{}` and `{}`", head.join("`, `"), tail)
2483 }
2484 _ => {
2485 let (head, tail) = witnesses.split_at(LIMIT);
2486 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2487 format!("`{}` and {} more", head.join("`, `"), tail.len())
2488 }
2489 }
2490 }
2491 let joined_patterns = joined_uncovered_patterns(
2492 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2493 );
2494
2495 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2496 lint.primary_message("some fields are not explicitly listed");
2497 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2498 lint.help(
2499 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2500 );
2501 lint.note(format!(
2502 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2503 ));
2504 });
2505 }
2506
2507 fn error_unmentioned_fields(
2517 &self,
2518 pat: &Pat<'_>,
2519 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2520 have_inaccessible_fields: bool,
2521 fields: &'tcx [hir::PatField<'tcx>],
2522 ) -> Diag<'a> {
2523 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2524 let field_names = if let [(_, field)] = unmentioned_fields {
2525 format!("field `{field}`{inaccessible}")
2526 } else {
2527 let fields = unmentioned_fields
2528 .iter()
2529 .map(|(_, name)| format!("`{name}`"))
2530 .collect::<Vec<String>>()
2531 .join(", ");
2532 format!("fields {fields}{inaccessible}")
2533 };
2534 let mut err = struct_span_code_err!(
2535 self.dcx(),
2536 pat.span,
2537 E0027,
2538 "pattern does not mention {}",
2539 field_names
2540 );
2541 err.span_label(pat.span, format!("missing {field_names}"));
2542 let len = unmentioned_fields.len();
2543 let (prefix, postfix, sp) = match fields {
2544 [] => match &pat.kind {
2545 PatKind::Struct(path, [], None) => {
2546 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2547 }
2548 _ => return err,
2549 },
2550 [.., field] => {
2551 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2554 match &pat.kind {
2555 PatKind::Struct(..) => (", ", " }", tail),
2556 _ => return err,
2557 }
2558 }
2559 };
2560 err.span_suggestion(
2561 sp,
2562 format!(
2563 "include the missing field{} in the pattern{}",
2564 pluralize!(len),
2565 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2566 ),
2567 format!(
2568 "{}{}{}{}",
2569 prefix,
2570 unmentioned_fields
2571 .iter()
2572 .map(|(_, name)| {
2573 let field_name = name.to_string();
2574 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2575 })
2576 .collect::<Vec<_>>()
2577 .join(", "),
2578 if have_inaccessible_fields { ", .." } else { "" },
2579 postfix,
2580 ),
2581 Applicability::MachineApplicable,
2582 );
2583 err.span_suggestion(
2584 sp,
2585 format!(
2586 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2587 these = pluralize!("this", len),
2588 s = pluralize!(len),
2589 them = if len == 1 { "it" } else { "them" },
2590 ),
2591 format!(
2592 "{}{}{}{}",
2593 prefix,
2594 unmentioned_fields
2595 .iter()
2596 .map(|(_, name)| {
2597 let field_name = name.to_string();
2598 format!("{field_name}: _")
2599 })
2600 .collect::<Vec<_>>()
2601 .join(", "),
2602 if have_inaccessible_fields { ", .." } else { "" },
2603 postfix,
2604 ),
2605 Applicability::MachineApplicable,
2606 );
2607 err.span_suggestion(
2608 sp,
2609 "or always ignore missing fields here",
2610 format!("{prefix}..{postfix}"),
2611 Applicability::MachineApplicable,
2612 );
2613 err
2614 }
2615
2616 fn check_pat_box(
2617 &self,
2618 span: Span,
2619 inner: &'tcx Pat<'tcx>,
2620 expected: Ty<'tcx>,
2621 pat_info: PatInfo<'tcx>,
2622 ) -> Ty<'tcx> {
2623 let tcx = self.tcx;
2624 let (box_ty, inner_ty) = self
2625 .check_dereferenceable(span, expected, inner)
2626 .and_then(|()| {
2627 let inner_ty = self.next_ty_var(inner.span);
2630 let box_ty = Ty::new_box(tcx, inner_ty);
2631 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2632 Ok((box_ty, inner_ty))
2633 })
2634 .unwrap_or_else(|guar| {
2635 let err = Ty::new_error(tcx, guar);
2636 (err, err)
2637 });
2638 self.check_pat(inner, inner_ty, pat_info);
2639 box_ty
2640 }
2641
2642 fn check_pat_deref(
2643 &self,
2644 span: Span,
2645 inner: &'tcx Pat<'tcx>,
2646 expected: Ty<'tcx>,
2647 pat_info: PatInfo<'tcx>,
2648 ) -> Ty<'tcx> {
2649 let target_ty = self.deref_pat_target(span, expected);
2650 self.check_pat(inner, target_ty, pat_info);
2651 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2652 expected
2653 }
2654
2655 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2656 let tcx = self.tcx;
2658 self.register_bound(
2659 source_ty,
2660 tcx.require_lang_item(hir::LangItem::DerefPure, span),
2661 self.misc(span),
2662 );
2663 let target_ty = Ty::new_projection(
2665 tcx,
2666 tcx.require_lang_item(hir::LangItem::DerefTarget, span),
2667 [source_ty],
2668 );
2669 let target_ty = self.normalize(span, target_ty);
2670 self.try_structurally_resolve_type(span, target_ty)
2671 }
2672
2673 fn register_deref_mut_bounds_if_needed(
2678 &self,
2679 span: Span,
2680 inner: &'tcx Pat<'tcx>,
2681 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2682 ) {
2683 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2684 for mutably_derefed_ty in derefed_tys {
2685 self.register_bound(
2686 mutably_derefed_ty,
2687 self.tcx.require_lang_item(hir::LangItem::DerefMut, span),
2688 self.misc(span),
2689 );
2690 }
2691 }
2692 }
2693
2694 fn check_pat_ref(
2696 &self,
2697 pat: &'tcx Pat<'tcx>,
2698 inner: &'tcx Pat<'tcx>,
2699 pat_pinned: Pinnedness,
2700 pat_mutbl: Mutability,
2701 mut expected: Ty<'tcx>,
2702 mut pat_info: PatInfo<'tcx>,
2703 ) -> Ty<'tcx> {
2704 let tcx = self.tcx;
2705
2706 let pat_prefix_span =
2707 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2708
2709 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2710 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2711 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2716 }
2717
2718 expected = self.try_structurally_resolve_type(pat.span, expected);
2719 if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode
2722 && pat_pinned == inh_pin
2723 {
2724 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2725 InheritedRefMatchRule::EatOuter => {
2726 if pat_mutbl > inh_mut {
2728 debug_assert!(ref_pat_matches_mut_ref);
2733 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2734 }
2735
2736 pat_info.binding_mode = ByRef::No;
2737 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2738 self.check_pat(inner, expected, pat_info);
2739 return expected;
2740 }
2741 InheritedRefMatchRule::EatInner => {
2742 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2743 && pat_mutbl <= r_mutbl
2744 {
2745 debug_assert!(ref_pat_matches_mut_ref);
2752 debug_assert!(self.downgrade_mut_inside_shared());
2756 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2757 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2758 } else {
2759 if pat_mutbl > inh_mut {
2762 debug_assert!(ref_pat_matches_mut_ref);
2771 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2772 }
2773
2774 pat_info.binding_mode = ByRef::No;
2775 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2776 self.check_pat(inner, expected, pat_info);
2777 return expected;
2778 }
2779 }
2780 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2781 pat_info.binding_mode = ByRef::No;
2783
2784 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2785 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2787 self.check_pat(inner, inner_ty, pat_info);
2794 return expected;
2795 } else {
2796 }
2803 } else {
2804 if pat_mutbl > inh_mut {
2807 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2809 }
2810
2811 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2812 self.check_pat(inner, expected, pat_info);
2813 return expected;
2814 }
2815 }
2816 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2817 pat_info.binding_mode = ByRef::No;
2820 self.add_rust_2024_migration_desugared_pat(
2821 pat_info.top_info.hir_id,
2822 pat,
2823 match pat_mutbl {
2824 Mutability::Not => '&', Mutability::Mut => 't', },
2827 inh_mut,
2828 )
2829 }
2830 }
2831 }
2832
2833 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2834 Ok(()) => {
2835 debug!("check_pat_ref: expected={:?}", expected);
2842 match expected.maybe_pinned_ref() {
2843 Some((r_ty, r_pinned, r_mutbl))
2844 if ((ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2845 || r_mutbl == pat_mutbl)
2846 && pat_pinned == r_pinned =>
2847 {
2848 if r_mutbl == Mutability::Not {
2849 pat_info.max_ref_mutbl = MutblCap::Not;
2850 }
2851 if r_pinned == Pinnedness::Pinned {
2852 pat_info.max_pinnedness = PinnednessCap::Pinned;
2853 }
2854
2855 (expected, r_ty)
2856 }
2857 _ => {
2858 let inner_ty = self.next_ty_var(inner.span);
2859 let ref_ty = self.new_ref_ty(pat.span, pat_pinned, pat_mutbl, inner_ty);
2860 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2861 let err = self.demand_eqtype_pat_diag(
2862 pat.span,
2863 expected,
2864 ref_ty,
2865 &pat_info.top_info,
2866 );
2867
2868 if let Err(mut err) = err {
2871 self.borrow_pat_suggestion(&mut err, pat);
2872 err.emit();
2873 }
2874 (ref_ty, inner_ty)
2875 }
2876 }
2877 }
2878 Err(guar) => {
2879 let err = Ty::new_error(tcx, guar);
2880 (err, err)
2881 }
2882 };
2883
2884 self.check_pat(inner, inner_ty, pat_info);
2885 ref_ty
2886 }
2887
2888 fn new_ref_ty(
2890 &self,
2891 span: Span,
2892 pinnedness: Pinnedness,
2893 mutbl: Mutability,
2894 ty: Ty<'tcx>,
2895 ) -> Ty<'tcx> {
2896 let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
2897 let ref_ty = Ty::new_ref(self.tcx, region, ty, mutbl);
2898 if pinnedness.is_pinned() {
2899 return self.new_pinned_ty(span, ref_ty);
2900 }
2901 ref_ty
2902 }
2903
2904 fn new_pinned_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
2906 Ty::new_adt(
2907 self.tcx,
2908 self.tcx.adt_def(self.tcx.require_lang_item(LangItem::Pin, span)),
2909 self.tcx.mk_args(&[ty.into()]),
2910 )
2911 }
2912
2913 fn error_inherited_ref_mutability_mismatch(
2914 &self,
2915 pat: &'tcx Pat<'tcx>,
2916 pat_prefix_span: Option<Span>,
2917 ) -> ErrorGuaranteed {
2918 let err_msg = "mismatched types";
2919 let err = if let Some(span) = pat_prefix_span {
2920 let mut err = self.dcx().struct_span_err(span, err_msg);
2921 err.code(E0308);
2922 err.note("cannot match inherited `&` with `&mut` pattern");
2923 err.span_suggestion_verbose(
2924 span,
2925 "replace this `&mut` pattern with `&`",
2926 "&",
2927 Applicability::MachineApplicable,
2928 );
2929 err
2930 } else {
2931 self.dcx().struct_span_err(pat.span, err_msg)
2932 };
2933 err.emit()
2934 }
2935
2936 fn try_resolve_slice_ty_to_array_ty(
2937 &self,
2938 before: &'tcx [Pat<'tcx>],
2939 slice: Option<&'tcx Pat<'tcx>>,
2940 span: Span,
2941 ) -> Option<Ty<'tcx>> {
2942 if slice.is_some() {
2943 return None;
2944 }
2945
2946 let tcx = self.tcx;
2947 let len = before.len();
2948 let inner_ty = self.next_ty_var(span);
2949
2950 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2951 }
2952
2953 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2984 match decl_origin {
2985 Some(DeclOrigin::LocalDecl { els: None }) => true,
2986 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2987 }
2988 }
2989
2990 fn check_pat_slice(
3001 &self,
3002 span: Span,
3003 before: &'tcx [Pat<'tcx>],
3004 slice: Option<&'tcx Pat<'tcx>>,
3005 after: &'tcx [Pat<'tcx>],
3006 expected: Ty<'tcx>,
3007 pat_info: PatInfo<'tcx>,
3008 ) -> Ty<'tcx> {
3009 let expected = self.try_structurally_resolve_type(span, expected);
3010
3011 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
3014 if let Some(resolved_arr_ty) =
3015 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
3016 {
3017 debug!(?resolved_arr_ty);
3018 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
3019 }
3020 }
3021
3022 let expected = self.structurally_resolve_type(span, expected);
3023 debug!(?expected);
3024
3025 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
3026 ty::Array(element_ty, len) => {
3028 let min = before.len() as u64 + after.len() as u64;
3029 let (opt_slice_ty, expected) =
3030 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
3031 assert!(opt_slice_ty.is_some() || slice.is_none());
3034 (element_ty, opt_slice_ty, expected)
3035 }
3036 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
3037 _ => {
3039 let guar = expected.error_reported().err().unwrap_or_else(|| {
3040 self.error_expected_array_or_slice(span, expected, pat_info)
3041 });
3042 let err = Ty::new_error(self.tcx, guar);
3043 (err, Some(err), err)
3044 }
3045 };
3046
3047 for elt in before {
3049 self.check_pat(elt, element_ty, pat_info);
3050 }
3051 if let Some(slice) = slice {
3053 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
3054 }
3055 for elt in after {
3057 self.check_pat(elt, element_ty, pat_info);
3058 }
3059 inferred
3060 }
3061
3062 fn check_array_pat_len(
3067 &self,
3068 span: Span,
3069 element_ty: Ty<'tcx>,
3070 arr_ty: Ty<'tcx>,
3071 slice: Option<&'tcx Pat<'tcx>>,
3072 len: ty::Const<'tcx>,
3073 min_len: u64,
3074 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
3075 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
3076
3077 let guar = if let Some(len) = len {
3078 if slice.is_none() {
3080 if min_len == len {
3084 return (None, arr_ty);
3085 }
3086
3087 self.error_scrutinee_inconsistent_length(span, min_len, len)
3088 } else if let Some(pat_len) = len.checked_sub(min_len) {
3089 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
3092 } else {
3093 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
3096 }
3097 } else if slice.is_none() {
3098 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
3101 self.demand_eqtype(span, updated_arr_ty, arr_ty);
3102 return (None, updated_arr_ty);
3103 } else {
3104 self.error_scrutinee_unfixed_length(span)
3108 };
3109
3110 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
3112 }
3113
3114 fn error_scrutinee_inconsistent_length(
3115 &self,
3116 span: Span,
3117 min_len: u64,
3118 size: u64,
3119 ) -> ErrorGuaranteed {
3120 struct_span_code_err!(
3121 self.dcx(),
3122 span,
3123 E0527,
3124 "pattern requires {} element{} but array has {}",
3125 min_len,
3126 pluralize!(min_len),
3127 size,
3128 )
3129 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
3130 .emit()
3131 }
3132
3133 fn error_scrutinee_with_rest_inconsistent_length(
3134 &self,
3135 span: Span,
3136 min_len: u64,
3137 size: u64,
3138 ) -> ErrorGuaranteed {
3139 struct_span_code_err!(
3140 self.dcx(),
3141 span,
3142 E0528,
3143 "pattern requires at least {} element{} but array has {}",
3144 min_len,
3145 pluralize!(min_len),
3146 size,
3147 )
3148 .with_span_label(
3149 span,
3150 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
3151 )
3152 .emit()
3153 }
3154
3155 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
3156 struct_span_code_err!(
3157 self.dcx(),
3158 span,
3159 E0730,
3160 "cannot pattern-match on an array without a fixed length",
3161 )
3162 .emit()
3163 }
3164
3165 fn error_expected_array_or_slice(
3166 &self,
3167 span: Span,
3168 expected_ty: Ty<'tcx>,
3169 pat_info: PatInfo<'tcx>,
3170 ) -> ErrorGuaranteed {
3171 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
3172
3173 let mut slice_pat_semantics = false;
3174 let mut as_deref = None;
3175 let mut slicing = None;
3176 if let ty::Ref(_, ty, _) = expected_ty.kind()
3177 && let ty::Array(..) | ty::Slice(..) = ty.kind()
3178 {
3179 slice_pat_semantics = true;
3180 } else if self
3181 .autoderef(span, expected_ty)
3182 .silence_errors()
3183 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
3184 && let Some(span) = ti.span
3185 && let Some(_) = ti.origin_expr
3186 {
3187 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
3188 let (is_slice_or_array_or_vector, resolved_ty) =
3189 self.is_slice_or_array_or_vector(resolved_ty);
3190 match resolved_ty.kind() {
3191 ty::Adt(adt_def, _)
3192 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
3193 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
3194 {
3195 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
3197 }
3198 _ => (),
3199 }
3200
3201 let is_top_level = current_depth <= 1;
3202 if is_slice_or_array_or_vector && is_top_level {
3203 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
3204 }
3205 }
3206 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
3207 span,
3208 ty: expected_ty,
3209 slice_pat_semantics,
3210 as_deref,
3211 slicing,
3212 })
3213 }
3214
3215 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
3216 match ty.kind() {
3217 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
3218 (true, ty)
3219 }
3220 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
3221 ty::Slice(..) | ty::Array(..) => (true, ty),
3222 _ => (false, ty),
3223 }
3224 }
3225
3226 fn add_rust_2024_migration_desugared_pat(
3229 &self,
3230 pat_id: HirId,
3231 subpat: &'tcx Pat<'tcx>,
3232 final_char: char,
3233 def_br_mutbl: Mutability,
3234 ) {
3235 let from_expansion = subpat.span.from_expansion();
3237 let trimmed_span = if from_expansion {
3238 subpat.span
3240 } else {
3241 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3242 trimmed.with_ctxt(subpat.span.ctxt())
3245 };
3246
3247 let mut typeck_results = self.typeck_results.borrow_mut();
3248 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3249 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3254 primary_labels: Vec::new(),
3255 bad_ref_modifiers: false,
3256 bad_mut_modifiers: false,
3257 bad_ref_pats: false,
3258 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3259 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3260 });
3261
3262 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3263 info.suggest_eliding_modes &= matches!(
3267 user_bind_annot,
3268 BindingMode(ByRef::Yes(_, mutbl), Mutability::Not) if mutbl == def_br_mutbl
3269 );
3270 if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) {
3271 info.bad_mut_modifiers = true;
3272 "`mut` binding modifier"
3273 } else {
3274 info.bad_ref_modifiers = true;
3275 match user_bind_annot.1 {
3276 Mutability::Not => "explicit `ref` binding modifier",
3277 Mutability::Mut => "explicit `ref mut` binding modifier",
3278 }
3279 }
3280 } else {
3281 info.bad_ref_pats = true;
3282 info.suggest_eliding_modes = false;
3286 "reference pattern"
3287 };
3288 let primary_label = if from_expansion {
3291 info.suggest_eliding_modes = false;
3293 "occurs within macro expansion".to_owned()
3297 } else {
3298 format!("{pat_kind} not allowed when implicitly borrowing")
3299 };
3300 info.primary_labels.push((trimmed_span, primary_label));
3301 }
3302}