1use std::cmp;
2use std::collections::hash_map::Entry::{Occupied, Vacant};
3
4use rustc_abi::FieldIdx;
5use rustc_ast as ast;
6use rustc_data_structures::fx::FxHashMap;
7use rustc_errors::codes::*;
8use rustc_errors::{
9 Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
10};
11use rustc_hir::def::{CtorKind, DefKind, Res};
12use rustc_hir::def_id::DefId;
13use rustc_hir::pat_util::EnumerateAndAdjustIterator;
14use rustc_hir::{
15 self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
16 PatExprKind, PatKind, expr_needs_parens,
17};
18use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
19use rustc_infer::infer;
20use rustc_middle::traits::PatternOriginExpr;
21use rustc_middle::ty::{self, Ty, TypeVisitableExt};
22use rustc_middle::{bug, span_bug};
23use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
24use rustc_session::parse::feature_err;
25use rustc_span::edit_distance::find_best_match_for_name;
26use rustc_span::edition::Edition;
27use rustc_span::hygiene::DesugaringKind;
28use rustc_span::source_map::Spanned;
29use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym};
30use rustc_trait_selection::infer::InferCtxtExt;
31use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
32use tracing::{debug, instrument, trace};
33use ty::VariantDef;
34use ty::adjustment::{PatAdjust, PatAdjustment};
35
36use super::report_unexpected_variant_res;
37use crate::expectation::Expectation;
38use crate::gather_locals::DeclOrigin;
39use crate::{FnCtxt, errors};
40
41const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
42This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
43pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \
44this type has no compile-time size. Therefore, all accesses to trait types must be through \
45pointers. If you encounter this error you should try to avoid dereferencing the pointer.
46
47You can read more about trait objects in the Trait Objects section of the Reference: \
48https://doc.rust-lang.org/reference/types.html#trait-objects";
49
50fn is_number(text: &str) -> bool {
51 text.chars().all(|c: char| c.is_digit(10))
52}
53
54#[derive(Copy, Clone)]
58struct TopInfo<'tcx> {
59 expected: Ty<'tcx>,
61 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
65 span: Option<Span>,
88 hir_id: HirId,
90}
91
92#[derive(Copy, Clone)]
93struct PatInfo<'tcx> {
94 binding_mode: ByRef,
95 max_ref_mutbl: MutblCap,
96 top_info: TopInfo<'tcx>,
97 decl_origin: Option<DeclOrigin<'tcx>>,
98
99 current_depth: u32,
101}
102
103impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
104 fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
105 let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
110 let mut count = 0;
111
112 while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
116 cur_expr = inner;
117 count += 1;
118 }
119
120 PatternOriginExpr {
121 peeled_span: cur_expr.span,
122 peeled_count: count,
123 peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
124 }
125 });
126
127 let code = ObligationCauseCode::Pattern {
128 span: ti.span,
129 root_ty: ti.expected,
130 origin_expr: origin_expr_info,
131 };
132 self.cause(cause_span, code)
133 }
134
135 fn demand_eqtype_pat_diag(
136 &'a self,
137 cause_span: Span,
138 expected: Ty<'tcx>,
139 actual: Ty<'tcx>,
140 ti: &TopInfo<'tcx>,
141 ) -> Result<(), Diag<'a>> {
142 self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
143 .map_err(|mut diag| {
144 if let Some(expr) = ti.origin_expr {
145 self.suggest_fn_call(&mut diag, expr, expected, |output| {
146 self.can_eq(self.param_env, output, actual)
147 });
148 }
149 diag
150 })
151 }
152
153 fn demand_eqtype_pat(
154 &self,
155 cause_span: Span,
156 expected: Ty<'tcx>,
157 actual: Ty<'tcx>,
158 ti: &TopInfo<'tcx>,
159 ) -> Result<(), ErrorGuaranteed> {
160 self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit())
161 }
162}
163
164#[derive(Clone, Copy, Debug, PartialEq, Eq)]
166enum AdjustMode {
167 Peel { kind: PeelKind },
170 Pass,
172}
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq)]
176enum PeelKind {
177 ExplicitDerefPat,
180 Implicit { until_adt: Option<DefId> },
185}
186
187impl AdjustMode {
188 const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
189 AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } }
190 }
191 const fn peel_all() -> AdjustMode {
192 AdjustMode::peel_until_adt(None)
193 }
194}
195
196#[derive(Clone, Copy, Debug, PartialEq, Eq)]
207enum MutblCap {
208 Not,
210
211 WeaklyNot(Option<Span>),
218
219 Mut,
221}
222
223impl MutblCap {
224 #[must_use]
225 fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
226 match self {
227 MutblCap::Not => MutblCap::Not,
228 _ => MutblCap::WeaklyNot(span),
229 }
230 }
231
232 #[must_use]
233 fn as_mutbl(self) -> Mutability {
234 match self {
235 MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
236 MutblCap::Mut => Mutability::Mut,
237 }
238 }
239}
240
241#[derive(Clone, Copy, Debug, PartialEq, Eq)]
247enum InheritedRefMatchRule {
248 EatOuter,
252 EatInner,
255 EatBoth {
258 consider_inherited_ref: bool,
268 },
269}
270
271#[derive(Clone, Copy, Debug)]
280struct ResolvedPat<'tcx> {
281 ty: Ty<'tcx>,
284 kind: ResolvedPatKind<'tcx>,
285}
286
287#[derive(Clone, Copy, Debug)]
288enum ResolvedPatKind<'tcx> {
289 Path { res: Res, pat_res: Res, segments: &'tcx [hir::PathSegment<'tcx>] },
290 Struct { variant: &'tcx VariantDef },
291 TupleStruct { res: Res, variant: &'tcx VariantDef },
292}
293
294impl<'tcx> ResolvedPat<'tcx> {
295 fn adjust_mode(&self) -> AdjustMode {
296 if let ResolvedPatKind::Path { res, .. } = self.kind
297 && matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
298 {
299 AdjustMode::Pass
303 } else {
304 AdjustMode::peel_until_adt(self.ty.ty_adt_def().map(|adt| adt.did()))
308 }
309 }
310}
311
312impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
313 fn downgrade_mut_inside_shared(&self) -> bool {
317 self.tcx.features().ref_pat_eat_one_layer_2024_structural()
320 }
321
322 fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule {
325 if edition.at_least_rust_2024() {
328 if self.tcx.features().ref_pat_eat_one_layer_2024() {
329 InheritedRefMatchRule::EatOuter
330 } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() {
331 InheritedRefMatchRule::EatInner
332 } else {
333 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false }
336 }
337 } else {
338 InheritedRefMatchRule::EatBoth {
339 consider_inherited_ref: self.tcx.features().ref_pat_eat_one_layer_2024()
340 || self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
341 }
342 }
343 }
344
345 fn ref_pat_matches_mut_ref(&self) -> bool {
348 self.tcx.features().ref_pat_eat_one_layer_2024()
351 || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
352 }
353
354 pub(crate) fn check_pat_top(
363 &self,
364 pat: &'tcx Pat<'tcx>,
365 expected: Ty<'tcx>,
366 span: Option<Span>,
367 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
368 decl_origin: Option<DeclOrigin<'tcx>>,
369 ) {
370 let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
371 let pat_info = PatInfo {
372 binding_mode: ByRef::No,
373 max_ref_mutbl: MutblCap::Mut,
374 top_info,
375 decl_origin,
376 current_depth: 0,
377 };
378 self.check_pat(pat, expected, pat_info);
379 }
380
381 #[instrument(level = "debug", skip(self, pat_info))]
387 fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
388 let opt_path_res = match pat.kind {
391 PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
392 Some(self.resolve_pat_path(*hir_id, *span, qpath))
393 }
394 PatKind::Struct(ref qpath, ..) => Some(self.resolve_pat_struct(pat, qpath)),
395 PatKind::TupleStruct(ref qpath, ..) => Some(self.resolve_pat_tuple_struct(pat, qpath)),
396 _ => None,
397 };
398 let adjust_mode = self.calc_adjust_mode(pat, opt_path_res);
399 let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
400 self.write_ty(pat.hir_id, ty);
401
402 if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id)
405 && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref)
406 {
407 self.register_deref_mut_bounds_if_needed(
408 pat.span,
409 pat,
410 derefed_tys.iter().filter_map(|adjust| match adjust.kind {
411 PatAdjust::OverloadedDeref => Some(adjust.source),
412 PatAdjust::BuiltinDeref => None,
413 }),
414 );
415 }
416
417 }
459
460 fn check_pat_inner(
462 &self,
463 pat: &'tcx Pat<'tcx>,
464 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
465 adjust_mode: AdjustMode,
466 expected: Ty<'tcx>,
467 pat_info: PatInfo<'tcx>,
468 ) -> Ty<'tcx> {
469 #[cfg(debug_assertions)]
470 if pat_info.binding_mode == ByRef::Yes(Mutability::Mut)
471 && pat_info.max_ref_mutbl != MutblCap::Mut
472 && self.downgrade_mut_inside_shared()
473 {
474 span_bug!(pat.span, "Pattern mutability cap violated!");
475 }
476
477 let expected = if let AdjustMode::Peel { .. } = adjust_mode
479 && pat.default_binding_modes
480 {
481 self.try_structurally_resolve_type(pat.span, expected)
482 } else {
483 expected
484 };
485 let old_pat_info = pat_info;
486 let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
487
488 match pat.kind {
489 _ if let AdjustMode::Peel { .. } = adjust_mode
492 && pat.default_binding_modes
493 && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() =>
494 {
495 debug!("inspecting {:?}", expected);
496
497 debug!("current discriminant is Ref, inserting implicit deref");
498 self.typeck_results
500 .borrow_mut()
501 .pat_adjustments_mut()
502 .entry(pat.hir_id)
503 .or_default()
504 .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
505
506 let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
507 ByRef::No |
510 ByRef::Yes(Mutability::Mut) => inner_mutability,
512 ByRef::Yes(Mutability::Not) => Mutability::Not,
515 });
516
517 let mut max_ref_mutbl = pat_info.max_ref_mutbl;
518 if self.downgrade_mut_inside_shared() {
519 binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
520 }
521 if binding_mode == ByRef::Yes(Mutability::Not) {
522 max_ref_mutbl = MutblCap::Not;
523 }
524 debug!("default binding mode is now {:?}", binding_mode);
525
526 let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info };
528 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
530 }
531 _ if self.tcx.features().deref_patterns()
534 && let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode
535 && pat.default_binding_modes
536 && let ty::Adt(scrutinee_adt, _) = *expected.kind()
541 && until_adt != Some(scrutinee_adt.did())
544 && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
549 && self
550 .type_implements_trait(deref_trait, [expected], self.param_env)
551 .may_apply() =>
552 {
553 debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
554 let mut inner_ty = self.deref_pat_target(pat.span, expected);
557 let mut typeck_results = self.typeck_results.borrow_mut();
561 let mut pat_adjustments_table = typeck_results.pat_adjustments_mut();
562 let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default();
563 if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) {
570 pat_adjustments
572 .push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected });
573 } else {
574 let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected);
575 inner_ty = Ty::new_error(self.tcx, guar);
576 }
577 drop(typeck_results);
578
579 self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, old_pat_info)
582 }
583 PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
584 PatKind::Never => expected,
586 PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), hir_id, .. }) => {
587 let ty = match opt_path_res.unwrap() {
588 Ok(ref pr) => {
589 self.check_pat_path(pat.hir_id, pat.span, pr, expected, &pat_info.top_info)
590 }
591 Err(guar) => Ty::new_error(self.tcx, guar),
592 };
593 self.write_ty(*hir_id, ty);
594 ty
595 }
596 PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info),
597 PatKind::Range(lhs, rhs, _) => {
598 self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info)
599 }
600 PatKind::Binding(ba, var_id, ident, sub) => {
601 self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
602 }
603 PatKind::TupleStruct(ref qpath, subpats, ddpos) => match opt_path_res.unwrap() {
604 Ok(ResolvedPat { ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) => self
605 .check_pat_tuple_struct(
606 pat, qpath, subpats, ddpos, res, ty, variant, expected, pat_info,
607 ),
608 Err(guar) => {
609 let ty_err = Ty::new_error(self.tcx, guar);
610 for subpat in subpats {
611 self.check_pat(subpat, ty_err, pat_info);
612 }
613 ty_err
614 }
615 Ok(pr) => span_bug!(pat.span, "tuple struct pattern resolved to {pr:?}"),
616 },
617 PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() {
618 Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self
619 .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info),
620 Err(guar) => {
621 let ty_err = Ty::new_error(self.tcx, guar);
622 for field in fields {
623 self.check_pat(field.pat, ty_err, pat_info);
624 }
625 ty_err
626 }
627 Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
628 },
629 PatKind::Guard(pat, cond) => {
630 self.check_pat(pat, expected, pat_info);
631 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
632 expected
633 }
634 PatKind::Or(pats) => {
635 for pat in pats {
636 self.check_pat(pat, expected, pat_info);
637 }
638 expected
639 }
640 PatKind::Tuple(elements, ddpos) => {
641 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
642 }
643 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
644 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
645 PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
646 PatKind::Slice(before, slice, after) => {
647 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
648 }
649 }
650 }
651
652 fn calc_adjust_mode(
656 &self,
657 pat: &'tcx Pat<'tcx>,
658 opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
659 ) -> AdjustMode {
660 match &pat.kind {
661 PatKind::Tuple(..)
664 | PatKind::Range(..)
665 | PatKind::Slice(..) => AdjustMode::peel_all(),
666 | PatKind::Box(_)
670 | PatKind::Deref(_) => AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat },
671 PatKind::Never => AdjustMode::peel_all(),
673 PatKind::Struct(..)
675 | PatKind::TupleStruct(..)
676 | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
677 opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
679 }
680
681 PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
687 ty::Ref(..) => AdjustMode::Pass,
688 _ => {
689 if cfg!(debug_assertions)
692 && self.tcx.features().deref_patterns()
693 && !matches!(lt.kind, PatExprKind::Lit { .. })
694 {
695 span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind);
696 }
697 AdjustMode::peel_all()
698 }
699 },
700
701 PatKind::Ref(..)
703 | PatKind::Missing
705 | PatKind::Wild
707 | PatKind::Err(_)
709 | PatKind::Binding(..)
714 | PatKind::Or(_)
718 | PatKind::Guard(..) => AdjustMode::Pass,
720 }
721 }
722
723 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
724 let ty = match <.kind {
725 rustc_hir::PatExprKind::Lit { lit, negated } => {
726 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
727 if *negated {
728 self.register_bound(
729 ty,
730 self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
731 ObligationCause::dummy_with_span(lt.span),
732 );
733 }
734 ty
735 }
736 rustc_hir::PatExprKind::ConstBlock(c) => {
737 self.check_expr_const_block(c, Expectation::NoExpectation)
738 }
739 rustc_hir::PatExprKind::Path(qpath) => {
740 let (res, opt_ty, segments) =
741 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
742 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
743 }
744 };
745 self.write_ty(lt.hir_id, ty);
746 ty
747 }
748
749 fn check_pat_lit(
750 &self,
751 span: Span,
752 lt: &hir::PatExpr<'tcx>,
753 expected: Ty<'tcx>,
754 ti: &TopInfo<'tcx>,
755 ) -> Ty<'tcx> {
756 let ty = self.node_ty(lt.hir_id);
759
760 let mut pat_ty = ty;
763 if let hir::PatExprKind::Lit {
764 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
765 } = lt.kind
766 {
767 let expected = self.structurally_resolve_type(span, expected);
768 if let ty::Ref(_, inner_ty, _) = *expected.kind()
769 && self.try_structurally_resolve_type(span, inner_ty).is_slice()
770 {
771 let tcx = self.tcx;
772 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
773 pat_ty =
774 Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
775 }
776 }
777
778 if self.tcx.features().string_deref_patterns()
779 && let hir::PatExprKind::Lit {
780 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
781 } = lt.kind
782 {
783 let tcx = self.tcx;
784 let expected = self.resolve_vars_if_possible(expected);
785 pat_ty = match expected.kind() {
786 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
787 ty::Str => Ty::new_static_str(tcx),
788 _ => pat_ty,
789 };
790 }
791
792 let cause = self.pattern_cause(ti, span);
803 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
804 err.emit_unless(
805 ti.span
806 .filter(|&s| {
807 s.is_desugaring(DesugaringKind::CondTemporary)
811 })
812 .is_some(),
813 );
814 }
815
816 pat_ty
817 }
818
819 fn check_pat_range(
820 &self,
821 span: Span,
822 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
823 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
824 expected: Ty<'tcx>,
825 ti: &TopInfo<'tcx>,
826 ) -> Ty<'tcx> {
827 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
828 None => None,
829 Some(expr) => {
830 let ty = self.check_pat_expr_unadjusted(expr);
831 let fail =
838 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
839 Some((fail, ty, expr.span))
840 }
841 };
842 let mut lhs = calc_side(lhs);
843 let mut rhs = calc_side(rhs);
844
845 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
846 let guar = self.emit_err_pat_range(span, lhs, rhs);
849 return Ty::new_error(self.tcx, guar);
850 }
851
852 let demand_eqtype = |x: &mut _, y| {
855 if let Some((ref mut fail, x_ty, x_span)) = *x
856 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
857 {
858 if let Some((_, y_ty, y_span)) = y {
859 self.endpoint_has_type(&mut err, y_span, y_ty);
860 }
861 err.emit();
862 *fail = true;
863 }
864 };
865 demand_eqtype(&mut lhs, rhs);
866 demand_eqtype(&mut rhs, lhs);
867
868 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
869 return Ty::new_misc_error(self.tcx);
870 }
871
872 let ty = self.structurally_resolve_type(span, expected);
877 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
878 if let Some((ref mut fail, _, _)) = lhs {
879 *fail = true;
880 }
881 if let Some((ref mut fail, _, _)) = rhs {
882 *fail = true;
883 }
884 let guar = self.emit_err_pat_range(span, lhs, rhs);
885 return Ty::new_error(self.tcx, guar);
886 }
887 ty
888 }
889
890 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
891 if !ty.references_error() {
892 err.span_label(span, format!("this is of type `{ty}`"));
893 }
894 }
895
896 fn emit_err_pat_range(
897 &self,
898 span: Span,
899 lhs: Option<(bool, Ty<'tcx>, Span)>,
900 rhs: Option<(bool, Ty<'tcx>, Span)>,
901 ) -> ErrorGuaranteed {
902 let span = match (lhs, rhs) {
903 (Some((true, ..)), Some((true, ..))) => span,
904 (Some((true, _, sp)), _) => sp,
905 (_, Some((true, _, sp))) => sp,
906 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
907 };
908 let mut err = struct_span_code_err!(
909 self.dcx(),
910 span,
911 E0029,
912 "only `char` and numeric types are allowed in range patterns"
913 );
914 let msg = |ty| {
915 let ty = self.resolve_vars_if_possible(ty);
916 format!("this is of type `{ty}` but it should be `char` or numeric")
917 };
918 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
919 err.span_label(first_span, msg(first_ty));
920 if let Some((_, ty, sp)) = second {
921 let ty = self.resolve_vars_if_possible(ty);
922 self.endpoint_has_type(&mut err, sp, ty);
923 }
924 };
925 match (lhs, rhs) {
926 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
927 err.span_label(lhs_sp, msg(lhs_ty));
928 err.span_label(rhs_sp, msg(rhs_ty));
929 }
930 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
931 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
932 _ => span_bug!(span, "Impossible, verified above."),
933 }
934 if (lhs, rhs).references_error() {
935 err.downgrade_to_delayed_bug();
936 }
937 if self.tcx.sess.teach(err.code.unwrap()) {
938 err.note(
939 "In a match expression, only numbers and characters can be matched \
940 against a range. This is because the compiler checks that the range \
941 is non-empty at compile-time, and is unable to evaluate arbitrary \
942 comparison functions. If you want to capture values of an orderable \
943 type between two end-points, you can use a guard.",
944 );
945 }
946 err.emit()
947 }
948
949 fn check_pat_ident(
950 &self,
951 pat: &'tcx Pat<'tcx>,
952 user_bind_annot: BindingMode,
953 var_id: HirId,
954 ident: Ident,
955 sub: Option<&'tcx Pat<'tcx>>,
956 expected: Ty<'tcx>,
957 pat_info: PatInfo<'tcx>,
958 ) -> Ty<'tcx> {
959 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
960
961 let bm = match user_bind_annot {
963 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
964 if pat.span.at_least_rust_2024()
967 && (self.tcx.features().ref_pat_eat_one_layer_2024()
968 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
969 {
970 if !self.tcx.features().mut_ref() {
971 feature_err(
972 &self.tcx.sess,
973 sym::mut_ref,
974 pat.span.until(ident.span),
975 "binding cannot be both mutable and by-reference",
976 )
977 .emit();
978 }
979
980 BindingMode(def_br, Mutability::Mut)
981 } else {
982 self.add_rust_2024_migration_desugared_pat(
984 pat_info.top_info.hir_id,
985 pat,
986 't', def_br_mutbl,
988 );
989 BindingMode(ByRef::No, Mutability::Mut)
990 }
991 }
992 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
993 BindingMode(ByRef::Yes(user_br_mutbl), _) => {
994 if let ByRef::Yes(def_br_mutbl) = def_br {
995 self.add_rust_2024_migration_desugared_pat(
997 pat_info.top_info.hir_id,
998 pat,
999 match user_br_mutbl {
1000 Mutability::Not => 'f', Mutability::Mut => 't', },
1003 def_br_mutbl,
1004 );
1005 }
1006 user_bind_annot
1007 }
1008 };
1009
1010 if bm.0 == ByRef::Yes(Mutability::Mut)
1011 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
1012 {
1013 let mut err = struct_span_code_err!(
1014 self.dcx(),
1015 ident.span,
1016 E0596,
1017 "cannot borrow as mutable inside an `&` pattern"
1018 );
1019
1020 if let Some(span) = and_pat_span {
1021 err.span_suggestion(
1022 span,
1023 "replace this `&` with `&mut`",
1024 "&mut ",
1025 Applicability::MachineApplicable,
1026 );
1027 }
1028 err.emit();
1029 }
1030
1031 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
1033
1034 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
1035
1036 let local_ty = self.local_ty(pat.span, pat.hir_id);
1037 let eq_ty = match bm.0 {
1038 ByRef::Yes(mutbl) => {
1039 self.new_ref_ty(pat.span, mutbl, expected)
1047 }
1048 ByRef::No => expected, };
1051
1052 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
1054
1055 if var_id != pat.hir_id {
1058 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
1059 }
1060
1061 if let Some(p) = sub {
1062 self.check_pat(p, expected, pat_info);
1063 }
1064
1065 local_ty
1066 }
1067
1068 fn check_binding_alt_eq_ty(
1072 &self,
1073 ba: BindingMode,
1074 span: Span,
1075 var_id: HirId,
1076 ty: Ty<'tcx>,
1077 ti: &TopInfo<'tcx>,
1078 ) {
1079 let var_ty = self.local_ty(span, var_id);
1080 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
1081 let var_ty = self.resolve_vars_if_possible(var_ty);
1082 let msg = format!("first introduced with type `{var_ty}` here");
1083 err.span_label(self.tcx.hir_span(var_id), msg);
1084 let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| {
1085 matches!(
1086 n,
1087 hir::Node::Expr(hir::Expr {
1088 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
1089 ..
1090 })
1091 )
1092 });
1093 let pre = if in_match { "in the same arm, " } else { "" };
1094 err.note(format!("{pre}a binding must have the same type in all alternatives"));
1095 self.suggest_adding_missing_ref_or_removing_ref(
1096 &mut err,
1097 span,
1098 var_ty,
1099 self.resolve_vars_if_possible(ty),
1100 ba,
1101 );
1102 err.emit();
1103 }
1104 }
1105
1106 fn suggest_adding_missing_ref_or_removing_ref(
1107 &self,
1108 err: &mut Diag<'_>,
1109 span: Span,
1110 expected: Ty<'tcx>,
1111 actual: Ty<'tcx>,
1112 ba: BindingMode,
1113 ) {
1114 match (expected.kind(), actual.kind(), ba) {
1115 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
1116 if self.can_eq(self.param_env, *inner_ty, actual) =>
1117 {
1118 err.span_suggestion_verbose(
1119 span.shrink_to_lo(),
1120 "consider adding `ref`",
1121 "ref ",
1122 Applicability::MaybeIncorrect,
1123 );
1124 }
1125 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
1126 if self.can_eq(self.param_env, expected, *inner_ty) =>
1127 {
1128 err.span_suggestion_verbose(
1129 span.with_hi(span.lo() + BytePos(4)),
1130 "consider removing `ref`",
1131 "",
1132 Applicability::MaybeIncorrect,
1133 );
1134 }
1135 _ => (),
1136 }
1137 }
1138
1139 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
1141 let tcx = self.tcx;
1142 if let PatKind::Ref(inner, mutbl) = pat.kind
1143 && let PatKind::Binding(_, _, binding, ..) = inner.kind
1144 {
1145 let binding_parent = tcx.parent_hir_node(pat.hir_id);
1146 debug!(?inner, ?pat, ?binding_parent);
1147
1148 let mutability = match mutbl {
1149 ast::Mutability::Mut => "mut",
1150 ast::Mutability::Not => "",
1151 };
1152
1153 let mut_var_suggestion = 'block: {
1154 if mutbl.is_not() {
1155 break 'block None;
1156 }
1157
1158 let ident_kind = match binding_parent {
1159 hir::Node::Param(_) => "parameter",
1160 hir::Node::LetStmt(_) => "variable",
1161 hir::Node::Arm(_) => "binding",
1162
1163 hir::Node::Pat(Pat { kind, .. }) => match kind {
1166 PatKind::Struct(..)
1167 | PatKind::TupleStruct(..)
1168 | PatKind::Or(..)
1169 | PatKind::Guard(..)
1170 | PatKind::Tuple(..)
1171 | PatKind::Slice(..) => "binding",
1172
1173 PatKind::Missing
1174 | PatKind::Wild
1175 | PatKind::Never
1176 | PatKind::Binding(..)
1177 | PatKind::Box(..)
1178 | PatKind::Deref(_)
1179 | PatKind::Ref(..)
1180 | PatKind::Expr(..)
1181 | PatKind::Range(..)
1182 | PatKind::Err(_) => break 'block None,
1183 },
1184
1185 _ => break 'block None,
1187 };
1188
1189 Some((
1190 pat.span,
1191 format!("to declare a mutable {ident_kind} use"),
1192 format!("mut {binding}"),
1193 ))
1194 };
1195
1196 match binding_parent {
1197 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1200 err.multipart_suggestion_verbose(
1201 format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
1202 vec![
1203 (pat.span.until(inner.span), "".to_owned()),
1204 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1205 ],
1206 Applicability::MachineApplicable
1207 );
1208
1209 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1210 err.span_note(sp, format!("{msg}: `{sugg}`"));
1211 }
1212 }
1213 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1214 for i in pat_arr.iter() {
1215 if let PatKind::Ref(the_ref, _) = i.kind
1216 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1217 {
1218 let BindingMode(_, mtblty) = mt;
1219 err.span_suggestion_verbose(
1220 i.span,
1221 format!("consider removing `&{mutability}` from the pattern"),
1222 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1223 Applicability::MaybeIncorrect,
1224 );
1225 }
1226 }
1227 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1228 err.span_note(sp, format!("{msg}: `{sugg}`"));
1229 }
1230 }
1231 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1232 err.span_suggestion_verbose(
1234 pat.span.until(inner.span),
1235 format!("consider removing `&{mutability}` from the pattern"),
1236 "",
1237 Applicability::MaybeIncorrect,
1238 );
1239
1240 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1241 err.span_note(sp, format!("{msg}: `{sugg}`"));
1242 }
1243 }
1244 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1245 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1246 }
1247 _ => {} }
1249 }
1250 }
1251
1252 fn check_dereferenceable(
1253 &self,
1254 span: Span,
1255 expected: Ty<'tcx>,
1256 inner: &Pat<'_>,
1257 ) -> Result<(), ErrorGuaranteed> {
1258 if let PatKind::Binding(..) = inner.kind
1259 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1260 && let ty::Dynamic(..) = pointee_ty.kind()
1261 {
1262 let type_str = self.ty_to_string(expected);
1265 let mut err = struct_span_code_err!(
1266 self.dcx(),
1267 span,
1268 E0033,
1269 "type `{}` cannot be dereferenced",
1270 type_str
1271 );
1272 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1273 if self.tcx.sess.teach(err.code.unwrap()) {
1274 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1275 }
1276 return Err(err.emit());
1277 }
1278 Ok(())
1279 }
1280
1281 fn resolve_pat_struct(
1282 &self,
1283 pat: &'tcx Pat<'tcx>,
1284 qpath: &hir::QPath<'tcx>,
1285 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1286 let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
1288 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
1289 }
1290
1291 fn check_pat_struct(
1292 &self,
1293 pat: &'tcx Pat<'tcx>,
1294 fields: &'tcx [hir::PatField<'tcx>],
1295 has_rest_pat: bool,
1296 pat_ty: Ty<'tcx>,
1297 variant: &'tcx VariantDef,
1298 expected: Ty<'tcx>,
1299 pat_info: PatInfo<'tcx>,
1300 ) -> Ty<'tcx> {
1301 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
1303
1304 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1306 Ok(()) => pat_ty,
1307 Err(guar) => Ty::new_error(self.tcx, guar),
1308 }
1309 }
1310
1311 fn resolve_pat_path(
1312 &self,
1313 path_id: HirId,
1314 span: Span,
1315 qpath: &'tcx hir::QPath<'_>,
1316 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1317 let tcx = self.tcx;
1318
1319 let (res, opt_ty, segments) =
1320 self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
1321 match res {
1322 Res::Err => {
1323 let e =
1324 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1325 self.set_tainted_by_errors(e);
1326 return Err(e);
1327 }
1328 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1329 let expected = "unit struct, unit variant or constant";
1330 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1331 return Err(e);
1332 }
1333 Res::SelfCtor(def_id) => {
1334 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1335 && adt_def.is_struct()
1336 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1337 {
1338 } else {
1340 let e = report_unexpected_variant_res(
1341 tcx,
1342 res,
1343 None,
1344 qpath,
1345 span,
1346 E0533,
1347 "unit struct",
1348 );
1349 return Err(e);
1350 }
1351 }
1352 Res::Def(
1353 DefKind::Ctor(_, CtorKind::Const)
1354 | DefKind::Const
1355 | DefKind::AssocConst
1356 | DefKind::ConstParam,
1357 _,
1358 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1360 }
1361
1362 let (pat_ty, pat_res) =
1364 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1365 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
1366 }
1367
1368 fn check_pat_path(
1369 &self,
1370 pat_id_for_diag: HirId,
1371 span: Span,
1372 resolved: &ResolvedPat<'tcx>,
1373 expected: Ty<'tcx>,
1374 ti: &TopInfo<'tcx>,
1375 ) -> Ty<'tcx> {
1376 if let Err(err) =
1377 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
1378 {
1379 self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
1380 }
1381 resolved.ty
1382 }
1383
1384 fn maybe_suggest_range_literal(
1385 &self,
1386 e: &mut Diag<'_>,
1387 opt_def_id: Option<hir::def_id::DefId>,
1388 ident: Ident,
1389 ) -> bool {
1390 match opt_def_id {
1391 Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
1392 Some(hir::Node::Item(hir::Item {
1393 kind: hir::ItemKind::Const(_, _, _, body_id),
1394 ..
1395 })) => match self.tcx.hir_node(body_id.hir_id) {
1396 hir::Node::Expr(expr) => {
1397 if hir::is_range_literal(expr) {
1398 let span = self.tcx.hir_span(body_id.hir_id);
1399 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1400 e.span_suggestion_verbose(
1401 ident.span,
1402 "you may want to move the range into the match block",
1403 snip,
1404 Applicability::MachineApplicable,
1405 );
1406 return true;
1407 }
1408 }
1409 }
1410 _ => (),
1411 },
1412 _ => (),
1413 },
1414 _ => (),
1415 }
1416 false
1417 }
1418
1419 fn emit_bad_pat_path(
1420 &self,
1421 mut e: Diag<'_>,
1422 hir_id: HirId,
1423 pat_span: Span,
1424 resolved_pat: &ResolvedPat<'tcx>,
1425 ) {
1426 let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
1427 span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
1428 };
1429
1430 if let Some(span) = self.tcx.hir_res_span(pat_res) {
1431 e.span_label(span, format!("{} defined here", res.descr()));
1432 if let [hir::PathSegment { ident, .. }] = &*segments {
1433 e.span_label(
1434 pat_span,
1435 format!(
1436 "`{}` is interpreted as {} {}, not a new binding",
1437 ident,
1438 res.article(),
1439 res.descr(),
1440 ),
1441 );
1442 match self.tcx.parent_hir_node(hir_id) {
1443 hir::Node::PatField(..) => {
1444 e.span_suggestion_verbose(
1445 ident.span.shrink_to_hi(),
1446 "bind the struct field to a different name instead",
1447 format!(": other_{}", ident.as_str().to_lowercase()),
1448 Applicability::HasPlaceholders,
1449 );
1450 }
1451 _ => {
1452 let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1453 ty::Adt(def, _) => match res {
1454 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1455 _ => (None, None),
1456 },
1457 _ => (None, None),
1458 };
1459
1460 let ranges = &[
1461 self.tcx.lang_items().range_struct(),
1462 self.tcx.lang_items().range_from_struct(),
1463 self.tcx.lang_items().range_to_struct(),
1464 self.tcx.lang_items().range_full_struct(),
1465 self.tcx.lang_items().range_inclusive_struct(),
1466 self.tcx.lang_items().range_to_inclusive_struct(),
1467 ];
1468 if type_def_id != None && ranges.contains(&type_def_id) {
1469 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1470 let msg = "constants only support matching by type, \
1471 if you meant to match against a range of values, \
1472 consider using a range pattern like `min ..= max` in the match block";
1473 e.note(msg);
1474 }
1475 } else {
1476 let msg = "introduce a new binding instead";
1477 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1478 e.span_suggestion(
1479 ident.span,
1480 msg,
1481 sugg,
1482 Applicability::HasPlaceholders,
1483 );
1484 }
1485 }
1486 };
1487 }
1488 }
1489 e.emit();
1490 }
1491
1492 fn resolve_pat_tuple_struct(
1493 &self,
1494 pat: &'tcx Pat<'tcx>,
1495 qpath: &'tcx hir::QPath<'tcx>,
1496 ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
1497 let tcx = self.tcx;
1498 let report_unexpected_res = |res: Res| {
1499 let expected = "tuple struct or tuple variant";
1500 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1501 Err(e)
1502 };
1503
1504 let (res, opt_ty, segments) =
1506 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1507 if res == Res::Err {
1508 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1509 self.set_tainted_by_errors(e);
1510 return Err(e);
1511 }
1512
1513 let (pat_ty, res) =
1515 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1516 if !pat_ty.is_fn() {
1517 return report_unexpected_res(res);
1518 }
1519
1520 let variant = match res {
1521 Res::Err => {
1522 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1523 }
1524 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1525 return report_unexpected_res(res);
1526 }
1527 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1528 _ => bug!("unexpected pattern resolution: {:?}", res),
1529 };
1530
1531 let pat_ty = pat_ty.fn_sig(tcx).output();
1533 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1534
1535 Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
1536 }
1537
1538 fn check_pat_tuple_struct(
1539 &self,
1540 pat: &'tcx Pat<'tcx>,
1541 qpath: &'tcx hir::QPath<'tcx>,
1542 subpats: &'tcx [Pat<'tcx>],
1543 ddpos: hir::DotDotPos,
1544 res: Res,
1545 pat_ty: Ty<'tcx>,
1546 variant: &'tcx VariantDef,
1547 expected: Ty<'tcx>,
1548 pat_info: PatInfo<'tcx>,
1549 ) -> Ty<'tcx> {
1550 let tcx = self.tcx;
1551 let on_error = |e| {
1552 for pat in subpats {
1553 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1554 }
1555 };
1556
1557 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
1559 let had_err = diag.map_err(|diag| diag.emit());
1560
1561 if subpats.len() == variant.fields.len()
1563 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1564 {
1565 let ty::Adt(_, args) = pat_ty.kind() else {
1566 bug!("unexpected pattern type {:?}", pat_ty);
1567 };
1568 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1569 let field = &variant.fields[FieldIdx::from_usize(i)];
1570 let field_ty = self.field_ty(subpat.span, field, args);
1571 self.check_pat(subpat, field_ty, pat_info);
1572
1573 self.tcx.check_stability(
1574 variant.fields[FieldIdx::from_usize(i)].did,
1575 Some(subpat.hir_id),
1576 subpat.span,
1577 None,
1578 );
1579 }
1580 if let Err(e) = had_err {
1581 on_error(e);
1582 return Ty::new_error(tcx, e);
1583 }
1584 } else {
1585 let e = self.emit_err_pat_wrong_number_of_fields(
1586 pat.span,
1587 res,
1588 qpath,
1589 subpats,
1590 &variant.fields.raw,
1591 expected,
1592 had_err,
1593 );
1594 on_error(e);
1595 return Ty::new_error(tcx, e);
1596 }
1597 pat_ty
1598 }
1599
1600 fn emit_err_pat_wrong_number_of_fields(
1601 &self,
1602 pat_span: Span,
1603 res: Res,
1604 qpath: &hir::QPath<'_>,
1605 subpats: &'tcx [Pat<'tcx>],
1606 fields: &'tcx [ty::FieldDef],
1607 expected: Ty<'tcx>,
1608 had_err: Result<(), ErrorGuaranteed>,
1609 ) -> ErrorGuaranteed {
1610 let subpats_ending = pluralize!(subpats.len());
1611 let fields_ending = pluralize!(fields.len());
1612
1613 let subpat_spans = if subpats.is_empty() {
1614 vec![pat_span]
1615 } else {
1616 subpats.iter().map(|p| p.span).collect()
1617 };
1618 let last_subpat_span = *subpat_spans.last().unwrap();
1619 let res_span = self.tcx.def_span(res.def_id());
1620 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1621 let field_def_spans = if fields.is_empty() {
1622 vec![res_span]
1623 } else {
1624 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1625 };
1626 let last_field_def_span = *field_def_spans.last().unwrap();
1627
1628 let mut err = struct_span_code_err!(
1629 self.dcx(),
1630 MultiSpan::from_spans(subpat_spans),
1631 E0023,
1632 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1633 subpats.len(),
1634 subpats_ending,
1635 res.descr(),
1636 fields.len(),
1637 fields_ending,
1638 );
1639 err.span_label(
1640 last_subpat_span,
1641 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1642 );
1643 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1644 err.span_label(qpath.span(), "");
1645 }
1646 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1647 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1648 }
1649 for span in &field_def_spans[..field_def_spans.len() - 1] {
1650 err.span_label(*span, "");
1651 }
1652 err.span_label(
1653 last_field_def_span,
1654 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1655 );
1656
1657 let missing_parentheses = match (expected.kind(), fields, had_err) {
1662 (ty::Adt(_, args), [field], Ok(())) => {
1666 let field_ty = self.field_ty(pat_span, field, args);
1667 match field_ty.kind() {
1668 ty::Tuple(fields) => fields.len() == subpats.len(),
1669 _ => false,
1670 }
1671 }
1672 _ => false,
1673 };
1674 if missing_parentheses {
1675 let (left, right) = match subpats {
1676 [] => (qpath.span().shrink_to_hi(), pat_span),
1685 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1694 };
1695 err.multipart_suggestion(
1696 "missing parentheses",
1697 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1698 Applicability::MachineApplicable,
1699 );
1700 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1701 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1702 let all_fields_span = match subpats {
1703 [] => after_fields_span,
1704 [field] => field.span,
1705 [first, .., last] => first.span.to(last.span),
1706 };
1707
1708 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1710 let first_tail_wildcard =
1711 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1712 (None, PatKind::Wild) => Some(pos),
1713 (Some(_), PatKind::Wild) => acc,
1714 _ => None,
1715 });
1716 let tail_span = match first_tail_wildcard {
1717 None => after_fields_span,
1718 Some(0) => subpats[0].span.to(after_fields_span),
1719 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1720 };
1721
1722 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1724 if !subpats.is_empty() {
1725 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1726 }
1727
1728 err.span_suggestion_verbose(
1729 after_fields_span,
1730 "use `_` to explicitly ignore each field",
1731 wildcard_sugg,
1732 Applicability::MaybeIncorrect,
1733 );
1734
1735 if fields.len() - subpats.len() > 1 || all_wildcards {
1738 if subpats.is_empty() || all_wildcards {
1739 err.span_suggestion_verbose(
1740 all_fields_span,
1741 "use `..` to ignore all fields",
1742 "..",
1743 Applicability::MaybeIncorrect,
1744 );
1745 } else {
1746 err.span_suggestion_verbose(
1747 tail_span,
1748 "use `..` to ignore the rest of the fields",
1749 ", ..",
1750 Applicability::MaybeIncorrect,
1751 );
1752 }
1753 }
1754 }
1755
1756 err.emit()
1757 }
1758
1759 fn check_pat_tuple(
1760 &self,
1761 span: Span,
1762 elements: &'tcx [Pat<'tcx>],
1763 ddpos: hir::DotDotPos,
1764 expected: Ty<'tcx>,
1765 pat_info: PatInfo<'tcx>,
1766 ) -> Ty<'tcx> {
1767 let tcx = self.tcx;
1768 let mut expected_len = elements.len();
1769 if ddpos.as_opt_usize().is_some() {
1770 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1772 expected_len = tys.len();
1773 }
1774 }
1775 let max_len = cmp::max(expected_len, elements.len());
1776
1777 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1778 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1779 let pat_ty = Ty::new_tup(tcx, element_tys);
1780 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
1781 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1784 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1785 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1786 }
1787 Ty::new_tup_from_iter(tcx, element_tys_iter)
1788 } else {
1789 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1790 self.check_pat(elem, element_tys[i], pat_info);
1791 }
1792 pat_ty
1793 }
1794 }
1795
1796 fn check_struct_pat_fields(
1797 &self,
1798 adt_ty: Ty<'tcx>,
1799 pat: &'tcx Pat<'tcx>,
1800 variant: &'tcx ty::VariantDef,
1801 fields: &'tcx [hir::PatField<'tcx>],
1802 has_rest_pat: bool,
1803 pat_info: PatInfo<'tcx>,
1804 ) -> Result<(), ErrorGuaranteed> {
1805 let tcx = self.tcx;
1806
1807 let ty::Adt(adt, args) = adt_ty.kind() else {
1808 span_bug!(pat.span, "struct pattern is not an ADT");
1809 };
1810
1811 let field_map = variant
1813 .fields
1814 .iter_enumerated()
1815 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
1816 .collect::<FxHashMap<_, _>>();
1817
1818 let mut used_fields = FxHashMap::default();
1820 let mut result = Ok(());
1821
1822 let mut inexistent_fields = vec![];
1823 for field in fields {
1825 let span = field.span;
1826 let ident = tcx.adjust_ident(field.ident, variant.def_id);
1827 let field_ty = match used_fields.entry(ident) {
1828 Occupied(occupied) => {
1829 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
1830 result = Err(guar);
1831 Ty::new_error(tcx, guar)
1832 }
1833 Vacant(vacant) => {
1834 vacant.insert(span);
1835 field_map
1836 .get(&ident)
1837 .map(|(i, f)| {
1838 self.write_field_index(field.hir_id, *i);
1839 self.tcx.check_stability(f.did, Some(field.hir_id), span, None);
1840 self.field_ty(span, f, args)
1841 })
1842 .unwrap_or_else(|| {
1843 inexistent_fields.push(field);
1844 Ty::new_misc_error(tcx)
1845 })
1846 }
1847 };
1848
1849 self.check_pat(field.pat, field_ty, pat_info);
1850 }
1851
1852 let mut unmentioned_fields = variant
1853 .fields
1854 .iter()
1855 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
1856 .filter(|(_, ident)| !used_fields.contains_key(ident))
1857 .collect::<Vec<_>>();
1858
1859 let inexistent_fields_err = if !inexistent_fields.is_empty()
1860 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
1861 {
1862 variant.has_errors()?;
1864 Some(self.error_inexistent_fields(
1865 adt.variant_descr(),
1866 &inexistent_fields,
1867 &mut unmentioned_fields,
1868 pat,
1869 variant,
1870 args,
1871 ))
1872 } else {
1873 None
1874 };
1875
1876 let non_exhaustive = variant.field_list_has_applicable_non_exhaustive();
1878 if non_exhaustive && !has_rest_pat {
1879 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
1880 }
1881
1882 let mut unmentioned_err = None;
1883 if adt.is_union() {
1885 if fields.len() != 1 {
1886 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
1887 }
1888 if has_rest_pat {
1889 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
1890 }
1891 } else if !unmentioned_fields.is_empty() {
1892 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
1893 .iter()
1894 .copied()
1895 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
1896 .collect();
1897
1898 if !has_rest_pat {
1899 if accessible_unmentioned_fields.is_empty() {
1900 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
1901 } else {
1902 unmentioned_err = Some(self.error_unmentioned_fields(
1903 pat,
1904 &accessible_unmentioned_fields,
1905 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
1906 fields,
1907 ));
1908 }
1909 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
1910 self.lint_non_exhaustive_omitted_patterns(
1911 pat,
1912 &accessible_unmentioned_fields,
1913 adt_ty,
1914 )
1915 }
1916 }
1917 match (inexistent_fields_err, unmentioned_err) {
1918 (Some(i), Some(u)) => {
1919 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
1920 i.delay_as_bug();
1923 u.delay_as_bug();
1924 Err(e)
1925 } else {
1926 i.emit();
1927 Err(u.emit())
1928 }
1929 }
1930 (None, Some(u)) => {
1931 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
1932 u.delay_as_bug();
1933 Err(e)
1934 } else {
1935 Err(u.emit())
1936 }
1937 }
1938 (Some(err), None) => Err(err.emit()),
1939 (None, None) => {
1940 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
1941 result
1942 }
1943 }
1944 }
1945
1946 fn error_tuple_variant_index_shorthand(
1947 &self,
1948 variant: &VariantDef,
1949 pat: &'_ Pat<'_>,
1950 fields: &[hir::PatField<'_>],
1951 ) -> Result<(), ErrorGuaranteed> {
1952 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
1956 (variant.ctor_kind(), &pat.kind)
1957 {
1958 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
1959 if has_shorthand_field_name {
1960 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
1961 let mut err = struct_span_code_err!(
1962 self.dcx(),
1963 pat.span,
1964 E0769,
1965 "tuple variant `{path}` written as struct variant",
1966 );
1967 err.span_suggestion_verbose(
1968 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
1969 "use the tuple variant pattern syntax instead",
1970 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
1971 Applicability::MaybeIncorrect,
1972 );
1973 return Err(err.emit());
1974 }
1975 }
1976 Ok(())
1977 }
1978
1979 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
1980 let sess = self.tcx.sess;
1981 let sm = sess.source_map();
1982 let sp_brace = sm.end_point(pat.span);
1983 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
1984 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
1985
1986 struct_span_code_err!(
1987 self.dcx(),
1988 pat.span,
1989 E0638,
1990 "`..` required with {descr} marked as non-exhaustive",
1991 )
1992 .with_span_suggestion_verbose(
1993 sp_comma,
1994 "add `..` at the end of the field list to ignore all other fields",
1995 sugg,
1996 Applicability::MachineApplicable,
1997 )
1998 .emit();
1999 }
2000
2001 fn error_field_already_bound(
2002 &self,
2003 span: Span,
2004 ident: Ident,
2005 other_field: Span,
2006 ) -> ErrorGuaranteed {
2007 struct_span_code_err!(
2008 self.dcx(),
2009 span,
2010 E0025,
2011 "field `{}` bound multiple times in the pattern",
2012 ident
2013 )
2014 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
2015 .with_span_label(other_field, format!("first use of `{ident}`"))
2016 .emit()
2017 }
2018
2019 fn error_inexistent_fields(
2020 &self,
2021 kind_name: &str,
2022 inexistent_fields: &[&hir::PatField<'tcx>],
2023 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
2024 pat: &'tcx Pat<'tcx>,
2025 variant: &ty::VariantDef,
2026 args: ty::GenericArgsRef<'tcx>,
2027 ) -> Diag<'a> {
2028 let tcx = self.tcx;
2029 let (field_names, t, plural) = if let [field] = inexistent_fields {
2030 (format!("a field named `{}`", field.ident), "this", "")
2031 } else {
2032 (
2033 format!(
2034 "fields named {}",
2035 inexistent_fields
2036 .iter()
2037 .map(|field| format!("`{}`", field.ident))
2038 .collect::<Vec<String>>()
2039 .join(", ")
2040 ),
2041 "these",
2042 "s",
2043 )
2044 };
2045 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
2046 let mut err = struct_span_code_err!(
2047 self.dcx(),
2048 spans,
2049 E0026,
2050 "{} `{}` does not have {}",
2051 kind_name,
2052 tcx.def_path_str(variant.def_id),
2053 field_names
2054 );
2055 if let Some(pat_field) = inexistent_fields.last() {
2056 err.span_label(
2057 pat_field.ident.span,
2058 format!(
2059 "{} `{}` does not have {} field{}",
2060 kind_name,
2061 tcx.def_path_str(variant.def_id),
2062 t,
2063 plural
2064 ),
2065 );
2066
2067 if let [(field_def, field)] = unmentioned_fields.as_slice()
2068 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
2069 {
2070 let suggested_name =
2071 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
2072 if let Some(suggested_name) = suggested_name {
2073 err.span_suggestion(
2074 pat_field.ident.span,
2075 "a field with a similar name exists",
2076 suggested_name,
2077 Applicability::MaybeIncorrect,
2078 );
2079
2080 if suggested_name.to_ident_string().parse::<usize>().is_err() {
2086 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
2088 }
2089 } else if inexistent_fields.len() == 1 {
2090 match pat_field.pat.kind {
2091 PatKind::Expr(_)
2092 if !self.may_coerce(
2093 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
2094 self.field_ty(field.span, field_def, args),
2095 ) => {}
2096 _ => {
2097 err.span_suggestion_short(
2098 pat_field.ident.span,
2099 format!(
2100 "`{}` has a field named `{}`",
2101 tcx.def_path_str(variant.def_id),
2102 field.name,
2103 ),
2104 field.name,
2105 Applicability::MaybeIncorrect,
2106 );
2107 }
2108 }
2109 }
2110 }
2111 }
2112 if tcx.sess.teach(err.code.unwrap()) {
2113 err.note(
2114 "This error indicates that a struct pattern attempted to \
2115 extract a nonexistent field from a struct. Struct fields \
2116 are identified by the name used before the colon : so struct \
2117 patterns should resemble the declaration of the struct type \
2118 being matched.\n\n\
2119 If you are using shorthand field patterns but want to refer \
2120 to the struct field by a different name, you should rename \
2121 it explicitly.",
2122 );
2123 }
2124 err
2125 }
2126
2127 fn error_tuple_variant_as_struct_pat(
2128 &self,
2129 pat: &Pat<'_>,
2130 fields: &'tcx [hir::PatField<'tcx>],
2131 variant: &ty::VariantDef,
2132 ) -> Result<(), ErrorGuaranteed> {
2133 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
2134 (variant.ctor_kind(), &pat.kind)
2135 {
2136 let is_tuple_struct_match = !pattern_fields.is_empty()
2137 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
2138 if is_tuple_struct_match {
2139 return Ok(());
2140 }
2141
2142 variant.has_errors()?;
2144
2145 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
2146 let mut err = struct_span_code_err!(
2147 self.dcx(),
2148 pat.span,
2149 E0769,
2150 "tuple variant `{}` written as struct variant",
2151 path
2152 );
2153 let (sugg, appl) = if fields.len() == variant.fields.len() {
2154 (
2155 self.get_suggested_tuple_struct_pattern(fields, variant),
2156 Applicability::MachineApplicable,
2157 )
2158 } else {
2159 (
2160 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
2161 Applicability::MaybeIncorrect,
2162 )
2163 };
2164 err.span_suggestion_verbose(
2165 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
2166 "use the tuple variant pattern syntax instead",
2167 format!("({sugg})"),
2168 appl,
2169 );
2170 return Err(err.emit());
2171 }
2172 Ok(())
2173 }
2174
2175 fn get_suggested_tuple_struct_pattern(
2176 &self,
2177 fields: &[hir::PatField<'_>],
2178 variant: &VariantDef,
2179 ) -> String {
2180 let variant_field_idents =
2181 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2182 fields
2183 .iter()
2184 .map(|field| {
2185 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2186 Ok(f) => {
2187 if variant_field_idents.contains(&field.ident) {
2190 String::from("_")
2191 } else {
2192 f
2193 }
2194 }
2195 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2196 }
2197 })
2198 .collect::<Vec<String>>()
2199 .join(", ")
2200 }
2201
2202 fn error_no_accessible_fields(
2218 &self,
2219 pat: &Pat<'_>,
2220 fields: &'tcx [hir::PatField<'tcx>],
2221 ) -> Diag<'a> {
2222 let mut err = self
2223 .dcx()
2224 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2225
2226 if let Some(field) = fields.last() {
2227 err.span_suggestion_verbose(
2228 field.span.shrink_to_hi(),
2229 "ignore the inaccessible and unused fields",
2230 ", ..",
2231 Applicability::MachineApplicable,
2232 );
2233 } else {
2234 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2235 qpath.span()
2236 } else {
2237 bug!("`error_no_accessible_fields` called on non-struct pattern");
2238 };
2239
2240 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2242 err.span_suggestion_verbose(
2243 span,
2244 "ignore the inaccessible and unused fields",
2245 " { .. }",
2246 Applicability::MachineApplicable,
2247 );
2248 }
2249 err
2250 }
2251
2252 fn lint_non_exhaustive_omitted_patterns(
2257 &self,
2258 pat: &Pat<'_>,
2259 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2260 ty: Ty<'tcx>,
2261 ) {
2262 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2263 const LIMIT: usize = 3;
2264 match witnesses {
2265 [] => {
2266 unreachable!(
2267 "expected an uncovered pattern, otherwise why are we emitting an error?"
2268 )
2269 }
2270 [witness] => format!("`{witness}`"),
2271 [head @ .., tail] if head.len() < LIMIT => {
2272 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2273 format!("`{}` and `{}`", head.join("`, `"), tail)
2274 }
2275 _ => {
2276 let (head, tail) = witnesses.split_at(LIMIT);
2277 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2278 format!("`{}` and {} more", head.join("`, `"), tail.len())
2279 }
2280 }
2281 }
2282 let joined_patterns = joined_uncovered_patterns(
2283 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2284 );
2285
2286 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2287 lint.primary_message("some fields are not explicitly listed");
2288 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2289 lint.help(
2290 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2291 );
2292 lint.note(format!(
2293 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2294 ));
2295 });
2296 }
2297
2298 fn error_unmentioned_fields(
2308 &self,
2309 pat: &Pat<'_>,
2310 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2311 have_inaccessible_fields: bool,
2312 fields: &'tcx [hir::PatField<'tcx>],
2313 ) -> Diag<'a> {
2314 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2315 let field_names = if let [(_, field)] = unmentioned_fields {
2316 format!("field `{field}`{inaccessible}")
2317 } else {
2318 let fields = unmentioned_fields
2319 .iter()
2320 .map(|(_, name)| format!("`{name}`"))
2321 .collect::<Vec<String>>()
2322 .join(", ");
2323 format!("fields {fields}{inaccessible}")
2324 };
2325 let mut err = struct_span_code_err!(
2326 self.dcx(),
2327 pat.span,
2328 E0027,
2329 "pattern does not mention {}",
2330 field_names
2331 );
2332 err.span_label(pat.span, format!("missing {field_names}"));
2333 let len = unmentioned_fields.len();
2334 let (prefix, postfix, sp) = match fields {
2335 [] => match &pat.kind {
2336 PatKind::Struct(path, [], false) => {
2337 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2338 }
2339 _ => return err,
2340 },
2341 [.., field] => {
2342 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2345 match &pat.kind {
2346 PatKind::Struct(..) => (", ", " }", tail),
2347 _ => return err,
2348 }
2349 }
2350 };
2351 err.span_suggestion(
2352 sp,
2353 format!(
2354 "include the missing field{} in the pattern{}",
2355 pluralize!(len),
2356 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2357 ),
2358 format!(
2359 "{}{}{}{}",
2360 prefix,
2361 unmentioned_fields
2362 .iter()
2363 .map(|(_, name)| {
2364 let field_name = name.to_string();
2365 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2366 })
2367 .collect::<Vec<_>>()
2368 .join(", "),
2369 if have_inaccessible_fields { ", .." } else { "" },
2370 postfix,
2371 ),
2372 Applicability::MachineApplicable,
2373 );
2374 err.span_suggestion(
2375 sp,
2376 format!(
2377 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2378 these = pluralize!("this", len),
2379 s = pluralize!(len),
2380 them = if len == 1 { "it" } else { "them" },
2381 ),
2382 format!(
2383 "{}{}{}{}",
2384 prefix,
2385 unmentioned_fields
2386 .iter()
2387 .map(|(_, name)| {
2388 let field_name = name.to_string();
2389 format!("{field_name}: _")
2390 })
2391 .collect::<Vec<_>>()
2392 .join(", "),
2393 if have_inaccessible_fields { ", .." } else { "" },
2394 postfix,
2395 ),
2396 Applicability::MachineApplicable,
2397 );
2398 err.span_suggestion(
2399 sp,
2400 "or always ignore missing fields here",
2401 format!("{prefix}..{postfix}"),
2402 Applicability::MachineApplicable,
2403 );
2404 err
2405 }
2406
2407 fn check_pat_box(
2408 &self,
2409 span: Span,
2410 inner: &'tcx Pat<'tcx>,
2411 expected: Ty<'tcx>,
2412 pat_info: PatInfo<'tcx>,
2413 ) -> Ty<'tcx> {
2414 let tcx = self.tcx;
2415 let (box_ty, inner_ty) = self
2416 .check_dereferenceable(span, expected, inner)
2417 .and_then(|()| {
2418 let inner_ty = self.next_ty_var(inner.span);
2421 let box_ty = Ty::new_box(tcx, inner_ty);
2422 self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
2423 Ok((box_ty, inner_ty))
2424 })
2425 .unwrap_or_else(|guar| {
2426 let err = Ty::new_error(tcx, guar);
2427 (err, err)
2428 });
2429 self.check_pat(inner, inner_ty, pat_info);
2430 box_ty
2431 }
2432
2433 fn check_pat_deref(
2434 &self,
2435 span: Span,
2436 inner: &'tcx Pat<'tcx>,
2437 expected: Ty<'tcx>,
2438 pat_info: PatInfo<'tcx>,
2439 ) -> Ty<'tcx> {
2440 let target_ty = self.deref_pat_target(span, expected);
2441 self.check_pat(inner, target_ty, pat_info);
2442 self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
2443 expected
2444 }
2445
2446 fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
2447 let tcx = self.tcx;
2449 self.register_bound(
2450 source_ty,
2451 tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
2452 self.misc(span),
2453 );
2454 let target_ty = Ty::new_projection(
2456 tcx,
2457 tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
2458 [source_ty],
2459 );
2460 let target_ty = self.normalize(span, target_ty);
2461 self.try_structurally_resolve_type(span, target_ty)
2462 }
2463
2464 fn register_deref_mut_bounds_if_needed(
2469 &self,
2470 span: Span,
2471 inner: &'tcx Pat<'tcx>,
2472 derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
2473 ) {
2474 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2475 for mutably_derefed_ty in derefed_tys {
2476 self.register_bound(
2477 mutably_derefed_ty,
2478 self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
2479 self.misc(span),
2480 );
2481 }
2482 }
2483 }
2484
2485 fn check_pat_ref(
2487 &self,
2488 pat: &'tcx Pat<'tcx>,
2489 inner: &'tcx Pat<'tcx>,
2490 pat_mutbl: Mutability,
2491 mut expected: Ty<'tcx>,
2492 mut pat_info: PatInfo<'tcx>,
2493 ) -> Ty<'tcx> {
2494 let tcx = self.tcx;
2495
2496 let pat_prefix_span =
2497 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2498
2499 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2500 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2501 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2506 }
2507
2508 expected = self.try_structurally_resolve_type(pat.span, expected);
2509 if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2512 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2513 InheritedRefMatchRule::EatOuter => {
2514 if pat_mutbl > inh_mut {
2516 debug_assert!(ref_pat_matches_mut_ref);
2521 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2522 }
2523
2524 pat_info.binding_mode = ByRef::No;
2525 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2526 self.check_pat(inner, expected, pat_info);
2527 return expected;
2528 }
2529 InheritedRefMatchRule::EatInner => {
2530 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2531 && pat_mutbl <= r_mutbl
2532 {
2533 debug_assert!(ref_pat_matches_mut_ref);
2540 debug_assert!(self.downgrade_mut_inside_shared());
2544 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2545 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2546 } else {
2547 if pat_mutbl > inh_mut {
2550 debug_assert!(ref_pat_matches_mut_ref);
2559 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2560 }
2561
2562 pat_info.binding_mode = ByRef::No;
2563 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2564 self.check_pat(inner, expected, pat_info);
2565 return expected;
2566 }
2567 }
2568 InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
2569 pat_info.binding_mode = ByRef::No;
2571
2572 if let ty::Ref(_, inner_ty, _) = *expected.kind() {
2573 if pat_mutbl.is_mut() && inh_mut.is_mut() {
2575 self.check_pat(inner, inner_ty, pat_info);
2582 return expected;
2583 } else {
2584 }
2591 } else {
2592 if pat_mutbl > inh_mut {
2595 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2597 }
2598
2599 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2600 self.check_pat(inner, expected, pat_info);
2601 return expected;
2602 }
2603 }
2604 InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
2605 pat_info.binding_mode = ByRef::No;
2608 self.add_rust_2024_migration_desugared_pat(
2609 pat_info.top_info.hir_id,
2610 pat,
2611 match pat_mutbl {
2612 Mutability::Not => '&', Mutability::Mut => 't', },
2615 inh_mut,
2616 )
2617 }
2618 }
2619 }
2620
2621 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2622 Ok(()) => {
2623 debug!("check_pat_ref: expected={:?}", expected);
2630 match *expected.kind() {
2631 ty::Ref(_, r_ty, r_mutbl)
2632 if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2633 || r_mutbl == pat_mutbl =>
2634 {
2635 if r_mutbl == Mutability::Not {
2636 pat_info.max_ref_mutbl = MutblCap::Not;
2637 }
2638
2639 (expected, r_ty)
2640 }
2641
2642 _ => {
2643 let inner_ty = self.next_ty_var(inner.span);
2644 let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
2645 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2646 let err = self.demand_eqtype_pat_diag(
2647 pat.span,
2648 expected,
2649 ref_ty,
2650 &pat_info.top_info,
2651 );
2652
2653 if let Err(mut err) = err {
2656 self.borrow_pat_suggestion(&mut err, pat);
2657 err.emit();
2658 }
2659 (ref_ty, inner_ty)
2660 }
2661 }
2662 }
2663 Err(guar) => {
2664 let err = Ty::new_error(tcx, guar);
2665 (err, err)
2666 }
2667 };
2668
2669 self.check_pat(inner, inner_ty, pat_info);
2670 ref_ty
2671 }
2672
2673 fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
2675 let region = self.next_region_var(infer::PatternRegion(span));
2676 Ty::new_ref(self.tcx, region, ty, mutbl)
2677 }
2678
2679 fn error_inherited_ref_mutability_mismatch(
2680 &self,
2681 pat: &'tcx Pat<'tcx>,
2682 pat_prefix_span: Option<Span>,
2683 ) -> ErrorGuaranteed {
2684 let err_msg = "mismatched types";
2685 let err = if let Some(span) = pat_prefix_span {
2686 let mut err = self.dcx().struct_span_err(span, err_msg);
2687 err.code(E0308);
2688 err.note("cannot match inherited `&` with `&mut` pattern");
2689 err.span_suggestion_verbose(
2690 span,
2691 "replace this `&mut` pattern with `&`",
2692 "&",
2693 Applicability::MachineApplicable,
2694 );
2695 err
2696 } else {
2697 self.dcx().struct_span_err(pat.span, err_msg)
2698 };
2699 err.emit()
2700 }
2701
2702 fn try_resolve_slice_ty_to_array_ty(
2703 &self,
2704 before: &'tcx [Pat<'tcx>],
2705 slice: Option<&'tcx Pat<'tcx>>,
2706 span: Span,
2707 ) -> Option<Ty<'tcx>> {
2708 if slice.is_some() {
2709 return None;
2710 }
2711
2712 let tcx = self.tcx;
2713 let len = before.len();
2714 let inner_ty = self.next_ty_var(span);
2715
2716 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2717 }
2718
2719 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2750 match decl_origin {
2751 Some(DeclOrigin::LocalDecl { els: None }) => true,
2752 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2753 }
2754 }
2755
2756 fn check_pat_slice(
2767 &self,
2768 span: Span,
2769 before: &'tcx [Pat<'tcx>],
2770 slice: Option<&'tcx Pat<'tcx>>,
2771 after: &'tcx [Pat<'tcx>],
2772 expected: Ty<'tcx>,
2773 pat_info: PatInfo<'tcx>,
2774 ) -> Ty<'tcx> {
2775 let expected = self.try_structurally_resolve_type(span, expected);
2776
2777 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
2780 if let Some(resolved_arr_ty) =
2781 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
2782 {
2783 debug!(?resolved_arr_ty);
2784 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
2785 }
2786 }
2787
2788 let expected = self.structurally_resolve_type(span, expected);
2789 debug!(?expected);
2790
2791 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
2792 ty::Array(element_ty, len) => {
2794 let min = before.len() as u64 + after.len() as u64;
2795 let (opt_slice_ty, expected) =
2796 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
2797 assert!(opt_slice_ty.is_some() || slice.is_none());
2800 (element_ty, opt_slice_ty, expected)
2801 }
2802 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
2803 _ => {
2805 let guar = expected.error_reported().err().unwrap_or_else(|| {
2806 self.error_expected_array_or_slice(span, expected, pat_info)
2807 });
2808 let err = Ty::new_error(self.tcx, guar);
2809 (err, Some(err), err)
2810 }
2811 };
2812
2813 for elt in before {
2815 self.check_pat(elt, element_ty, pat_info);
2816 }
2817 if let Some(slice) = slice {
2819 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
2820 }
2821 for elt in after {
2823 self.check_pat(elt, element_ty, pat_info);
2824 }
2825 inferred
2826 }
2827
2828 fn check_array_pat_len(
2833 &self,
2834 span: Span,
2835 element_ty: Ty<'tcx>,
2836 arr_ty: Ty<'tcx>,
2837 slice: Option<&'tcx Pat<'tcx>>,
2838 len: ty::Const<'tcx>,
2839 min_len: u64,
2840 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
2841 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
2842
2843 let guar = if let Some(len) = len {
2844 if slice.is_none() {
2846 if min_len == len {
2850 return (None, arr_ty);
2851 }
2852
2853 self.error_scrutinee_inconsistent_length(span, min_len, len)
2854 } else if let Some(pat_len) = len.checked_sub(min_len) {
2855 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
2858 } else {
2859 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
2862 }
2863 } else if slice.is_none() {
2864 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
2867 self.demand_eqtype(span, updated_arr_ty, arr_ty);
2868 return (None, updated_arr_ty);
2869 } else {
2870 self.error_scrutinee_unfixed_length(span)
2874 };
2875
2876 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
2878 }
2879
2880 fn error_scrutinee_inconsistent_length(
2881 &self,
2882 span: Span,
2883 min_len: u64,
2884 size: u64,
2885 ) -> ErrorGuaranteed {
2886 struct_span_code_err!(
2887 self.dcx(),
2888 span,
2889 E0527,
2890 "pattern requires {} element{} but array has {}",
2891 min_len,
2892 pluralize!(min_len),
2893 size,
2894 )
2895 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
2896 .emit()
2897 }
2898
2899 fn error_scrutinee_with_rest_inconsistent_length(
2900 &self,
2901 span: Span,
2902 min_len: u64,
2903 size: u64,
2904 ) -> ErrorGuaranteed {
2905 struct_span_code_err!(
2906 self.dcx(),
2907 span,
2908 E0528,
2909 "pattern requires at least {} element{} but array has {}",
2910 min_len,
2911 pluralize!(min_len),
2912 size,
2913 )
2914 .with_span_label(
2915 span,
2916 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
2917 )
2918 .emit()
2919 }
2920
2921 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
2922 struct_span_code_err!(
2923 self.dcx(),
2924 span,
2925 E0730,
2926 "cannot pattern-match on an array without a fixed length",
2927 )
2928 .emit()
2929 }
2930
2931 fn error_expected_array_or_slice(
2932 &self,
2933 span: Span,
2934 expected_ty: Ty<'tcx>,
2935 pat_info: PatInfo<'tcx>,
2936 ) -> ErrorGuaranteed {
2937 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
2938
2939 let mut slice_pat_semantics = false;
2940 let mut as_deref = None;
2941 let mut slicing = None;
2942 if let ty::Ref(_, ty, _) = expected_ty.kind()
2943 && let ty::Array(..) | ty::Slice(..) = ty.kind()
2944 {
2945 slice_pat_semantics = true;
2946 } else if self
2947 .autoderef(span, expected_ty)
2948 .silence_errors()
2949 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
2950 && let Some(span) = ti.span
2951 && let Some(_) = ti.origin_expr
2952 {
2953 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
2954 let (is_slice_or_array_or_vector, resolved_ty) =
2955 self.is_slice_or_array_or_vector(resolved_ty);
2956 match resolved_ty.kind() {
2957 ty::Adt(adt_def, _)
2958 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
2959 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
2960 {
2961 as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() });
2963 }
2964 _ => (),
2965 }
2966
2967 let is_top_level = current_depth <= 1;
2968 if is_slice_or_array_or_vector && is_top_level {
2969 slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() });
2970 }
2971 }
2972 self.dcx().emit_err(errors::ExpectedArrayOrSlice {
2973 span,
2974 ty: expected_ty,
2975 slice_pat_semantics,
2976 as_deref,
2977 slicing,
2978 })
2979 }
2980
2981 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
2982 match ty.kind() {
2983 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
2984 (true, ty)
2985 }
2986 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
2987 ty::Slice(..) | ty::Array(..) => (true, ty),
2988 _ => (false, ty),
2989 }
2990 }
2991
2992 fn add_rust_2024_migration_desugared_pat(
2995 &self,
2996 pat_id: HirId,
2997 subpat: &'tcx Pat<'tcx>,
2998 final_char: char,
2999 def_br_mutbl: Mutability,
3000 ) {
3001 let from_expansion = subpat.span.from_expansion();
3003 let trimmed_span = if from_expansion {
3004 subpat.span
3006 } else {
3007 let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
3008 trimmed.with_ctxt(subpat.span.ctxt())
3011 };
3012
3013 let mut typeck_results = self.typeck_results.borrow_mut();
3014 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
3015 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
3020 primary_labels: Vec::new(),
3021 bad_modifiers: false,
3022 bad_ref_pats: false,
3023 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
3024 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
3025 });
3026
3027 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
3028 info.bad_modifiers = true;
3029 info.suggest_eliding_modes &=
3033 user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
3034 "binding modifier"
3035 } else {
3036 info.bad_ref_pats = true;
3037 info.suggest_eliding_modes = false;
3041 "reference pattern"
3042 };
3043 let primary_label = if from_expansion {
3046 info.suggest_eliding_modes = false;
3048 "occurs within macro expansion".to_owned()
3052 } else {
3053 let dbm_str = match def_br_mutbl {
3054 Mutability::Not => "ref",
3055 Mutability::Mut => "ref mut",
3056 };
3057 format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
3058 };
3059 info.primary_labels.push((trimmed_span, primary_label));
3060 }
3061}