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::ConstBlock(c) => {
929 self.check_expr_const_block(c, Expectation::NoExpectation)
930 }
931 rustc_hir::PatExprKind::Path(qpath) => {
932 let (res, opt_ty, segments) =
933 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
934 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
935 }
936 };
937 self.write_ty(lt.hir_id, ty);
938 ty
939 }
940
941 fn check_pat_lit(
942 &self,
943 span: Span,
944 lt: &hir::PatExpr<'tcx>,
945 expected: Ty<'tcx>,
946 ti: &TopInfo<'tcx>,
947 ) -> Ty<'tcx> {
948 let ty = self.node_ty(lt.hir_id);
951
952 let mut pat_ty = ty;
957 if let hir::PatExprKind::Lit {
958 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
959 } = lt.kind
960 {
961 let tcx = self.tcx;
962 let expected = self.structurally_resolve_type(span, expected);
963 match *expected.kind() {
964 ty::Ref(_, inner_ty, _)
966 if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
967 {
968 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
969 pat_ty = Ty::new_imm_ref(
970 tcx,
971 tcx.lifetimes.re_static,
972 Ty::new_slice(tcx, tcx.types.u8),
973 );
974 }
975 ty::Array(..) if tcx.features().deref_patterns() => {
977 pat_ty = match *ty.kind() {
978 ty::Ref(_, inner_ty, _) => inner_ty,
979 _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
980 }
981 }
982 ty::Slice(..) if tcx.features().deref_patterns() => {
984 pat_ty = Ty::new_slice(tcx, tcx.types.u8);
985 }
986 _ => {}
988 }
989 }
990
991 if self.tcx.features().deref_patterns()
994 && let hir::PatExprKind::Lit {
995 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
996 } = lt.kind
997 && self.try_structurally_resolve_type(span, expected).is_str()
998 {
999 pat_ty = self.tcx.types.str_;
1000 }
1001
1002 if self.tcx.features().string_deref_patterns()
1003 && let hir::PatExprKind::Lit {
1004 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
1005 } = lt.kind
1006 {
1007 let tcx = self.tcx;
1008 let expected = self.resolve_vars_if_possible(expected);
1009 pat_ty = match expected.kind() {
1010 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
1011 ty::Str => Ty::new_static_str(tcx),
1012 _ => pat_ty,
1013 };
1014 }
1015
1016 let cause = self.pattern_cause(ti, span);
1027 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
1028 err.emit();
1029 }
1030
1031 pat_ty
1032 }
1033
1034 fn check_pat_range(
1035 &self,
1036 span: Span,
1037 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
1038 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
1039 expected: Ty<'tcx>,
1040 ti: &TopInfo<'tcx>,
1041 ) -> Ty<'tcx> {
1042 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
1043 None => None,
1044 Some(expr) => {
1045 let ty = self.check_pat_expr_unadjusted(expr);
1046 let ty = self.try_structurally_resolve_type(expr.span, ty);
1053 let fail =
1054 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
1055 Some((fail, ty, expr.span))
1056 }
1057 };
1058 let mut lhs = calc_side(lhs);
1059 let mut rhs = calc_side(rhs);
1060
1061 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
1062 let guar = self.emit_err_pat_range(span, lhs, rhs);
1065 return Ty::new_error(self.tcx, guar);
1066 }
1067
1068 let demand_eqtype = |x: &mut _, y| {
1071 if let Some((ref mut fail, x_ty, x_span)) = *x
1072 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
1073 {
1074 if let Some((_, y_ty, y_span)) = y {
1075 self.endpoint_has_type(&mut err, y_span, y_ty);
1076 }
1077 err.emit();
1078 *fail = true;
1079 }
1080 };
1081 demand_eqtype(&mut lhs, rhs);
1082 demand_eqtype(&mut rhs, lhs);
1083
1084 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
1085 return Ty::new_misc_error(self.tcx);
1086 }
1087
1088 let ty = self.structurally_resolve_type(span, expected);
1093 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
1094 if let Some((ref mut fail, _, _)) = lhs {
1095 *fail = true;
1096 }
1097 if let Some((ref mut fail, _, _)) = rhs {
1098 *fail = true;
1099 }
1100 let guar = self.emit_err_pat_range(span, lhs, rhs);
1101 return Ty::new_error(self.tcx, guar);
1102 }
1103 ty
1104 }
1105
1106 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
1107 if !ty.references_error() {
1108 err.span_label(span, format!("this is of type `{ty}`"));
1109 }
1110 }
1111
1112 fn emit_err_pat_range(
1113 &self,
1114 span: Span,
1115 lhs: Option<(bool, Ty<'tcx>, Span)>,
1116 rhs: Option<(bool, Ty<'tcx>, Span)>,
1117 ) -> ErrorGuaranteed {
1118 let span = match (lhs, rhs) {
1119 (Some((true, ..)), Some((true, ..))) => span,
1120 (Some((true, _, sp)), _) => sp,
1121 (_, Some((true, _, sp))) => sp,
1122 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
1123 };
1124 let mut err = struct_span_code_err!(
1125 self.dcx(),
1126 span,
1127 E0029,
1128 "only `char` and numeric types are allowed in range patterns"
1129 );
1130 let msg = |ty| {
1131 let ty = self.resolve_vars_if_possible(ty);
1132 format!("this is of type `{ty}` but it should be `char` or numeric")
1133 };
1134 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
1135 err.span_label(first_span, msg(first_ty));
1136 if let Some((_, ty, sp)) = second {
1137 let ty = self.resolve_vars_if_possible(ty);
1138 self.endpoint_has_type(&mut err, sp, ty);
1139 }
1140 };
1141 match (lhs, rhs) {
1142 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
1143 err.span_label(lhs_sp, msg(lhs_ty));
1144 err.span_label(rhs_sp, msg(rhs_ty));
1145 }
1146 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
1147 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
1148 _ => span_bug!(span, "Impossible, verified above."),
1149 }
1150 if (lhs, rhs).references_error() {
1151 err.downgrade_to_delayed_bug();
1152 }
1153 if self.tcx.sess.teach(err.code.unwrap()) {
1154 err.note(
1155 "In a match expression, only numbers and characters can be matched \
1156 against a range. This is because the compiler checks that the range \
1157 is non-empty at compile-time, and is unable to evaluate arbitrary \
1158 comparison functions. If you want to capture values of an orderable \
1159 type between two end-points, you can use a guard.",
1160 );
1161 }
1162 err.emit()
1163 }
1164
1165 fn check_pat_ident(
1166 &self,
1167 pat: &'tcx Pat<'tcx>,
1168 user_bind_annot: BindingMode,
1169 var_id: HirId,
1170 ident: Ident,
1171 sub: Option<&'tcx Pat<'tcx>>,
1172 expected: Ty<'tcx>,
1173 pat_info: PatInfo<'tcx>,
1174 ) -> Ty<'tcx> {
1175 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
1176
1177 let bm = match user_bind_annot {
1179 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(_, def_br_mutbl) = def_br => {
1180 if pat.span.at_least_rust_2024()
1183 && (self.tcx.features().ref_pat_eat_one_layer_2024()
1184 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
1185 {
1186 if !self.tcx.features().mut_ref() {
1187 feature_err(
1188 self.tcx.sess,
1189 sym::mut_ref,
1190 pat.span.until(ident.span),
1191 "binding cannot be both mutable and by-reference",
1192 )
1193 .emit();
1194 }
1195
1196 BindingMode(def_br, Mutability::Mut)
1197 } else {
1198 self.add_rust_2024_migration_desugared_pat(
1200 pat_info.top_info.hir_id,
1201 pat,
1202 't', def_br_mutbl,
1204 );
1205 BindingMode(ByRef::No, Mutability::Mut)
1206 }
1207 }
1208 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
1209 BindingMode(ByRef::Yes(_, user_br_mutbl), _) => {
1210 if let ByRef::Yes(_, def_br_mutbl) = def_br {
1211 self.add_rust_2024_migration_desugared_pat(
1213 pat_info.top_info.hir_id,
1214 pat,
1215 match user_br_mutbl {
1216 Mutability::Not => 'f', Mutability::Mut => 't', },
1219 def_br_mutbl,
1220 );
1221 }
1222 user_bind_annot
1223 }
1224 };
1225
1226 if pat_info.max_pinnedness == PinnednessCap::Pinned
1229 && matches!(bm.0, ByRef::Yes(Pinnedness::Not, _))
1230 {
1231 self.register_bound(
1232 expected,
1233 self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
1234 self.misc(pat.span),
1235 )
1236 }
1237
1238 if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
1239 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1240 {
1241 let mut err = struct_span_code_err!(
1242 self.dcx(),
1243 ident.span,
1244 E0596,
1245 "cannot borrow as mutable inside an `&` pattern"
1246 );
1247
1248 if let Some(span) = and_pat_span {
1249 err.span_suggestion(
1250 span,
1251 "replace this `&` with `&mut`",
1252 "&mut ",
1253 Applicability::MachineApplicable,
1254 );
1255 }
1256 err.emit();
1257 }
1258
1259 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1261
1262 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1263
1264 let local_ty = self.local_ty(pat.span, pat.hir_id);
1265 let eq_ty = match bm.0 {
1266 ByRef::Yes(pinnedness, mutbl) => {
1267 self.new_ref_ty(pat.span, pinnedness, mutbl, expected)
1279 }
1280 ByRef::No => expected, };
1283
1284 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1286
1287 if var_id != pat.hir_id {
1290 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1291 }
1292
1293 if let Some(p) = sub {
1294 self.check_pat(p, expected, pat_info);
1295 }
1296
1297 local_ty
1298 }
1299
1300 fn check_binding_alt_eq_ty(
1304 &self,
1305 ba: BindingMode,
1306 span: Span,
1307 var_id: HirId,
1308 ty: Ty<'tcx>,
1309 ti: &TopInfo<'tcx>,
1310 ) {
1311 let var_ty = self.local_ty(span, var_id);
1312 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1313 let var_ty = self.resolve_vars_if_possible(var_ty);
1314 let msg = format!("first introduced with type `{var_ty}` here");
1315 err.span_label(self.tcx.hir_span(var_id), msg);
1316 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1317 matches!(
1318 n,
1319 hir::Node::Expr(hir::Expr {
1320 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1321 ..
1322 })
1323 )
1324 });
1325 let pre = if in_match { "in the same arm, " } else { "" };
1326 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1327 self.suggest_adding_missing_ref_or_removing_ref(
1328 &mut err,
1329 span,
1330 var_ty,
1331 self.resolve_vars_if_possible(ty),
1332 ba,
1333 );
1334 err.emit();
1335 }
1336 }
1337
1338 fn suggest_adding_missing_ref_or_removing_ref(
1339 &self,
1340 err: &mut Diag<'_>,
1341 span: Span,
1342 expected: Ty<'tcx>,
1343 actual: Ty<'tcx>,
1344 ba: BindingMode,
1345 ) {
1346 match (expected.kind(), actual.kind(), ba) {
1347 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1348 if self.can_eq(self.param_env, *inner_ty, actual) =>
1349 {
1350 err.span_suggestion_verbose(
1351 span.shrink_to_lo(),
1352 "consider adding `ref`",
1353 "ref ",
1354 Applicability::MaybeIncorrect,
1355 );
1356 }
1357 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1358 if self.can_eq(self.param_env, expected, *inner_ty) =>
1359 {
1360 err.span_suggestion_verbose(
1361 span.with_hi(span.lo() + BytePos(4)),
1362 "consider removing `ref`",
1363 "",
1364 Applicability::MaybeIncorrect,
1365 );
1366 }
1367 _ => (),
1368 }
1369 }
1370
1371 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1374 let tcx = self.tcx;
1375 if let PatKind::Ref(inner, pinned, mutbl) = pat.kind
1376 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1377 {
1378 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1379 debug!(?inner, ?pat, ?binding_parent);
1380
1381 let pin_and_mut = pinned.prefix_str(mutbl).trim_end();
1382
1383 let mut_var_suggestion = 'block: {
1384 if mutbl.is_not() {
1385 break 'block None;
1386 }
1387
1388 let ident_kind = match binding_parent {
1389 hir::Node::Param(_) => "parameter",
1390 hir::Node::LetStmt(_) => "variable",
1391 hir::Node::Arm(_) => "binding",
1392
1393 hir::Node::Pat(Pat { kind, .. }) => match kind {
1396 PatKind::Struct(..)
1397 | PatKind::TupleStruct(..)
1398 | PatKind::Or(..)
1399 | PatKind::Guard(..)
1400 | PatKind::Tuple(..)
1401 | PatKind::Slice(..) => "binding",
1402
1403 PatKind::Missing
1404 | PatKind::Wild
1405 | PatKind::Never
1406 | PatKind::Binding(..)
1407 | PatKind::Box(..)
1408 | PatKind::Deref(_)
1409 | PatKind::Ref(..)
1410 | PatKind::Expr(..)
1411 | PatKind::Range(..)
1412 | PatKind::Err(_) => break 'block None,
1413 },
1414
1415 _ => break 'block None,
1417 };
1418
1419 Some((
1420 pat.span,
1421 format!("to declare a mutable {ident_kind} use"),
1422 format!("mut {binding}"),
1423 ))
1424 };
1425
1426 match binding_parent {
1427 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1430 err.multipart_suggestion_verbose(
1431 format!("to take parameter `{binding}` by reference, move `&{pin_and_mut}` to the type"),
1432 vec![
1433 (pat.span.until(inner.span), "".to_owned()),
1434 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1435 ],
1436 Applicability::MachineApplicable
1437 );
1438
1439 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1440 err.span_note(sp, format!("{msg}: `{sugg}`"));
1441 }
1442 }
1443 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1444 for i in pat_arr.iter() {
1445 if let PatKind::Ref(the_ref, _, _) = i.kind
1446 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1447 {
1448 let BindingMode(_, mtblty) = mt;
1449 err.span_suggestion_verbose(
1450 i.span,
1451 format!("consider removing `&{pin_and_mut}` from the pattern"),
1452 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1453 Applicability::MaybeIncorrect,
1454 );
1455 }
1456 }
1457 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1458 err.span_note(sp, format!("{msg}: `{sugg}`"));
1459 }
1460 }
1461 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1462 err.span_suggestion_verbose(
1464 pat.span.until(inner.span),
1465 format!("consider removing `&{pin_and_mut}` from the pattern"),
1466 "",
1467 Applicability::MaybeIncorrect,
1468 );
1469
1470 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1471 err.span_note(sp, format!("{msg}: `{sugg}`"));
1472 }
1473 }
1474 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1475 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1476 }
1477 _ => {} }
1479 }
1480 }
1481
1482 fn check_dereferenceable(
1483 &self,
1484 span: Span,
1485 expected: Ty<'tcx>,
1486 inner: &Pat<'_>,
1487 ) -> Result<(), ErrorGuaranteed> {
1488 if let PatKind::Binding(..) = inner.kind
1489 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1490 && let ty::Dynamic(..) = pointee_ty.kind()
1491 {
1492 let type_str = self.ty_to_string(expected);
1495 let mut err = struct_span_code_err!(
1496 self.dcx(),
1497 span,
1498 E0033,
1499 "type `{}` cannot be dereferenced",
1500 type_str
1501 );
1502 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1503 if self.tcx.sess.teach(err.code.unwrap()) {
1504 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1505 }
1506 return Err(err.emit());
1507 }
1508 Ok(())
1509 }
1510
1511 fn resolve_pat_struct(
1512 &self,
1513 pat: &'tcx Pat<'tcx>,
1514 qpath: &hir::QPath<'tcx>,
1515 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1516 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1518 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1519 }
1520
1521 fn check_pat_struct(
1522 &self,
1523 pat: &'tcx Pat<'tcx>,
1524 fields: &'tcx [hir::PatField<'tcx>],
1525 has_rest_pat: bool,
1526 pat_ty: Ty<'tcx>,
1527 variant: &'tcx VariantDef,
1528 expected: Ty<'tcx>,
1529 pat_info: PatInfo<'tcx>,
1530 ) -> Ty<'tcx> {
1531 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1533
1534 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1536 Ok(()) => pat_ty,
1537 Err(guar) => Ty::new_error(self.tcx, guar),
1538 }
1539 }
1540
1541 fn resolve_pat_path(
1542 &self,
1543 path_id: HirId,
1544 span: Span,
1545 qpath: &'tcx hir::QPath<'_>,
1546 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1547 let tcx = self.tcx;
1548
1549 let (res, opt_ty, segments) =
1550 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1551 match res {
1552 Res::Err => {
1553 let e =
1554 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1555 self.set_tainted_by_errors(e);
1556 return Err(e);
1557 }
1558 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1559 let expected = "unit struct, unit variant or constant";
1560 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1561 return Err(e);
1562 }
1563 Res::SelfCtor(def_id) => {
1564 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1565 && adt_def.is_struct()
1566 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1567 {
1568 } else {
1570 let e = report_unexpected_variant_res(
1571 tcx,
1572 res,
1573 None,
1574 qpath,
1575 span,
1576 E0533,
1577 "unit struct",
1578 );
1579 return Err(e);
1580 }
1581 }
1582 Res::Def(
1583 DefKind::Ctor(_, CtorKind::Const)
1584 | DefKind::Const
1585 | DefKind::AssocConst
1586 | DefKind::ConstParam,
1587 _,
1588 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1590 }
1591
1592 let (pat_ty, pat_res) =
1594 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1595 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1596 }
1597
1598 fn check_pat_path(
1599 &self,
1600 pat_id_for_diag: HirId,
1601 span: Span,
1602 resolved: &ResolvedPat<'tcx>,
1603 expected: Ty<'tcx>,
1604 ti: &TopInfo<'tcx>,
1605 ) -> Ty<'tcx> {
1606 if let Err(err) =
1607 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1608 {
1609 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1610 }
1611 resolved.ty
1612 }
1613
1614 fn maybe_suggest_range_literal(
1615 &self,
1616 e: &mut Diag<'_>,
1617 opt_def_id: Option<hir::def_id::DefId>,
1618 ident: Ident,
1619 ) -> bool {
1620 if let Some(def_id) = opt_def_id
1621 && let Some(hir::Node::Item(hir::Item {
1622 kind: hir::ItemKind::Const(_, _, _, ct_rhs),
1623 ..
1624 })) = self.tcx.hir_get_if_local(def_id)
1625 && let hir::Node::Expr(expr) = self.tcx.hir_node(ct_rhs.hir_id())
1626 && hir::is_range_literal(expr)
1627 {
1628 let span = self.tcx.hir_span(ct_rhs.hir_id());
1629 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1630 e.span_suggestion_verbose(
1631 ident.span,
1632 "you may want to move the range into the match block",
1633 snip,
1634 Applicability::MachineApplicable,
1635 );
1636 return true;
1637 }
1638 }
1639 false
1640 }
1641
1642 fn emit_bad_pat_path(
1643 &self,
1644 mut e: Diag<'_>,
1645 hir_id: HirId,
1646 pat_span: Span,
1647 resolved_pat: &ResolvedPat<'tcx>,
1648 ) {
1649 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1650 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1651 };
1652
1653 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1654 e.span_label(span, format!("{} defined here", res.descr()));
1655 if let [hir::PathSegment { ident, .. }] = segments {
1656 e.span_label(
1657 pat_span,
1658 format!(
1659 "`{}` is interpreted as {} {}, not a new binding",
1660 ident,
1661 res.article(),
1662 res.descr(),
1663 ),
1664 );
1665 match self.tcx.parent_hir_node(hir_id) {
1666 hir::Node::PatField(..) => {
1667 e.span_suggestion_verbose(
1668 ident.span.shrink_to_hi(),
1669 "bind the struct field to a different name instead",
1670 format!(": other_{}", ident.as_str().to_lowercase()),
1671 Applicability::HasPlaceholders,
1672 );
1673 }
1674 _ => {
1675 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1676 ty::Adt(def, _) => match res {
1677 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1678 _ => (None, None),
1679 },
1680 _ => (None, None),
1681 };
1682
1683 let is_range = matches!(
1684 type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
1685 Some(
1686 LangItem::Range
1687 | LangItem::RangeFrom
1688 | LangItem::RangeTo
1689 | LangItem::RangeFull
1690 | LangItem::RangeInclusiveStruct
1691 | LangItem::RangeToInclusive,
1692 )
1693 );
1694 if is_range {
1695 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1696 let msg = "constants only support matching by type, \
1697 if you meant to match against a range of values, \
1698 consider using a range pattern like `min ..= max` in the match block";
1699 e.note(msg);
1700 }
1701 } else {
1702 let msg = "introduce a new binding instead";
1703 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1704 e.span_suggestion(
1705 ident.span,
1706 msg,
1707 sugg,
1708 Applicability::HasPlaceholders,
1709 );
1710 }
1711 }
1712 };
1713 }
1714 }
1715 e.emit();
1716 }
1717
1718 fn resolve_pat_tuple_struct(
1719 &self,
1720 pat: &'tcx Pat<'tcx>,
1721 qpath: &'tcx hir::QPath<'tcx>,
1722 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1723 let tcx = self.tcx;
1724 let report_unexpected_res = |res: Res| {
1725 let expected = "tuple struct or tuple variant";
1726 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1727 Err(e)
1728 };
1729
1730 let (res, opt_ty, segments) =
1732 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1733 if res == Res::Err {
1734 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1735 self.set_tainted_by_errors(e);
1736 return Err(e);
1737 }
1738
1739 let (pat_ty, res) =
1741 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1742 if !pat_ty.is_fn() {
1743 return report_unexpected_res(res);
1744 }
1745
1746 let variant = match res {
1747 Res::Err => {
1748 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1749 }
1750 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1751 return report_unexpected_res(res);
1752 }
1753 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1754 _ => bug!("unexpected pattern resolution: {:?}", res),
1755 };
1756
1757 let pat_ty = pat_ty.fn_sig(tcx).output();
1759 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1760
1761 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1762 }
1763
1764 fn check_pat_tuple_struct(
1765 &self,
1766 pat: &'tcx Pat<'tcx>,
1767 qpath: &'tcx hir::QPath<'tcx>,
1768 subpats: &'tcx [Pat<'tcx>],
1769 ddpos: hir::DotDotPos,
1770 res: Res,
1771 pat_ty: Ty<'tcx>,
1772 variant: &'tcx VariantDef,
1773 expected: Ty<'tcx>,
1774 pat_info: PatInfo<'tcx>,
1775 ) -> Ty<'tcx> {
1776 let tcx = self.tcx;
1777 let on_error = |e| {
1778 for pat in subpats {
1779 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1780 }
1781 };
1782
1783 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1785 let had_err = diag.map_err(|diag| diag.emit());
1786
1787 if subpats.len() == variant.fields.len()
1789 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1790 {
1791 let ty::Adt(_, args) = pat_ty.kind() else {
1792 bug!("unexpected pattern type {:?}", pat_ty);
1793 };
1794 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1795 let field = &variant.fields[FieldIdx::from_usize(i)];
1796 let field_ty = self.field_ty(subpat.span, field, args);
1797 self.check_pat(subpat, field_ty, pat_info);
1798
1799 self.tcx.check_stability(
1800 variant.fields[FieldIdx::from_usize(i)].did,
1801 Some(subpat.hir_id),
1802 subpat.span,
1803 None,
1804 );
1805 }
1806 if let Err(e) = had_err {
1807 on_error(e);
1808 return Ty::new_error(tcx, e);
1809 }
1810 } else {
1811 let e = self.emit_err_pat_wrong_number_of_fields(
1812 pat.span,
1813 res,
1814 qpath,
1815 subpats,
1816 &variant.fields.raw,
1817 expected,
1818 had_err,
1819 );
1820 on_error(e);
1821 return Ty::new_error(tcx, e);
1822 }
1823 pat_ty
1824 }
1825
1826 fn emit_err_pat_wrong_number_of_fields(
1827 &self,
1828 pat_span: Span,
1829 res: Res,
1830 qpath: &hir::QPath<'_>,
1831 subpats: &'tcx [Pat<'tcx>],
1832 fields: &'tcx [ty::FieldDef],
1833 expected: Ty<'tcx>,
1834 had_err: Result<(), ErrorGuaranteed>,
1835 ) -> ErrorGuaranteed {
1836 let subpats_ending = pluralize!(subpats.len());
1837 let fields_ending = pluralize!(fields.len());
1838
1839 let subpat_spans = if subpats.is_empty() {
1840 vec![pat_span]
1841 } else {
1842 subpats.iter().map(|p| p.span).collect()
1843 };
1844 let last_subpat_span = *subpat_spans.last().unwrap();
1845 let res_span = self.tcx.def_span(res.def_id());
1846 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1847 let field_def_spans = if fields.is_empty() {
1848 vec![res_span]
1849 } else {
1850 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1851 };
1852 let last_field_def_span = *field_def_spans.last().unwrap();
1853
1854 let mut err = struct_span_code_err!(
1855 self.dcx(),
1856 MultiSpan::from_spans(subpat_spans),
1857 E0023,
1858 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1859 subpats.len(),
1860 subpats_ending,
1861 res.descr(),
1862 fields.len(),
1863 fields_ending,
1864 );
1865 err.span_label(
1866 last_subpat_span,
1867 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1868 );
1869 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1870 err.span_label(qpath.span(), "");
1871 }
1872 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1873 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1874 }
1875 for span in &field_def_spans[..field_def_spans.len() - 1] {
1876 err.span_label(*span, "");
1877 }
1878 err.span_label(
1879 last_field_def_span,
1880 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1881 );
1882
1883 let missing_parentheses = match (expected.kind(), fields, had_err) {
1888 (ty::Adt(_, args), [field], Ok(())) => {
1892 let field_ty = self.field_ty(pat_span, field, args);
1893 match field_ty.kind() {
1894 ty::Tuple(fields) => fields.len() == subpats.len(),
1895 _ => false,
1896 }
1897 }
1898 _ => false,
1899 };
1900 if missing_parentheses {
1901 let (left, right) = match subpats {
1902 [] => (qpath.span().shrink_to_hi(), pat_span),
1911 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1920 };
1921 err.multipart_suggestion(
1922 "missing parentheses",
1923 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1924 Applicability::MachineApplicable,
1925 );
1926 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1927 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1928 let all_fields_span = match subpats {
1929 [] => after_fields_span,
1930 [field] => field.span,
1931 [first, .., last] => first.span.to(last.span),
1932 };
1933
1934 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1936 let first_tail_wildcard =
1937 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1938 (None, PatKind::Wild) => Some(pos),
1939 (Some(_), PatKind::Wild) => acc,
1940 _ => None,
1941 });
1942 let tail_span = match first_tail_wildcard {
1943 None => after_fields_span,
1944 Some(0) => subpats[0].span.to(after_fields_span),
1945 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1946 };
1947
1948 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1950 if !subpats.is_empty() {
1951 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1952 }
1953
1954 err.span_suggestion_verbose(
1955 after_fields_span,
1956 "use `_` to explicitly ignore each field",
1957 wildcard_sugg,
1958 Applicability::MaybeIncorrect,
1959 );
1960
1961 if fields.len() - subpats.len() > 1 || all_wildcards {
1964 if subpats.is_empty() || all_wildcards {
1965 err.span_suggestion_verbose(
1966 all_fields_span,
1967 "use `..` to ignore all fields",
1968 "..",
1969 Applicability::MaybeIncorrect,
1970 );
1971 } else {
1972 err.span_suggestion_verbose(
1973 tail_span,
1974 "use `..` to ignore the rest of the fields",
1975 ", ..",
1976 Applicability::MaybeIncorrect,
1977 );
1978 }
1979 }
1980 }
1981
1982 err.emit()
1983 }
1984
1985 fn check_pat_tuple(
1986 &self,
1987 span: Span,
1988 elements: &'tcx [Pat<'tcx>],
1989 ddpos: hir::DotDotPos,
1990 expected: Ty<'tcx>,
1991 pat_info: PatInfo<'tcx>,
1992 ) -> Ty<'tcx> {
1993 let tcx = self.tcx;
1994 let mut expected_len = elements.len();
1995 if ddpos.as_opt_usize().is_some() {
1996 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1998 expected_len = tys.len();
1999 }
2000 }
2001 let max_len = cmp::max(expected_len, elements.len());
2002
2003 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
2004 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
2005 let pat_ty = Ty::new_tup(tcx, element_tys);
2006 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
2007 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
2010 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
2011 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
2012 }
2013 Ty::new_tup_from_iter(tcx, element_tys_iter)
2014 } else {
2015 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
2016 self.check_pat(elem, element_tys[i], pat_info);
2017 }
2018 pat_ty
2019 }
2020 }
2021
2022 fn check_struct_pat_fields(
2023 &self,
2024 adt_ty: Ty<'tcx>,
2025 pat: &'tcx Pat<'tcx>,
2026 variant: &'tcx ty::VariantDef,
2027 fields: &'tcx [hir::PatField<'tcx>],
2028 has_rest_pat: bool,
2029 pat_info: PatInfo<'tcx>,
2030 ) -> Result<(), ErrorGuaranteed> {
2031 let tcx = self.tcx;
2032
2033 let ty::Adt(adt, args) = adt_ty.kind() else {
2034 span_bug!(pat.span, "struct pattern is not an ADT");
2035 };
2036
2037 let field_map = variant
2039 .fields
2040 .iter_enumerated()
2041 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
2042 .collect::<FxHashMap<_, _>>();
2043
2044 let mut used_fields = FxHashMap::default();
2046 let mut result = Ok(());
2047
2048 let mut inexistent_fields = vec![];
2049 for field in fields {
2051 let span = field.span;
2052 let ident = tcx.adjust_ident(field.ident, variant.def_id);
2053 let field_ty = match used_fields.entry(ident) {
2054 Occupied(occupied) => {
2055 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
2056 result = Err(guar);
2057 Ty::new_error(tcx, guar)
2058 }
2059 Vacant(vacant) => {
2060 vacant.insert(span);
2061 field_map
2062 .get(&ident)
2063 .map(|(i, f)| {
2064 self.write_field_index(field.hir_id, *i);
2065 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
2066 self.field_ty(span, f, args)
2067 })
2068 .unwrap_or_else(|| {
2069 inexistent_fields.push(field);
2070 Ty::new_misc_error(tcx)
2071 })
2072 }
2073 };
2074
2075 self.check_pat(field.pat, field_ty, pat_info);
2076 }
2077
2078 let mut unmentioned_fields = variant
2079 .fields
2080 .iter()
2081 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
2082 .filter(|(_, ident)| !used_fields.contains_key(ident))
2083 .collect::<Vec<_>>();
2084
2085 let inexistent_fields_err = if !inexistent_fields.is_empty()
2086 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
2087 {
2088 variant.has_errors()?;
2090 Some(self.error_inexistent_fields(
2091 adt.variant_descr(),
2092 &inexistent_fields,
2093 &mut unmentioned_fields,
2094 pat,
2095 variant,
2096 args,
2097 ))
2098 } else {
2099 None
2100 };
2101
2102 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
2104 if non_exhaustive && !has_rest_pat {
2105 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
2106 }
2107
2108 let mut unmentioned_err = None;
2109 if adt.is_union() {
2111 if fields.len() != 1 {
2112 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
2113 }
2114 if has_rest_pat {
2115 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
2116 }
2117 } else if !unmentioned_fields.is_empty() {
2118 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
2119 .iter()
2120 .copied()
2121 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
2122 .collect();
2123
2124 if !has_rest_pat {
2125 if accessible_unmentioned_fields.is_empty() {
2126 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
2127 } else {
2128 unmentioned_err = Some(self.error_unmentioned_fields(
2129 pat,
2130 &accessible_unmentioned_fields,
2131 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
2132 fields,
2133 ));
2134 }
2135 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
2136 self.lint_non_exhaustive_omitted_patterns(
2137 pat,
2138 &accessible_unmentioned_fields,
2139 adt_ty,
2140 )
2141 }
2142 }
2143 match (inexistent_fields_err, unmentioned_err) {
2144 (Some(i), Some(u)) => {
2145 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2146 i.delay_as_bug();
2149 u.delay_as_bug();
2150 Err(e)
2151 } else {
2152 i.emit();
2153 Err(u.emit())
2154 }
2155 }
2156 (None, Some(u)) => {
2157 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2158 u.delay_as_bug();
2159 Err(e)
2160 } else {
2161 Err(u.emit())
2162 }
2163 }
2164 (Some(err), None) => Err(err.emit()),
2165 (None, None) => {
2166 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
2167 result
2168 }
2169 }
2170 }
2171
2172 fn error_tuple_variant_index_shorthand(
2173 &self,
2174 variant: &VariantDef,
2175 pat: &'_ Pat<'_>,
2176 fields: &[hir::PatField<'_>],
2177 ) -> Result<(), ErrorGuaranteed> {
2178 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
2182 (variant.ctor_kind(), &pat.kind)
2183 {
2184 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
2185 if has_shorthand_field_name {
2186 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2187 let mut err = struct_span_code_err!(
2188 self.dcx(),
2189 pat.span,
2190 E0769,
2191 "tuple variant `{path}` written as struct variant",
2192 );
2193 err.span_suggestion_verbose(
2194 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2195 "use the tuple variant pattern syntax instead",
2196 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
2197 Applicability::MaybeIncorrect,
2198 );
2199 return Err(err.emit());
2200 }
2201 }
2202 Ok(())
2203 }
2204
2205 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
2206 let sess = self.tcx.sess;
2207 let sm = sess.source_map();
2208 let sp_brace = sm.end_point(pat.span);
2209 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
2210 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
2211
2212 struct_span_code_err!(
2213 self.dcx(),
2214 pat.span,
2215 E0638,
2216 "`..` required with {descr} marked as non-exhaustive",
2217 )
2218 .with_span_suggestion_verbose(
2219 sp_comma,
2220 "add `..` at the end of the field list to ignore all other fields",
2221 sugg,
2222 Applicability::MachineApplicable,
2223 )
2224 .emit();
2225 }
2226
2227 fn error_field_already_bound(
2228 &self,
2229 span: Span,
2230 ident: Ident,
2231 other_field: Span,
2232 ) -> ErrorGuaranteed {
2233 struct_span_code_err!(
2234 self.dcx(),
2235 span,
2236 E0025,
2237 "field `{}` bound multiple times in the pattern",
2238 ident
2239 )
2240 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2241 .with_span_label(other_field, format!("first use of `{ident}`"))
2242 .emit()
2243 }
2244
2245 fn error_inexistent_fields(
2246 &self,
2247 kind_name: &str,
2248 inexistent_fields: &[&hir::PatField<'tcx>],
2249 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2250 pat: &'tcx Pat<'tcx>,
2251 variant: &ty::VariantDef,
2252 args: ty::GenericArgsRef<'tcx>,
2253 ) -> Diag<'a> {
2254 let tcx = self.tcx;
2255 let (field_names, t, plural) = if let [field] = inexistent_fields {
2256 (format!("a field named `{}`", field.ident), "this", "")
2257 } else {
2258 (
2259 format!(
2260 "fields named {}",
2261 inexistent_fields
2262 .iter()
2263 .map(|field| format!("`{}`", field.ident))
2264 .collect::<Vec<String>>()
2265 .join(", ")
2266 ),
2267 "these",
2268 "s",
2269 )
2270 };
2271 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2272 let mut err = struct_span_code_err!(
2273 self.dcx(),
2274 spans,
2275 E0026,
2276 "{} `{}` does not have {}",
2277 kind_name,
2278 tcx.def_path_str(variant.def_id),
2279 field_names
2280 );
2281 if let Some(pat_field) = inexistent_fields.last() {
2282 err.span_label(
2283 pat_field.ident.span,
2284 format!(
2285 "{} `{}` does not have {} field{}",
2286 kind_name,
2287 tcx.def_path_str(variant.def_id),
2288 t,
2289 plural
2290 ),
2291 );
2292
2293 if let [(field_def, field)] = unmentioned_fields.as_slice()
2294 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2295 {
2296 let suggested_name =
2297 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2298 if let Some(suggested_name) = suggested_name {
2299 err.span_suggestion(
2300 pat_field.ident.span,
2301 "a field with a similar name exists",
2302 suggested_name,
2303 Applicability::MaybeIncorrect,
2304 );
2305
2306 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2312 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2314 }
2315 } else if inexistent_fields.len() == 1 {
2316 match pat_field.pat.kind {
2317 PatKind::Expr(_)
2318 if !self.may_coerce(
2319 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2320 self.field_ty(field.span, field_def, args),
2321 ) => {}
2322 _ => {
2323 err.span_suggestion_short(
2324 pat_field.ident.span,
2325 format!(
2326 "`{}` has a field named `{}`",
2327 tcx.def_path_str(variant.def_id),
2328 field.name,
2329 ),
2330 field.name,
2331 Applicability::MaybeIncorrect,
2332 );
2333 }
2334 }
2335 }
2336 }
2337 }
2338 if tcx.sess.teach(err.code.unwrap()) {
2339 err.note(
2340 "This error indicates that a struct pattern attempted to \
2341 extract a nonexistent field from a struct. Struct fields \
2342 are identified by the name used before the colon : so struct \
2343 patterns should resemble the declaration of the struct type \
2344 being matched.\n\n\
2345 If you are using shorthand field patterns but want to refer \
2346 to the struct field by a different name, you should rename \
2347 it explicitly.",
2348 );
2349 }
2350 err
2351 }
2352
2353 fn error_tuple_variant_as_struct_pat(
2354 &self,
2355 pat: &Pat<'_>,
2356 fields: &'tcx [hir::PatField<'tcx>],
2357 variant: &ty::VariantDef,
2358 ) -> Result<(), ErrorGuaranteed> {
2359 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2360 (variant.ctor_kind(), &pat.kind)
2361 {
2362 let is_tuple_struct_match = !pattern_fields.is_empty()
2363 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2364 if is_tuple_struct_match {
2365 return Ok(());
2366 }
2367
2368 variant.has_errors()?;
2370
2371 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2372 let mut err = struct_span_code_err!(
2373 self.dcx(),
2374 pat.span,
2375 E0769,
2376 "tuple variant `{}` written as struct variant",
2377 path
2378 );
2379 let (sugg, appl) = if fields.len() == variant.fields.len() {
2380 (
2381 self.get_suggested_tuple_struct_pattern(fields, variant),
2382 Applicability::MachineApplicable,
2383 )
2384 } else {
2385 (
2386 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2387 Applicability::MaybeIncorrect,
2388 )
2389 };
2390 err.span_suggestion_verbose(
2391 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2392 "use the tuple variant pattern syntax instead",
2393 format!("({sugg})"),
2394 appl,
2395 );
2396 return Err(err.emit());
2397 }
2398 Ok(())
2399 }
2400
2401 fn get_suggested_tuple_struct_pattern(
2402 &self,
2403 fields: &[hir::PatField<'_>],
2404 variant: &VariantDef,
2405 ) -> String {
2406 let variant_field_idents =
2407 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2408 fields
2409 .iter()
2410 .map(|field| {
2411 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2412 Ok(f) => {
2413 if variant_field_idents.contains(&field.ident) {
2416 String::from("_")
2417 } else {
2418 f
2419 }
2420 }
2421 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2422 }
2423 })
2424 .collect::<Vec<String>>()
2425 .join(", ")
2426 }
2427
2428 fn error_no_accessible_fields(
2444 &self,
2445 pat: &Pat<'_>,
2446 fields: &'tcx [hir::PatField<'tcx>],
2447 ) -> Diag<'a> {
2448 let mut err = self
2449 .dcx()
2450 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2451
2452 if let Some(field) = fields.last() {
2453 err.span_suggestion_verbose(
2454 field.span.shrink_to_hi(),
2455 "ignore the inaccessible and unused fields",
2456 ", ..",
2457 Applicability::MachineApplicable,
2458 );
2459 } else {
2460 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2461 qpath.span()
2462 } else {
2463 bug!("`error_no_accessible_fields` called on non-struct pattern");
2464 };
2465
2466 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2468 err.span_suggestion_verbose(
2469 span,
2470 "ignore the inaccessible and unused fields",
2471 " { .. }",
2472 Applicability::MachineApplicable,
2473 );
2474 }
2475 err
2476 }
2477
2478 fn lint_non_exhaustive_omitted_patterns(
2483 &self,
2484 pat: &Pat<'_>,
2485 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2486 ty: Ty<'tcx>,
2487 ) {
2488 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2489 const LIMIT: usize = 3;
2490 match witnesses {
2491 [] => {
2492 unreachable!(
2493 "expected an uncovered pattern, otherwise why are we emitting an error?"
2494 )
2495 }
2496 [witness] => format!("`{witness}`"),
2497 [head @ .., tail] if head.len() < LIMIT => {
2498 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2499 format!("`{}` and `{}`", head.join("`, `"), tail)
2500 }
2501 _ => {
2502 let (head, tail) = witnesses.split_at(LIMIT);
2503 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2504 format!("`{}` and {} more", head.join("`, `"), tail.len())
2505 }
2506 }
2507 }
2508 let joined_patterns = joined_uncovered_patterns(
2509 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2510 );
2511
2512 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2513 lint.primary_message("some fields are not explicitly listed");
2514 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2515 lint.help(
2516 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2517 );
2518 lint.note(format!(
2519 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2520 ));
2521 });
2522 }
2523
2524 fn error_unmentioned_fields(
2534 &self,
2535 pat: &Pat<'_>,
2536 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2537 have_inaccessible_fields: bool,
2538 fields: &'tcx [hir::PatField<'tcx>],
2539 ) -> Diag<'a> {
2540 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2541 let field_names = if let [(_, field)] = unmentioned_fields {
2542 format!("field `{field}`{inaccessible}")
2543 } else {
2544 let fields = unmentioned_fields
2545 .iter()
2546 .map(|(_, name)| format!("`{name}`"))
2547 .collect::<Vec<String>>()
2548 .join(", ");
2549 format!("fields {fields}{inaccessible}")
2550 };
2551 let mut err = struct_span_code_err!(
2552 self.dcx(),
2553 pat.span,
2554 E0027,
2555 "pattern does not mention {}",
2556 field_names
2557 );
2558 err.span_label(pat.span, format!("missing {field_names}"));
2559 let len = unmentioned_fields.len();
2560 let (prefix, postfix, sp) = match fields {
2561 [] => match &pat.kind {
2562 PatKind::Struct(path, [], None) => {
2563 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2564 }
2565 _ => return err,
2566 },
2567 [.., field] => {
2568 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2571 match &pat.kind {
2572 PatKind::Struct(..) => (", ", " }", tail),
2573 _ => return err,
2574 }
2575 }
2576 };
2577 err.span_suggestion(
2578 sp,
2579 format!(
2580 "include the missing field{} in the pattern{}",
2581 pluralize!(len),
2582 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2583 ),
2584 format!(
2585 "{}{}{}{}",
2586 prefix,
2587 unmentioned_fields
2588 .iter()
2589 .map(|(_, name)| {
2590 let field_name = name.to_string();
2591 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2592 })
2593 .collect::<Vec<_>>()
2594 .join(", "),
2595 if have_inaccessible_fields { ", .." } else { "" },
2596 postfix,
2597 ),
2598 Applicability::MachineApplicable,
2599 );
2600 err.span_suggestion(
2601 sp,
2602 format!(
2603 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2604 these = pluralize!("this", len),
2605 s = pluralize!(len),
2606 them = if len == 1 { "it" } else { "them" },
2607 ),
2608 format!(
2609 "{}{}{}{}",
2610 prefix,
2611 unmentioned_fields
2612 .iter()
2613 .map(|(_, name)| {
2614 let field_name = name.to_string();
2615 format!("{field_name}: _")
2616 })
2617 .collect::<Vec<_>>()
2618 .join(", "),
2619 if have_inaccessible_fields { ", .." } else { "" },
2620 postfix,
2621 ),
2622 Applicability::MachineApplicable,
2623 );
2624 err.span_suggestion(
2625 sp,
2626 "or always ignore missing fields here",
2627 format!("{prefix}..{postfix}"),
2628 Applicability::MachineApplicable,
2629 );
2630 err
2631 }
2632
2633 fn check_pat_box(
2634 &self,
2635 span: Span,
2636 inner: &'tcx Pat<'tcx>,
2637 expected: Ty<'tcx>,
2638 pat_info: PatInfo<'tcx>,
2639 ) -> Ty<'tcx> {
2640 let tcx = self.tcx;
2641 let (box_ty, inner_ty) = self
2642 .check_dereferenceable(span, expected, inner)
2643 .and_then(|()| {
2644 let inner_ty = self.next_ty_var(inner.span);
2647 let box_ty = Ty::new_box(tcx, inner_ty);
2648 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2649 Ok((box_ty, inner_ty))
2650 })
2651 .unwrap_or_else(|guar| {
2652 let err = Ty::new_error(tcx, guar);
2653 (err, err)
2654 });
2655 self.check_pat(inner, inner_ty, pat_info);
2656 box_ty
2657 }
2658
2659 fn check_pat_deref(
2660 &self,
2661 span: Span,
2662 inner: &'tcx Pat<'tcx>,
2663 expected: Ty<'tcx>,
2664 pat_info: PatInfo<'tcx>,
2665 ) -> Ty<'tcx> {
2666 let target_ty = self.deref_pat_target(span, expected);
2667 self.check_pat(inner, target_ty, pat_info);
2668 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2669 expected
2670 }
2671
2672 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2673 let tcx = self.tcx;
2675 self.register_bound(
2676 source_ty,
2677 tcx.require_lang_item(hir::LangItem::DerefPure, span),
2678 self.misc(span),
2679 );
2680 let target_ty = Ty::new_projection(
2682 tcx,
2683 tcx.require_lang_item(hir::LangItem::DerefTarget, span),
2684 [source_ty],
2685 );
2686 let target_ty = self.normalize(span, target_ty);
2687 self.try_structurally_resolve_type(span, target_ty)
2688 }
2689
2690 fn register_deref_mut_bounds_if_needed(
2695 &self,
2696 span: Span,
2697 inner: &'tcx Pat<'tcx>,
2698 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2699 ) {
2700 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2701 for mutably_derefed_ty in derefed_tys {
2702 self.register_bound(
2703 mutably_derefed_ty,
2704 self.tcx.require_lang_item(hir::LangItem::DerefMut, span),
2705 self.misc(span),
2706 );
2707 }
2708 }
2709 }
2710
2711 fn check_pat_ref(
2713 &self,
2714 pat: &'tcx Pat<'tcx>,
2715 inner: &'tcx Pat<'tcx>,
2716 pat_pinned: Pinnedness,
2717 pat_mutbl: Mutability,
2718 mut expected: Ty<'tcx>,
2719 mut pat_info: PatInfo<'tcx>,
2720 ) -> Ty<'tcx> {
2721 let tcx = self.tcx;
2722
2723 let pat_prefix_span =
2724 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2725
2726 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2727 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2728 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2733 }
2734
2735 expected = self.try_structurally_resolve_type(pat.span, expected);
2736 if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode
2739 && pat_pinned == inh_pin
2740 {
2741 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2742 InheritedRefMatchRule::EatOuter => {
2743 if pat_mutbl > inh_mut {
2745 debug_assert!(ref_pat_matches_mut_ref);
2750 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2751 }
2752
2753 pat_info.binding_mode = ByRef::No;
2754 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2755 self.check_pat(inner, expected, pat_info);
2756 return expected;
2757 }
2758 InheritedRefMatchRule::EatInner => {
2759 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2760 && pat_mutbl <= r_mutbl
2761 {
2762 debug_assert!(ref_pat_matches_mut_ref);
2769 debug_assert!(self.downgrade_mut_inside_shared());
2773 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2774 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2775 } else {
2776 if pat_mutbl > inh_mut {
2779 debug_assert!(ref_pat_matches_mut_ref);
2788 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2789 }
2790
2791 pat_info.binding_mode = ByRef::No;
2792 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2793 self.check_pat(inner, expected, pat_info);
2794 return expected;
2795 }
2796 }
2797 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2798 pat_info.binding_mode = ByRef::No;
2800
2801 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2802 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2804 self.check_pat(inner, inner_ty, pat_info);
2811 return expected;
2812 } else {
2813 }
2820 } else {
2821 if pat_mutbl > inh_mut {
2824 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2826 }
2827
2828 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2829 self.check_pat(inner, expected, pat_info);
2830 return expected;
2831 }
2832 }
2833 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2834 pat_info.binding_mode = ByRef::No;
2837 self.add_rust_2024_migration_desugared_pat(
2838 pat_info.top_info.hir_id,
2839 pat,
2840 match pat_mutbl {
2841 Mutability::Not => '&', Mutability::Mut => 't', },
2844 inh_mut,
2845 )
2846 }
2847 }
2848 }
2849
2850 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2851 Ok(()) => {
2852 debug!("check_pat_ref: expected={:?}", expected);
2859 match expected.maybe_pinned_ref() {
2860 Some((r_ty, r_pinned, r_mutbl))
2861 if ((ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2862 || r_mutbl == pat_mutbl)
2863 && pat_pinned == r_pinned =>
2864 {
2865 if r_mutbl == Mutability::Not {
2866 pat_info.max_ref_mutbl = MutblCap::Not;
2867 }
2868 if r_pinned == Pinnedness::Pinned {
2869 pat_info.max_pinnedness = PinnednessCap::Pinned;
2870 }
2871
2872 (expected, r_ty)
2873 }
2874 _ => {
2875 let inner_ty = self.next_ty_var(inner.span);
2876 let ref_ty = self.new_ref_ty(pat.span, pat_pinned, pat_mutbl, inner_ty);
2877 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2878 let err = self.demand_eqtype_pat_diag(
2879 pat.span,
2880 expected,
2881 ref_ty,
2882 &pat_info.top_info,
2883 );
2884
2885 if let Err(mut err) = err {
2888 self.borrow_pat_suggestion(&mut err, pat);
2889 err.emit();
2890 }
2891 (ref_ty, inner_ty)
2892 }
2893 }
2894 }
2895 Err(guar) => {
2896 let err = Ty::new_error(tcx, guar);
2897 (err, err)
2898 }
2899 };
2900
2901 self.check_pat(inner, inner_ty, pat_info);
2902 ref_ty
2903 }
2904
2905 fn new_ref_ty(
2907 &self,
2908 span: Span,
2909 pinnedness: Pinnedness,
2910 mutbl: Mutability,
2911 ty: Ty<'tcx>,
2912 ) -> Ty<'tcx> {
2913 let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
2914 let ref_ty = Ty::new_ref(self.tcx, region, ty, mutbl);
2915 if pinnedness.is_pinned() {
2916 return self.new_pinned_ty(span, ref_ty);
2917 }
2918 ref_ty
2919 }
2920
2921 fn new_pinned_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
2923 Ty::new_adt(
2924 self.tcx,
2925 self.tcx.adt_def(self.tcx.require_lang_item(LangItem::Pin, span)),
2926 self.tcx.mk_args(&[ty.into()]),
2927 )
2928 }
2929
2930 fn error_inherited_ref_mutability_mismatch(
2931 &self,
2932 pat: &'tcx Pat<'tcx>,
2933 pat_prefix_span: Option<Span>,
2934 ) -> ErrorGuaranteed {
2935 let err_msg = "mismatched types";
2936 let err = if let Some(span) = pat_prefix_span {
2937 let mut err = self.dcx().struct_span_err(span, err_msg);
2938 err.code(E0308);
2939 err.note("cannot match inherited `&` with `&mut` pattern");
2940 err.span_suggestion_verbose(
2941 span,
2942 "replace this `&mut` pattern with `&`",
2943 "&",
2944 Applicability::MachineApplicable,
2945 );
2946 err
2947 } else {
2948 self.dcx().struct_span_err(pat.span, err_msg)
2949 };
2950 err.emit()
2951 }
2952
2953 fn try_resolve_slice_ty_to_array_ty(
2954 &self,
2955 before: &'tcx [Pat<'tcx>],
2956 slice: Option<&'tcx Pat<'tcx>>,
2957 span: Span,
2958 ) -> Option<Ty<'tcx>> {
2959 if slice.is_some() {
2960 return None;
2961 }
2962
2963 let tcx = self.tcx;
2964 let len = before.len();
2965 let inner_ty = self.next_ty_var(span);
2966
2967 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2968 }
2969
2970 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
3001 match decl_origin {
3002 Some(DeclOrigin::LocalDecl { els: None }) => true,
3003 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
3004 }
3005 }
3006
3007 fn check_pat_slice(
3018 &self,
3019 span: Span,
3020 before: &'tcx [Pat<'tcx>],
3021 slice: Option<&'tcx Pat<'tcx>>,
3022 after: &'tcx [Pat<'tcx>],
3023 expected: Ty<'tcx>,
3024 pat_info: PatInfo<'tcx>,
3025 ) -> Ty<'tcx> {
3026 let expected = self.try_structurally_resolve_type(span, expected);
3027
3028 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
3031 if let Some(resolved_arr_ty) =
3032 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
3033 {
3034 debug!(?resolved_arr_ty);
3035 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
3036 }
3037 }
3038
3039 let expected = self.structurally_resolve_type(span, expected);
3040 debug!(?expected);
3041
3042 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
3043 ty::Array(element_ty, len) => {
3045 let min = before.len() as u64 + after.len() as u64;
3046 let (opt_slice_ty, expected) =
3047 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
3048 assert!(opt_slice_ty.is_some() || slice.is_none());
3051 (element_ty, opt_slice_ty, expected)
3052 }
3053 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
3054 _ => {
3056 let guar = expected.error_reported().err().unwrap_or_else(|| {
3057 self.error_expected_array_or_slice(span, expected, pat_info)
3058 });
3059 let err = Ty::new_error(self.tcx, guar);
3060 (err, Some(err), err)
3061 }
3062 };
3063
3064 for elt in before {
3066 self.check_pat(elt, element_ty, pat_info);
3067 }
3068 if let Some(slice) = slice {
3070 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
3071 }
3072 for elt in after {
3074 self.check_pat(elt, element_ty, pat_info);
3075 }
3076 inferred
3077 }
3078
3079 fn check_array_pat_len(
3084 &self,
3085 span: Span,
3086 element_ty: Ty<'tcx>,
3087 arr_ty: Ty<'tcx>,
3088 slice: Option<&'tcx Pat<'tcx>>,
3089 len: ty::Const<'tcx>,
3090 min_len: u64,
3091 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
3092 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
3093
3094 let guar = if let Some(len) = len {
3095 if slice.is_none() {
3097 if min_len == len {
3101 return (None, arr_ty);
3102 }
3103
3104 self.error_scrutinee_inconsistent_length(span, min_len, len)
3105 } else if let Some(pat_len) = len.checked_sub(min_len) {
3106 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
3109 } else {
3110 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
3113 }
3114 } else if slice.is_none() {
3115 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
3118 self.demand_eqtype(span, updated_arr_ty, arr_ty);
3119 return (None, updated_arr_ty);
3120 } else {
3121 self.error_scrutinee_unfixed_length(span)
3125 };
3126
3127 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
3129 }
3130
3131 fn error_scrutinee_inconsistent_length(
3132 &self,
3133 span: Span,
3134 min_len: u64,
3135 size: u64,
3136 ) -> ErrorGuaranteed {
3137 struct_span_code_err!(
3138 self.dcx(),
3139 span,
3140 E0527,
3141 "pattern requires {} element{} but array has {}",
3142 min_len,
3143 pluralize!(min_len),
3144 size,
3145 )
3146 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
3147 .emit()
3148 }
3149
3150 fn error_scrutinee_with_rest_inconsistent_length(
3151 &self,
3152 span: Span,
3153 min_len: u64,
3154 size: u64,
3155 ) -> ErrorGuaranteed {
3156 struct_span_code_err!(
3157 self.dcx(),
3158 span,
3159 E0528,
3160 "pattern requires at least {} element{} but array has {}",
3161 min_len,
3162 pluralize!(min_len),
3163 size,
3164 )
3165 .with_span_label(
3166 span,
3167 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
3168 )
3169 .emit()
3170 }
3171
3172 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
3173 struct_span_code_err!(
3174 self.dcx(),
3175 span,
3176 E0730,
3177 "cannot pattern-match on an array without a fixed length",
3178 )
3179 .emit()
3180 }
3181
3182 fn error_expected_array_or_slice(
3183 &self,
3184 span: Span,
3185 expected_ty: Ty<'tcx>,
3186 pat_info: PatInfo<'tcx>,
3187 ) -> ErrorGuaranteed {
3188 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
3189
3190 let mut slice_pat_semantics = false;
3191 let mut as_deref = None;
3192 let mut slicing = None;
3193 if let ty::Ref(_, ty, _) = expected_ty.kind()
3194 && let ty::Array(..) | ty::Slice(..) = ty.kind()
3195 {
3196 slice_pat_semantics = true;
3197 } else if self
3198 .autoderef(span, expected_ty)
3199 .silence_errors()
3200 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
3201 && let Some(span) = ti.span
3202 && let Some(_) = ti.origin_expr
3203 {
3204 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
3205 let (is_slice_or_array_or_vector, resolved_ty) =
3206 self.is_slice_or_array_or_vector(resolved_ty);
3207 match resolved_ty.kind() {
3208 ty::Adt(adt_def, _)
3209 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
3210 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
3211 {
3212 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
3214 }
3215 _ => (),
3216 }
3217
3218 let is_top_level = current_depth <= 1;
3219 if is_slice_or_array_or_vector && is_top_level {
3220 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
3221 }
3222 }
3223 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
3224 span,
3225 ty: expected_ty,
3226 slice_pat_semantics,
3227 as_deref,
3228 slicing,
3229 })
3230 }
3231
3232 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
3233 match ty.kind() {
3234 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
3235 (true, ty)
3236 }
3237 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
3238 ty::Slice(..) | ty::Array(..) => (true, ty),
3239 _ => (false, ty),
3240 }
3241 }
3242
3243 fn add_rust_2024_migration_desugared_pat(
3246 &self,
3247 pat_id: HirId,
3248 subpat: &'tcx Pat<'tcx>,
3249 final_char: char,
3250 def_br_mutbl: Mutability,
3251 ) {
3252 let from_expansion = subpat.span.from_expansion();
3254 let trimmed_span = if from_expansion {
3255 subpat.span
3257 } else {
3258 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3259 trimmed.with_ctxt(subpat.span.ctxt())
3262 };
3263
3264 let mut typeck_results = self.typeck_results.borrow_mut();
3265 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3266 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3271 primary_labels: Vec::new(),
3272 bad_ref_modifiers: false,
3273 bad_mut_modifiers: false,
3274 bad_ref_pats: false,
3275 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3276 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3277 });
3278
3279 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3280 info.suggest_eliding_modes &= matches!(
3284 user_bind_annot,
3285 BindingMode(ByRef::Yes(_, mutbl), Mutability::Not) if mutbl == def_br_mutbl
3286 );
3287 if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) {
3288 info.bad_mut_modifiers = true;
3289 "`mut` binding modifier"
3290 } else {
3291 info.bad_ref_modifiers = true;
3292 match user_bind_annot.1 {
3293 Mutability::Not => "explicit `ref` binding modifier",
3294 Mutability::Mut => "explicit `ref mut` binding modifier",
3295 }
3296 }
3297 } else {
3298 info.bad_ref_pats = true;
3299 info.suggest_eliding_modes = false;
3303 "reference pattern"
3304 };
3305 let primary_label = if from_expansion {
3308 info.suggest_eliding_modes = false;
3310 "occurs within macro expansion".to_owned()
3314 } else {
3315 format!("{pat_kind} not allowed when implicitly borrowing")
3316 };
3317 info.primary_labels.push((trimmed_span, primary_label));
3318 }
3319}