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_ref_mutbl: MutblCap,
95 top_info: TopInfo<'tcx>,
96 decl_origin: Option<DeclOrigin<'tcx>>,
97
98 current_depth: u32,
100}
101
102impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
103 fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
104 let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
109 let mut count = 0;
110
111 while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
115 cur_expr = inner;
116 count += 1;
117 }
118
119 PatternOriginExpr {
120 peeled_span: cur_expr.span,
121 peeled_count: count,
122 peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
123 }
124 });
125
126 let code = ObligationCauseCode::Pattern {
127 span: ti.span,
128 root_ty: ti.expected,
129 origin_expr: origin_expr_info,
130 };
131 self.cause(cause_span, code)
132 }
133
134 fn demand_eqtype_pat_diag(
135 &'a self,
136 cause_span: Span,
137 expected: Ty<'tcx>,
138 actual: Ty<'tcx>,
139 ti: &TopInfo<'tcx>,
140 ) -> Result<(), Diag<'a>> {
141 self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
142 .map_err(|mut diag| {
143 if let Some(expr) = ti.origin_expr {
144 self.suggest_fn_call(&mut diag, expr, expected, |output| {
145 self.can_eq(self.param_env, output, actual)
146 });
147 }
148 diag
149 })
150 }
151
152 fn demand_eqtype_pat(
153 &self,
154 cause_span: Span,
155 expected: Ty<'tcx>,
156 actual: Ty<'tcx>,
157 ti: &TopInfo<'tcx>,
158 ) -> Result<(), ErrorGuaranteed> {
159 self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit())
160 }
161}
162
163#[derive(Clone, Copy, Debug, PartialEq, Eq)]
165enum AdjustMode {
166 Peel { kind: PeelKind },
169 Pass,
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq)]
175enum PeelKind {
176 ExplicitDerefPat,
179 Implicit {
181 until_adt: Option<DefId>,
184 pat_ref_layers: usize,
187 },
188}
189
190impl AdjustMode {
191 const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
192 AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } }
193 }
194 const fn peel_all() -> AdjustMode {
195 AdjustMode::peel_until_adt(None)
196 }
197}
198
199#[derive(Clone, Copy, Debug, PartialEq, Eq)]
210enum MutblCap {
211 Not,
213
214 WeaklyNot(Option<Span>),
221
222 Mut,
224}
225
226impl MutblCap {
227 #[must_use]
228 fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
229 match self {
230 MutblCap::Not => MutblCap::Not,
231 _ => MutblCap::WeaklyNot(span),
232 }
233 }
234
235 #[must_use]
236 fn as_mutbl(self) -> Mutability {
237 match self {
238 MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
239 MutblCap::Mut => Mutability::Mut,
240 }
241 }
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq)]
250enum InheritedRefMatchRule {
251 EatOuter,
255 EatInner,
258 EatBoth {
261 consider_inherited_ref: bool,
272 },
273}
274
275#[derive(Clone, Copy, Debug)]
284struct ResolvedPat<'tcx> {
285 ty: Ty<'tcx>,
288 kind: ResolvedPatKind<'tcx>,
289}
290
291#[derive(Clone, Copy, Debug)]
292enum ResolvedPatKind<'tcx> {
293 Path { res: Res, pat_res: Res, segments: &'tcx [hir::PathSegment<'tcx>] },
294 Struct { variant: &'tcx VariantDef },
295 TupleStruct { res: Res, variant: &'tcx VariantDef },
296}
297
298impl<'tcx> ResolvedPat<'tcx> {
299 fn adjust_mode(&self) -> AdjustMode {
300 if let ResolvedPatKind::Path { res, .. } = self.kind
301 && matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
302 {
303 AdjustMode::Pass
307 } else {
308 AdjustMode::peel_until_adt(self.ty.ty_adt_def().map(|adt| adt.did()))
312 }
313 }
314}
315
316impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
317 fn downgrade_mut_inside_shared(&self) -> bool {
321 self.tcx.features().ref_pat_eat_one_layer_2024_structural()
324 }
325
326 fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule {
329 if edition.at_least_rust_2024() {
332 if self.tcx.features().ref_pat_eat_one_layer_2024() {
333 InheritedRefMatchRule::EatOuter
334 } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() {
335 InheritedRefMatchRule::EatInner
336 } else {
337 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false }
340 }
341 } else {
342 InheritedRefMatchRule::EatBoth {
343 consider_inherited_ref: self.tcx.features().ref_pat_eat_one_layer_2024()
344 || self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
345 }
346 }
347 }
348
349 fn ref_pat_matches_mut_ref(&self) -> bool {
352 self.tcx.features().ref_pat_eat_one_layer_2024()
355 || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
356 }
357
358 pub(crate) fn check_pat_top(
367 &self,
368 pat: &'tcx Pat<'tcx>,
369 expected: Ty<'tcx>,
370 span: Option<Span>,
371 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
372 decl_origin: Option<DeclOrigin<'tcx>>,
373 ) {
374 let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
375 let pat_info = PatInfo {
376 binding_mode: ByRef::No,
377 max_ref_mutbl: MutblCap::Mut,
378 top_info,
379 decl_origin,
380 current_depth: 0,
381 };
382 self.check_pat(pat, expected, pat_info);
383 }
384
385 #[instrument(level = "debug", skip(self, pat_info))]
391 fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
392 let opt_path_res = match pat.kind {
395 PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
396 Some(self.resolve_pat_path(*hir_id, *span, qpath))
397 }
398 PatKind::Struct(ref qpath, ..) => Some(self.resolve_pat_struct(pat, qpath)),
399 PatKind::TupleStruct(ref qpath, ..) => Some(self.resolve_pat_tuple_struct(pat, qpath)),
400 _ => None,
401 };
402 let adjust_mode = self.calc_adjust_mode(pat, opt_path_res);
403 let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
404 self.write_ty(pat.hir_id, ty);
405
406 if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id)
409 && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref)
410 {
411 self.register_deref_mut_bounds_if_needed(
412 pat.span,
413 pat,
414 derefed_tys.iter().filter_map(|adjust| match adjust.kind {
415 PatAdjust::OverloadedDeref => Some(adjust.source),
416 PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None,
417 }),
418 );
419 }
420
421 }
463
464 fn check_pat_inner(
466 &self,
467 pat: &'tcx Pat<'tcx>,
468 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
469 adjust_mode: AdjustMode,
470 expected: Ty<'tcx>,
471 pat_info: PatInfo<'tcx>,
472 ) -> Ty<'tcx> {
473 #[cfg(debug_assertions)]
474 if matches!(pat_info.binding_mode, ByRef::Yes(_, Mutability::Mut))
475 && pat_info.max_ref_mutbl != MutblCap::Mut
476 && self.downgrade_mut_inside_shared()
477 {
478 span_bug!(pat.span, "Pattern mutability cap violated!");
479 }
480
481 let expected = if let AdjustMode::Peel { .. } = adjust_mode
483 && pat.default_binding_modes
484 {
485 self.try_structurally_resolve_type(pat.span, expected)
486 } else {
487 expected
488 };
489 let old_pat_info = pat_info;
490 let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
491
492 let adjust_binding_mode = |inner_pinnedness, inner_mutability| {
493 match pat_info.binding_mode {
494 ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
498 ByRef::Yes(pinnedness, Mutability::Mut) => ByRef::Yes(pinnedness, inner_mutability),
501 ByRef::Yes(pinnedness, Mutability::Not) => ByRef::Yes(pinnedness, Mutability::Not),
505 }
506 };
507
508 match pat.kind {
509 _ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
512 && pat.default_binding_modes
513 && let &ty::Ref(_, inner_ty, inner_mutability) = expected.kind()
514 && self.should_peel_ref(peel_kind, expected) =>
515 {
516 debug!("inspecting {:?}", expected);
517
518 debug!("current discriminant is Ref, inserting implicit deref");
519 self.typeck_results
521 .borrow_mut()
522 .pat_adjustments_mut()
523 .entry(pat.hir_id)
524 .or_default()
525 .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
526
527 let mut binding_mode = adjust_binding_mode(Pinnedness::Not, inner_mutability);
528
529 let mut max_ref_mutbl = pat_info.max_ref_mutbl;
530 if self.downgrade_mut_inside_shared() {
531 binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
532 }
533 if matches!(binding_mode, ByRef::Yes(_, Mutability::Not)) {
534 max_ref_mutbl = MutblCap::Not;
535 }
536 debug!("default binding mode is now {:?}", binding_mode);
537
538 let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info };
540 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
542 }
543 _ if self.tcx.features().pin_ergonomics()
546 && let AdjustMode::Peel { kind: peel_kind } = adjust_mode
547 && pat.default_binding_modes
548 && self.should_peel_smart_pointer(peel_kind, expected)
549 && let Some(pinned_ty) = expected.pinned_ty()
550 && let &ty::Ref(_, inner_ty, inner_mutability) = pinned_ty.kind() =>
554 {
555 debug!("scrutinee ty {expected:?} is a pinned reference, inserting pin deref");
556
557 if let Some(adt) = inner_ty.ty_adt_def()
560 && !adt.is_pin_project()
561 && !adt.is_pin()
562 {
563 let def_span: Option<Span> = self.tcx.hir_span_if_local(adt.did());
564 let sugg_span = def_span.map(|span| span.shrink_to_lo());
565 self.dcx().emit_err(crate::errors::ProjectOnNonPinProjectType {
566 span: pat.span,
567 def_span,
568 sugg_span,
569 });
570 }
571
572 let binding_mode = adjust_binding_mode(Pinnedness::Pinned, inner_mutability);
573 if matches!(binding_mode, ByRef::Yes(Pinnedness::Not, _)) {
576 self.register_bound(
577 inner_ty,
578 self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
579 self.misc(pat.span),
580 )
581 }
582 debug!("default binding mode is now {:?}", binding_mode);
583
584 let new_pat_info = PatInfo { binding_mode, ..old_pat_info };
586
587 self.check_deref_pattern(
588 pat,
589 opt_path_res,
590 adjust_mode,
591 expected,
592 inner_ty,
593 PatAdjust::PinDeref,
594 new_pat_info,
595 )
596 }
597 _ if self.tcx.features().deref_patterns()
600 && let AdjustMode::Peel { kind: peel_kind } = adjust_mode
601 && pat.default_binding_modes
602 && self.should_peel_smart_pointer(peel_kind, expected) =>
603 {
604 debug!("scrutinee ty {expected:?} is a smart pointer, inserting pin deref");
605
606 let inner_ty = self.deref_pat_target(pat.span, expected);
609 self.check_deref_pattern(
613 pat,
614 opt_path_res,
615 adjust_mode,
616 expected,
617 inner_ty,
618 PatAdjust::OverloadedDeref,
619 old_pat_info,
620 )
621 }
622 PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
623 PatKind::Never => expected,
625 PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), hir_id, .. }) => {
626 let ty = match opt_path_res.unwrap() {
627 Ok(ref pr) => {
628 self.check_pat_path(pat.hir_id, pat.span, pr, expected, &pat_info.top_info)
629 }
630 Err(guar) => Ty::new_error(self.tcx, guar),
631 };
632 self.write_ty(*hir_id, ty);
633 ty
634 }
635 PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info),
636 PatKind::Range(lhs, rhs, _) => {
637 self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info)
638 }
639 PatKind::Binding(ba, var_id, ident, sub) => {
640 self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
641 }
642 PatKind::TupleStruct(ref qpath, subpats, ddpos) => match opt_path_res.unwrap() {
643 Ok(ResolvedPat { ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) => self
644 .check_pat_tuple_struct(
645 pat, qpath, subpats, ddpos, res, ty, variant, expected, pat_info,
646 ),
647 Err(guar) => {
648 let ty_err = Ty::new_error(self.tcx, guar);
649 for subpat in subpats {
650 self.check_pat(subpat, ty_err, pat_info);
651 }
652 ty_err
653 }
654 Ok(pr) => span_bug!(pat.span, "tuple struct pattern resolved to {pr:?}"),
655 },
656 PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() {
657 Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self
658 .check_pat_struct(
659 pat,
660 fields,
661 has_rest_pat.is_some(),
662 ty,
663 variant,
664 expected,
665 pat_info,
666 ),
667 Err(guar) => {
668 let ty_err = Ty::new_error(self.tcx, guar);
669 for field in fields {
670 self.check_pat(field.pat, ty_err, pat_info);
671 }
672 ty_err
673 }
674 Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
675 },
676 PatKind::Guard(pat, cond) => {
677 self.check_pat(pat, expected, pat_info);
678 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
679 expected
680 }
681 PatKind::Or(pats) => {
682 for pat in pats {
683 self.check_pat(pat, expected, pat_info);
684 }
685 expected
686 }
687 PatKind::Tuple(elements, ddpos) => {
688 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
689 }
690 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
691 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
692 PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
693 PatKind::Slice(before, slice, after) => {
694 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
695 }
696 }
697 }
698
699 fn check_deref_pattern(
700 &self,
701 pat: &'tcx Pat<'tcx>,
702 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
703 adjust_mode: AdjustMode,
704 expected: Ty<'tcx>,
705 mut inner_ty: Ty<'tcx>,
706 pat_adjust_kind: PatAdjust,
707 pat_info: PatInfo<'tcx>,
708 ) -> Ty<'tcx> {
709 debug_assert!(
710 !matches!(pat_adjust_kind, PatAdjust::BuiltinDeref),
711 "unexpected deref pattern for builtin reference type {expected:?}",
712 );
713
714 let mut typeck_results = self.typeck_results.borrow_mut();
715 let mut pat_adjustments_table = typeck_results.pat_adjustments_mut();
716 let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default();
717 if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) {
724 pat_adjustments.push(PatAdjustment { kind: pat_adjust_kind, source: expected });
726 } else {
727 let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected);
728 inner_ty = Ty::new_error(self.tcx, guar);
729 }
730 drop(typeck_results);
731
732 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, pat_info)
735 }
736
737 fn calc_adjust_mode(
741 &self,
742 pat: &'tcx Pat<'tcx>,
743 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
744 ) -> AdjustMode {
745 match &pat.kind {
746 PatKind::Tuple(..) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::peel_all(),
749 PatKind::Box(_) | PatKind::Deref(_) => {
753 AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat }
754 }
755 PatKind::Never => AdjustMode::peel_all(),
757 PatKind::Struct(..)
759 | PatKind::TupleStruct(..)
760 | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
761 opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
763 }
764
765 PatKind::Expr(lt) => {
770 if cfg!(debug_assertions)
773 && self.tcx.features().deref_patterns()
774 && !matches!(lt.kind, PatExprKind::Lit { .. })
775 {
776 span_bug!(
777 lt.span,
778 "FIXME(deref_patterns): adjust mode unimplemented for {:?}",
779 lt.kind
780 );
781 }
782 let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
784 if self.tcx.features().deref_patterns() {
786 let mut peeled_ty = lit_ty;
787 let mut pat_ref_layers = 0;
788 while let ty::Ref(_, inner_ty, mutbl) =
789 *self.try_structurally_resolve_type(pat.span, peeled_ty).kind()
790 {
791 debug_assert!(mutbl.is_not());
793 pat_ref_layers += 1;
794 peeled_ty = inner_ty;
795 }
796 AdjustMode::Peel {
797 kind: PeelKind::Implicit { until_adt: None, pat_ref_layers },
798 }
799 } else {
800 if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
801 }
802 }
803
804 PatKind::Ref(..)
806 | PatKind::Missing
808 | PatKind::Wild
810 | PatKind::Err(_)
812 | PatKind::Binding(..)
817 | PatKind::Or(_)
821 | PatKind::Guard(..) => AdjustMode::Pass,
823 }
824 }
825
826 fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
828 debug_assert!(expected.is_ref());
829 let pat_ref_layers = match peel_kind {
830 PeelKind::ExplicitDerefPat => 0,
831 PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
832 };
833
834 if pat_ref_layers == 0 {
837 return true;
838 }
839 debug_assert!(
840 self.tcx.features().deref_patterns(),
841 "Peeling for patterns with reference types is gated by `deref_patterns`."
842 );
843
844 let mut expected_ref_layers = 0;
850 while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
851 if mutbl.is_mut() {
852 return true;
855 }
856 expected_ref_layers += 1;
857 expected = inner_ty;
858 }
859 pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
860 }
861
862 fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
864 if let PeelKind::Implicit { until_adt, .. } = peel_kind
866 && let ty::Adt(scrutinee_adt, _) = *expected.kind()
871 && until_adt != Some(scrutinee_adt.did())
874 && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
879 && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
880 {
881 true
882 } else {
883 false
884 }
885 }
886
887 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
888 let ty = match <.kind {
889 rustc_hir::PatExprKind::Lit { lit, negated } => {
890 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
891 if *negated {
892 self.register_bound(
893 ty,
894 self.tcx.require_lang_item(LangItem::Neg, lt.span),
895 ObligationCause::dummy_with_span(lt.span),
896 );
897 }
898 ty
899 }
900 rustc_hir::PatExprKind::ConstBlock(c) => {
901 self.check_expr_const_block(c, Expectation::NoExpectation)
902 }
903 rustc_hir::PatExprKind::Path(qpath) => {
904 let (res, opt_ty, segments) =
905 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
906 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
907 }
908 };
909 self.write_ty(lt.hir_id, ty);
910 ty
911 }
912
913 fn check_pat_lit(
914 &self,
915 span: Span,
916 lt: &hir::PatExpr<'tcx>,
917 expected: Ty<'tcx>,
918 ti: &TopInfo<'tcx>,
919 ) -> Ty<'tcx> {
920 let ty = self.node_ty(lt.hir_id);
923
924 let mut pat_ty = ty;
929 if let hir::PatExprKind::Lit {
930 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
931 } = lt.kind
932 {
933 let tcx = self.tcx;
934 let expected = self.structurally_resolve_type(span, expected);
935 match *expected.kind() {
936 ty::Ref(_, inner_ty, _)
938 if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
939 {
940 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
941 pat_ty = Ty::new_imm_ref(
942 tcx,
943 tcx.lifetimes.re_static,
944 Ty::new_slice(tcx, tcx.types.u8),
945 );
946 }
947 ty::Array(..) if tcx.features().deref_patterns() => {
949 pat_ty = match *ty.kind() {
950 ty::Ref(_, inner_ty, _) => inner_ty,
951 _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
952 }
953 }
954 ty::Slice(..) if tcx.features().deref_patterns() => {
956 pat_ty = Ty::new_slice(tcx, tcx.types.u8);
957 }
958 _ => {}
960 }
961 }
962
963 if self.tcx.features().deref_patterns()
966 && let hir::PatExprKind::Lit {
967 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
968 } = lt.kind
969 && self.try_structurally_resolve_type(span, expected).is_str()
970 {
971 pat_ty = self.tcx.types.str_;
972 }
973
974 if self.tcx.features().string_deref_patterns()
975 && let hir::PatExprKind::Lit {
976 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
977 } = lt.kind
978 {
979 let tcx = self.tcx;
980 let expected = self.resolve_vars_if_possible(expected);
981 pat_ty = match expected.kind() {
982 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
983 ty::Str => Ty::new_static_str(tcx),
984 _ => pat_ty,
985 };
986 }
987
988 let cause = self.pattern_cause(ti, span);
999 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
1000 err.emit();
1001 }
1002
1003 pat_ty
1004 }
1005
1006 fn check_pat_range(
1007 &self,
1008 span: Span,
1009 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
1010 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
1011 expected: Ty<'tcx>,
1012 ti: &TopInfo<'tcx>,
1013 ) -> Ty<'tcx> {
1014 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
1015 None => None,
1016 Some(expr) => {
1017 let ty = self.check_pat_expr_unadjusted(expr);
1018 let ty = self.try_structurally_resolve_type(expr.span, ty);
1025 let fail =
1026 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
1027 Some((fail, ty, expr.span))
1028 }
1029 };
1030 let mut lhs = calc_side(lhs);
1031 let mut rhs = calc_side(rhs);
1032
1033 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
1034 let guar = self.emit_err_pat_range(span, lhs, rhs);
1037 return Ty::new_error(self.tcx, guar);
1038 }
1039
1040 let demand_eqtype = |x: &mut _, y| {
1043 if let Some((ref mut fail, x_ty, x_span)) = *x
1044 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
1045 {
1046 if let Some((_, y_ty, y_span)) = y {
1047 self.endpoint_has_type(&mut err, y_span, y_ty);
1048 }
1049 err.emit();
1050 *fail = true;
1051 }
1052 };
1053 demand_eqtype(&mut lhs, rhs);
1054 demand_eqtype(&mut rhs, lhs);
1055
1056 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
1057 return Ty::new_misc_error(self.tcx);
1058 }
1059
1060 let ty = self.structurally_resolve_type(span, expected);
1065 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
1066 if let Some((ref mut fail, _, _)) = lhs {
1067 *fail = true;
1068 }
1069 if let Some((ref mut fail, _, _)) = rhs {
1070 *fail = true;
1071 }
1072 let guar = self.emit_err_pat_range(span, lhs, rhs);
1073 return Ty::new_error(self.tcx, guar);
1074 }
1075 ty
1076 }
1077
1078 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
1079 if !ty.references_error() {
1080 err.span_label(span, format!("this is of type `{ty}`"));
1081 }
1082 }
1083
1084 fn emit_err_pat_range(
1085 &self,
1086 span: Span,
1087 lhs: Option<(bool, Ty<'tcx>, Span)>,
1088 rhs: Option<(bool, Ty<'tcx>, Span)>,
1089 ) -> ErrorGuaranteed {
1090 let span = match (lhs, rhs) {
1091 (Some((true, ..)), Some((true, ..))) => span,
1092 (Some((true, _, sp)), _) => sp,
1093 (_, Some((true, _, sp))) => sp,
1094 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
1095 };
1096 let mut err = struct_span_code_err!(
1097 self.dcx(),
1098 span,
1099 E0029,
1100 "only `char` and numeric types are allowed in range patterns"
1101 );
1102 let msg = |ty| {
1103 let ty = self.resolve_vars_if_possible(ty);
1104 format!("this is of type `{ty}` but it should be `char` or numeric")
1105 };
1106 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
1107 err.span_label(first_span, msg(first_ty));
1108 if let Some((_, ty, sp)) = second {
1109 let ty = self.resolve_vars_if_possible(ty);
1110 self.endpoint_has_type(&mut err, sp, ty);
1111 }
1112 };
1113 match (lhs, rhs) {
1114 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
1115 err.span_label(lhs_sp, msg(lhs_ty));
1116 err.span_label(rhs_sp, msg(rhs_ty));
1117 }
1118 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
1119 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
1120 _ => span_bug!(span, "Impossible, verified above."),
1121 }
1122 if (lhs, rhs).references_error() {
1123 err.downgrade_to_delayed_bug();
1124 }
1125 if self.tcx.sess.teach(err.code.unwrap()) {
1126 err.note(
1127 "In a match expression, only numbers and characters can be matched \
1128 against a range. This is because the compiler checks that the range \
1129 is non-empty at compile-time, and is unable to evaluate arbitrary \
1130 comparison functions. If you want to capture values of an orderable \
1131 type between two end-points, you can use a guard.",
1132 );
1133 }
1134 err.emit()
1135 }
1136
1137 fn check_pat_ident(
1138 &self,
1139 pat: &'tcx Pat<'tcx>,
1140 user_bind_annot: BindingMode,
1141 var_id: HirId,
1142 ident: Ident,
1143 sub: Option<&'tcx Pat<'tcx>>,
1144 expected: Ty<'tcx>,
1145 pat_info: PatInfo<'tcx>,
1146 ) -> Ty<'tcx> {
1147 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
1148
1149 let bm = match user_bind_annot {
1151 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(_, def_br_mutbl) = def_br => {
1152 if pat.span.at_least_rust_2024()
1155 && (self.tcx.features().ref_pat_eat_one_layer_2024()
1156 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
1157 {
1158 if !self.tcx.features().mut_ref() {
1159 feature_err(
1160 self.tcx.sess,
1161 sym::mut_ref,
1162 pat.span.until(ident.span),
1163 "binding cannot be both mutable and by-reference",
1164 )
1165 .emit();
1166 }
1167
1168 BindingMode(def_br, Mutability::Mut)
1169 } else {
1170 self.add_rust_2024_migration_desugared_pat(
1172 pat_info.top_info.hir_id,
1173 pat,
1174 't', def_br_mutbl,
1176 );
1177 BindingMode(ByRef::No, Mutability::Mut)
1178 }
1179 }
1180 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
1181 BindingMode(ByRef::Yes(_, user_br_mutbl), _) => {
1182 if let ByRef::Yes(_, def_br_mutbl) = def_br {
1183 self.add_rust_2024_migration_desugared_pat(
1185 pat_info.top_info.hir_id,
1186 pat,
1187 match user_br_mutbl {
1188 Mutability::Not => 'f', Mutability::Mut => 't', },
1191 def_br_mutbl,
1192 );
1193 }
1194 user_bind_annot
1195 }
1196 };
1197
1198 if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
1199 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1200 {
1201 let mut err = struct_span_code_err!(
1202 self.dcx(),
1203 ident.span,
1204 E0596,
1205 "cannot borrow as mutable inside an `&` pattern"
1206 );
1207
1208 if let Some(span) = and_pat_span {
1209 err.span_suggestion(
1210 span,
1211 "replace this `&` with `&mut`",
1212 "&mut ",
1213 Applicability::MachineApplicable,
1214 );
1215 }
1216 err.emit();
1217 }
1218
1219 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1221
1222 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1223
1224 let local_ty = self.local_ty(pat.span, pat.hir_id);
1225 let eq_ty = match bm.0 {
1226 ByRef::Yes(Pinnedness::Not, mutbl) => {
1227 self.new_ref_ty(pat.span, mutbl, expected)
1235 }
1236 ByRef::Yes(Pinnedness::Pinned, mutbl) => Ty::new_adt(
1238 self.tcx,
1239 self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, pat.span)),
1240 self.tcx.mk_args(&[self.new_ref_ty(pat.span, mutbl, expected).into()]),
1241 ),
1242 ByRef::No => expected, };
1245
1246 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1248
1249 if var_id != pat.hir_id {
1252 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1253 }
1254
1255 if let Some(p) = sub {
1256 self.check_pat(p, expected, pat_info);
1257 }
1258
1259 local_ty
1260 }
1261
1262 fn check_binding_alt_eq_ty(
1266 &self,
1267 ba: BindingMode,
1268 span: Span,
1269 var_id: HirId,
1270 ty: Ty<'tcx>,
1271 ti: &TopInfo<'tcx>,
1272 ) {
1273 let var_ty = self.local_ty(span, var_id);
1274 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1275 let var_ty = self.resolve_vars_if_possible(var_ty);
1276 let msg = format!("first introduced with type `{var_ty}` here");
1277 err.span_label(self.tcx.hir_span(var_id), msg);
1278 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1279 matches!(
1280 n,
1281 hir::Node::Expr(hir::Expr {
1282 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1283 ..
1284 })
1285 )
1286 });
1287 let pre = if in_match { "in the same arm, " } else { "" };
1288 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1289 self.suggest_adding_missing_ref_or_removing_ref(
1290 &mut err,
1291 span,
1292 var_ty,
1293 self.resolve_vars_if_possible(ty),
1294 ba,
1295 );
1296 err.emit();
1297 }
1298 }
1299
1300 fn suggest_adding_missing_ref_or_removing_ref(
1301 &self,
1302 err: &mut Diag<'_>,
1303 span: Span,
1304 expected: Ty<'tcx>,
1305 actual: Ty<'tcx>,
1306 ba: BindingMode,
1307 ) {
1308 match (expected.kind(), actual.kind(), ba) {
1309 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1310 if self.can_eq(self.param_env, *inner_ty, actual) =>
1311 {
1312 err.span_suggestion_verbose(
1313 span.shrink_to_lo(),
1314 "consider adding `ref`",
1315 "ref ",
1316 Applicability::MaybeIncorrect,
1317 );
1318 }
1319 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1320 if self.can_eq(self.param_env, expected, *inner_ty) =>
1321 {
1322 err.span_suggestion_verbose(
1323 span.with_hi(span.lo() + BytePos(4)),
1324 "consider removing `ref`",
1325 "",
1326 Applicability::MaybeIncorrect,
1327 );
1328 }
1329 _ => (),
1330 }
1331 }
1332
1333 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1335 let tcx = self.tcx;
1336 if let PatKind::Ref(inner, mutbl) = pat.kind
1337 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1338 {
1339 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1340 debug!(?inner, ?pat, ?binding_parent);
1341
1342 let mutability = match mutbl {
1343 ast::Mutability::Mut => "mut",
1344 ast::Mutability::Not => "",
1345 };
1346
1347 let mut_var_suggestion = 'block: {
1348 if mutbl.is_not() {
1349 break 'block None;
1350 }
1351
1352 let ident_kind = match binding_parent {
1353 hir::Node::Param(_) => "parameter",
1354 hir::Node::LetStmt(_) => "variable",
1355 hir::Node::Arm(_) => "binding",
1356
1357 hir::Node::Pat(Pat { kind, .. }) => match kind {
1360 PatKind::Struct(..)
1361 | PatKind::TupleStruct(..)
1362 | PatKind::Or(..)
1363 | PatKind::Guard(..)
1364 | PatKind::Tuple(..)
1365 | PatKind::Slice(..) => "binding",
1366
1367 PatKind::Missing
1368 | PatKind::Wild
1369 | PatKind::Never
1370 | PatKind::Binding(..)
1371 | PatKind::Box(..)
1372 | PatKind::Deref(_)
1373 | PatKind::Ref(..)
1374 | PatKind::Expr(..)
1375 | PatKind::Range(..)
1376 | PatKind::Err(_) => break 'block None,
1377 },
1378
1379 _ => break 'block None,
1381 };
1382
1383 Some((
1384 pat.span,
1385 format!("to declare a mutable {ident_kind} use"),
1386 format!("mut {binding}"),
1387 ))
1388 };
1389
1390 match binding_parent {
1391 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1394 err.multipart_suggestion_verbose(
1395 format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
1396 vec![
1397 (pat.span.until(inner.span), "".to_owned()),
1398 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1399 ],
1400 Applicability::MachineApplicable
1401 );
1402
1403 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1404 err.span_note(sp, format!("{msg}: `{sugg}`"));
1405 }
1406 }
1407 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1408 for i in pat_arr.iter() {
1409 if let PatKind::Ref(the_ref, _) = i.kind
1410 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1411 {
1412 let BindingMode(_, mtblty) = mt;
1413 err.span_suggestion_verbose(
1414 i.span,
1415 format!("consider removing `&{mutability}` from the pattern"),
1416 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1417 Applicability::MaybeIncorrect,
1418 );
1419 }
1420 }
1421 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1422 err.span_note(sp, format!("{msg}: `{sugg}`"));
1423 }
1424 }
1425 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1426 err.span_suggestion_verbose(
1428 pat.span.until(inner.span),
1429 format!("consider removing `&{mutability}` from the pattern"),
1430 "",
1431 Applicability::MaybeIncorrect,
1432 );
1433
1434 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1435 err.span_note(sp, format!("{msg}: `{sugg}`"));
1436 }
1437 }
1438 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1439 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1440 }
1441 _ => {} }
1443 }
1444 }
1445
1446 fn check_dereferenceable(
1447 &self,
1448 span: Span,
1449 expected: Ty<'tcx>,
1450 inner: &Pat<'_>,
1451 ) -> Result<(), ErrorGuaranteed> {
1452 if let PatKind::Binding(..) = inner.kind
1453 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1454 && let ty::Dynamic(..) = pointee_ty.kind()
1455 {
1456 let type_str = self.ty_to_string(expected);
1459 let mut err = struct_span_code_err!(
1460 self.dcx(),
1461 span,
1462 E0033,
1463 "type `{}` cannot be dereferenced",
1464 type_str
1465 );
1466 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1467 if self.tcx.sess.teach(err.code.unwrap()) {
1468 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1469 }
1470 return Err(err.emit());
1471 }
1472 Ok(())
1473 }
1474
1475 fn resolve_pat_struct(
1476 &self,
1477 pat: &'tcx Pat<'tcx>,
1478 qpath: &hir::QPath<'tcx>,
1479 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1480 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1482 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1483 }
1484
1485 fn check_pat_struct(
1486 &self,
1487 pat: &'tcx Pat<'tcx>,
1488 fields: &'tcx [hir::PatField<'tcx>],
1489 has_rest_pat: bool,
1490 pat_ty: Ty<'tcx>,
1491 variant: &'tcx VariantDef,
1492 expected: Ty<'tcx>,
1493 pat_info: PatInfo<'tcx>,
1494 ) -> Ty<'tcx> {
1495 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1497
1498 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1500 Ok(()) => pat_ty,
1501 Err(guar) => Ty::new_error(self.tcx, guar),
1502 }
1503 }
1504
1505 fn resolve_pat_path(
1506 &self,
1507 path_id: HirId,
1508 span: Span,
1509 qpath: &'tcx hir::QPath<'_>,
1510 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1511 let tcx = self.tcx;
1512
1513 let (res, opt_ty, segments) =
1514 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1515 match res {
1516 Res::Err => {
1517 let e =
1518 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1519 self.set_tainted_by_errors(e);
1520 return Err(e);
1521 }
1522 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1523 let expected = "unit struct, unit variant or constant";
1524 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1525 return Err(e);
1526 }
1527 Res::SelfCtor(def_id) => {
1528 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1529 && adt_def.is_struct()
1530 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1531 {
1532 } else {
1534 let e = report_unexpected_variant_res(
1535 tcx,
1536 res,
1537 None,
1538 qpath,
1539 span,
1540 E0533,
1541 "unit struct",
1542 );
1543 return Err(e);
1544 }
1545 }
1546 Res::Def(
1547 DefKind::Ctor(_, CtorKind::Const)
1548 | DefKind::Const
1549 | DefKind::AssocConst
1550 | DefKind::ConstParam,
1551 _,
1552 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1554 }
1555
1556 let (pat_ty, pat_res) =
1558 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1559 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1560 }
1561
1562 fn check_pat_path(
1563 &self,
1564 pat_id_for_diag: HirId,
1565 span: Span,
1566 resolved: &ResolvedPat<'tcx>,
1567 expected: Ty<'tcx>,
1568 ti: &TopInfo<'tcx>,
1569 ) -> Ty<'tcx> {
1570 if let Err(err) =
1571 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1572 {
1573 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1574 }
1575 resolved.ty
1576 }
1577
1578 fn maybe_suggest_range_literal(
1579 &self,
1580 e: &mut Diag<'_>,
1581 opt_def_id: Option<hir::def_id::DefId>,
1582 ident: Ident,
1583 ) -> bool {
1584 if let Some(def_id) = opt_def_id
1585 && let Some(hir::Node::Item(hir::Item {
1586 kind: hir::ItemKind::Const(_, _, _, body_id),
1587 ..
1588 })) = self.tcx.hir_get_if_local(def_id)
1589 && let hir::Node::Expr(expr) = self.tcx.hir_node(body_id.hir_id)
1590 && hir::is_range_literal(expr)
1591 {
1592 let span = self.tcx.hir_span(body_id.hir_id);
1593 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1594 e.span_suggestion_verbose(
1595 ident.span,
1596 "you may want to move the range into the match block",
1597 snip,
1598 Applicability::MachineApplicable,
1599 );
1600 return true;
1601 }
1602 }
1603 false
1604 }
1605
1606 fn emit_bad_pat_path(
1607 &self,
1608 mut e: Diag<'_>,
1609 hir_id: HirId,
1610 pat_span: Span,
1611 resolved_pat: &ResolvedPat<'tcx>,
1612 ) {
1613 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1614 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1615 };
1616
1617 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1618 e.span_label(span, format!("{} defined here", res.descr()));
1619 if let [hir::PathSegment { ident, .. }] = segments {
1620 e.span_label(
1621 pat_span,
1622 format!(
1623 "`{}` is interpreted as {} {}, not a new binding",
1624 ident,
1625 res.article(),
1626 res.descr(),
1627 ),
1628 );
1629 match self.tcx.parent_hir_node(hir_id) {
1630 hir::Node::PatField(..) => {
1631 e.span_suggestion_verbose(
1632 ident.span.shrink_to_hi(),
1633 "bind the struct field to a different name instead",
1634 format!(": other_{}", ident.as_str().to_lowercase()),
1635 Applicability::HasPlaceholders,
1636 );
1637 }
1638 _ => {
1639 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1640 ty::Adt(def, _) => match res {
1641 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1642 _ => (None, None),
1643 },
1644 _ => (None, None),
1645 };
1646
1647 let is_range = matches!(
1648 type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
1649 Some(
1650 LangItem::Range
1651 | LangItem::RangeFrom
1652 | LangItem::RangeTo
1653 | LangItem::RangeFull
1654 | LangItem::RangeInclusiveStruct
1655 | LangItem::RangeToInclusive,
1656 )
1657 );
1658 if is_range {
1659 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1660 let msg = "constants only support matching by type, \
1661 if you meant to match against a range of values, \
1662 consider using a range pattern like `min ..= max` in the match block";
1663 e.note(msg);
1664 }
1665 } else {
1666 let msg = "introduce a new binding instead";
1667 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1668 e.span_suggestion(
1669 ident.span,
1670 msg,
1671 sugg,
1672 Applicability::HasPlaceholders,
1673 );
1674 }
1675 }
1676 };
1677 }
1678 }
1679 e.emit();
1680 }
1681
1682 fn resolve_pat_tuple_struct(
1683 &self,
1684 pat: &'tcx Pat<'tcx>,
1685 qpath: &'tcx hir::QPath<'tcx>,
1686 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1687 let tcx = self.tcx;
1688 let report_unexpected_res = |res: Res| {
1689 let expected = "tuple struct or tuple variant";
1690 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1691 Err(e)
1692 };
1693
1694 let (res, opt_ty, segments) =
1696 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1697 if res == Res::Err {
1698 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1699 self.set_tainted_by_errors(e);
1700 return Err(e);
1701 }
1702
1703 let (pat_ty, res) =
1705 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1706 if !pat_ty.is_fn() {
1707 return report_unexpected_res(res);
1708 }
1709
1710 let variant = match res {
1711 Res::Err => {
1712 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1713 }
1714 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1715 return report_unexpected_res(res);
1716 }
1717 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1718 _ => bug!("unexpected pattern resolution: {:?}", res),
1719 };
1720
1721 let pat_ty = pat_ty.fn_sig(tcx).output();
1723 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1724
1725 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1726 }
1727
1728 fn check_pat_tuple_struct(
1729 &self,
1730 pat: &'tcx Pat<'tcx>,
1731 qpath: &'tcx hir::QPath<'tcx>,
1732 subpats: &'tcx [Pat<'tcx>],
1733 ddpos: hir::DotDotPos,
1734 res: Res,
1735 pat_ty: Ty<'tcx>,
1736 variant: &'tcx VariantDef,
1737 expected: Ty<'tcx>,
1738 pat_info: PatInfo<'tcx>,
1739 ) -> Ty<'tcx> {
1740 let tcx = self.tcx;
1741 let on_error = |e| {
1742 for pat in subpats {
1743 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1744 }
1745 };
1746
1747 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1749 let had_err = diag.map_err(|diag| diag.emit());
1750
1751 if subpats.len() == variant.fields.len()
1753 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1754 {
1755 let ty::Adt(_, args) = pat_ty.kind() else {
1756 bug!("unexpected pattern type {:?}", pat_ty);
1757 };
1758 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1759 let field = &variant.fields[FieldIdx::from_usize(i)];
1760 let field_ty = self.field_ty(subpat.span, field, args);
1761 self.check_pat(subpat, field_ty, pat_info);
1762
1763 self.tcx.check_stability(
1764 variant.fields[FieldIdx::from_usize(i)].did,
1765 Some(subpat.hir_id),
1766 subpat.span,
1767 None,
1768 );
1769 }
1770 if let Err(e) = had_err {
1771 on_error(e);
1772 return Ty::new_error(tcx, e);
1773 }
1774 } else {
1775 let e = self.emit_err_pat_wrong_number_of_fields(
1776 pat.span,
1777 res,
1778 qpath,
1779 subpats,
1780 &variant.fields.raw,
1781 expected,
1782 had_err,
1783 );
1784 on_error(e);
1785 return Ty::new_error(tcx, e);
1786 }
1787 pat_ty
1788 }
1789
1790 fn emit_err_pat_wrong_number_of_fields(
1791 &self,
1792 pat_span: Span,
1793 res: Res,
1794 qpath: &hir::QPath<'_>,
1795 subpats: &'tcx [Pat<'tcx>],
1796 fields: &'tcx [ty::FieldDef],
1797 expected: Ty<'tcx>,
1798 had_err: Result<(), ErrorGuaranteed>,
1799 ) -> ErrorGuaranteed {
1800 let subpats_ending = pluralize!(subpats.len());
1801 let fields_ending = pluralize!(fields.len());
1802
1803 let subpat_spans = if subpats.is_empty() {
1804 vec![pat_span]
1805 } else {
1806 subpats.iter().map(|p| p.span).collect()
1807 };
1808 let last_subpat_span = *subpat_spans.last().unwrap();
1809 let res_span = self.tcx.def_span(res.def_id());
1810 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1811 let field_def_spans = if fields.is_empty() {
1812 vec![res_span]
1813 } else {
1814 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1815 };
1816 let last_field_def_span = *field_def_spans.last().unwrap();
1817
1818 let mut err = struct_span_code_err!(
1819 self.dcx(),
1820 MultiSpan::from_spans(subpat_spans),
1821 E0023,
1822 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1823 subpats.len(),
1824 subpats_ending,
1825 res.descr(),
1826 fields.len(),
1827 fields_ending,
1828 );
1829 err.span_label(
1830 last_subpat_span,
1831 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1832 );
1833 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1834 err.span_label(qpath.span(), "");
1835 }
1836 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1837 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1838 }
1839 for span in &field_def_spans[..field_def_spans.len() - 1] {
1840 err.span_label(*span, "");
1841 }
1842 err.span_label(
1843 last_field_def_span,
1844 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1845 );
1846
1847 let missing_parentheses = match (expected.kind(), fields, had_err) {
1852 (ty::Adt(_, args), [field], Ok(())) => {
1856 let field_ty = self.field_ty(pat_span, field, args);
1857 match field_ty.kind() {
1858 ty::Tuple(fields) => fields.len() == subpats.len(),
1859 _ => false,
1860 }
1861 }
1862 _ => false,
1863 };
1864 if missing_parentheses {
1865 let (left, right) = match subpats {
1866 [] => (qpath.span().shrink_to_hi(), pat_span),
1875 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1884 };
1885 err.multipart_suggestion(
1886 "missing parentheses",
1887 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1888 Applicability::MachineApplicable,
1889 );
1890 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1891 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1892 let all_fields_span = match subpats {
1893 [] => after_fields_span,
1894 [field] => field.span,
1895 [first, .., last] => first.span.to(last.span),
1896 };
1897
1898 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1900 let first_tail_wildcard =
1901 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1902 (None, PatKind::Wild) => Some(pos),
1903 (Some(_), PatKind::Wild) => acc,
1904 _ => None,
1905 });
1906 let tail_span = match first_tail_wildcard {
1907 None => after_fields_span,
1908 Some(0) => subpats[0].span.to(after_fields_span),
1909 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1910 };
1911
1912 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1914 if !subpats.is_empty() {
1915 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1916 }
1917
1918 err.span_suggestion_verbose(
1919 after_fields_span,
1920 "use `_` to explicitly ignore each field",
1921 wildcard_sugg,
1922 Applicability::MaybeIncorrect,
1923 );
1924
1925 if fields.len() - subpats.len() > 1 || all_wildcards {
1928 if subpats.is_empty() || all_wildcards {
1929 err.span_suggestion_verbose(
1930 all_fields_span,
1931 "use `..` to ignore all fields",
1932 "..",
1933 Applicability::MaybeIncorrect,
1934 );
1935 } else {
1936 err.span_suggestion_verbose(
1937 tail_span,
1938 "use `..` to ignore the rest of the fields",
1939 ", ..",
1940 Applicability::MaybeIncorrect,
1941 );
1942 }
1943 }
1944 }
1945
1946 err.emit()
1947 }
1948
1949 fn check_pat_tuple(
1950 &self,
1951 span: Span,
1952 elements: &'tcx [Pat<'tcx>],
1953 ddpos: hir::DotDotPos,
1954 expected: Ty<'tcx>,
1955 pat_info: PatInfo<'tcx>,
1956 ) -> Ty<'tcx> {
1957 let tcx = self.tcx;
1958 let mut expected_len = elements.len();
1959 if ddpos.as_opt_usize().is_some() {
1960 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1962 expected_len = tys.len();
1963 }
1964 }
1965 let max_len = cmp::max(expected_len, elements.len());
1966
1967 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1968 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1969 let pat_ty = Ty::new_tup(tcx, element_tys);
1970 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
1971 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1974 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1975 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1976 }
1977 Ty::new_tup_from_iter(tcx, element_tys_iter)
1978 } else {
1979 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1980 self.check_pat(elem, element_tys[i], pat_info);
1981 }
1982 pat_ty
1983 }
1984 }
1985
1986 fn check_struct_pat_fields(
1987 &self,
1988 adt_ty: Ty<'tcx>,
1989 pat: &'tcx Pat<'tcx>,
1990 variant: &'tcx ty::VariantDef,
1991 fields: &'tcx [hir::PatField<'tcx>],
1992 has_rest_pat: bool,
1993 pat_info: PatInfo<'tcx>,
1994 ) -> Result<(), ErrorGuaranteed> {
1995 let tcx = self.tcx;
1996
1997 let ty::Adt(adt, args) = adt_ty.kind() else {
1998 span_bug!(pat.span, "struct pattern is not an ADT");
1999 };
2000
2001 let field_map = variant
2003 .fields
2004 .iter_enumerated()
2005 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
2006 .collect::<FxHashMap<_, _>>();
2007
2008 let mut used_fields = FxHashMap::default();
2010 let mut result = Ok(());
2011
2012 let mut inexistent_fields = vec![];
2013 for field in fields {
2015 let span = field.span;
2016 let ident = tcx.adjust_ident(field.ident, variant.def_id);
2017 let field_ty = match used_fields.entry(ident) {
2018 Occupied(occupied) => {
2019 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
2020 result = Err(guar);
2021 Ty::new_error(tcx, guar)
2022 }
2023 Vacant(vacant) => {
2024 vacant.insert(span);
2025 field_map
2026 .get(&ident)
2027 .map(|(i, f)| {
2028 self.write_field_index(field.hir_id, *i);
2029 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
2030 self.field_ty(span, f, args)
2031 })
2032 .unwrap_or_else(|| {
2033 inexistent_fields.push(field);
2034 Ty::new_misc_error(tcx)
2035 })
2036 }
2037 };
2038
2039 self.check_pat(field.pat, field_ty, pat_info);
2040 }
2041
2042 let mut unmentioned_fields = variant
2043 .fields
2044 .iter()
2045 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
2046 .filter(|(_, ident)| !used_fields.contains_key(ident))
2047 .collect::<Vec<_>>();
2048
2049 let inexistent_fields_err = if !inexistent_fields.is_empty()
2050 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
2051 {
2052 variant.has_errors()?;
2054 Some(self.error_inexistent_fields(
2055 adt.variant_descr(),
2056 &inexistent_fields,
2057 &mut unmentioned_fields,
2058 pat,
2059 variant,
2060 args,
2061 ))
2062 } else {
2063 None
2064 };
2065
2066 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
2068 if non_exhaustive && !has_rest_pat {
2069 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
2070 }
2071
2072 let mut unmentioned_err = None;
2073 if adt.is_union() {
2075 if fields.len() != 1 {
2076 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
2077 }
2078 if has_rest_pat {
2079 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
2080 }
2081 } else if !unmentioned_fields.is_empty() {
2082 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
2083 .iter()
2084 .copied()
2085 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
2086 .collect();
2087
2088 if !has_rest_pat {
2089 if accessible_unmentioned_fields.is_empty() {
2090 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
2091 } else {
2092 unmentioned_err = Some(self.error_unmentioned_fields(
2093 pat,
2094 &accessible_unmentioned_fields,
2095 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
2096 fields,
2097 ));
2098 }
2099 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
2100 self.lint_non_exhaustive_omitted_patterns(
2101 pat,
2102 &accessible_unmentioned_fields,
2103 adt_ty,
2104 )
2105 }
2106 }
2107 match (inexistent_fields_err, unmentioned_err) {
2108 (Some(i), Some(u)) => {
2109 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2110 i.delay_as_bug();
2113 u.delay_as_bug();
2114 Err(e)
2115 } else {
2116 i.emit();
2117 Err(u.emit())
2118 }
2119 }
2120 (None, Some(u)) => {
2121 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
2122 u.delay_as_bug();
2123 Err(e)
2124 } else {
2125 Err(u.emit())
2126 }
2127 }
2128 (Some(err), None) => Err(err.emit()),
2129 (None, None) => {
2130 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
2131 result
2132 }
2133 }
2134 }
2135
2136 fn error_tuple_variant_index_shorthand(
2137 &self,
2138 variant: &VariantDef,
2139 pat: &'_ Pat<'_>,
2140 fields: &[hir::PatField<'_>],
2141 ) -> Result<(), ErrorGuaranteed> {
2142 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
2146 (variant.ctor_kind(), &pat.kind)
2147 {
2148 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
2149 if has_shorthand_field_name {
2150 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2151 let mut err = struct_span_code_err!(
2152 self.dcx(),
2153 pat.span,
2154 E0769,
2155 "tuple variant `{path}` written as struct variant",
2156 );
2157 err.span_suggestion_verbose(
2158 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2159 "use the tuple variant pattern syntax instead",
2160 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
2161 Applicability::MaybeIncorrect,
2162 );
2163 return Err(err.emit());
2164 }
2165 }
2166 Ok(())
2167 }
2168
2169 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
2170 let sess = self.tcx.sess;
2171 let sm = sess.source_map();
2172 let sp_brace = sm.end_point(pat.span);
2173 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
2174 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
2175
2176 struct_span_code_err!(
2177 self.dcx(),
2178 pat.span,
2179 E0638,
2180 "`..` required with {descr} marked as non-exhaustive",
2181 )
2182 .with_span_suggestion_verbose(
2183 sp_comma,
2184 "add `..` at the end of the field list to ignore all other fields",
2185 sugg,
2186 Applicability::MachineApplicable,
2187 )
2188 .emit();
2189 }
2190
2191 fn error_field_already_bound(
2192 &self,
2193 span: Span,
2194 ident: Ident,
2195 other_field: Span,
2196 ) -> ErrorGuaranteed {
2197 struct_span_code_err!(
2198 self.dcx(),
2199 span,
2200 E0025,
2201 "field `{}` bound multiple times in the pattern",
2202 ident
2203 )
2204 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2205 .with_span_label(other_field, format!("first use of `{ident}`"))
2206 .emit()
2207 }
2208
2209 fn error_inexistent_fields(
2210 &self,
2211 kind_name: &str,
2212 inexistent_fields: &[&hir::PatField<'tcx>],
2213 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2214 pat: &'tcx Pat<'tcx>,
2215 variant: &ty::VariantDef,
2216 args: ty::GenericArgsRef<'tcx>,
2217 ) -> Diag<'a> {
2218 let tcx = self.tcx;
2219 let (field_names, t, plural) = if let [field] = inexistent_fields {
2220 (format!("a field named `{}`", field.ident), "this", "")
2221 } else {
2222 (
2223 format!(
2224 "fields named {}",
2225 inexistent_fields
2226 .iter()
2227 .map(|field| format!("`{}`", field.ident))
2228 .collect::<Vec<String>>()
2229 .join(", ")
2230 ),
2231 "these",
2232 "s",
2233 )
2234 };
2235 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2236 let mut err = struct_span_code_err!(
2237 self.dcx(),
2238 spans,
2239 E0026,
2240 "{} `{}` does not have {}",
2241 kind_name,
2242 tcx.def_path_str(variant.def_id),
2243 field_names
2244 );
2245 if let Some(pat_field) = inexistent_fields.last() {
2246 err.span_label(
2247 pat_field.ident.span,
2248 format!(
2249 "{} `{}` does not have {} field{}",
2250 kind_name,
2251 tcx.def_path_str(variant.def_id),
2252 t,
2253 plural
2254 ),
2255 );
2256
2257 if let [(field_def, field)] = unmentioned_fields.as_slice()
2258 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2259 {
2260 let suggested_name =
2261 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2262 if let Some(suggested_name) = suggested_name {
2263 err.span_suggestion(
2264 pat_field.ident.span,
2265 "a field with a similar name exists",
2266 suggested_name,
2267 Applicability::MaybeIncorrect,
2268 );
2269
2270 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2276 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2278 }
2279 } else if inexistent_fields.len() == 1 {
2280 match pat_field.pat.kind {
2281 PatKind::Expr(_)
2282 if !self.may_coerce(
2283 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2284 self.field_ty(field.span, field_def, args),
2285 ) => {}
2286 _ => {
2287 err.span_suggestion_short(
2288 pat_field.ident.span,
2289 format!(
2290 "`{}` has a field named `{}`",
2291 tcx.def_path_str(variant.def_id),
2292 field.name,
2293 ),
2294 field.name,
2295 Applicability::MaybeIncorrect,
2296 );
2297 }
2298 }
2299 }
2300 }
2301 }
2302 if tcx.sess.teach(err.code.unwrap()) {
2303 err.note(
2304 "This error indicates that a struct pattern attempted to \
2305 extract a nonexistent field from a struct. Struct fields \
2306 are identified by the name used before the colon : so struct \
2307 patterns should resemble the declaration of the struct type \
2308 being matched.\n\n\
2309 If you are using shorthand field patterns but want to refer \
2310 to the struct field by a different name, you should rename \
2311 it explicitly.",
2312 );
2313 }
2314 err
2315 }
2316
2317 fn error_tuple_variant_as_struct_pat(
2318 &self,
2319 pat: &Pat<'_>,
2320 fields: &'tcx [hir::PatField<'tcx>],
2321 variant: &ty::VariantDef,
2322 ) -> Result<(), ErrorGuaranteed> {
2323 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2324 (variant.ctor_kind(), &pat.kind)
2325 {
2326 let is_tuple_struct_match = !pattern_fields.is_empty()
2327 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2328 if is_tuple_struct_match {
2329 return Ok(());
2330 }
2331
2332 variant.has_errors()?;
2334
2335 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2336 let mut err = struct_span_code_err!(
2337 self.dcx(),
2338 pat.span,
2339 E0769,
2340 "tuple variant `{}` written as struct variant",
2341 path
2342 );
2343 let (sugg, appl) = if fields.len() == variant.fields.len() {
2344 (
2345 self.get_suggested_tuple_struct_pattern(fields, variant),
2346 Applicability::MachineApplicable,
2347 )
2348 } else {
2349 (
2350 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2351 Applicability::MaybeIncorrect,
2352 )
2353 };
2354 err.span_suggestion_verbose(
2355 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2356 "use the tuple variant pattern syntax instead",
2357 format!("({sugg})"),
2358 appl,
2359 );
2360 return Err(err.emit());
2361 }
2362 Ok(())
2363 }
2364
2365 fn get_suggested_tuple_struct_pattern(
2366 &self,
2367 fields: &[hir::PatField<'_>],
2368 variant: &VariantDef,
2369 ) -> String {
2370 let variant_field_idents =
2371 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2372 fields
2373 .iter()
2374 .map(|field| {
2375 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2376 Ok(f) => {
2377 if variant_field_idents.contains(&field.ident) {
2380 String::from("_")
2381 } else {
2382 f
2383 }
2384 }
2385 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2386 }
2387 })
2388 .collect::<Vec<String>>()
2389 .join(", ")
2390 }
2391
2392 fn error_no_accessible_fields(
2408 &self,
2409 pat: &Pat<'_>,
2410 fields: &'tcx [hir::PatField<'tcx>],
2411 ) -> Diag<'a> {
2412 let mut err = self
2413 .dcx()
2414 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2415
2416 if let Some(field) = fields.last() {
2417 err.span_suggestion_verbose(
2418 field.span.shrink_to_hi(),
2419 "ignore the inaccessible and unused fields",
2420 ", ..",
2421 Applicability::MachineApplicable,
2422 );
2423 } else {
2424 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2425 qpath.span()
2426 } else {
2427 bug!("`error_no_accessible_fields` called on non-struct pattern");
2428 };
2429
2430 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2432 err.span_suggestion_verbose(
2433 span,
2434 "ignore the inaccessible and unused fields",
2435 " { .. }",
2436 Applicability::MachineApplicable,
2437 );
2438 }
2439 err
2440 }
2441
2442 fn lint_non_exhaustive_omitted_patterns(
2447 &self,
2448 pat: &Pat<'_>,
2449 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2450 ty: Ty<'tcx>,
2451 ) {
2452 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2453 const LIMIT: usize = 3;
2454 match witnesses {
2455 [] => {
2456 unreachable!(
2457 "expected an uncovered pattern, otherwise why are we emitting an error?"
2458 )
2459 }
2460 [witness] => format!("`{witness}`"),
2461 [head @ .., tail] if head.len() < LIMIT => {
2462 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2463 format!("`{}` and `{}`", head.join("`, `"), tail)
2464 }
2465 _ => {
2466 let (head, tail) = witnesses.split_at(LIMIT);
2467 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2468 format!("`{}` and {} more", head.join("`, `"), tail.len())
2469 }
2470 }
2471 }
2472 let joined_patterns = joined_uncovered_patterns(
2473 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2474 );
2475
2476 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2477 lint.primary_message("some fields are not explicitly listed");
2478 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2479 lint.help(
2480 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2481 );
2482 lint.note(format!(
2483 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2484 ));
2485 });
2486 }
2487
2488 fn error_unmentioned_fields(
2498 &self,
2499 pat: &Pat<'_>,
2500 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2501 have_inaccessible_fields: bool,
2502 fields: &'tcx [hir::PatField<'tcx>],
2503 ) -> Diag<'a> {
2504 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2505 let field_names = if let [(_, field)] = unmentioned_fields {
2506 format!("field `{field}`{inaccessible}")
2507 } else {
2508 let fields = unmentioned_fields
2509 .iter()
2510 .map(|(_, name)| format!("`{name}`"))
2511 .collect::<Vec<String>>()
2512 .join(", ");
2513 format!("fields {fields}{inaccessible}")
2514 };
2515 let mut err = struct_span_code_err!(
2516 self.dcx(),
2517 pat.span,
2518 E0027,
2519 "pattern does not mention {}",
2520 field_names
2521 );
2522 err.span_label(pat.span, format!("missing {field_names}"));
2523 let len = unmentioned_fields.len();
2524 let (prefix, postfix, sp) = match fields {
2525 [] => match &pat.kind {
2526 PatKind::Struct(path, [], None) => {
2527 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2528 }
2529 _ => return err,
2530 },
2531 [.., field] => {
2532 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2535 match &pat.kind {
2536 PatKind::Struct(..) => (", ", " }", tail),
2537 _ => return err,
2538 }
2539 }
2540 };
2541 err.span_suggestion(
2542 sp,
2543 format!(
2544 "include the missing field{} in the pattern{}",
2545 pluralize!(len),
2546 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2547 ),
2548 format!(
2549 "{}{}{}{}",
2550 prefix,
2551 unmentioned_fields
2552 .iter()
2553 .map(|(_, name)| {
2554 let field_name = name.to_string();
2555 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2556 })
2557 .collect::<Vec<_>>()
2558 .join(", "),
2559 if have_inaccessible_fields { ", .." } else { "" },
2560 postfix,
2561 ),
2562 Applicability::MachineApplicable,
2563 );
2564 err.span_suggestion(
2565 sp,
2566 format!(
2567 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2568 these = pluralize!("this", len),
2569 s = pluralize!(len),
2570 them = if len == 1 { "it" } else { "them" },
2571 ),
2572 format!(
2573 "{}{}{}{}",
2574 prefix,
2575 unmentioned_fields
2576 .iter()
2577 .map(|(_, name)| {
2578 let field_name = name.to_string();
2579 format!("{field_name}: _")
2580 })
2581 .collect::<Vec<_>>()
2582 .join(", "),
2583 if have_inaccessible_fields { ", .." } else { "" },
2584 postfix,
2585 ),
2586 Applicability::MachineApplicable,
2587 );
2588 err.span_suggestion(
2589 sp,
2590 "or always ignore missing fields here",
2591 format!("{prefix}..{postfix}"),
2592 Applicability::MachineApplicable,
2593 );
2594 err
2595 }
2596
2597 fn check_pat_box(
2598 &self,
2599 span: Span,
2600 inner: &'tcx Pat<'tcx>,
2601 expected: Ty<'tcx>,
2602 pat_info: PatInfo<'tcx>,
2603 ) -> Ty<'tcx> {
2604 let tcx = self.tcx;
2605 let (box_ty, inner_ty) = self
2606 .check_dereferenceable(span, expected, inner)
2607 .and_then(|()| {
2608 let inner_ty = self.next_ty_var(inner.span);
2611 let box_ty = Ty::new_box(tcx, inner_ty);
2612 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2613 Ok((box_ty, inner_ty))
2614 })
2615 .unwrap_or_else(|guar| {
2616 let err = Ty::new_error(tcx, guar);
2617 (err, err)
2618 });
2619 self.check_pat(inner, inner_ty, pat_info);
2620 box_ty
2621 }
2622
2623 fn check_pat_deref(
2624 &self,
2625 span: Span,
2626 inner: &'tcx Pat<'tcx>,
2627 expected: Ty<'tcx>,
2628 pat_info: PatInfo<'tcx>,
2629 ) -> Ty<'tcx> {
2630 let target_ty = self.deref_pat_target(span, expected);
2631 self.check_pat(inner, target_ty, pat_info);
2632 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2633 expected
2634 }
2635
2636 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2637 let tcx = self.tcx;
2639 self.register_bound(
2640 source_ty,
2641 tcx.require_lang_item(hir::LangItem::DerefPure, span),
2642 self.misc(span),
2643 );
2644 let target_ty = Ty::new_projection(
2646 tcx,
2647 tcx.require_lang_item(hir::LangItem::DerefTarget, span),
2648 [source_ty],
2649 );
2650 let target_ty = self.normalize(span, target_ty);
2651 self.try_structurally_resolve_type(span, target_ty)
2652 }
2653
2654 fn register_deref_mut_bounds_if_needed(
2659 &self,
2660 span: Span,
2661 inner: &'tcx Pat<'tcx>,
2662 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2663 ) {
2664 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2665 for mutably_derefed_ty in derefed_tys {
2666 self.register_bound(
2667 mutably_derefed_ty,
2668 self.tcx.require_lang_item(hir::LangItem::DerefMut, span),
2669 self.misc(span),
2670 );
2671 }
2672 }
2673 }
2674
2675 fn check_pat_ref(
2677 &self,
2678 pat: &'tcx Pat<'tcx>,
2679 inner: &'tcx Pat<'tcx>,
2680 pat_mutbl: Mutability,
2681 mut expected: Ty<'tcx>,
2682 mut pat_info: PatInfo<'tcx>,
2683 ) -> Ty<'tcx> {
2684 let tcx = self.tcx;
2685
2686 let pat_prefix_span =
2687 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2688
2689 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2690 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2691 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2696 }
2697
2698 expected = self.try_structurally_resolve_type(pat.span, expected);
2699 if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode
2702 && (!self.tcx.features().pin_ergonomics() || inh_pin == Pinnedness::Not)
2705 {
2706 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2707 InheritedRefMatchRule::EatOuter => {
2708 if pat_mutbl > inh_mut {
2710 debug_assert!(ref_pat_matches_mut_ref);
2715 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2716 }
2717
2718 pat_info.binding_mode = ByRef::No;
2719 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2720 self.check_pat(inner, expected, pat_info);
2721 return expected;
2722 }
2723 InheritedRefMatchRule::EatInner => {
2724 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2725 && pat_mutbl <= r_mutbl
2726 {
2727 debug_assert!(ref_pat_matches_mut_ref);
2734 debug_assert!(self.downgrade_mut_inside_shared());
2738 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2739 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2740 } else {
2741 if pat_mutbl > inh_mut {
2744 debug_assert!(ref_pat_matches_mut_ref);
2753 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2754 }
2755
2756 pat_info.binding_mode = ByRef::No;
2757 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2758 self.check_pat(inner, expected, pat_info);
2759 return expected;
2760 }
2761 }
2762 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2763 pat_info.binding_mode = ByRef::No;
2765
2766 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2767 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2769 self.check_pat(inner, inner_ty, pat_info);
2776 return expected;
2777 } else {
2778 }
2785 } else {
2786 if pat_mutbl > inh_mut {
2789 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2791 }
2792
2793 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2794 self.check_pat(inner, expected, pat_info);
2795 return expected;
2796 }
2797 }
2798 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2799 pat_info.binding_mode = ByRef::No;
2802 self.add_rust_2024_migration_desugared_pat(
2803 pat_info.top_info.hir_id,
2804 pat,
2805 match pat_mutbl {
2806 Mutability::Not => '&', Mutability::Mut => 't', },
2809 inh_mut,
2810 )
2811 }
2812 }
2813 }
2814
2815 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2816 Ok(()) => {
2817 debug!("check_pat_ref: expected={:?}", expected);
2824 match *expected.kind() {
2825 ty::Ref(_, r_ty, r_mutbl)
2826 if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2827 || r_mutbl == pat_mutbl =>
2828 {
2829 if r_mutbl == Mutability::Not {
2830 pat_info.max_ref_mutbl = MutblCap::Not;
2831 }
2832
2833 (expected, r_ty)
2834 }
2835
2836 _ => {
2837 let inner_ty = self.next_ty_var(inner.span);
2838 let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
2839 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2840 let err = self.demand_eqtype_pat_diag(
2841 pat.span,
2842 expected,
2843 ref_ty,
2844 &pat_info.top_info,
2845 );
2846
2847 if let Err(mut err) = err {
2850 self.borrow_pat_suggestion(&mut err, pat);
2851 err.emit();
2852 }
2853 (ref_ty, inner_ty)
2854 }
2855 }
2856 }
2857 Err(guar) => {
2858 let err = Ty::new_error(tcx, guar);
2859 (err, err)
2860 }
2861 };
2862
2863 self.check_pat(inner, inner_ty, pat_info);
2864 ref_ty
2865 }
2866
2867 fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
2869 let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
2870 Ty::new_ref(self.tcx, region, ty, mutbl)
2871 }
2872
2873 fn error_inherited_ref_mutability_mismatch(
2874 &self,
2875 pat: &'tcx Pat<'tcx>,
2876 pat_prefix_span: Option<Span>,
2877 ) -> ErrorGuaranteed {
2878 let err_msg = "mismatched types";
2879 let err = if let Some(span) = pat_prefix_span {
2880 let mut err = self.dcx().struct_span_err(span, err_msg);
2881 err.code(E0308);
2882 err.note("cannot match inherited `&` with `&mut` pattern");
2883 err.span_suggestion_verbose(
2884 span,
2885 "replace this `&mut` pattern with `&`",
2886 "&",
2887 Applicability::MachineApplicable,
2888 );
2889 err
2890 } else {
2891 self.dcx().struct_span_err(pat.span, err_msg)
2892 };
2893 err.emit()
2894 }
2895
2896 fn try_resolve_slice_ty_to_array_ty(
2897 &self,
2898 before: &'tcx [Pat<'tcx>],
2899 slice: Option<&'tcx Pat<'tcx>>,
2900 span: Span,
2901 ) -> Option<Ty<'tcx>> {
2902 if slice.is_some() {
2903 return None;
2904 }
2905
2906 let tcx = self.tcx;
2907 let len = before.len();
2908 let inner_ty = self.next_ty_var(span);
2909
2910 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2911 }
2912
2913 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2944 match decl_origin {
2945 Some(DeclOrigin::LocalDecl { els: None }) => true,
2946 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2947 }
2948 }
2949
2950 fn check_pat_slice(
2961 &self,
2962 span: Span,
2963 before: &'tcx [Pat<'tcx>],
2964 slice: Option<&'tcx Pat<'tcx>>,
2965 after: &'tcx [Pat<'tcx>],
2966 expected: Ty<'tcx>,
2967 pat_info: PatInfo<'tcx>,
2968 ) -> Ty<'tcx> {
2969 let expected = self.try_structurally_resolve_type(span, expected);
2970
2971 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
2974 if let Some(resolved_arr_ty) =
2975 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
2976 {
2977 debug!(?resolved_arr_ty);
2978 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
2979 }
2980 }
2981
2982 let expected = self.structurally_resolve_type(span, expected);
2983 debug!(?expected);
2984
2985 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
2986 ty::Array(element_ty, len) => {
2988 let min = before.len() as u64 + after.len() as u64;
2989 let (opt_slice_ty, expected) =
2990 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
2991 assert!(opt_slice_ty.is_some() || slice.is_none());
2994 (element_ty, opt_slice_ty, expected)
2995 }
2996 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
2997 _ => {
2999 let guar = expected.error_reported().err().unwrap_or_else(|| {
3000 self.error_expected_array_or_slice(span, expected, pat_info)
3001 });
3002 let err = Ty::new_error(self.tcx, guar);
3003 (err, Some(err), err)
3004 }
3005 };
3006
3007 for elt in before {
3009 self.check_pat(elt, element_ty, pat_info);
3010 }
3011 if let Some(slice) = slice {
3013 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
3014 }
3015 for elt in after {
3017 self.check_pat(elt, element_ty, pat_info);
3018 }
3019 inferred
3020 }
3021
3022 fn check_array_pat_len(
3027 &self,
3028 span: Span,
3029 element_ty: Ty<'tcx>,
3030 arr_ty: Ty<'tcx>,
3031 slice: Option<&'tcx Pat<'tcx>>,
3032 len: ty::Const<'tcx>,
3033 min_len: u64,
3034 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
3035 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
3036
3037 let guar = if let Some(len) = len {
3038 if slice.is_none() {
3040 if min_len == len {
3044 return (None, arr_ty);
3045 }
3046
3047 self.error_scrutinee_inconsistent_length(span, min_len, len)
3048 } else if let Some(pat_len) = len.checked_sub(min_len) {
3049 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
3052 } else {
3053 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
3056 }
3057 } else if slice.is_none() {
3058 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
3061 self.demand_eqtype(span, updated_arr_ty, arr_ty);
3062 return (None, updated_arr_ty);
3063 } else {
3064 self.error_scrutinee_unfixed_length(span)
3068 };
3069
3070 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
3072 }
3073
3074 fn error_scrutinee_inconsistent_length(
3075 &self,
3076 span: Span,
3077 min_len: u64,
3078 size: u64,
3079 ) -> ErrorGuaranteed {
3080 struct_span_code_err!(
3081 self.dcx(),
3082 span,
3083 E0527,
3084 "pattern requires {} element{} but array has {}",
3085 min_len,
3086 pluralize!(min_len),
3087 size,
3088 )
3089 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
3090 .emit()
3091 }
3092
3093 fn error_scrutinee_with_rest_inconsistent_length(
3094 &self,
3095 span: Span,
3096 min_len: u64,
3097 size: u64,
3098 ) -> ErrorGuaranteed {
3099 struct_span_code_err!(
3100 self.dcx(),
3101 span,
3102 E0528,
3103 "pattern requires at least {} element{} but array has {}",
3104 min_len,
3105 pluralize!(min_len),
3106 size,
3107 )
3108 .with_span_label(
3109 span,
3110 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
3111 )
3112 .emit()
3113 }
3114
3115 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
3116 struct_span_code_err!(
3117 self.dcx(),
3118 span,
3119 E0730,
3120 "cannot pattern-match on an array without a fixed length",
3121 )
3122 .emit()
3123 }
3124
3125 fn error_expected_array_or_slice(
3126 &self,
3127 span: Span,
3128 expected_ty: Ty<'tcx>,
3129 pat_info: PatInfo<'tcx>,
3130 ) -> ErrorGuaranteed {
3131 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
3132
3133 let mut slice_pat_semantics = false;
3134 let mut as_deref = None;
3135 let mut slicing = None;
3136 if let ty::Ref(_, ty, _) = expected_ty.kind()
3137 && let ty::Array(..) | ty::Slice(..) = ty.kind()
3138 {
3139 slice_pat_semantics = true;
3140 } else if self
3141 .autoderef(span, expected_ty)
3142 .silence_errors()
3143 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
3144 && let Some(span) = ti.span
3145 && let Some(_) = ti.origin_expr
3146 {
3147 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
3148 let (is_slice_or_array_or_vector, resolved_ty) =
3149 self.is_slice_or_array_or_vector(resolved_ty);
3150 match resolved_ty.kind() {
3151 ty::Adt(adt_def, _)
3152 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
3153 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
3154 {
3155 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
3157 }
3158 _ => (),
3159 }
3160
3161 let is_top_level = current_depth <= 1;
3162 if is_slice_or_array_or_vector && is_top_level {
3163 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
3164 }
3165 }
3166 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
3167 span,
3168 ty: expected_ty,
3169 slice_pat_semantics,
3170 as_deref,
3171 slicing,
3172 })
3173 }
3174
3175 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
3176 match ty.kind() {
3177 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
3178 (true, ty)
3179 }
3180 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
3181 ty::Slice(..) | ty::Array(..) => (true, ty),
3182 _ => (false, ty),
3183 }
3184 }
3185
3186 fn add_rust_2024_migration_desugared_pat(
3189 &self,
3190 pat_id: HirId,
3191 subpat: &'tcx Pat<'tcx>,
3192 final_char: char,
3193 def_br_mutbl: Mutability,
3194 ) {
3195 let from_expansion = subpat.span.from_expansion();
3197 let trimmed_span = if from_expansion {
3198 subpat.span
3200 } else {
3201 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3202 trimmed.with_ctxt(subpat.span.ctxt())
3205 };
3206
3207 let mut typeck_results = self.typeck_results.borrow_mut();
3208 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3209 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3214 primary_labels: Vec::new(),
3215 bad_ref_modifiers: false,
3216 bad_mut_modifiers: false,
3217 bad_ref_pats: false,
3218 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3219 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3220 });
3221
3222 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3223 info.suggest_eliding_modes &= matches!(
3227 user_bind_annot,
3228 BindingMode(ByRef::Yes(_, mutbl), Mutability::Not) if mutbl == def_br_mutbl
3229 );
3230 if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) {
3231 info.bad_mut_modifiers = true;
3232 "`mut` binding modifier"
3233 } else {
3234 info.bad_ref_modifiers = true;
3235 match user_bind_annot.1 {
3236 Mutability::Not => "explicit `ref` binding modifier",
3237 Mutability::Mut => "explicit `ref mut` binding modifier",
3238 }
3239 }
3240 } else {
3241 info.bad_ref_pats = true;
3242 info.suggest_eliding_modes = false;
3246 "reference pattern"
3247 };
3248 let primary_label = if from_expansion {
3251 info.suggest_eliding_modes = false;
3253 "occurs within macro expansion".to_owned()
3257 } else {
3258 format!("{pat_kind} not allowed when implicitly borrowing")
3259 };
3260 info.primary_labels.push((trimmed_span, primary_label));
3261 }
3262}