Skip to content

Implement match ergonomics 2024 #122978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
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
  • Loading branch information
Jules-Bertholet committed Mar 25, 2024
commit ed6e6c9a5227eba1b30265a62f43f3c6de3fe63d
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which impl
hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding
.label = `mut` dereferences the type of this binding
.help = this will change in edition 2024
.suggestion = desugar the match ergonomics

hir_typeck_expected_default_return_type = expected `()` because of default return type

Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,16 @@ pub struct DereferencingMutBinding {
#[label]
#[help]
pub span: Span,
#[subdiagnostic]
pub sugg: DereferencingMutBindingSuggestion,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(hir_typeck_suggestion, applicability = "machine-applicable")]
pub struct DereferencingMutBindingSuggestion {
#[suggestion_part(code = "{code}")]
pub lo: Span,
pub code: String,
#[suggestion_part(code = ")")]
pub hi: Option<Span>,
}
47 changes: 39 additions & 8 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Never => expected,
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
PatKind::Binding(ba, var_id, _, sub) => {
self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
PatKind::Binding(ba, var_id, ident, sub) => {
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
}
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
Expand Down Expand Up @@ -623,28 +623,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat: &'tcx Pat<'tcx>,
ba: BindingAnnotation,
var_id: HirId,
ident: Ident,
sub: Option<&'tcx Pat<'tcx>>,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let PatInfo { binding_mode: BindingAnnotation(def_br, _), top_info: ti, .. } = pat_info;

// Determine the binding mode...
let bm = match ba {
BindingAnnotation(ByRef::No, Mutability::Mut)
if !pat.span.at_least_rust_2024() && matches!(def_br, ByRef::Yes(_)) =>
let bm = match (ba, def_br) {
(BindingAnnotation(ByRef::No, Mutability::Mut), ByRef::Yes(brmut))
if !pat.span.at_least_rust_2024() =>
{
// `mut x` resets the binding mode in edition <= 2021.

let using_and_mut = brmut == Mutability::Mut;
let maybe_mut_kw = if using_and_mut { "mut " } else { "(" };
let (suggestion_span, pre_sub_str) = if let Some(sub) = sub {
(pat.span.until(sub.span), " @ ")
} else {
(pat.span, if using_and_mut { "" } else { ")" })
};
let ident_str = ident.as_str();
let ref_mut_str = match self.shallow_resolve(expected).kind() {
ty::Ref(_, _, emut) if *emut == brmut => {
if using_and_mut {
"ref mut "
} else {
"ref "
}
}
_ => "",
};

self.tcx.emit_node_span_lint(
lint::builtin::DEREFERENCING_MUT_BINDING,
pat.hir_id,
pat.span,
errors::DereferencingMutBinding { span: pat.span },
errors::DereferencingMutBinding {
span: pat.span,
sugg: errors::DereferencingMutBindingSuggestion {
lo: suggestion_span,
code: format!(
"&{maybe_mut_kw}mut {ref_mut_str}{ident_str}{pre_sub_str}"
),
hi: (!using_and_mut && sub.is_some())
.then_some(pat.span.with_lo(pat.span.hi())),
},
},
);
BindingAnnotation(ByRef::No, Mutability::Mut)
}
BindingAnnotation(ByRef::No, mutbl) => BindingAnnotation(def_br, mutbl),
BindingAnnotation(ByRef::Yes(_), _) => ba,
(BindingAnnotation(ByRef::No, mutbl), _) => BindingAnnotation(def_br, mutbl),
(BindingAnnotation(ByRef::Yes(_), _), _) => ba,
};
// ...and store it in a side table:
self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
Expand Down
52 changes: 52 additions & 0 deletions tests/ui/pattern/match-2024-migration.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//@ run-pass
//@ run-rustfix
//@ rustfix-only-machine-applicable
#![allow(unused_variables, unused_mut)]
#![warn(dereferencing_mut_binding)]
fn main() {
// A tuple is a "non-reference pattern".
// A `mut` binding pattern resets the binding mode to by-value
// in edition <= 2021.

let mut p = (0u8, 0u8);
let (a, &mut mut b) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let (a, &(mut b)) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let (a, &mut mut b @ _) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let (a, &(mut b @ _)) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let mut p = (&0u8, &0u8);
let (a, &mut mut b) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;

let (a, &(mut ref b)) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;

let (a, &mut mut b @ _) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;

let (a, &(mut ref b @ _)) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;
}
52 changes: 52 additions & 0 deletions tests/ui/pattern/match-2024-migration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//@ run-pass
//@ run-rustfix
//@ rustfix-only-machine-applicable
#![allow(unused_variables, unused_mut)]
#![warn(dereferencing_mut_binding)]
fn main() {
// A tuple is a "non-reference pattern".
// A `mut` binding pattern resets the binding mode to by-value
// in edition <= 2021.

let mut p = (0u8, 0u8);
let (a, mut b) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let (a, mut b) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let (a, mut b @ _) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let (a, mut b @ _) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: u8 = b;

let mut p = (&0u8, &0u8);
let (a, mut b) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;

let (a, mut b) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;

let (a, mut b @ _) = &mut p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;

let (a, mut b @ _) = &p;
//~^ WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
let _: &u8 = b;
}
145 changes: 145 additions & 0 deletions tests/ui/pattern/match-2024-migration.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:12:13
|
LL | let (a, mut b) = &mut p;
| ^^^^^
| |
| `mut` dereferences the type of this binding
| help: desugar the match ergonomics: `&mut mut b`
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:12:13
|
LL | let (a, mut b) = &mut p;
| ^^^^^
note: the lint level is defined here
--> $DIR/match-2024-migration.rs:5:9
|
LL | #![warn(dereferencing_mut_binding)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:17:13
|
LL | let (a, mut b) = &p;
| ^^^^^
| |
| `mut` dereferences the type of this binding
| help: desugar the match ergonomics: `&(mut b)`
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:17:13
|
LL | let (a, mut b) = &p;
| ^^^^^

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:22:13
|
LL | let (a, mut b @ _) = &mut p;
| --------^
| |
| `mut` dereferences the type of this binding
| help: desugar the match ergonomics: `&mut mut b @`
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:22:13
|
LL | let (a, mut b @ _) = &mut p;
| ^^^^^^^^^

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:27:13
|
LL | let (a, mut b @ _) = &p;
| ^^^^^^^^^ `mut` dereferences the type of this binding
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:27:13
|
LL | let (a, mut b @ _) = &p;
| ^^^^^^^^^
help: desugar the match ergonomics
|
LL | let (a, &(mut b @ _)) = &p;
| ~~~~~~~~~ +

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:33:13
|
LL | let (a, mut b) = &mut p;
| ^^^^^
| |
| `mut` dereferences the type of this binding
| help: desugar the match ergonomics: `&mut mut b`
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:33:13
|
LL | let (a, mut b) = &mut p;
| ^^^^^

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:38:13
|
LL | let (a, mut b) = &p;
| ^^^^^
| |
| `mut` dereferences the type of this binding
| help: desugar the match ergonomics: `&(mut ref b)`
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:38:13
|
LL | let (a, mut b) = &p;
| ^^^^^

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:43:13
|
LL | let (a, mut b @ _) = &mut p;
| --------^
| |
| `mut` dereferences the type of this binding
| help: desugar the match ergonomics: `&mut mut b @`
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:43:13
|
LL | let (a, mut b @ _) = &mut p;
| ^^^^^^^^^

warning: dereferencing `mut` binding
--> $DIR/match-2024-migration.rs:48:13
|
LL | let (a, mut b @ _) = &p;
| ^^^^^^^^^ `mut` dereferences the type of this binding
|
= warning: this changes meaning in Rust 2024
= note: for more information, see FIXME none yet
help: this will change in edition 2024
--> $DIR/match-2024-migration.rs:48:13
|
LL | let (a, mut b @ _) = &p;
| ^^^^^^^^^
help: desugar the match ergonomics
|
LL | let (a, &(mut ref b @ _)) = &p;
| ~~~~~~~~~~~~~ +

warning: 8 warnings emitted

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//@ run-rustfix
#![allow(unused_variables)]
#![warn(dereferencing_mut_binding)]
fn main() {
struct U;

Expand All @@ -10,6 +9,4 @@ fn main() {
let mut p = (U, U);
let (a, ref mut b) = &mut p;
//~^ ERROR cannot move out of a mutable reference
//~| WARN dereferencing `mut`
//~| WARN this changes meaning in Rust 2024
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//@ run-rustfix
#![allow(unused_variables)]
#![warn(dereferencing_mut_binding)]
fn main() {
struct U;

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