Skip to content

Commit 767f820

Browse files
committed
separate labels for default binding mode spans into their own notes
1 parent a064e78 commit 767f820

File tree

7 files changed

+291
-183
lines changed

7 files changed

+291
-183
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
804804

805805
// Determine the binding mode...
806806
let bm = match user_bind_annot {
807-
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
807+
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
808808
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
809809
// using other experimental matching features compatible with it.
810810
if pat.span.at_least_rust_2024()
@@ -828,18 +828,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
828828
pat_info.top_info.hir_id,
829829
pat,
830830
ident.span,
831+
def_br_mutbl,
831832
);
832833
BindingMode(ByRef::No, Mutability::Mut)
833834
}
834835
}
835836
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
836837
BindingMode(ByRef::Yes(_), _) => {
837-
if matches!(def_br, ByRef::Yes(_)) {
838+
if let ByRef::Yes(def_br_mutbl) = def_br {
838839
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
839840
self.add_rust_2024_migration_desugared_pat(
840841
pat_info.top_info.hir_id,
841842
pat,
842843
ident.span,
844+
def_br_mutbl,
843845
);
844846
}
845847
user_bind_annot
@@ -2378,6 +2380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23782380
pat_info.top_info.hir_id,
23792381
pat,
23802382
inner.span,
2383+
inh_mut,
23812384
)
23822385
}
23832386
}
@@ -2769,6 +2772,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27692772
pat_id: HirId,
27702773
subpat: &'tcx Pat<'tcx>,
27712774
cutoff_span: Span,
2775+
def_br_mutbl: Mutability,
27722776
) {
27732777
// Try to trim the span we're labeling to just the `&` or binding mode that's an issue.
27742778
// If the subpattern's span is is from an expansion, the emitted label will not be trimmed.
@@ -2791,16 +2795,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27912795
// NB: This wording assumes the only expansions that can produce problematic reference
27922796
// patterns and bindings are macros. If a desugaring or AST pass is added that can do
27932797
// so, we may want to inspect the span's source callee or macro backtrace.
2794-
"occurs within macro expansion"
2798+
"occurs within macro expansion".to_owned()
27952799
} else {
2796-
if matches!(subpat.kind, PatKind::Binding(_, _, _, _)) {
2800+
let pat_kind = if matches!(subpat.kind, PatKind::Binding(_, _, _, _)) {
27972801
info.bad_modifiers |= true;
2798-
"this binding modifier"
2802+
"binding modifier"
27992803
} else {
28002804
info.bad_ref_pats |= true;
2801-
"this reference pattern"
2802-
}
2805+
"reference pattern"
2806+
};
2807+
let dbm_str = match def_br_mutbl {
2808+
Mutability::Not => "ref",
2809+
Mutability::Mut => "ref mut",
2810+
};
2811+
format!("{pat_kind} not allowed under `{dbm_str}` default binding mode")
28032812
};
2804-
info.primary_labels.push((trimmed_span, primary_label.to_owned()));
2813+
info.primary_labels.push((trimmed_span, primary_label));
28052814
}
28062815
}

compiler/rustc_mir_build/src/errors.rs

