Skip to content

Commit ed6e6c9

Browse files
Implement edition migration lint
Leads to bad results when combined with machine-applicable error fixes; not sure if that is considered acceptable. Again, I don't know what I am doing wrt type system stuff so needs more review there
1 parent eea20a1 commit ed6e6c9

12 files changed

+323
-40
lines changed

compiler/rustc_hir_typeck/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which impl
4949
hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding
5050
.label = `mut` dereferences the type of this binding
5151
.help = this will change in edition 2024
52+
.suggestion = desugar the match ergonomics
5253
5354
hir_typeck_expected_default_return_type = expected `()` because of default return type
5455

compiler/rustc_hir_typeck/src/errors.rs

+12
Original file line numberDiff line numberDiff line change
@@ -628,4 +628,16 @@ pub struct DereferencingMutBinding {
628628
#[label]
629629
#[help]
630630
pub span: Span,
631+
#[subdiagnostic]
632+
pub sugg: DereferencingMutBindingSuggestion,
633+
}
634+
635+
#[derive(Subdiagnostic)]
636+
#[multipart_suggestion(hir_typeck_suggestion, applicability = "machine-applicable")]
637+
pub struct DereferencingMutBindingSuggestion {
638+
#[suggestion_part(code = "{code}")]
639+
pub lo: Span,
640+
pub code: String,
641+
#[suggestion_part(code = ")")]
642+
pub hi: Option<Span>,
631643
}

compiler/rustc_hir_typeck/src/pat.rs

+39-8
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
195195
PatKind::Never => expected,
196196
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
197197
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
198-
PatKind::Binding(ba, var_id, _, sub) => {
199-
self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
198+
PatKind::Binding(ba, var_id, ident, sub) => {
199+
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
200200
}
201201
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
202202
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
@@ -623,28 +623,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
623623
pat: &'tcx Pat<'tcx>,
624624
ba: BindingAnnotation,
625625
var_id: HirId,
626+
ident: Ident,
626627
sub: Option<&'tcx Pat<'tcx>>,
627628
expected: Ty<'tcx>,
628629
pat_info: PatInfo<'tcx, '_>,
629630
) -> Ty<'tcx> {
630631
let PatInfo { binding_mode: BindingAnnotation(def_br, _), top_info: ti, .. } = pat_info;
631632

