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::pat_util::EnumerateAndAdjustIterator;
13use rustc_hir::{
14 self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
15 PatExprKind, PatKind, expr_needs_parens,
16};
17use rustc_infer::infer;
18use rustc_middle::traits::PatternOriginExpr;
19use rustc_middle::ty::{self, Ty, TypeVisitableExt};
20use rustc_middle::{bug, span_bug};
21use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
22use rustc_session::parse::feature_err;
23use rustc_span::edit_distance::find_best_match_for_name;
24use rustc_span::edition::Edition;
25use rustc_span::hygiene::DesugaringKind;
26use rustc_span::source_map::Spanned;
27use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym};
28use rustc_trait_selection::infer::InferCtxtExt;
29use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
30use tracing::{debug, instrument, trace};
31use ty::VariantDef;
32
33use super::report_unexpected_variant_res;
34use crate::expectation::Expectation;
35use crate::gather_locals::DeclOrigin;
36use crate::{FnCtxt, LoweredTy, errors};
37
38const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
39This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
40pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \
41this type has no compile-time size. Therefore, all accesses to trait types must be through \
42pointers. If you encounter this error you should try to avoid dereferencing the pointer.
43
44You can read more about trait objects in the Trait Objects section of the Reference: \
45https://doc.rust-lang.org/reference/types.html#trait-objects";
46
47fn is_number(text: &str) -> bool {
48 text.chars().all(|c: char| c.is_digit(10))
49}
50
51#[derive(Copy, Clone)]
55struct TopInfo<'tcx> {
56 expected: Ty<'tcx>,
58 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
62 span: Option<Span>,
85 hir_id: HirId,
87}
88
89#[derive(Copy, Clone)]
90struct PatInfo<'a, 'tcx> {
91 binding_mode: ByRef,
92 max_ref_mutbl: MutblCap,
93 top_info: &'a TopInfo<'tcx>,
94 decl_origin: Option<DeclOrigin<'tcx>>,
95
96 current_depth: u32,
98}
99
100impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
101 fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
102 let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
107 let mut count = 0;
108
109 while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
113 cur_expr = inner;
114 count += 1;
115 }
116
117 PatternOriginExpr {
118 peeled_span: cur_expr.span,
119 peeled_count: count,
120 peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
121 }
122 });
123
124 let code = ObligationCauseCode::Pattern {
125 span: ti.span,
126 root_ty: ti.expected,
127 origin_expr: origin_expr_info,
128 };
129 self.cause(cause_span, code)
130 }
131
132 fn demand_eqtype_pat_diag(
133 &'a self,
134 cause_span: Span,
135 expected: Ty<'tcx>,
136 actual: Ty<'tcx>,
137 ti: &TopInfo<'tcx>,
138 ) -> Result<(), Diag<'a>> {
139 self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
140 .map_err(|mut diag| {
141 if let Some(expr) = ti.origin_expr {
142 self.suggest_fn_call(&mut diag, expr, expected, |output| {
143 self.can_eq(self.param_env, output, actual)
144 });
145 }
146 diag
147 })
148 }
149
150 fn demand_eqtype_pat(
151 &self,
152 cause_span: Span,
153 expected: Ty<'tcx>,
154 actual: Ty<'tcx>,
155 ti: &TopInfo<'tcx>,
156 ) -> Result<(), ErrorGuaranteed> {
157 self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit())
158 }
159}
160
161#[derive(Clone, Copy, Debug, PartialEq, Eq)]
163enum AdjustMode {
164 Peel,
166 Reset,
169 Pass,
171}
172
173#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184enum MutblCap {
185 Not,
187
188 WeaklyNot(Option<Span>),
195
196 Mut,
198}
199
200impl MutblCap {
201 #[must_use]
202 fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
203 match self {
204 MutblCap::Not => MutblCap::Not,
205 _ => MutblCap::WeaklyNot(span),
206 }
207 }
208
209 #[must_use]
210 fn as_mutbl(self) -> Mutability {
211 match self {
212 MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
213 MutblCap::Mut => Mutability::Mut,
214 }
215 }
216}
217
218#[derive(Clone, Copy, Debug, PartialEq, Eq)]
224enum InheritedRefMatchRule {
225 EatOuter,
229 EatInner,
232 EatBoth,
237}
238
239impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
240 fn downgrade_mut_inside_shared(&self) -> bool {
244 self.tcx.features().ref_pat_eat_one_layer_2024_structural()
247 }
248
249 fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule {
252 if edition.at_least_rust_2024() {
255 if self.tcx.features().ref_pat_eat_one_layer_2024() {
256 InheritedRefMatchRule::EatOuter
257 } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() {
258 InheritedRefMatchRule::EatInner
259 } else {
260 InheritedRefMatchRule::EatBoth
263 }
264 } else {
265 InheritedRefMatchRule::EatBoth
266 }
267 }
268
269 fn ref_pat_matches_mut_ref(&self) -> bool {
272 self.tcx.features().ref_pat_eat_one_layer_2024()
275 || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
276 }
277
278 pub(crate) fn check_pat_top(
287 &self,
288 pat: &'tcx Pat<'tcx>,
289 expected: Ty<'tcx>,
290 span: Option<Span>,
291 origin_expr: Option<&'tcx hir::Expr<'tcx>>,
292 decl_origin: Option<DeclOrigin<'tcx>>,
293 ) {
294 let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
295 let pat_info = PatInfo {
296 binding_mode: ByRef::No,
297 max_ref_mutbl: MutblCap::Mut,
298 top_info: &info,
299 decl_origin,
300 current_depth: 0,
301 };
302 self.check_pat(pat, expected, pat_info);
303 }
304
305 #[instrument(level = "debug", skip(self, pat_info))]
311 fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
312 let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
313
314 let path_res = match pat.kind {
315 PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
316 Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
317 }
318 _ => None,
319 };
320 let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
321 let (expected, binding_mode, max_ref_mutbl) =
322 self.calc_default_binding_mode(pat, expected, binding_mode, adjust_mode, max_ref_mutbl);
323 let pat_info = PatInfo {
324 binding_mode,
325 max_ref_mutbl,
326 top_info: ti,
327 decl_origin: pat_info.decl_origin,
328 current_depth: current_depth + 1,
329 };
330
331 let ty = match pat.kind {
332 PatKind::Wild | PatKind::Err(_) => expected,
333 PatKind::Never => expected,
335 PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
336 let ty = self.check_pat_path(
337 *hir_id,
338 pat.hir_id,
339 *span,
340 qpath,
341 path_res.unwrap(),
342 expected,
343 ti,
344 );
345 self.write_ty(*hir_id, ty);
346 ty
347 }
348 PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
349 PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
350 PatKind::Binding(ba, var_id, ident, sub) => {
351 self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
352 }
353 PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
354 self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
355 }
356 PatKind::Struct(ref qpath, fields, has_rest_pat) => {
357 self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
358 }
359 PatKind::Guard(pat, cond) => {
360 self.check_pat(pat, expected, pat_info);
361 self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
362 expected
363 }
364 PatKind::Or(pats) => {
365 for pat in pats {
366 self.check_pat(pat, expected, pat_info);
367 }
368 expected
369 }
370 PatKind::Tuple(elements, ddpos) => {
371 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
372 }
373 PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
374 PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
375 PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
376 PatKind::Slice(before, slice, after) => {
377 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
378 }
379 };
380
381 self.write_ty(pat.hir_id, ty);
382
383 }
425
426 fn calc_default_binding_mode(
429 &self,
430 pat: &'tcx Pat<'tcx>,
431 expected: Ty<'tcx>,
432 def_br: ByRef,
433 adjust_mode: AdjustMode,
434 max_ref_mutbl: MutblCap,
435 ) -> (Ty<'tcx>, ByRef, MutblCap) {
436 #[cfg(debug_assertions)]
437 if def_br == ByRef::Yes(Mutability::Mut)
438 && max_ref_mutbl != MutblCap::Mut
439 && self.downgrade_mut_inside_shared()
440 {
441 span_bug!(pat.span, "Pattern mutability cap violated!");
442 }
443 match adjust_mode {
444 AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
445 AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut),
446 AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl),
447 }
448 }
449
450 fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
454 if !pat.default_binding_modes {
457 return AdjustMode::Reset;
458 }
459 match &pat.kind {
460 PatKind::Struct(..)
463 | PatKind::TupleStruct(..)
464 | PatKind::Tuple(..)
465 | PatKind::Box(_)
466 | PatKind::Deref(_)
467 | PatKind::Range(..)
468 | PatKind::Slice(..) => AdjustMode::Peel,
469 PatKind::Never => AdjustMode::Peel,
471 PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() {
472 Res::Def(DefKind::Const | DefKind::AssocConst, _) => AdjustMode::Pass,
476 _ => AdjustMode::Peel,
481 },
482
483 PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
489 ty::Ref(..) => AdjustMode::Pass,
490 _ => AdjustMode::Peel,
491 },
492
493 PatKind::Ref(..) => AdjustMode::Pass,
495 PatKind::Wild
497 | PatKind::Err(_)
499 | PatKind::Binding(..)
504 | PatKind::Or(_)
508 | PatKind::Guard(..) => AdjustMode::Pass,
510 }
511 }
512
513 fn peel_off_references(
517 &self,
518 pat: &'tcx Pat<'tcx>,
519 expected: Ty<'tcx>,
520 mut def_br: ByRef,
521 mut max_ref_mutbl: MutblCap,
522 ) -> (Ty<'tcx>, ByRef, MutblCap) {
523 let mut expected = self.try_structurally_resolve_type(pat.span, expected);
524 let mut pat_adjustments = vec![];
533 while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
534 debug!("inspecting {:?}", expected);
535
536 debug!("current discriminant is Ref, inserting implicit deref");
537 pat_adjustments.push(expected);
539
540 expected = self.try_structurally_resolve_type(pat.span, inner_ty);
541 def_br = ByRef::Yes(match def_br {
542 ByRef::No |
545 ByRef::Yes(Mutability::Mut) => inner_mutability,
547 ByRef::Yes(Mutability::Not) => Mutability::Not,
550 });
551 }
552
553 if self.downgrade_mut_inside_shared() {
554 def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
555 }
556 if def_br == ByRef::Yes(Mutability::Not) {
557 max_ref_mutbl = MutblCap::Not;
558 }
559
560 if !pat_adjustments.is_empty() {
561 debug!("default binding mode is now {:?}", def_br);
562 self.typeck_results
563 .borrow_mut()
564 .pat_adjustments_mut()
565 .insert(pat.hir_id, pat_adjustments);
566 }
567
568 (expected, def_br, max_ref_mutbl)
569 }
570
571 fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
572 let ty = match <.kind {
573 rustc_hir::PatExprKind::Lit { lit, negated } => {
574 let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
575 if *negated {
576 self.register_bound(
577 ty,
578 self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
579 ObligationCause::dummy_with_span(lt.span),
580 );
581 }
582 ty
583 }
584 rustc_hir::PatExprKind::ConstBlock(c) => {
585 self.check_expr_const_block(c, Expectation::NoExpectation)
586 }
587 rustc_hir::PatExprKind::Path(qpath) => {
588 let (res, opt_ty, segments) =
589 self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
590 self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0
591 }
592 };
593 self.write_ty(lt.hir_id, ty);
594 ty
595 }
596
597 fn check_pat_lit(
598 &self,
599 span: Span,
600 lt: &hir::PatExpr<'tcx>,
601 expected: Ty<'tcx>,
602 ti: &TopInfo<'tcx>,
603 ) -> Ty<'tcx> {
604 let ty = self.node_ty(lt.hir_id);
607
608 let mut pat_ty = ty;
611 if let hir::PatExprKind::Lit {
612 lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
613 } = lt.kind
614 {
615 let expected = self.structurally_resolve_type(span, expected);
616 if let ty::Ref(_, inner_ty, _) = *expected.kind()
617 && self.try_structurally_resolve_type(span, inner_ty).is_slice()
618 {
619 let tcx = self.tcx;
620 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
621 self.typeck_results
622 .borrow_mut()
623 .treat_byte_string_as_slice
624 .insert(lt.hir_id.local_id);
625 pat_ty =
626 Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
627 }
628 }
629
630 if self.tcx.features().string_deref_patterns()
631 && let hir::PatExprKind::Lit {
632 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
633 } = lt.kind
634 {
635 let tcx = self.tcx;
636 let expected = self.resolve_vars_if_possible(expected);
637 pat_ty = match expected.kind() {
638 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
639 ty::Str => Ty::new_static_str(tcx),
640 _ => pat_ty,
641 };
642 }
643
644 let cause = self.pattern_cause(ti, span);
655 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
656 err.emit_unless(
657 ti.span
658 .filter(|&s| {
659 s.is_desugaring(DesugaringKind::CondTemporary)
663 })
664 .is_some(),
665 );
666 }
667
668 pat_ty
669 }
670
671 fn check_pat_range(
672 &self,
673 span: Span,
674 lhs: Option<&'tcx hir::PatExpr<'tcx>>,
675 rhs: Option<&'tcx hir::PatExpr<'tcx>>,
676 expected: Ty<'tcx>,
677 ti: &TopInfo<'tcx>,
678 ) -> Ty<'tcx> {
679 let calc_side = |opt_expr: Option<&'tcx hir::PatExpr<'tcx>>| match opt_expr {
680 None => None,
681 Some(expr) => {
682 let ty = self.check_pat_expr_unadjusted(expr);
683 let fail =
690 !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
691 Some((fail, ty, expr.span))
692 }
693 };
694 let mut lhs = calc_side(lhs);
695 let mut rhs = calc_side(rhs);
696
697 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
698 let guar = self.emit_err_pat_range(span, lhs, rhs);
701 return Ty::new_error(self.tcx, guar);
702 }
703
704 let demand_eqtype = |x: &mut _, y| {
707 if let Some((ref mut fail, x_ty, x_span)) = *x
708 && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti)
709 {
710 if let Some((_, y_ty, y_span)) = y {
711 self.endpoint_has_type(&mut err, y_span, y_ty);
712 }
713 err.emit();
714 *fail = true;
715 }
716 };
717 demand_eqtype(&mut lhs, rhs);
718 demand_eqtype(&mut rhs, lhs);
719
720 if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
721 return Ty::new_misc_error(self.tcx);
722 }
723
724 let ty = self.structurally_resolve_type(span, expected);
729 if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
730 if let Some((ref mut fail, _, _)) = lhs {
731 *fail = true;
732 }
733 if let Some((ref mut fail, _, _)) = rhs {
734 *fail = true;
735 }
736 let guar = self.emit_err_pat_range(span, lhs, rhs);
737 return Ty::new_error(self.tcx, guar);
738 }
739 ty
740 }
741
742 fn endpoint_has_type(&self, err: &mut Diag<'_>, span: Span, ty: Ty<'_>) {
743 if !ty.references_error() {
744 err.span_label(span, format!("this is of type `{ty}`"));
745 }
746 }
747
748 fn emit_err_pat_range(
749 &self,
750 span: Span,
751 lhs: Option<(bool, Ty<'tcx>, Span)>,
752 rhs: Option<(bool, Ty<'tcx>, Span)>,
753 ) -> ErrorGuaranteed {
754 let span = match (lhs, rhs) {
755 (Some((true, ..)), Some((true, ..))) => span,
756 (Some((true, _, sp)), _) => sp,
757 (_, Some((true, _, sp))) => sp,
758 _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
759 };
760 let mut err = struct_span_code_err!(
761 self.dcx(),
762 span,
763 E0029,
764 "only `char` and numeric types are allowed in range patterns"
765 );
766 let msg = |ty| {
767 let ty = self.resolve_vars_if_possible(ty);
768 format!("this is of type `{ty}` but it should be `char` or numeric")
769 };
770 let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
771 err.span_label(first_span, msg(first_ty));
772 if let Some((_, ty, sp)) = second {
773 let ty = self.resolve_vars_if_possible(ty);
774 self.endpoint_has_type(&mut err, sp, ty);
775 }
776 };
777 match (lhs, rhs) {
778 (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
779 err.span_label(lhs_sp, msg(lhs_ty));
780 err.span_label(rhs_sp, msg(rhs_ty));
781 }
782 (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
783 (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
784 _ => span_bug!(span, "Impossible, verified above."),
785 }
786 if (lhs, rhs).references_error() {
787 err.downgrade_to_delayed_bug();
788 }
789 if self.tcx.sess.teach(err.code.unwrap()) {
790 err.note(
791 "In a match expression, only numbers and characters can be matched \
792 against a range. This is because the compiler checks that the range \
793 is non-empty at compile-time, and is unable to evaluate arbitrary \
794 comparison functions. If you want to capture values of an orderable \
795 type between two end-points, you can use a guard.",
796 );
797 }
798 err.emit()
799 }
800
801 fn check_pat_ident(
802 &self,
803 pat: &'tcx Pat<'tcx>,
804 user_bind_annot: BindingMode,
805 var_id: HirId,
806 ident: Ident,
807 sub: Option<&'tcx Pat<'tcx>>,
808 expected: Ty<'tcx>,
809 pat_info: PatInfo<'_, 'tcx>,
810 ) -> Ty<'tcx> {
811 let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
812
813 let bm = match user_bind_annot {
815 BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
816 if pat.span.at_least_rust_2024()
819 && (self.tcx.features().ref_pat_eat_one_layer_2024()
820 || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
821 {
822 if !self.tcx.features().mut_ref() {
823 feature_err(
824 &self.tcx.sess,
825 sym::mut_ref,
826 pat.span.until(ident.span),
827 "binding cannot be both mutable and by-reference",
828 )
829 .emit();
830 }
831
832 BindingMode(def_br, Mutability::Mut)
833 } else {
834 self.add_rust_2024_migration_desugared_pat(
836 pat_info.top_info.hir_id,
837 pat,
838 ident.span,
839 def_br_mutbl,
840 );
841 BindingMode(ByRef::No, Mutability::Mut)
842 }
843 }
844 BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
845 BindingMode(ByRef::Yes(_), _) => {
846 if let ByRef::Yes(def_br_mutbl) = def_br {
847 self.add_rust_2024_migration_desugared_pat(
849 pat_info.top_info.hir_id,
850 pat,
851 ident.span,
852 def_br_mutbl,
853 );
854 }
855 user_bind_annot
856 }
857 };
858
859 if bm.0 == ByRef::Yes(Mutability::Mut)
860 && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
861 {
862 let mut err = struct_span_code_err!(
863 self.dcx(),
864 ident.span,
865 E0596,
866 "cannot borrow as mutable inside an `&` pattern"
867 );
868
869 if let Some(span) = and_pat_span {
870 err.span_suggestion(
871 span,
872 "replace this `&` with `&mut`",
873 "&mut ",
874 Applicability::MachineApplicable,
875 );
876 }
877 err.emit();
878 }
879
880 self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
882
883 debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
884
885 let local_ty = self.local_ty(pat.span, pat.hir_id);
886 let eq_ty = match bm.0 {
887 ByRef::Yes(mutbl) => {
888 self.new_ref_ty(pat.span, mutbl, expected)
896 }
897 ByRef::No => expected, };
900
901 let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti);
903
904 if var_id != pat.hir_id {
907 self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, ti);
908 }
909
910 if let Some(p) = sub {
911 self.check_pat(p, expected, pat_info);
912 }
913
914 local_ty
915 }
916
917 fn check_binding_alt_eq_ty(
921 &self,
922 ba: BindingMode,
923 span: Span,
924 var_id: HirId,
925 ty: Ty<'tcx>,
926 ti: &TopInfo<'tcx>,
927 ) {
928 let var_ty = self.local_ty(span, var_id);
929 if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
930 let hir = self.tcx.hir();
931 let var_ty = self.resolve_vars_if_possible(var_ty);
932 let msg = format!("first introduced with type `{var_ty}` here");
933 err.span_label(hir.span(var_id), msg);
934 let in_match = hir.parent_iter(var_id).any(|(_, n)| {
935 matches!(
936 n,
937 hir::Node::Expr(hir::Expr {
938 kind: hir::ExprKind::Match(.., hir::MatchSource::Normal),
939 ..
940 })
941 )
942 });
943 let pre = if in_match { "in the same arm, " } else { "" };
944 err.note(format!("{pre}a binding must have the same type in all alternatives"));
945 self.suggest_adding_missing_ref_or_removing_ref(
946 &mut err,
947 span,
948 var_ty,
949 self.resolve_vars_if_possible(ty),
950 ba,
951 );
952 err.emit();
953 }
954 }
955
956 fn suggest_adding_missing_ref_or_removing_ref(
957 &self,
958 err: &mut Diag<'_>,
959 span: Span,
960 expected: Ty<'tcx>,
961 actual: Ty<'tcx>,
962 ba: BindingMode,
963 ) {
964 match (expected.kind(), actual.kind(), ba) {
965 (ty::Ref(_, inner_ty, _), _, BindingMode::NONE)
966 if self.can_eq(self.param_env, *inner_ty, actual) =>
967 {
968 err.span_suggestion_verbose(
969 span.shrink_to_lo(),
970 "consider adding `ref`",
971 "ref ",
972 Applicability::MaybeIncorrect,
973 );
974 }
975 (_, ty::Ref(_, inner_ty, _), BindingMode::REF)
976 if self.can_eq(self.param_env, expected, *inner_ty) =>
977 {
978 err.span_suggestion_verbose(
979 span.with_hi(span.lo() + BytePos(4)),
980 "consider removing `ref`",
981 "",
982 Applicability::MaybeIncorrect,
983 );
984 }
985 _ => (),
986 }
987 }
988
989 fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
991 let tcx = self.tcx;
992 if let PatKind::Ref(inner, mutbl) = pat.kind
993 && let PatKind::Binding(_, _, binding, ..) = inner.kind
994 {
995 let binding_parent = tcx.parent_hir_node(pat.hir_id);
996 debug!(?inner, ?pat, ?binding_parent);
997
998 let mutability = match mutbl {
999 ast::Mutability::Mut => "mut",
1000 ast::Mutability::Not => "",
1001 };
1002
1003 let mut_var_suggestion = 'block: {
1004 if mutbl.is_not() {
1005 break 'block None;
1006 }
1007
1008 let ident_kind = match binding_parent {
1009 hir::Node::Param(_) => "parameter",
1010 hir::Node::LetStmt(_) => "variable",
1011 hir::Node::Arm(_) => "binding",
1012
1013 hir::Node::Pat(Pat { kind, .. }) => match kind {
1016 PatKind::Struct(..)
1017 | PatKind::TupleStruct(..)
1018 | PatKind::Or(..)
1019 | PatKind::Guard(..)
1020 | PatKind::Tuple(..)
1021 | PatKind::Slice(..) => "binding",
1022
1023 PatKind::Wild
1024 | PatKind::Never
1025 | PatKind::Binding(..)
1026 | PatKind::Box(..)
1027 | PatKind::Deref(_)
1028 | PatKind::Ref(..)
1029 | PatKind::Expr(..)
1030 | PatKind::Range(..)
1031 | PatKind::Err(_) => break 'block None,
1032 },
1033
1034 _ => break 'block None,
1036 };
1037
1038 Some((
1039 pat.span,
1040 format!("to declare a mutable {ident_kind} use"),
1041 format!("mut {binding}"),
1042 ))
1043 };
1044
1045 match binding_parent {
1046 hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
1049 err.multipart_suggestion_verbose(
1050 format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
1051 vec![
1052 (pat.span.until(inner.span), "".to_owned()),
1053 (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
1054 ],
1055 Applicability::MachineApplicable
1056 );
1057
1058 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1059 err.span_note(sp, format!("{msg}: `{sugg}`"));
1060 }
1061 }
1062 hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
1063 for i in pat_arr.iter() {
1064 if let PatKind::Ref(the_ref, _) = i.kind
1065 && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
1066 {
1067 let BindingMode(_, mtblty) = mt;
1068 err.span_suggestion_verbose(
1069 i.span,
1070 format!("consider removing `&{mutability}` from the pattern"),
1071 mtblty.prefix_str().to_string() + &ident.name.to_string(),
1072 Applicability::MaybeIncorrect,
1073 );
1074 }
1075 }
1076 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1077 err.span_note(sp, format!("{msg}: `{sugg}`"));
1078 }
1079 }
1080 hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
1081 err.span_suggestion_verbose(
1083 pat.span.until(inner.span),
1084 format!("consider removing `&{mutability}` from the pattern"),
1085 "",
1086 Applicability::MaybeIncorrect,
1087 );
1088
1089 if let Some((sp, msg, sugg)) = mut_var_suggestion {
1090 err.span_note(sp, format!("{msg}: `{sugg}`"));
1091 }
1092 }
1093 _ if let Some((sp, msg, sugg)) = mut_var_suggestion => {
1094 err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable);
1095 }
1096 _ => {} }
1098 }
1099 }
1100
1101 fn check_dereferenceable(
1102 &self,
1103 span: Span,
1104 expected: Ty<'tcx>,
1105 inner: &Pat<'_>,
1106 ) -> Result<(), ErrorGuaranteed> {
1107 if let PatKind::Binding(..) = inner.kind
1108 && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
1109 && let ty::Dynamic(..) = pointee_ty.kind()
1110 {
1111 let type_str = self.ty_to_string(expected);
1114 let mut err = struct_span_code_err!(
1115 self.dcx(),
1116 span,
1117 E0033,
1118 "type `{}` cannot be dereferenced",
1119 type_str
1120 );
1121 err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
1122 if self.tcx.sess.teach(err.code.unwrap()) {
1123 err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
1124 }
1125 return Err(err.emit());
1126 }
1127 Ok(())
1128 }
1129
1130 fn check_pat_struct(
1131 &self,
1132 pat: &'tcx Pat<'tcx>,
1133 qpath: &hir::QPath<'tcx>,
1134 fields: &'tcx [hir::PatField<'tcx>],
1135 has_rest_pat: bool,
1136 expected: Ty<'tcx>,
1137 pat_info: PatInfo<'_, 'tcx>,
1138 ) -> Ty<'tcx> {
1139 let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
1141 Ok(data) => data,
1142 Err(guar) => {
1143 let err = Ty::new_error(self.tcx, guar);
1144 for field in fields {
1145 self.check_pat(field.pat, err, pat_info);
1146 }
1147 return err;
1148 }
1149 };
1150
1151 let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info);
1153
1154 match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
1156 Ok(()) => pat_ty,
1157 Err(guar) => Ty::new_error(self.tcx, guar),
1158 }
1159 }
1160
1161 fn check_pat_path(
1162 &self,
1163 path_id: HirId,
1164 pat_id_for_diag: HirId,
1165 span: Span,
1166 qpath: &hir::QPath<'_>,
1167 path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
1168 expected: Ty<'tcx>,
1169 ti: &TopInfo<'tcx>,
1170 ) -> Ty<'tcx> {
1171 let tcx = self.tcx;
1172
1173 let (res, opt_ty, segments) = path_resolution;
1175 match res {
1176 Res::Err => {
1177 let e =
1178 self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
1179 self.set_tainted_by_errors(e);
1180 return Ty::new_error(tcx, e);
1181 }
1182 Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
1183 let expected = "unit struct, unit variant or constant";
1184 let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
1185 return Ty::new_error(tcx, e);
1186 }
1187 Res::SelfCtor(def_id) => {
1188 if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
1189 && adt_def.is_struct()
1190 && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
1191 {
1192 } else {
1194 let e = report_unexpected_variant_res(
1195 tcx,
1196 res,
1197 None,
1198 qpath,
1199 span,
1200 E0533,
1201 "unit struct",
1202 );
1203 return Ty::new_error(tcx, e);
1204 }
1205 }
1206 Res::Def(
1207 DefKind::Ctor(_, CtorKind::Const)
1208 | DefKind::Const
1209 | DefKind::AssocConst
1210 | DefKind::ConstParam,
1211 _,
1212 ) => {} _ => bug!("unexpected pattern resolution: {:?}", res),
1214 }
1215
1216 let (pat_ty, pat_res) =
1218 self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
1219 if let Err(err) =
1220 self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
1221 {
1222 self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments);
1223 }
1224 pat_ty
1225 }
1226
1227 fn maybe_suggest_range_literal(
1228 &self,
1229 e: &mut Diag<'_>,
1230 opt_def_id: Option<hir::def_id::DefId>,
1231 ident: Ident,
1232 ) -> bool {
1233 match opt_def_id {
1234 Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
1235 Some(hir::Node::Item(hir::Item {
1236 kind: hir::ItemKind::Const(_, _, body_id),
1237 ..
1238 })) => match self.tcx.hir_node(body_id.hir_id) {
1239 hir::Node::Expr(expr) => {
1240 if hir::is_range_literal(expr) {
1241 let span = self.tcx.hir().span(body_id.hir_id);
1242 if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
1243 e.span_suggestion_verbose(
1244 ident.span,
1245 "you may want to move the range into the match block",
1246 snip,
1247 Applicability::MachineApplicable,
1248 );
1249 return true;
1250 }
1251 }
1252 }
1253 _ => (),
1254 },
1255 _ => (),
1256 },
1257 _ => (),
1258 }
1259 false
1260 }
1261
1262 fn emit_bad_pat_path(
1263 &self,
1264 mut e: Diag<'_>,
1265 hir_id: HirId,
1266 pat_span: Span,
1267 res: Res,
1268 pat_res: Res,
1269 pat_ty: Ty<'tcx>,
1270 segments: &'tcx [hir::PathSegment<'tcx>],
1271 ) {
1272 if let Some(span) = self.tcx.hir().res_span(pat_res) {
1273 e.span_label(span, format!("{} defined here", res.descr()));
1274 if let [hir::PathSegment { ident, .. }] = &*segments {
1275 e.span_label(
1276 pat_span,
1277 format!(
1278 "`{}` is interpreted as {} {}, not a new binding",
1279 ident,
1280 res.article(),
1281 res.descr(),
1282 ),
1283 );
1284 match self.tcx.parent_hir_node(hir_id) {
1285 hir::Node::PatField(..) => {
1286 e.span_suggestion_verbose(
1287 ident.span.shrink_to_hi(),
1288 "bind the struct field to a different name instead",
1289 format!(": other_{}", ident.as_str().to_lowercase()),
1290 Applicability::HasPlaceholders,
1291 );
1292 }
1293 _ => {
1294 let (type_def_id, item_def_id) = match pat_ty.kind() {
1295 ty::Adt(def, _) => match res {
1296 Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
1297 _ => (None, None),
1298 },
1299 _ => (None, None),
1300 };
1301
1302 let ranges = &[
1303 self.tcx.lang_items().range_struct(),
1304 self.tcx.lang_items().range_from_struct(),
1305 self.tcx.lang_items().range_to_struct(),
1306 self.tcx.lang_items().range_full_struct(),
1307 self.tcx.lang_items().range_inclusive_struct(),
1308 self.tcx.lang_items().range_to_inclusive_struct(),
1309 ];
1310 if type_def_id != None && ranges.contains(&type_def_id) {
1311 if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1312 let msg = "constants only support matching by type, \
1313 if you meant to match against a range of values, \
1314 consider using a range pattern like `min ..= max` in the match block";
1315 e.note(msg);
1316 }
1317 } else {
1318 let msg = "introduce a new binding instead";
1319 let sugg = format!("other_{}", ident.as_str().to_lowercase());
1320 e.span_suggestion(
1321 ident.span,
1322 msg,
1323 sugg,
1324 Applicability::HasPlaceholders,
1325 );
1326 }
1327 }
1328 };
1329 }
1330 }
1331 e.emit();
1332 }
1333
1334 fn check_pat_tuple_struct(
1335 &self,
1336 pat: &'tcx Pat<'tcx>,
1337 qpath: &'tcx hir::QPath<'tcx>,
1338 subpats: &'tcx [Pat<'tcx>],
1339 ddpos: hir::DotDotPos,
1340 expected: Ty<'tcx>,
1341 pat_info: PatInfo<'_, 'tcx>,
1342 ) -> Ty<'tcx> {
1343 let tcx = self.tcx;
1344 let on_error = |e| {
1345 for pat in subpats {
1346 self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1347 }
1348 };
1349 let report_unexpected_res = |res: Res| {
1350 let expected = "tuple struct or tuple variant";
1351 let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
1352 on_error(e);
1353 e
1354 };
1355
1356 let (res, opt_ty, segments) =
1358 self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
1359 if res == Res::Err {
1360 let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
1361 self.set_tainted_by_errors(e);
1362 on_error(e);
1363 return Ty::new_error(tcx, e);
1364 }
1365
1366 let (pat_ty, res) =
1368 self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
1369 if !pat_ty.is_fn() {
1370 let e = report_unexpected_res(res);
1371 return Ty::new_error(tcx, e);
1372 }
1373
1374 let variant = match res {
1375 Res::Err => {
1376 self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
1377 }
1378 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
1379 let e = report_unexpected_res(res);
1380 return Ty::new_error(tcx, e);
1381 }
1382 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
1383 _ => bug!("unexpected pattern resolution: {:?}", res),
1384 };
1385
1386 let pat_ty = pat_ty.fn_sig(tcx).output();
1388 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1389
1390 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info);
1392 let had_err = diag.map_err(|diag| diag.emit());
1393
1394 if subpats.len() == variant.fields.len()
1396 || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
1397 {
1398 let ty::Adt(_, args) = pat_ty.kind() else {
1399 bug!("unexpected pattern type {:?}", pat_ty);
1400 };
1401 for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1402 let field = &variant.fields[FieldIdx::from_usize(i)];
1403 let field_ty = self.field_ty(subpat.span, field, args);
1404 self.check_pat(subpat, field_ty, pat_info);
1405
1406 self.tcx.check_stability(
1407 variant.fields[FieldIdx::from_usize(i)].did,
1408 Some(pat.hir_id),
1409 subpat.span,
1410 None,
1411 );
1412 }
1413 if let Err(e) = had_err {
1414 on_error(e);
1415 return Ty::new_error(tcx, e);
1416 }
1417 } else {
1418 let e = self.emit_err_pat_wrong_number_of_fields(
1419 pat.span,
1420 res,
1421 qpath,
1422 subpats,
1423 &variant.fields.raw,
1424 expected,
1425 had_err,
1426 );
1427 on_error(e);
1428 return Ty::new_error(tcx, e);
1429 }
1430 pat_ty
1431 }
1432
1433 fn emit_err_pat_wrong_number_of_fields(
1434 &self,
1435 pat_span: Span,
1436 res: Res,
1437 qpath: &hir::QPath<'_>,
1438 subpats: &'tcx [Pat<'tcx>],
1439 fields: &'tcx [ty::FieldDef],
1440 expected: Ty<'tcx>,
1441 had_err: Result<(), ErrorGuaranteed>,
1442 ) -> ErrorGuaranteed {
1443 let subpats_ending = pluralize!(subpats.len());
1444 let fields_ending = pluralize!(fields.len());
1445
1446 let subpat_spans = if subpats.is_empty() {
1447 vec![pat_span]
1448 } else {
1449 subpats.iter().map(|p| p.span).collect()
1450 };
1451 let last_subpat_span = *subpat_spans.last().unwrap();
1452 let res_span = self.tcx.def_span(res.def_id());
1453 let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1454 let field_def_spans = if fields.is_empty() {
1455 vec![res_span]
1456 } else {
1457 fields.iter().map(|f| f.ident(self.tcx).span).collect()
1458 };
1459 let last_field_def_span = *field_def_spans.last().unwrap();
1460
1461 let mut err = struct_span_code_err!(
1462 self.dcx(),
1463 MultiSpan::from_spans(subpat_spans),
1464 E0023,
1465 "this pattern has {} field{}, but the corresponding {} has {} field{}",
1466 subpats.len(),
1467 subpats_ending,
1468 res.descr(),
1469 fields.len(),
1470 fields_ending,
1471 );
1472 err.span_label(
1473 last_subpat_span,
1474 format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1475 );
1476 if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
1477 err.span_label(qpath.span(), "");
1478 }
1479 if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
1480 err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1481 }
1482 for span in &field_def_spans[..field_def_spans.len() - 1] {
1483 err.span_label(*span, "");
1484 }
1485 err.span_label(
1486 last_field_def_span,
1487 format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1488 );
1489
1490 let missing_parentheses = match (expected.kind(), fields, had_err) {
1495 (ty::Adt(_, args), [field], Ok(())) => {
1499 let field_ty = self.field_ty(pat_span, field, args);
1500 match field_ty.kind() {
1501 ty::Tuple(fields) => fields.len() == subpats.len(),
1502 _ => false,
1503 }
1504 }
1505 _ => false,
1506 };
1507 if missing_parentheses {
1508 let (left, right) = match subpats {
1509 [] => (qpath.span().shrink_to_hi(), pat_span),
1518 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
1527 };
1528 err.multipart_suggestion(
1529 "missing parentheses",
1530 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
1531 Applicability::MachineApplicable,
1532 );
1533 } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
1534 let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
1535 let all_fields_span = match subpats {
1536 [] => after_fields_span,
1537 [field] => field.span,
1538 [first, .., last] => first.span.to(last.span),
1539 };
1540
1541 let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
1543 let first_tail_wildcard =
1544 subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
1545 (None, PatKind::Wild) => Some(pos),
1546 (Some(_), PatKind::Wild) => acc,
1547 _ => None,
1548 });
1549 let tail_span = match first_tail_wildcard {
1550 None => after_fields_span,
1551 Some(0) => subpats[0].span.to(after_fields_span),
1552 Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
1553 };
1554
1555 let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
1557 if !subpats.is_empty() {
1558 wildcard_sugg = String::from(", ") + &wildcard_sugg;
1559 }
1560
1561 err.span_suggestion_verbose(
1562 after_fields_span,
1563 "use `_` to explicitly ignore each field",
1564 wildcard_sugg,
1565 Applicability::MaybeIncorrect,
1566 );
1567
1568 if fields.len() - subpats.len() > 1 || all_wildcards {
1571 if subpats.is_empty() || all_wildcards {
1572 err.span_suggestion_verbose(
1573 all_fields_span,
1574 "use `..` to ignore all fields",
1575 "..",
1576 Applicability::MaybeIncorrect,
1577 );
1578 } else {
1579 err.span_suggestion_verbose(
1580 tail_span,
1581 "use `..` to ignore the rest of the fields",
1582 ", ..",
1583 Applicability::MaybeIncorrect,
1584 );
1585 }
1586 }
1587 }
1588
1589 err.emit()
1590 }
1591
1592 fn check_pat_tuple(
1593 &self,
1594 span: Span,
1595 elements: &'tcx [Pat<'tcx>],
1596 ddpos: hir::DotDotPos,
1597 expected: Ty<'tcx>,
1598 pat_info: PatInfo<'_, 'tcx>,
1599 ) -> Ty<'tcx> {
1600 let tcx = self.tcx;
1601 let mut expected_len = elements.len();
1602 if ddpos.as_opt_usize().is_some() {
1603 if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
1605 expected_len = tys.len();
1606 }
1607 }
1608 let max_len = cmp::max(expected_len, elements.len());
1609
1610 let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
1611 let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
1612 let pat_ty = Ty::new_tup(tcx, element_tys);
1613 if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, pat_info.top_info) {
1614 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
1617 for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1618 self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
1619 }
1620 Ty::new_tup_from_iter(tcx, element_tys_iter)
1621 } else {
1622 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
1623 self.check_pat(elem, element_tys[i], pat_info);
1624 }
1625 pat_ty
1626 }
1627 }
1628
1629 fn check_struct_pat_fields(
1630 &self,
1631 adt_ty: Ty<'tcx>,
1632 pat: &'tcx Pat<'tcx>,
1633 variant: &'tcx ty::VariantDef,
1634 fields: &'tcx [hir::PatField<'tcx>],
1635 has_rest_pat: bool,
1636 pat_info: PatInfo<'_, 'tcx>,
1637 ) -> Result<(), ErrorGuaranteed> {
1638 let tcx = self.tcx;
1639
1640 let ty::Adt(adt, args) = adt_ty.kind() else {
1641 span_bug!(pat.span, "struct pattern is not an ADT");
1642 };
1643
1644 let field_map = variant
1646 .fields
1647 .iter_enumerated()
1648 .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
1649 .collect::<FxHashMap<_, _>>();
1650
1651 let mut used_fields = FxHashMap::default();
1653 let mut result = Ok(());
1654
1655 let mut inexistent_fields = vec![];
1656 for field in fields {
1658 let span = field.span;
1659 let ident = tcx.adjust_ident(field.ident, variant.def_id);
1660 let field_ty = match used_fields.entry(ident) {
1661 Occupied(occupied) => {
1662 let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
1663 result = Err(guar);
1664 Ty::new_error(tcx, guar)
1665 }
1666 Vacant(vacant) => {
1667 vacant.insert(span);
1668 field_map
1669 .get(&ident)
1670 .map(|(i, f)| {
1671 self.write_field_index(field.hir_id, *i);
1672 self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
1673 self.field_ty(span, f, args)
1674 })
1675 .unwrap_or_else(|| {
1676 inexistent_fields.push(field);
1677 Ty::new_misc_error(tcx)
1678 })
1679 }
1680 };
1681
1682 self.check_pat(field.pat, field_ty, pat_info);
1683 }
1684
1685 let mut unmentioned_fields = variant
1686 .fields
1687 .iter()
1688 .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
1689 .filter(|(_, ident)| !used_fields.contains_key(ident))
1690 .collect::<Vec<_>>();
1691
1692 let inexistent_fields_err = if !inexistent_fields.is_empty()
1693 && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore)
1694 {
1695 variant.has_errors()?;
1697 Some(self.error_inexistent_fields(
1698 adt.variant_descr(),
1699 &inexistent_fields,
1700 &mut unmentioned_fields,
1701 pat,
1702 variant,
1703 args,
1704 ))
1705 } else {
1706 None
1707 };
1708
1709 let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local();
1711 if non_exhaustive && !has_rest_pat {
1712 self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
1713 }
1714
1715 let mut unmentioned_err = None;
1716 if adt.is_union() {
1718 if fields.len() != 1 {
1719 self.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
1720 }
1721 if has_rest_pat {
1722 self.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
1723 }
1724 } else if !unmentioned_fields.is_empty() {
1725 let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
1726 .iter()
1727 .copied()
1728 .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span))
1729 .collect();
1730
1731 if !has_rest_pat {
1732 if accessible_unmentioned_fields.is_empty() {
1733 unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
1734 } else {
1735 unmentioned_err = Some(self.error_unmentioned_fields(
1736 pat,
1737 &accessible_unmentioned_fields,
1738 accessible_unmentioned_fields.len() != unmentioned_fields.len(),
1739 fields,
1740 ));
1741 }
1742 } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
1743 self.lint_non_exhaustive_omitted_patterns(
1744 pat,
1745 &accessible_unmentioned_fields,
1746 adt_ty,
1747 )
1748 }
1749 }
1750 match (inexistent_fields_err, unmentioned_err) {
1751 (Some(i), Some(u)) => {
1752 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
1753 i.delay_as_bug();
1756 u.delay_as_bug();
1757 Err(e)
1758 } else {
1759 i.emit();
1760 Err(u.emit())
1761 }
1762 }
1763 (None, Some(u)) => {
1764 if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
1765 u.delay_as_bug();
1766 Err(e)
1767 } else {
1768 Err(u.emit())
1769 }
1770 }
1771 (Some(err), None) => Err(err.emit()),
1772 (None, None) => {
1773 self.error_tuple_variant_index_shorthand(variant, pat, fields)?;
1774 result
1775 }
1776 }
1777 }
1778
1779 fn error_tuple_variant_index_shorthand(
1780 &self,
1781 variant: &VariantDef,
1782 pat: &'_ Pat<'_>,
1783 fields: &[hir::PatField<'_>],
1784 ) -> Result<(), ErrorGuaranteed> {
1785 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) =
1789 (variant.ctor_kind(), &pat.kind)
1790 {
1791 let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
1792 if has_shorthand_field_name {
1793 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
1794 let mut err = struct_span_code_err!(
1795 self.dcx(),
1796 pat.span,
1797 E0769,
1798 "tuple variant `{path}` written as struct variant",
1799 );
1800 err.span_suggestion_verbose(
1801 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
1802 "use the tuple variant pattern syntax instead",
1803 format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)),
1804 Applicability::MaybeIncorrect,
1805 );
1806 return Err(err.emit());
1807 }
1808 }
1809 Ok(())
1810 }
1811
1812 fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) {
1813 let sess = self.tcx.sess;
1814 let sm = sess.source_map();
1815 let sp_brace = sm.end_point(pat.span);
1816 let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi()));
1817 let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
1818
1819 struct_span_code_err!(
1820 self.dcx(),
1821 pat.span,
1822 E0638,
1823 "`..` required with {descr} marked as non-exhaustive",
1824 )
1825 .with_span_suggestion_verbose(
1826 sp_comma,
1827 "add `..` at the end of the field list to ignore all other fields",
1828 sugg,
1829 Applicability::MachineApplicable,
1830 )
1831 .emit();
1832 }
1833
1834 fn error_field_already_bound(
1835 &self,
1836 span: Span,
1837 ident: Ident,
1838 other_field: Span,
1839 ) -> ErrorGuaranteed {
1840 struct_span_code_err!(
1841 self.dcx(),
1842 span,
1843 E0025,
1844 "field `{}` bound multiple times in the pattern",
1845 ident
1846 )
1847 .with_span_label(span, format!("multiple uses of `{ident}` in pattern"))
1848 .with_span_label(other_field, format!("first use of `{ident}`"))
1849 .emit()
1850 }
1851
1852 fn error_inexistent_fields(
1853 &self,
1854 kind_name: &str,
1855 inexistent_fields: &[&hir::PatField<'tcx>],
1856 unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
1857 pat: &'tcx Pat<'tcx>,
1858 variant: &ty::VariantDef,
1859 args: ty::GenericArgsRef<'tcx>,
1860 ) -> Diag<'a> {
1861 let tcx = self.tcx;
1862 let (field_names, t, plural) = if let [field] = inexistent_fields {
1863 (format!("a field named `{}`", field.ident), "this", "")
1864 } else {
1865 (
1866 format!(
1867 "fields named {}",
1868 inexistent_fields
1869 .iter()
1870 .map(|field| format!("`{}`", field.ident))
1871 .collect::<Vec<String>>()
1872 .join(", ")
1873 ),
1874 "these",
1875 "s",
1876 )
1877 };
1878 let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
1879 let mut err = struct_span_code_err!(
1880 self.dcx(),
1881 spans,
1882 E0026,
1883 "{} `{}` does not have {}",
1884 kind_name,
1885 tcx.def_path_str(variant.def_id),
1886 field_names
1887 );
1888 if let Some(pat_field) = inexistent_fields.last() {
1889 err.span_label(
1890 pat_field.ident.span,
1891 format!(
1892 "{} `{}` does not have {} field{}",
1893 kind_name,
1894 tcx.def_path_str(variant.def_id),
1895 t,
1896 plural
1897 ),
1898 );
1899
1900 if let [(field_def, field)] = unmentioned_fields.as_slice()
1901 && self.is_field_suggestable(field_def, pat.hir_id, pat.span)
1902 {
1903 let suggested_name =
1904 find_best_match_for_name(&[field.name], pat_field.ident.name, None);
1905 if let Some(suggested_name) = suggested_name {
1906 err.span_suggestion(
1907 pat_field.ident.span,
1908 "a field with a similar name exists",
1909 suggested_name,
1910 Applicability::MaybeIncorrect,
1911 );
1912
1913 if suggested_name.to_ident_string().parse::<usize>().is_err() {
1919 unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
1921 }
1922 } else if inexistent_fields.len() == 1 {
1923 match pat_field.pat.kind {
1924 PatKind::Expr(_)
1925 if !self.may_coerce(
1926 self.typeck_results.borrow().node_type(pat_field.pat.hir_id),
1927 self.field_ty(field.span, field_def, args),
1928 ) => {}
1929 _ => {
1930 err.span_suggestion_short(
1931 pat_field.ident.span,
1932 format!(
1933 "`{}` has a field named `{}`",
1934 tcx.def_path_str(variant.def_id),
1935 field.name,
1936 ),
1937 field.name,
1938 Applicability::MaybeIncorrect,
1939 );
1940 }
1941 }
1942 }
1943 }
1944 }
1945 if tcx.sess.teach(err.code.unwrap()) {
1946 err.note(
1947 "This error indicates that a struct pattern attempted to \
1948 extract a nonexistent field from a struct. Struct fields \
1949 are identified by the name used before the colon : so struct \
1950 patterns should resemble the declaration of the struct type \
1951 being matched.\n\n\
1952 If you are using shorthand field patterns but want to refer \
1953 to the struct field by a different name, you should rename \
1954 it explicitly.",
1955 );
1956 }
1957 err
1958 }
1959
1960 fn error_tuple_variant_as_struct_pat(
1961 &self,
1962 pat: &Pat<'_>,
1963 fields: &'tcx [hir::PatField<'tcx>],
1964 variant: &ty::VariantDef,
1965 ) -> Result<(), ErrorGuaranteed> {
1966 if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) =
1967 (variant.ctor_kind(), &pat.kind)
1968 {
1969 let is_tuple_struct_match = !pattern_fields.is_empty()
1970 && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number);
1971 if is_tuple_struct_match {
1972 return Ok(());
1973 }
1974
1975 variant.has_errors()?;
1977
1978 let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath);
1979 let mut err = struct_span_code_err!(
1980 self.dcx(),
1981 pat.span,
1982 E0769,
1983 "tuple variant `{}` written as struct variant",
1984 path
1985 );
1986 let (sugg, appl) = if fields.len() == variant.fields.len() {
1987 (
1988 self.get_suggested_tuple_struct_pattern(fields, variant),
1989 Applicability::MachineApplicable,
1990 )
1991 } else {
1992 (
1993 variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
1994 Applicability::MaybeIncorrect,
1995 )
1996 };
1997 err.span_suggestion_verbose(
1998 qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()),
1999 "use the tuple variant pattern syntax instead",
2000 format!("({sugg})"),
2001 appl,
2002 );
2003 return Err(err.emit());
2004 }
2005 Ok(())
2006 }
2007
2008 fn get_suggested_tuple_struct_pattern(
2009 &self,
2010 fields: &[hir::PatField<'_>],
2011 variant: &VariantDef,
2012 ) -> String {
2013 let variant_field_idents =
2014 variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
2015 fields
2016 .iter()
2017 .map(|field| {
2018 match self.tcx.sess.source_map().span_to_snippet(field.pat.span) {
2019 Ok(f) => {
2020 if variant_field_idents.contains(&field.ident) {
2023 String::from("_")
2024 } else {
2025 f
2026 }
2027 }
2028 Err(_) => rustc_hir_pretty::pat_to_string(&self.tcx, field.pat),
2029 }
2030 })
2031 .collect::<Vec<String>>()
2032 .join(", ")
2033 }
2034
2035 fn error_no_accessible_fields(
2051 &self,
2052 pat: &Pat<'_>,
2053 fields: &'tcx [hir::PatField<'tcx>],
2054 ) -> Diag<'a> {
2055 let mut err = self
2056 .dcx()
2057 .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
2058
2059 if let Some(field) = fields.last() {
2060 err.span_suggestion_verbose(
2061 field.span.shrink_to_hi(),
2062 "ignore the inaccessible and unused fields",
2063 ", ..",
2064 Applicability::MachineApplicable,
2065 );
2066 } else {
2067 let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind {
2068 qpath.span()
2069 } else {
2070 bug!("`error_no_accessible_fields` called on non-struct pattern");
2071 };
2072
2073 let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi());
2075 err.span_suggestion_verbose(
2076 span,
2077 "ignore the inaccessible and unused fields",
2078 " { .. }",
2079 Applicability::MachineApplicable,
2080 );
2081 }
2082 err
2083 }
2084
2085 fn lint_non_exhaustive_omitted_patterns(
2090 &self,
2091 pat: &Pat<'_>,
2092 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2093 ty: Ty<'tcx>,
2094 ) {
2095 fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
2096 const LIMIT: usize = 3;
2097 match witnesses {
2098 [] => {
2099 unreachable!(
2100 "expected an uncovered pattern, otherwise why are we emitting an error?"
2101 )
2102 }
2103 [witness] => format!("`{witness}`"),
2104 [head @ .., tail] if head.len() < LIMIT => {
2105 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2106 format!("`{}` and `{}`", head.join("`, `"), tail)
2107 }
2108 _ => {
2109 let (head, tail) = witnesses.split_at(LIMIT);
2110 let head: Vec<_> = head.iter().map(<_>::to_string).collect();
2111 format!("`{}` and {} more", head.join("`, `"), tail.len())
2112 }
2113 }
2114 }
2115 let joined_patterns = joined_uncovered_patterns(
2116 &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
2117 );
2118
2119 self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| {
2120 lint.primary_message("some fields are not explicitly listed");
2121 lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
2122 lint.help(
2123 "ensure that all fields are mentioned explicitly by adding the suggested fields",
2124 );
2125 lint.note(format!(
2126 "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found",
2127 ));
2128 });
2129 }
2130
2131 fn error_unmentioned_fields(
2141 &self,
2142 pat: &Pat<'_>,
2143 unmentioned_fields: &[(&ty::FieldDef, Ident)],
2144 have_inaccessible_fields: bool,
2145 fields: &'tcx [hir::PatField<'tcx>],
2146 ) -> Diag<'a> {
2147 let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
2148 let field_names = if let [(_, field)] = unmentioned_fields {
2149 format!("field `{field}`{inaccessible}")
2150 } else {
2151 let fields = unmentioned_fields
2152 .iter()
2153 .map(|(_, name)| format!("`{name}`"))
2154 .collect::<Vec<String>>()
2155 .join(", ");
2156 format!("fields {fields}{inaccessible}")
2157 };
2158 let mut err = struct_span_code_err!(
2159 self.dcx(),
2160 pat.span,
2161 E0027,
2162 "pattern does not mention {}",
2163 field_names
2164 );
2165 err.span_label(pat.span, format!("missing {field_names}"));
2166 let len = unmentioned_fields.len();
2167 let (prefix, postfix, sp) = match fields {
2168 [] => match &pat.kind {
2169 PatKind::Struct(path, [], false) => {
2170 (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
2171 }
2172 _ => return err,
2173 },
2174 [.., field] => {
2175 let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
2178 match &pat.kind {
2179 PatKind::Struct(..) => (", ", " }", tail),
2180 _ => return err,
2181 }
2182 }
2183 };
2184 err.span_suggestion(
2185 sp,
2186 format!(
2187 "include the missing field{} in the pattern{}",
2188 pluralize!(len),
2189 if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
2190 ),
2191 format!(
2192 "{}{}{}{}",
2193 prefix,
2194 unmentioned_fields
2195 .iter()
2196 .map(|(_, name)| {
2197 let field_name = name.to_string();
2198 if is_number(&field_name) { format!("{field_name}: _") } else { field_name }
2199 })
2200 .collect::<Vec<_>>()
2201 .join(", "),
2202 if have_inaccessible_fields { ", .." } else { "" },
2203 postfix,
2204 ),
2205 Applicability::MachineApplicable,
2206 );
2207 err.span_suggestion(
2208 sp,
2209 format!(
2210 "if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
2211 these = pluralize!("this", len),
2212 s = pluralize!(len),
2213 them = if len == 1 { "it" } else { "them" },
2214 ),
2215 format!(
2216 "{}{}{}{}",
2217 prefix,
2218 unmentioned_fields
2219 .iter()
2220 .map(|(_, name)| {
2221 let field_name = name.to_string();
2222 format!("{field_name}: _")
2223 })
2224 .collect::<Vec<_>>()
2225 .join(", "),
2226 if have_inaccessible_fields { ", .." } else { "" },
2227 postfix,
2228 ),
2229 Applicability::MachineApplicable,
2230 );
2231 err.span_suggestion(
2232 sp,
2233 "or always ignore missing fields here",
2234 format!("{prefix}..{postfix}"),
2235 Applicability::MachineApplicable,
2236 );
2237 err
2238 }
2239
2240 fn check_pat_box(
2241 &self,
2242 span: Span,
2243 inner: &'tcx Pat<'tcx>,
2244 expected: Ty<'tcx>,
2245 pat_info: PatInfo<'_, 'tcx>,
2246 ) -> Ty<'tcx> {
2247 let tcx = self.tcx;
2248 let (box_ty, inner_ty) = self
2249 .check_dereferenceable(span, expected, inner)
2250 .and_then(|()| {
2251 let inner_ty = self.next_ty_var(inner.span);
2254 let box_ty = Ty::new_box(tcx, inner_ty);
2255 self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info)?;
2256 Ok((box_ty, inner_ty))
2257 })
2258 .unwrap_or_else(|guar| {
2259 let err = Ty::new_error(tcx, guar);
2260 (err, err)
2261 });
2262 self.check_pat(inner, inner_ty, pat_info);
2263 box_ty
2264 }
2265
2266 fn check_pat_deref(
2267 &self,
2268 span: Span,
2269 inner: &'tcx Pat<'tcx>,
2270 expected: Ty<'tcx>,
2271 pat_info: PatInfo<'_, 'tcx>,
2272 ) -> Ty<'tcx> {
2273 let tcx = self.tcx;
2274 self.register_bound(
2276 expected,
2277 tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
2278 self.misc(span),
2279 );
2280 let ty = Ty::new_projection(
2282 tcx,
2283 tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
2284 [expected],
2285 );
2286 let ty = self.normalize(span, ty);
2287 let ty = self.try_structurally_resolve_type(span, ty);
2288 self.check_pat(inner, ty, pat_info);
2289
2290 if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2295 self.register_bound(
2296 expected,
2297 tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
2298 self.misc(span),
2299 );
2300 }
2301
2302 expected
2303 }
2304
2305 fn check_pat_ref(
2307 &self,
2308 pat: &'tcx Pat<'tcx>,
2309 inner: &'tcx Pat<'tcx>,
2310 pat_mutbl: Mutability,
2311 mut expected: Ty<'tcx>,
2312 mut pat_info: PatInfo<'_, 'tcx>,
2313 ) -> Ty<'tcx> {
2314 let tcx = self.tcx;
2315
2316 let pat_prefix_span =
2317 inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
2318
2319 let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref();
2320 if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not {
2321 pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
2326 }
2327
2328 expected = self.try_structurally_resolve_type(pat.span, expected);
2329 if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
2332 match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
2333 InheritedRefMatchRule::EatOuter => {
2334 if pat_mutbl > inh_mut {
2336 debug_assert!(ref_pat_matches_mut_ref);
2341 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2342 }
2343
2344 pat_info.binding_mode = ByRef::No;
2345 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2346 self.check_pat(inner, expected, pat_info);
2347 return expected;
2348 }
2349 InheritedRefMatchRule::EatInner => {
2350 if let ty::Ref(_, _, r_mutbl) = *expected.kind()
2351 && pat_mutbl <= r_mutbl
2352 {
2353 debug_assert!(ref_pat_matches_mut_ref);
2360 debug_assert!(self.downgrade_mut_inside_shared());
2364 let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
2365 pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
2366 } else {
2367 if pat_mutbl > inh_mut {
2370 debug_assert!(ref_pat_matches_mut_ref);
2375 self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
2376 }
2377
2378 pat_info.binding_mode = ByRef::No;
2379 self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2380 self.check_pat(inner, expected, pat_info);
2381 return expected;
2382 }
2383 }
2384 InheritedRefMatchRule::EatBoth => {
2385 pat_info.binding_mode = ByRef::No;
2387 self.add_rust_2024_migration_desugared_pat(
2388 pat_info.top_info.hir_id,
2389 pat,
2390 inner.span,
2391 inh_mut,
2392 )
2393 }
2394 }
2395 }
2396
2397 let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2398 Ok(()) => {
2399 debug!("check_pat_ref: expected={:?}", expected);
2406 match *expected.kind() {
2407 ty::Ref(_, r_ty, r_mutbl)
2408 if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
2409 || r_mutbl == pat_mutbl =>
2410 {
2411 if r_mutbl == Mutability::Not {
2412 pat_info.max_ref_mutbl = MutblCap::Not;
2413 }
2414
2415 (expected, r_ty)
2416 }
2417
2418 _ => {
2419 let inner_ty = self.next_ty_var(inner.span);
2420 let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
2421 debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2422 let err = self.demand_eqtype_pat_diag(
2423 pat.span,
2424 expected,
2425 ref_ty,
2426 pat_info.top_info,
2427 );
2428
2429 if let Err(mut err) = err {
2432 self.borrow_pat_suggestion(&mut err, pat);
2433 err.emit();
2434 }
2435 (ref_ty, inner_ty)
2436 }
2437 }
2438 }
2439 Err(guar) => {
2440 let err = Ty::new_error(tcx, guar);
2441 (err, err)
2442 }
2443 };
2444
2445 self.check_pat(inner, inner_ty, pat_info);
2446 ref_ty
2447 }
2448
2449 fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
2451 let region = self.next_region_var(infer::PatternRegion(span));
2452 Ty::new_ref(self.tcx, region, ty, mutbl)
2453 }
2454
2455 fn error_inherited_ref_mutability_mismatch(
2456 &self,
2457 pat: &'tcx Pat<'tcx>,
2458 pat_prefix_span: Option<Span>,
2459 ) -> ErrorGuaranteed {
2460 let err_msg = "mismatched types";
2461 let err = if let Some(span) = pat_prefix_span {
2462 let mut err = self.dcx().struct_span_err(span, err_msg);
2463 err.code(E0308);
2464 err.note("cannot match inherited `&` with `&mut` pattern");
2465 err.span_suggestion_verbose(
2466 span,
2467 "replace this `&mut` pattern with `&`",
2468 "&",
2469 Applicability::MachineApplicable,
2470 );
2471 err
2472 } else {
2473 self.dcx().struct_span_err(pat.span, err_msg)
2474 };
2475 err.emit()
2476 }
2477
2478 fn try_resolve_slice_ty_to_array_ty(
2479 &self,
2480 before: &'tcx [Pat<'tcx>],
2481 slice: Option<&'tcx Pat<'tcx>>,
2482 span: Span,
2483 ) -> Option<Ty<'tcx>> {
2484 if slice.is_some() {
2485 return None;
2486 }
2487
2488 let tcx = self.tcx;
2489 let len = before.len();
2490 let inner_ty = self.next_ty_var(span);
2491
2492 Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
2493 }
2494
2495 fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
2526 match decl_origin {
2527 Some(DeclOrigin::LocalDecl { els: None }) => true,
2528 Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
2529 }
2530 }
2531
2532 fn check_pat_slice(
2543 &self,
2544 span: Span,
2545 before: &'tcx [Pat<'tcx>],
2546 slice: Option<&'tcx Pat<'tcx>>,
2547 after: &'tcx [Pat<'tcx>],
2548 expected: Ty<'tcx>,
2549 pat_info: PatInfo<'_, 'tcx>,
2550 ) -> Ty<'tcx> {
2551 let expected = self.try_structurally_resolve_type(span, expected);
2552
2553 if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
2556 if let Some(resolved_arr_ty) =
2557 self.try_resolve_slice_ty_to_array_ty(before, slice, span)
2558 {
2559 debug!(?resolved_arr_ty);
2560 let _ = self.demand_eqtype(span, expected, resolved_arr_ty);
2561 }
2562 }
2563
2564 let expected = self.structurally_resolve_type(span, expected);
2565 debug!(?expected);
2566
2567 let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
2568 ty::Array(element_ty, len) => {
2570 let min = before.len() as u64 + after.len() as u64;
2571 let (opt_slice_ty, expected) =
2572 self.check_array_pat_len(span, element_ty, expected, slice, len, min);
2573 assert!(opt_slice_ty.is_some() || slice.is_none());
2576 (element_ty, opt_slice_ty, expected)
2577 }
2578 ty::Slice(element_ty) => (element_ty, Some(expected), expected),
2579 _ => {
2581 let guar = expected.error_reported().err().unwrap_or_else(|| {
2582 self.error_expected_array_or_slice(span, expected, pat_info)
2583 });
2584 let err = Ty::new_error(self.tcx, guar);
2585 (err, Some(err), err)
2586 }
2587 };
2588
2589 for elt in before {
2591 self.check_pat(elt, element_ty, pat_info);
2592 }
2593 if let Some(slice) = slice {
2595 self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
2596 }
2597 for elt in after {
2599 self.check_pat(elt, element_ty, pat_info);
2600 }
2601 inferred
2602 }
2603
2604 fn check_array_pat_len(
2609 &self,
2610 span: Span,
2611 element_ty: Ty<'tcx>,
2612 arr_ty: Ty<'tcx>,
2613 slice: Option<&'tcx Pat<'tcx>>,
2614 len: ty::Const<'tcx>,
2615 min_len: u64,
2616 ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
2617 let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
2618
2619 let guar = if let Some(len) = len {
2620 if slice.is_none() {
2622 if min_len == len {
2626 return (None, arr_ty);
2627 }
2628
2629 self.error_scrutinee_inconsistent_length(span, min_len, len)
2630 } else if let Some(pat_len) = len.checked_sub(min_len) {
2631 return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
2634 } else {
2635 self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len)
2638 }
2639 } else if slice.is_none() {
2640 let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
2643 self.demand_eqtype(span, updated_arr_ty, arr_ty);
2644 return (None, updated_arr_ty);
2645 } else {
2646 self.error_scrutinee_unfixed_length(span)
2650 };
2651
2652 (Some(Ty::new_error(self.tcx, guar)), arr_ty)
2654 }
2655
2656 fn error_scrutinee_inconsistent_length(
2657 &self,
2658 span: Span,
2659 min_len: u64,
2660 size: u64,
2661 ) -> ErrorGuaranteed {
2662 struct_span_code_err!(
2663 self.dcx(),
2664 span,
2665 E0527,
2666 "pattern requires {} element{} but array has {}",
2667 min_len,
2668 pluralize!(min_len),
2669 size,
2670 )
2671 .with_span_label(span, format!("expected {} element{}", size, pluralize!(size)))
2672 .emit()
2673 }
2674
2675 fn error_scrutinee_with_rest_inconsistent_length(
2676 &self,
2677 span: Span,
2678 min_len: u64,
2679 size: u64,
2680 ) -> ErrorGuaranteed {
2681 struct_span_code_err!(
2682 self.dcx(),
2683 span,
2684 E0528,
2685 "pattern requires at least {} element{} but array has {}",
2686 min_len,
2687 pluralize!(min_len),
2688 size,
2689 )
2690 .with_span_label(
2691 span,
2692 format!("pattern cannot match array of {} element{}", size, pluralize!(size),),
2693 )
2694 .emit()
2695 }
2696
2697 fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
2698 struct_span_code_err!(
2699 self.dcx(),
2700 span,
2701 E0730,
2702 "cannot pattern-match on an array without a fixed length",
2703 )
2704 .emit()
2705 }
2706
2707 fn error_expected_array_or_slice(
2708 &self,
2709 span: Span,
2710 expected_ty: Ty<'tcx>,
2711 pat_info: PatInfo<'_, 'tcx>,
2712 ) -> ErrorGuaranteed {
2713 let PatInfo { top_info: ti, current_depth, .. } = pat_info;
2714
2715 let mut err = struct_span_code_err!(
2716 self.dcx(),
2717 span,
2718 E0529,
2719 "expected an array or slice, found `{expected_ty}`"
2720 );
2721 if let ty::Ref(_, ty, _) = expected_ty.kind()
2722 && let ty::Array(..) | ty::Slice(..) = ty.kind()
2723 {
2724 err.help("the semantics of slice patterns changed recently; see issue #62254");
2725 } else if self
2726 .autoderef(span, expected_ty)
2727 .silence_errors()
2728 .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
2729 && let Some(span) = ti.span
2730 && let Some(_) = ti.origin_expr
2731 {
2732 let resolved_ty = self.resolve_vars_if_possible(ti.expected);
2733 let (is_slice_or_array_or_vector, resolved_ty) =
2734 self.is_slice_or_array_or_vector(resolved_ty);
2735 match resolved_ty.kind() {
2736 ty::Adt(adt_def, _)
2737 if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
2738 || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
2739 {
2740 err.span_suggestion_verbose(
2742 span.shrink_to_hi(),
2743 "consider using `as_deref` here",
2744 ".as_deref()",
2745 Applicability::MaybeIncorrect,
2746 );
2747 }
2748 _ => (),
2749 }
2750
2751 let is_top_level = current_depth <= 1;
2752 if is_slice_or_array_or_vector && is_top_level {
2753 err.span_suggestion_verbose(
2754 span.shrink_to_hi(),
2755 "consider slicing here",
2756 "[..]",
2757 Applicability::MachineApplicable,
2758 );
2759 }
2760 }
2761 err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
2762 err.emit()
2763 }
2764
2765 fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
2766 match ty.kind() {
2767 ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
2768 (true, ty)
2769 }
2770 ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
2771 ty::Slice(..) | ty::Array(..) => (true, ty),
2772 _ => (false, ty),
2773 }
2774 }
2775
2776 fn add_rust_2024_migration_desugared_pat(
2779 &self,
2780 pat_id: HirId,
2781 subpat: &'tcx Pat<'tcx>,
2782 cutoff_span: Span,
2783 def_br_mutbl: Mutability,
2784 ) {
2785 let source_map = self.tcx.sess.source_map();
2788 let cutoff_span = source_map
2789 .span_extend_prev_while(cutoff_span, |c| c.is_whitespace() || c == '(')
2790 .unwrap_or(cutoff_span);
2791 let trimmed_span = subpat.span.until(cutoff_span).with_ctxt(subpat.span.ctxt());
2794
2795 let mut typeck_results = self.typeck_results.borrow_mut();
2796 let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
2797 let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo {
2802 primary_labels: Vec::new(),
2803 bad_modifiers: false,
2804 bad_ref_pats: false,
2805 suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024()
2806 && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
2807 });
2808
2809 let from_expansion = subpat.span.from_expansion();
2812 let primary_label = if from_expansion {
2813 "occurs within macro expansion".to_owned()
2817 } else {
2818 let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind {
2819 info.bad_modifiers |= true;
2820 info.suggest_eliding_modes &=
2824 user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
2825 "binding modifier"
2826 } else {
2827 info.bad_ref_pats |= true;
2828 info.suggest_eliding_modes = false;
2832 "reference pattern"
2833 };
2834 let dbm_str = match def_br_mutbl {
2835 Mutability::Not => "ref",
2836 Mutability::Mut => "ref mut",
2837 };
2838 format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
2839 };
2840 info.primary_labels.push((trimmed_span, primary_label));
2841 }
2842}