+21
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,27 @@ impl Subdiagnostic for Rust2024IncompatiblePatSugg {
11231123
diag: &mut Diag<'_, G>,
11241124
_f: &F,
11251125
) {
1126+
// Format and emit explanatory notes about default binding modes. Reversing the spans' order
1127+
// means if we have nested spans, the innermost ones will be visited first.
1128+
for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() {
1129+
// Don't point to a macro call site.
1130+
if !span.from_expansion() {
1131+
let dbm_str = match def_br_mutbl {
1132+
ty::Mutability::Not => "ref",
1133+
ty::Mutability::Mut => "ref mut",
1134+
};
1135+
let note_msg = format!(
1136+
"the default binding mode changed to `{dbm_str}` because this has type `{}_`",
1137+
def_br_mutbl.ref_prefix_str()
1138+
);
1139+
let label_msg = format!("the default binding mode is `{dbm_str}`, introduced here");
1140+
let mut label = MultiSpan::from(span);
1141+
label.push_span_label(span, label_msg);
1142+
diag.span_note(label, note_msg);
1143+
}
1144+
}
1145+
1146+
// Format and emit the suggestion.
11261147
let applicability =
11271148
if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
11281149
Applicability::MachineApplicable

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

-10
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,6 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
6666
for (span, label) in &info.primary_labels {
6767
spans.push_span_label(*span, label.clone());
6868
}
69-
for (span, label_mutbl) in &sugg.default_mode_labels {
70-
// Don't point to a macro call site.
71-
if !span.from_expansion() {
72-
let label = match label_mutbl {
73-
Mutability::Not => "default binding mode is `ref`",
74-
Mutability::Mut => "default binding mode is `ref mut`",
75-
};
76-
spans.push_span_label(*span, label.to_owned())
77-
}
78-
}
7969
// If a relevant span is from at least edition 2024, this is a hard error.
8070
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
8171
if is_hard_error {

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr

+24-16
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ error: binding modifiers may only be written when the default binding mode is `m
1414
--> $DIR/ref-binding-on-inh-ref-errors.rs:67:10
1515
|
1616
LL | let [ref mut x] = &[0];
17-
| -^^^^^^^---
18-
| ||
19-
| |this binding modifier
20-
| default binding mode is `ref`
17+
| ^^^^^^^ binding modifier not allowed under `ref` default binding mode
2118
|
2219
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
20+
note: the default binding mode changed to `ref` because this has type `&_`
21+
--> $DIR/ref-binding-on-inh-ref-errors.rs:67:9
22+
|
23+
LL | let [ref mut x] = &[0];
24+
| ^^^^^^^^^^^ the default binding mode is `ref`, introduced here
2325
help: make the implied reference pattern explicit
2426
|
2527
LL | let &[ref mut x] = &[0];
@@ -35,12 +37,14 @@ error: binding modifiers may only be written when the default binding mode is `m
3537
--> $DIR/ref-binding-on-inh-ref-errors.rs:75:10
3638
|
3739
LL | let [ref x] = &[0];
38-
| -^^^---
39-
| ||
40-
| |this binding modifier
41-
| default binding mode is `ref`
40+
| ^^^ binding modifier not allowed under `ref` default binding mode
4241
|
4342
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
43+
note: the default binding mode changed to `ref` because this has type `&_`
44+
--> $DIR/ref-binding-on-inh-ref-errors.rs:75:9
45+
|
46+
LL | let [ref x] = &[0];
47+
| ^^^^^^^ the default binding mode is `ref`, introduced here
4448
help: make the implied reference pattern explicit
4549
|
4650
LL | let &[ref x] = &[0];
@@ -50,12 +54,14 @@ error: binding modifiers may only be written when the default binding mode is `m
5054
--> $DIR/ref-binding-on-inh-ref-errors.rs:79:10
5155
|
5256
LL | let [ref x] = &mut [0];
53-
| -^^^---
54-
| ||
55-
| |this binding modifier
56-
| default binding mode is `ref mut`
57+
| ^^^ binding modifier not allowed under `ref mut` default binding mode
5758
|
5859
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
60+
note: the default binding mode changed to `ref mut` because this has type `&mut _`
61+
--> $DIR/ref-binding-on-inh-ref-errors.rs:79:9
62+
|
63+
LL | let [ref x] = &mut [0];
64+
| ^^^^^^^ the default binding mode is `ref mut`, introduced here
5965
help: make the implied reference pattern explicit
6066
|
6167
LL | let &mut [ref x] = &mut [0];
@@ -65,12 +71,14 @@ error: binding modifiers may only be written when the default binding mode is `m
6571
--> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
6672
|
6773
LL | let [ref mut x] = &mut [0];
68-
| -^^^^^^^---
69-
| ||
70-
| |this binding modifier
71-
| default binding mode is `ref mut`
74+
| ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode
7275
|
7376
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
77+
note: the default binding mode changed to `ref mut` because this has type `&mut _`
78+
--> $DIR/ref-binding-on-inh-ref-errors.rs:83:9
79+
|
80+
LL | let [ref mut x] = &mut [0];
81+
| ^^^^^^^^^^^ the default binding mode is `ref mut`, introduced here
7482
help: make the implied reference pattern explicit
7583
|
7684
LL | let &mut [ref mut x] = &mut [0];

0 commit comments

Comments
 (0)