632633
// Determine the binding mode...
633-
let bm = match ba {
634-
BindingAnnotation(ByRef::No, Mutability::Mut)
635-
if !pat.span.at_least_rust_2024() && matches!(def_br, ByRef::Yes(_)) =>
634+
let bm = match (ba, def_br) {
635+
(BindingAnnotation(ByRef::No, Mutability::Mut), ByRef::Yes(brmut))
636+
if !pat.span.at_least_rust_2024() =>
636637
{
637638
// `mut x` resets the binding mode in edition <= 2021.
639+
640+
let using_and_mut = brmut == Mutability::Mut;
641+
let maybe_mut_kw = if using_and_mut { "mut " } else { "(" };
642+
let (suggestion_span, pre_sub_str) = if let Some(sub) = sub {
643+
(pat.span.until(sub.span), " @ ")
644+
} else {
645+
(pat.span, if using_and_mut { "" } else { ")" })
646+
};
647+
let ident_str = ident.as_str();
648+
let ref_mut_str = match self.shallow_resolve(expected).kind() {
649+
ty::Ref(_, _, emut) if *emut == brmut => {
650+
if using_and_mut {
651+
"ref mut "
652+
} else {
653+
"ref "
654+
}
655+
}
656+
_ => "",
657+
};
658+
638659
self.tcx.emit_node_span_lint(
639660
lint::builtin::DEREFERENCING_MUT_BINDING,
640661
pat.hir_id,
641662
pat.span,
642-
errors::DereferencingMutBinding { span: pat.span },
663+
errors::DereferencingMutBinding {
664+
span: pat.span,
665+
sugg: errors::DereferencingMutBindingSuggestion {
666+
lo: suggestion_span,
667+
code: format!(
668+
"&{maybe_mut_kw}mut {ref_mut_str}{ident_str}{pre_sub_str}"
669+
),
670+
hi: (!using_and_mut && sub.is_some())
671+
.then_some(pat.span.with_lo(pat.span.hi())),
672+
},
673+
},
643674
);
644675
BindingAnnotation(ByRef::No, Mutability::Mut)
645676
}
646-
BindingAnnotation(ByRef::No, mutbl) => BindingAnnotation(def_br, mutbl),
647-
BindingAnnotation(ByRef::Yes(_), _) => ba,
677+
(BindingAnnotation(ByRef::No, mutbl), _) => BindingAnnotation(def_br, mutbl),
678+
(BindingAnnotation(ByRef::Yes(_), _), _) => ba,
648679
};
649680
// ...and store it in a side table:
650681
self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//@ run-pass
2+
//@ run-rustfix
3+
//@ rustfix-only-machine-applicable
4+
#![allow(unused_variables, unused_mut)]
5+
#![warn(dereferencing_mut_binding)]
6+
fn main() {
7+
// A tuple is a "non-reference pattern".
8+
// A `mut` binding pattern resets the binding mode to by-value
9+
// in edition <= 2021.
10+
11+
let mut p = (0u8, 0u8);
12+
let (a, &mut mut b) = &mut p;
13+
//~^ WARN dereferencing `mut`
14+
//~| WARN this changes meaning in Rust 2024
15+
let _: u8 = b;
16+
17+
let (a, &(mut b)) = &p;
18+
//~^ WARN dereferencing `mut`
19+
//~| WARN this changes meaning in Rust 2024
20+
let _: u8 = b;
21+
22+
let (a, &mut mut b @ _) = &mut p;
23+
//~^ WARN dereferencing `mut`
24+
//~| WARN this changes meaning in Rust 2024
25+
let _: u8 = b;
26+
27+
let (a, &(mut b @ _)) = &p;
28+
//~^ WARN dereferencing `mut`
29+
//~| WARN this changes meaning in Rust 2024
30+
let _: u8 = b;
31+
32+
let mut p = (&0u8, &0u8);
33+
let (a, &mut mut b) = &mut p;
34+
//~^ WARN dereferencing `mut`
35+
//~| WARN this changes meaning in Rust 2024
36+
let _: &u8 = b;
37+
38+
let (a, &(mut ref b)) = &p;
39+
//~^ WARN dereferencing `mut`
40+
//~| WARN this changes meaning in Rust 2024
41+
let _: &u8 = b;
42+
43+
let (a, &mut mut b @ _) = &mut p;
44+
//~^ WARN dereferencing `mut`
45+
//~| WARN this changes meaning in Rust 2024
46+
let _: &u8 = b;
47+
48+
let (a, &(mut ref b @ _)) = &p;
49+
//~^ WARN dereferencing `mut`
50+
//~| WARN this changes meaning in Rust 2024
51+
let _: &u8 = b;
52+
}
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//@ run-pass
2+
//@ run-rustfix
3+
//@ rustfix-only-machine-applicable
4+
#![allow(unused_variables, unused_mut)]
5+
#![warn(dereferencing_mut_binding)]
6+
fn main() {
7+
// A tuple is a "non-reference pattern".
8+
// A `mut` binding pattern resets the binding mode to by-value
9+
// in edition <= 2021.
10+
11+
let mut p = (0u8, 0u8);
12+
let (a, mut b) = &mut p;
13+
//~^ WARN dereferencing `mut`
14+
//~| WARN this changes meaning in Rust 2024
15+
let _: u8 = b;
16+
17+
let (a, mut b) = &p;
18+
//~^ WARN dereferencing `mut`
19+
//~| WARN this changes meaning in Rust 2024
20+
let _: u8 = b;
21+
22+
let (a, mut b @ _) = &mut p;
23+
//~^ WARN dereferencing `mut`
24+
//~| WARN this changes meaning in Rust 2024
25+
let _: u8 = b;
26+
27+
let (a, mut b @ _) = &p;
28+
//~^ WARN dereferencing `mut`
29+
//~| WARN this changes meaning in Rust 2024
30+
let _: u8 = b;
31+
32+
let mut p = (&0u8, &0u8);
33+
let (a, mut b) = &mut p;
34+
//~^ WARN dereferencing `mut`
35+
//~| WARN this changes meaning in Rust 2024
36+
let _: &u8 = b;
37+
38+
let (a, mut b) = &p;
39+
//~^ WARN dereferencing `mut`
40+
//~| WARN this changes meaning in Rust 2024
41+
let _: &u8 = b;
42+
43+
let (a, mut b @ _) = &mut p;
44+
//~^ WARN dereferencing `mut`
45+
//~| WARN this changes meaning in Rust 2024
46+
let _: &u8 = b;
47+
48+
let (a, mut b @ _) = &p;
49+
//~^ WARN dereferencing `mut`
50+
//~| WARN this changes meaning in Rust 2024
51+
let _: &u8 = b;
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
warning: dereferencing `mut` binding
2+
--> $DIR/match-2024-migration.rs:12:13
3+
|
4+
LL | let (a, mut b) = &mut p;
5+
| ^^^^^
6+
| |
7+
| `mut` dereferences the type of this binding
8+
| help: desugar the match ergonomics: `&mut mut b`
9+
|
10+
= warning: this changes meaning in Rust 2024
11+
= note: for more information, see FIXME none yet
12+
help: this will change in edition 2024
13+
--> $DIR/match-2024-migration.rs:12:13
14+
|
15+
LL | let (a, mut b) = &mut p;
16+
| ^^^^^
17+
note: the lint level is defined here
18+
--> $DIR/match-2024-migration.rs:5:9
19+
|
20+
LL | #![warn(dereferencing_mut_binding)]
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
22+
23+
warning: dereferencing `mut` binding
24+
--> $DIR/match-2024-migration.rs:17:13
25+
|
26+
LL | let (a, mut b) = &p;
27+
| ^^^^^
28+
| |
29+
| `mut` dereferences the type of this binding
30+
| help: desugar the match ergonomics: `&(mut b)`
31+
|
32+
= warning: this changes meaning in Rust 2024
33+
= note: for more information, see FIXME none yet
34+
help: this will change in edition 2024
35+
--> $DIR/match-2024-migration.rs:17:13
36+
|
37+
LL | let (a, mut b) = &p;
38+
| ^^^^^
39+
40+
warning: dereferencing `mut` binding
41+
--> $DIR/match-2024-migration.rs:22:13
42+
|
43+
LL | let (a, mut b @ _) = &mut p;
44+
| --------^
45+
| |
46+
| `mut` dereferences the type of this binding
47+
| help: desugar the match ergonomics: `&mut mut b @`
48+
|
49+
= warning: this changes meaning in Rust 2024
50+
= note: for more information, see FIXME none yet
51+
help: this will change in edition 2024
52+
--> $DIR/match-2024-migration.rs:22:13
53+
|
54+
LL | let (a, mut b @ _) = &mut p;
55+
| ^^^^^^^^^
56+
57+
warning: dereferencing `mut` binding
58+
--> $DIR/match-2024-migration.rs:27:13
59+
|
60+
LL | let (a, mut b @ _) = &p;
61+
| ^^^^^^^^^ `mut` dereferences the type of this binding
62+
|
63+
= warning: this changes meaning in Rust 2024
64+
= note: for more information, see FIXME none yet
65+
help: this will change in edition 2024
66+
--> $DIR/match-2024-migration.rs:27:13
67+
|
68+
LL | let (a, mut b @ _) = &p;
69+
| ^^^^^^^^^
70+
help: desugar the match ergonomics
71+
|
72+
LL | let (a, &(mut b @ _)) = &p;
73+
| ~~~~~~~~~ +
74+
75+
warning: dereferencing `mut` binding
76+
--> $DIR/match-2024-migration.rs:33:13
77+
|
78+
LL | let (a, mut b) = &mut p;
79+
| ^^^^^
80+
| |
81+
| `mut` dereferences the type of this binding
82+
| help: desugar the match ergonomics: `&mut mut b`
83+
|
84+
= warning: this changes meaning in Rust 2024
85+
= note: for more information, see FIXME none yet
86+
help: this will change in edition 2024
87+
--> $DIR/match-2024-migration.rs:33:13
88+
|
89+
LL | let (a, mut b) = &mut p;
90+
| ^^^^^
91+
92+
warning: dereferencing `mut` binding
93+
--> $DIR/match-2024-migration.rs:38:13
94+
|
95+
LL | let (a, mut b) = &p;
96+
| ^^^^^
97+
| |
98+
| `mut` dereferences the type of this binding
99+
| help: desugar the match ergonomics: `&(mut ref b)`
100+
|
101+
= warning: this changes meaning in Rust 2024
102+
= note: for more information, see FIXME none yet
103+
help: this will change in edition 2024
104+
--> $DIR/match-2024-migration.rs:38:13
105+
|
106+
LL | let (a, mut b) = &p;
107+
| ^^^^^
108+
109+
warning: dereferencing `mut` binding
110+
--> $DIR/match-2024-migration.rs:43:13
111+
|
112+
LL | let (a, mut b @ _) = &mut p;
113+
| --------^
114+
| |
115+
| `mut` dereferences the type of this binding
116+
| help: desugar the match ergonomics: `&mut mut b @`
117+
|
118+
= warning: this changes meaning in Rust 2024
119+
= note: for more information, see FIXME none yet
120+
help: this will change in edition 2024
121+
--> $DIR/match-2024-migration.rs:43:13
122+
|
123+
LL | let (a, mut b @ _) = &mut p;
124+
| ^^^^^^^^^
125+
126+
warning: dereferencing `mut` binding
127+
--> $DIR/match-2024-migration.rs:48:13
128+
|
129+
LL | let (a, mut b @ _) = &p;
130+
| ^^^^^^^^^ `mut` dereferences the type of this binding
131+
|
132+
= warning: this changes meaning in Rust 2024
133+
= note: for more information, see FIXME none yet
134+
help: this will change in edition 2024
135+
--> $DIR/match-2024-migration.rs:48:13
136+
|
137+
LL | let (a, mut b @ _) = &p;
138+
| ^^^^^^^^^
139+
help: desugar the match ergonomics
140+
|
141+
LL | let (a, &(mut ref b @ _)) = &p;
142+
| ~~~~~~~~~~~~~ +
143+
144+
warning: 8 warnings emitted
145+
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//@ run-rustfix
22
#![allow(unused_variables)]
3-
#![warn(dereferencing_mut_binding)]
43
fn main() {
54
struct U;
65

@@ -10,6 +9,4 @@ fn main() {
109
let mut p = (U, U);
1110
let (a, ref mut b) = &mut p;
1211
//~^ ERROR cannot move out of a mutable reference
13-
//~| WARN dereferencing `mut`
14-
//~| WARN this changes meaning in Rust 2024
1512
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//@ run-rustfix
22
#![allow(unused_variables)]
3-
#![warn(dereferencing_mut_binding)]
43
fn main() {
54
struct U;
65

@@ -10,6 +9,4 @@ fn main() {
109
let mut p = (U, U);
1110
let (a, mut b) = &mut p;
1211
//~^ ERROR cannot move out of a mutable reference
13-
//~| WARN dereferencing `mut`
14-
//~| WARN this changes meaning in Rust 2024
1512
}

0 commit comments

Comments
 (0)