Skip to content

Commit 928722f

Browse files
committed
Reorder
1 parent 9d6d5d4 commit 928722f

File tree

1 file changed

+144
-141
lines changed

1 file changed

+144
-141
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 144 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,111 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
572572
}
573573
}
574574

575+
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
576+
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
577+
///
578+
/// For example, this would reject:
579+
/// - `ref x @ Some(ref mut y)`,
580+
/// - `ref mut x @ Some(ref y)`,
581+
/// - `ref mut x @ Some(ref mut y)`,
582+
/// - `ref mut? x @ Some(y)`, and
583+
/// - `x @ Some(ref mut? y)`.
584+
///
585+
/// This analysis is *not* subsumed by NLL.
586+
fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) {
587+
// Extract `sub` in `binding @ sub`.
588+
let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else {
589+
return;
590+
};
591+
592+
let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
593+
594+
let sess = cx.tcx.sess;
595+
596+
// Get the binding move, extract the mutability if by-ref.
597+
let mut_outer = match mode {
598+
BindingMode::ByValue if is_binding_by_move(ty) => {
599+
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
600+
let mut conflicts_ref = Vec::new();
601+
sub.each_binding(|_, mode, _, span| match mode {
602+
BindingMode::ByValue => {}
603+
BindingMode::ByRef(_) => conflicts_ref.push(span),
604+
});
605+
if !conflicts_ref.is_empty() {
606+
sess.emit_err(BorrowOfMovedValue {
607+
binding_span: pat.span,
608+
conflicts_ref,
609+
name,
610+
ty,
611+
suggest_borrowing: Some(pat.span.shrink_to_lo()),
612+
});
613+
}
614+
return;
615+
}
616+
BindingMode::ByValue => return,
617+
BindingMode::ByRef(m) => m.mutability(),
618+
};
619+
620+
// We now have `ref $mut_outer binding @ sub` (semantically).
621+
// Recurse into each binding in `sub` and find mutability or move conflicts.
622+
let mut conflicts_move = Vec::new();
623+
let mut conflicts_mut_mut = Vec::new();
624+
let mut conflicts_mut_ref = Vec::new();
625+
sub.each_binding(|name, mode, ty, span| {
626+
match mode {
627+
BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) {
628+
// Both sides are `ref`.
629+
(Mutability::Not, Mutability::Not) => {}
630+
// 2x `ref mut`.
631+
(Mutability::Mut, Mutability::Mut) => {
632+
conflicts_mut_mut.push(Conflict::Mut { span, name })
633+
}
634+
(Mutability::Not, Mutability::Mut) => {
635+
conflicts_mut_ref.push(Conflict::Mut { span, name })
636+
}
637+
(Mutability::Mut, Mutability::Not) => {
638+
conflicts_mut_ref.push(Conflict::Ref { span, name })
639+
}
640+
},
641+
BindingMode::ByValue if is_binding_by_move(ty) => {
642+
conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
643+
}
644+
BindingMode::ByValue => {} // `ref mut?` + by-copy is fine.
645+
}
646+
});
647+
648+
let report_mut_mut = !conflicts_mut_mut.is_empty();
649+
let report_mut_ref = !conflicts_mut_ref.is_empty();
650+
let report_move_conflict = !conflicts_move.is_empty();
651+
652+
let mut occurrences = match mut_outer {
653+
Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }],
654+
Mutability::Not => vec![Conflict::Ref { span: pat.span, name }],
655+
};
656+
occurrences.extend(conflicts_mut_mut);
657+
occurrences.extend(conflicts_mut_ref);
658+
occurrences.extend(conflicts_move);
659+
660+
// Report errors if any.
661+
if report_mut_mut {
662+
// Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
663+
sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences });
664+
} else if report_mut_ref {
665+
// Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
666+
match mut_outer {
667+
Mutability::Mut => {
668+
sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences });
669+
}
670+
Mutability::Not => {
671+
sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences });
672+
}
673+
};
674+
} else if report_move_conflict {
675+
// Report by-ref and by-move conflicts, e.g. `ref x @ y`.
676+
sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences });
677+
}
678+
}
679+
575680
fn check_for_bindings_named_same_as_variants(
576681
cx: &MatchVisitor<'_, '_, '_>,
577682
pat: &Pat<'_>,
@@ -616,25 +721,6 @@ fn check_for_bindings_named_same_as_variants(
616721
});
617722
}
618723

