Skip to content

Commit 0f1f69a

Browse files
authored
Unrolled build for rust-lang#137269
Rollup merge of rust-lang#137269 - dianne:fix-ref-pat-label-span, r=davidtwco Pattern Migration 2024: properly label `&` patterns whose subpatterns are from macro expansions See the failing test output in the first commit for an example of what this going wrong looks like. The error/lint diagnostic tries to point to just the `&` or `&mut` of reference patterns when labeling the causes, to make the output clearer (rust-lang#134394). The trimming there wasn't quite right though: it used the interior of the reference pattern as a cutoff and extended backwards to find where to trim the pattern's span, but this breaks if the `&` and the interior are from different sources. This PR instead trims by starting at the start of the pattern and ending at the final character of the `&` (or `&mut`, `ref`, `ref mut`, or `mut`, depending on what the error/lint is labeling); that way, there's no opportunity for failure from mixing sources. I'm not 100% happy with this approach, but I'm also not sure what the best practices are as far as hacky `SourceMap` munching goes, so please let me know if something else would be preferred. Since `SourceMap::span_through_char` can't change the syntax context of the span, I've also removed a call to `Span::with_ctxt` (we care about the edition of the span in question since this is a hard error in Rust 2024). If we want to be extra safe in case that changes, I can re-add it or track error hardness separately in the `rust_2024_migration_desugared_pats` table.
2 parents 4e1356b + 2be26f0 commit 0f1f69a

File tree

4 files changed

+52
-15
lines changed

4 files changed

+52
-15
lines changed

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -847,20 +847,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
847847
self.add_rust_2024_migration_desugared_pat(
848848
pat_info.top_info.hir_id,
849849
pat,
850-
ident.span,
850+
't', // last char of `mut`
851851
def_br_mutbl,
852852
);
853853
BindingMode(ByRef::No, Mutability::Mut)
854854
}
855855
}
856856
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
857-
BindingMode(ByRef::Yes(_), _) => {
857+
BindingMode(ByRef::Yes(user_br_mutbl), _) => {
858858
if let ByRef::Yes(def_br_mutbl) = def_br {
859859
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
860860
self.add_rust_2024_migration_desugared_pat(
861861
pat_info.top_info.hir_id,
862862
pat,
863-
ident.span,
863+
match user_br_mutbl {
864+
Mutability::Not => 'f', // last char of `ref`
865+
Mutability::Mut => 't', // last char of `ref mut`
866+
},
864867
def_br_mutbl,
865868
);
866869
}
@@ -2440,7 +2443,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24402443
self.add_rust_2024_migration_desugared_pat(
24412444
pat_info.top_info.hir_id,
24422445
pat,
2443-
inner.span,
2446+
match pat_mutbl {
2447+
Mutability::Not => '&', // last char of `&`
2448+
Mutability::Mut => 't', // last char of `&mut`
2449+
},
24442450
inh_mut,
24452451
)
24462452
}
@@ -2832,18 +2838,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28322838
&self,
28332839
pat_id: HirId,
28342840
subpat: &'tcx Pat<'tcx>,
2835-
cutoff_span: Span,
2841+
final_char: char,
28362842
def_br_mutbl: Mutability,
28372843
) {
28382844
// Try to trim the span we're labeling to just the `&` or binding mode that's an issue.
2839-
// If the subpattern's span is is from an expansion, the emitted label will not be trimmed.
2840-
let source_map = self.tcx.sess.source_map();
2841-
let cutoff_span = source_map
2842-
.span_extend_prev_while(cutoff_span, |c| c.is_whitespace() || c == '(')
2843-
.unwrap_or(cutoff_span);
2844-
// Ensure we use the syntax context and thus edition of `subpat.span`; this will be a hard
2845-
// error if the subpattern is of edition >= 2024.
2846-
let trimmed_span = subpat.span.until(cutoff_span).with_ctxt(subpat.span.ctxt());
2845+
let from_expansion = subpat.span.from_expansion();
2846+
let trimmed_span = if from_expansion {
2847+
// If the subpattern is from an expansion, highlight the whole macro call instead.
2848+
subpat.span
2849+
} else {
2850+
let trimmed = self.tcx.sess.source_map().span_through_char(subpat.span, final_char);
2851+
// The edition of the trimmed span should be the same as `subpat.span`; this will be a
2852+
// a hard error if the subpattern is of edition >= 2024. We set it manually to be sure:
2853+
trimmed.with_ctxt(subpat.span.ctxt())
2854+
};
28472855

28482856
let mut typeck_results = self.typeck_results.borrow_mut();
28492857
let mut table = typeck_results.rust_2024_migration_desugared_pats_mut();
@@ -2877,7 +2885,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28772885
};
28782886
// Only provide a detailed label if the problematic subpattern isn't from an expansion.
28792887
// In the case that it's from a macro, we'll add a more detailed note in the emitter.
2880-
let from_expansion = subpat.span.from_expansion();
28812888
let primary_label = if from_expansion {
28822889
// We can't suggest eliding modifiers within expansions.
28832890
info.suggest_eliding_modes = false;

tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,10 @@ fn main() {
244244
let &[migration_lint_macros::bind_ref!(a)] = &[0];
245245
//~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
246246
assert_type_eq(a, &0u32);
247+
248+
// Test that we use the correct span when labeling a `&` whose subpattern is from an expansion.
249+
let &[&migration_lint_macros::bind_ref!(a)] = &[&0];
250+
//~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
251+
//~| WARN: this changes meaning in Rust 2024
252+
assert_type_eq(a, &0u32);
247253
}

tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,10 @@ fn main() {
244244
let [migration_lint_macros::bind_ref!(a)] = &[0];
245245
//~^ ERROR: binding modifiers may only be written when the default binding mode is `move`
246246
assert_type_eq(a, &0u32);
247+
248+
// Test that we use the correct span when labeling a `&` whose subpattern is from an expansion.
249+
let [&migration_lint_macros::bind_ref!(a)] = &[&0];
250+
//~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024
251+
//~| WARN: this changes meaning in Rust 2024
252+
assert_type_eq(a, &0u32);
247253
}

tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,5 +580,23 @@ help: make the implied reference pattern explicit
580580
LL | let &[migration_lint_macros::bind_ref!(a)] = &[0];
581581
| +
582582

583-
error: aborting due to 30 previous errors
583+
error: reference patterns may only be written when the default binding mode is `move` in Rust 2024
584+
--> $DIR/migration_lint.rs:249:10
585+
|
586+
LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0];
587+
| ^ reference pattern not allowed under `ref` default binding mode
588+
|
589+
= warning: this changes meaning in Rust 2024
590+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
591+
note: matching on a reference type with a non-reference pattern changes the default binding mode
592+
--> $DIR/migration_lint.rs:249:9
593+
|
594+
LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0];
595+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_`
596+
help: make the implied reference pattern explicit
597+
|
598+
LL | let &[&migration_lint_macros::bind_ref!(a)] = &[&0];
599+
| +
600+
601+
error: aborting due to 31 previous errors
584602

0 commit comments

Comments
 (0)