Skip to content

Commit 5c83ca2

Browse files
committed
don't suggest removing the open parenthesis in &(...)
If the inside of a `&` pattern has excess parentheses, the span for the `&`'s subpattern in the HIR will point inside the parens. Thus, if we suggest removing the `&`, we have to be careful about anything in between the `&` and the subpattern in the source.
1 parent bde0734 commit 5c83ca2

File tree

4 files changed

+33
-4
lines changed

4 files changed

+33
-4
lines changed

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

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_index::IndexVec;
77
use rustc_lint as lint;
88
use rustc_middle::span_bug;
99
use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults};
10+
use rustc_span::source_map::SourceMap;
1011
use rustc_span::{Ident, Span};
1112

1213
use crate::errors::*;
@@ -113,7 +114,7 @@ impl<'a> PatMigration<'a> {
113114
for (span, label) in self.labels {
114115
spans.push_span_label(*span, label.clone());
115116
}
116-
let sugg = self.build_suggestion(typeck_results);
117+
let sugg = self.build_suggestion(tcx.sess.source_map(), typeck_results);
117118
// If a relevant span is from at least edition 2024, this is a hard error.
118119
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
119120
if is_hard_error {
@@ -135,8 +136,9 @@ impl<'a> PatMigration<'a> {
135136
}
136137
}
137138

138-
fn build_suggestion(
139+
fn build_suggestion<'tcx>(
139140
&self,
141+
source_map: &'tcx SourceMap,
140142
typeck_results: &'a TypeckResults<'_>,
141143
) -> Rust2024IncompatiblePatSugg {
142144
let mut removed_modifiers = 0;
@@ -167,7 +169,10 @@ impl<'a> PatMigration<'a> {
167169
PatDerefKind::Explicit { inner_span } if !deref.suggest => {
168170
// This is a ref pattern in the source but not the suggestion; suggest removing it.
169171
removed_ref_pats += 1;
170-
Some((deref.span.with_hi(inner_span.lo()), String::new()))
172+
// Avoid eating the '(' in `&(...)`
173+
let span = source_map.span_until_char(deref.span.with_hi(inner_span.lo()), '(');
174+
// But *do* eat the ' ' in `&mut [...]`
175+
Some((source_map.span_extend_while_whitespace(span), String::new()))
171176
}
172177
PatDerefKind::Implicit { hir_id } if deref.suggest => {
173178
// This is a ref pattern in the suggestion but not the source; suggest adding it.

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

+5
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,9 @@ fn main() {
228228
assert_type_eq(b, &0u32);
229229
assert_type_eq(c, &[0u32]);
230230
assert_type_eq(d, 0u32);
231+
232+
// Test that we don't remove excess open parentheses when removing reference patterns
233+
let [(_)] = &[&0];
234+
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
235+
//~| WARN: this changes meaning in Rust 2024
231236
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,9 @@ fn main() {
228228
assert_type_eq(b, &0u32);
229229
assert_type_eq(c, &[0u32]);
230230
assert_type_eq(d, 0u32);
231+
232+
// Test that we don't remove excess open parentheses when removing reference patterns
233+
let [&(_)] = &[&0];
234+
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
235+
//~| WARN: this changes meaning in Rust 2024
231236
}

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -380,5 +380,19 @@ LL - let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
380380
LL + let [&Foo(a @ [b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2];
381381
|
382382

383-
error: aborting due to 27 previous errors
383+
error: this pattern relies on behavior which may change in edition 2024
384+
--> $DIR/migration_lint.rs:233:10
385+
|
386+
LL | let [&(_)] = &[&0];
387+
| ^^ cannot implicitly match against multiple layers of reference
388+
|
389+
= warning: this changes meaning in Rust 2024
390+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
391+
help: make the reference pattern implicit
392+
|
393+
LL - let [&(_)] = &[&0];
394+
LL + let [(_)] = &[&0];
395+
|
396+
397+
error: aborting due to 28 previous errors
384398

0 commit comments

Comments
 (0)