619-
/// Checks for common cases of "catchall" patterns that may not be intended as such.
620-
fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
621-
use Constructor::*;
622-
match pat.ctor() {
623-
Wildcard => true,
624-
Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
625-
_ => false,
626-
}
627-
}
628-
629-
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
630-
tcx.emit_spanned_lint(
631-
UNREACHABLE_PATTERNS,
632-
id,
633-
span,
634-
UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
635-
);
636-
}
637-
638724
fn irrefutable_let_patterns(
639725
tcx: TyCtxt<'_>,
640726
id: HirId,
@@ -680,19 +766,31 @@ fn report_arm_reachability<'p, 'tcx>(
680766
cx: &MatchCheckCtxt<'p, 'tcx>,
681767
report: &UsefulnessReport<'p, 'tcx>,
682768
) {
769+
let report_unreachable_pattern = |span, hir_id, catchall: Option<Span>| {
770+
cx.tcx.emit_spanned_lint(
771+
UNREACHABLE_PATTERNS,
772+
hir_id,
773+
span,
774+
UnreachablePattern {
775+
span: if catchall.is_some() { Some(span) } else { None },
776+
catchall,
777+
},
778+
);
779+
};
780+
683781
use Reachability::*;
684782
let mut catchall = None;
685783
for (arm, is_useful) in report.arm_usefulness.iter() {
686784
match is_useful {
687-
Unreachable => unreachable_pattern(cx.tcx, arm.pat.span(), arm.hir_id, catchall),
785+
Unreachable => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall),
688786
Reachable(unreachables) if unreachables.is_empty() => {}
689787
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
690788
Reachable(unreachables) => {
691789
let mut unreachables = unreachables.clone();
692790
// Emit lints in the order in which they occur in the file.
693791
unreachables.sort_unstable();
694792
for span in unreachables {
695-
unreachable_pattern(cx.tcx, span, arm.hir_id, None);
793+
report_unreachable_pattern(span, arm.hir_id, None);
696794
}
697795
}
698796
}
@@ -702,15 +800,14 @@ fn report_arm_reachability<'p, 'tcx>(
702800
}
703801
}
704802

705-
fn collect_non_exhaustive_tys<'tcx>(
706-
pat: &WitnessPat<'tcx>,
707-
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
708-
) {
709-
if matches!(pat.ctor(), Constructor::NonExhaustive) {
710-
non_exhaustive_tys.insert(pat.ty());
803+
/// Checks for common cases of "catchall" patterns that may not be intended as such.
804+
fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
805+
use Constructor::*;
806+
match pat.ctor() {
807+
Wildcard => true,
808+
Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
809+
_ => false,
711810
}
712-
pat.iter_fields()
713-
.for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
714811
}
715812

716813
/// Report that a match is not exhaustive.
@@ -748,7 +845,14 @@ fn non_exhaustive_match<'p, 'tcx>(
748845
sp,
749846
format!("non-exhaustive patterns: {joined_patterns} not covered"),
750847
);
751-
err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
848+
err.span_label(
849+
sp,
850+
format!(
851+
"pattern{} {} not covered",
852+
rustc_errors::pluralize!(witnesses.len()),
853+
joined_patterns
854+
),
855+
);
752856
patterns_len = witnesses.len();
753857
pattern = if witnesses.len() < 4 {
754858
witnesses
@@ -895,7 +999,7 @@ fn non_exhaustive_match<'p, 'tcx>(
895999
err.emit()
8961000
}
8971001

898-
pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
1002+
fn joined_uncovered_patterns<'p, 'tcx>(
8991003
cx: &MatchCheckCtxt<'p, 'tcx>,
9001004
witnesses: &[WitnessPat<'tcx>],
9011005
) -> String {
@@ -916,11 +1020,15 @@ pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
9161020
}
9171021
}
9181022

919-
pub(crate) fn pattern_not_covered_label(
920-
witnesses: &[WitnessPat<'_>],
921-
joined_patterns: &str,
922-
) -> String {
923-
format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns)
1023+
fn collect_non_exhaustive_tys<'tcx>(
1024+
pat: &WitnessPat<'tcx>,
1025+
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
1026+
) {
1027+
if matches!(pat.ctor(), Constructor::NonExhaustive) {
1028+
non_exhaustive_tys.insert(pat.ty());
1029+
}
1030+
pat.iter_fields()
1031+
.for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
9241032
}
9251033

9261034
/// Point at the definition of non-covered `enum` variants.
@@ -982,108 +1090,3 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
9821090
}
9831091
covered
9841092
}
985-
986-
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
987-
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
988-
///
989-
/// For example, this would reject:
990-
/// - `ref x @ Some(ref mut y)`,
991-
/// - `ref mut x @ Some(ref y)`,
992-
/// - `ref mut x @ Some(ref mut y)`,
993-
/// - `ref mut? x @ Some(y)`, and
994-
/// - `x @ Some(ref mut? y)`.
995-
///
996-
/// This analysis is *not* subsumed by NLL.
997-
fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) {
998-
// Extract `sub` in `binding @ sub`.
999-
let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else {
1000-
return;
1001-
};
1002-
1003-
let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
1004-
1005-
let sess = cx.tcx.sess;
1006-
1007-
// Get the binding move, extract the mutability if by-ref.
1008-
let mut_outer = match mode {
1009-
BindingMode::ByValue if is_binding_by_move(ty) => {
1010-
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
1011-
let mut conflicts_ref = Vec::new();
1012-
sub.each_binding(|_, mode, _, span| match mode {
1013-
BindingMode::ByValue => {}
1014-
BindingMode::ByRef(_) => conflicts_ref.push(span),
1015-
});
1016-
if !conflicts_ref.is_empty() {
1017-
sess.emit_err(BorrowOfMovedValue {
1018-
binding_span: pat.span,
1019-
conflicts_ref,
1020-
name,
1021-
ty,
1022-
suggest_borrowing: Some(pat.span.shrink_to_lo()),
1023-
});
1024-
}
1025-
return;
1026-
}
1027-
BindingMode::ByValue => return,
1028-
BindingMode::ByRef(m) => m.mutability(),
1029-
};
1030-
1031-
// We now have `ref $mut_outer binding @ sub` (semantically).
1032-
// Recurse into each binding in `sub` and find mutability or move conflicts.
1033-
let mut conflicts_move = Vec::new();
1034-
let mut conflicts_mut_mut = Vec::new();
1035-
let mut conflicts_mut_ref = Vec::new();
1036-
sub.each_binding(|name, mode, ty, span| {
1037-
match mode {
1038-
BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) {
1039-
// Both sides are `ref`.
1040-
(Mutability::Not, Mutability::Not) => {}
1041-
// 2x `ref mut`.
1042-
(Mutability::Mut, Mutability::Mut) => {
1043-
conflicts_mut_mut.push(Conflict::Mut { span, name })
1044-
}
1045-
(Mutability::Not, Mutability::Mut) => {
1046-
conflicts_mut_ref.push(Conflict::Mut { span, name })
1047-
}
1048-
(Mutability::Mut, Mutability::Not) => {
1049-
conflicts_mut_ref.push(Conflict::Ref { span, name })
1050-
}
1051-
},
1052-
BindingMode::ByValue if is_binding_by_move(ty) => {
1053-
conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
1054-
}
1055-
BindingMode::ByValue => {} // `ref mut?` + by-copy is fine.
1056-
}
1057-
});
1058-
1059-
let report_mut_mut = !conflicts_mut_mut.is_empty();
1060-
let report_mut_ref = !conflicts_mut_ref.is_empty();
1061-
let report_move_conflict = !conflicts_move.is_empty();
1062-
1063-
let mut occurrences = match mut_outer {
1064-
Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }],
1065-
Mutability::Not => vec![Conflict::Ref { span: pat.span, name }],
1066-
};
1067-
occurrences.extend(conflicts_mut_mut);
1068-
occurrences.extend(conflicts_mut_ref);
1069-
occurrences.extend(conflicts_move);
1070-
1071-
// Report errors if any.
1072-
if report_mut_mut {
1073-
// Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
1074-
sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences });
1075-
} else if report_mut_ref {
1076-
// Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
1077-
match mut_outer {
1078-
Mutability::Mut => {
1079-
sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences });
1080-
}
1081-
Mutability::Not => {
1082-
sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences });
1083-
}
1084-
};
1085-
} else if report_move_conflict {
1086-
// Report by-ref and by-move conflicts, e.g. `ref x @ y`.
1087-
sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences });
1088-
}
1089-
}

0 commit comments

Comments
 (0)