Skip to content

Commit 45796d1

Browse files
committed
Auto merge of #123080 - Jules-Bertholet:mut-ref-mut, r=Nadrieril
Match ergonomics 2024: implement mutable by-reference bindings Implements the mutable by-reference bindings portion of match ergonomics 2024 (#123076), with the `mut ref`/`mut ref mut` syntax, under feature gate `mut_ref`. r? `@Nadrieril` `@rustbot` label A-patterns A-edition-2024
2 parents 58dcd1f + e931595 commit 45796d1

File tree

58 files changed

+529
-378
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+529
-378
lines changed

compiler/rustc_ast/src/ast.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -702,19 +702,10 @@ pub struct PatField {
702702
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
703703
#[derive(Encodable, Decodable, HashStable_Generic)]
704704
pub enum ByRef {
705-
Yes,
705+
Yes(Mutability),
706706
No,
707707
}
708708

709-
impl From<bool> for ByRef {
710-
fn from(b: bool) -> ByRef {
711-
match b {
712-
false => ByRef::No,
713-
true => ByRef::Yes,
714-
}
715-
}
716-
}
717-
718709
/// Explicit binding annotations given in the HIR for a binding. Note
719710
/// that this is not the final binding *mode* that we infer after type
720711
/// inference.
@@ -724,16 +715,20 @@ pub struct BindingAnnotation(pub ByRef, pub Mutability);
724715

725716
impl BindingAnnotation {
726717
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
727-
pub const REF: Self = Self(ByRef::Yes, Mutability::Not);
718+
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
728719
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
729-
pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut);
720+
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
721+
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
722+
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
730723

731724
pub fn prefix_str(self) -> &'static str {
732725
match self {
733726
Self::NONE => "",
734727
Self::REF => "ref ",
735728
Self::MUT => "mut ",
736729
Self::REF_MUT => "ref mut ",
730+
Self::MUT_REF => "mut ref ",
731+
Self::MUT_REF_MUT => "mut ref mut ",
737732
}
738733
}
739734
}

compiler/rustc_ast_lowering/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1847,8 +1847,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18471847
// the case where we have a mutable pattern to a reference as that would
18481848
// no longer be an `ImplicitSelf`.
18491849
TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
1850-
hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef,
1851-
hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef,
1850+
hir::Mutability::Not => hir::ImplicitSelfKind::RefImm,
1851+
hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut,
18521852
},
18531853
_ => hir::ImplicitSelfKind::None,
18541854
}

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
565565
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
566566
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
567567
gate_all!(postfix_match, "postfix match is experimental");
568+
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
568569

569570
if !visitor.features.never_patterns {
570571
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_ast_pretty/src/pprust/state.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1545,12 +1545,15 @@ impl<'a> State<'a> {
15451545
PatKind::Wild => self.word("_"),
15461546
PatKind::Never => self.word("!"),
15471547
PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
1548-
if *by_ref == ByRef::Yes {
1549-
self.word_nbsp("ref");
1550-
}
15511548
if mutbl.is_mut() {
15521549
self.word_nbsp("mut");
15531550
}
1551+
if let ByRef::Yes(rmutbl) = by_ref {
1552+
self.word_nbsp("ref");
1553+
if rmutbl.is_mut() {
1554+
self.word_nbsp("mut");
1555+
}
1556+
}
15541557
self.print_ident(*ident);
15551558
if let Some(p) = sub {
15561559
self.space();

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
use core::ops::ControlFlow;
55
use hir::{ExprKind, Param};
66
use rustc_errors::{Applicability, Diag};
7-
use rustc_hir as hir;
87
use rustc_hir::intravisit::Visitor;
9-
use rustc_hir::Node;
8+
use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node};
109
use rustc_infer::traits;
1110
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
1211
use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
@@ -304,7 +303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
304303
{
305304
match *decl.local_info() {
306305
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
307-
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
306+
binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
308307
opt_ty_info: Some(sp),
309308
opt_match_place: _,
310309
pat_span: _,
@@ -342,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
342341
} else if decl.mutability.is_not() {
343342
if matches!(
344343
decl.local_info(),
345-
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef))
344+
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
346345
) {
347346
err.note(
348347
"as `Self` may be unsized, this call attempts to take `&mut &mut self`",
@@ -407,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
407406
if let Some(fn_decl) = node.fn_decl() {
408407
if !matches!(
409408
fn_decl.implicit_self,
410-
hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef
409+
hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
411410
) {
412411
err.span_suggestion(
413412
upvar_ident.span,
@@ -717,7 +716,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
717716
debug!("local_decl: {:?}", local_decl);
718717
let pat_span = match *local_decl.local_info() {
719718
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
720-
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
719+
binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
721720
opt_ty_info: _,
722721
opt_match_place: _,
723722
pat_span,
@@ -1070,7 +1069,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
10701069
}
10711070

10721071
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1073-
binding_mode: ty::BindingMode::BindByValue(_),
1072+
binding_mode: BindingAnnotation(ByRef::No, _),
10741073
opt_ty_info,
10751074
..
10761075
})) => {
@@ -1138,7 +1137,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11381137
}
11391138

11401139
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1141-
binding_mode: ty::BindingMode::BindByReference(_),
1140+
binding_mode: BindingAnnotation(ByRef::Yes(_), _),
11421141
..
11431142
})) => {
11441143
let pattern_span: Span = local_decl.source_info.span;
@@ -1329,7 +1328,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
13291328
match *local_decl.local_info() {
13301329
// Check if mutably borrowing a mutable reference.
13311330
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1332-
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
1331+
binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
13331332
..
13341333
})) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
13351334
LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
@@ -1338,7 +1337,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
13381337
//
13391338
// Deliberately fall into this case for all implicit self types,
13401339
// so that we don't fall into the next case with them.
1341-
kind == hir::ImplicitSelfKind::MutRef
1340+
kind == hir::ImplicitSelfKind::RefMut
13421341
}
13431342
_ if Some(kw::SelfLower) == local_name => {
13441343
// Otherwise, check if the name is the `self` keyword - in which case

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ declare_features! (
529529
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
530530
/// Allows the `#[must_not_suspend]` attribute.
531531
(unstable, must_not_suspend, "1.57.0", Some(83310)),
532+
/// Allows `mut ref` and `mut ref mut` identifier patterns.
533+
(incomplete, mut_ref, "CURRENT_RUSTC_VERSION", Some(123076)),
532534
/// Allows using `#[naked]` on functions.
533535
(unstable, naked_functions, "1.9.0", Some(90957)),
534536
/// Allows specifying the as-needed link modifier

compiler/rustc_hir/src/hir.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2733,9 +2733,9 @@ pub enum ImplicitSelfKind {
27332733
/// Represents a `fn x(mut self);`.
27342734
Mut,
27352735
/// Represents a `fn x(&self);`.
2736-
ImmRef,
2736+
RefImm,
27372737
/// Represents a `fn x(&mut self);`.
2738-
MutRef,
2738+
RefMut,
27392739
/// Represents when a function does not have a self argument or
27402740
/// when a function has a `self: X` argument.
27412741
None,

compiler/rustc_hir_analysis/src/check/errs.rs

+17-25
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,15 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
1414
&& matches!(borrow_kind, hir::BorrowKind::Ref)
1515
&& let Some(var) = is_path_static_mut(*expr)
1616
{
17-
handle_static_mut_ref(
18-
tcx,
19-
span,
20-
var,
21-
span.edition().at_least_rust_2024(),
22-
matches!(m, Mutability::Mut),
23-
hir_id,
24-
);
17+
handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id);
2518
}
2619
}
2720

2821
/// Check for shared or mutable references of `static mut` inside statement
2922
pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
3023
if let hir::StmtKind::Let(loc) = stmt.kind
3124
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
32-
&& matches!(ba.0, rustc_ast::ByRef::Yes)
25+
&& let hir::ByRef::Yes(rmutbl) = ba.0
3326
&& let Some(init) = loc.init
3427
&& let Some(var) = is_path_static_mut(*init)
3528
{
@@ -38,7 +31,7 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
3831
init.span,
3932
var,
4033
loc.span.edition().at_least_rust_2024(),
41-
matches!(ba.1, Mutability::Mut),
34+
rmutbl,
4235
stmt.hir_id,
4336
);
4437
}
@@ -60,28 +53,27 @@ fn handle_static_mut_ref(
6053
span: Span,
6154
var: String,
6255
e2024: bool,
63-
mutable: bool,
56+
mutable: Mutability,
6457
hir_id: hir::HirId,
6558
) {
6659
if e2024 {
67-
let (sugg, shared) = if mutable {
60+
let (sugg, shared) = if mutable == Mutability::Mut {
6861
(errors::StaticMutRefSugg::Mut { span, var }, "mutable")
6962
} else {
7063
(errors::StaticMutRefSugg::Shared { span, var }, "shared")
7164
};
7265
tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
73-
return;
74-
}
75-
76-
let (sugg, shared) = if mutable {
77-
(errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
7866
} else {
79-
(errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
80-
};
81-
tcx.emit_node_span_lint(
82-
STATIC_MUT_REFS,
83-
hir_id,
84-
span,
85-
errors::RefOfMutStatic { span, sugg, shared },
86-
);
67+
let (sugg, shared) = if mutable == Mutability::Mut {
68+
(errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
69+
} else {
70+
(errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
71+
};
72+
tcx.emit_node_span_lint(
73+
STATIC_MUT_REFS,
74+
hir_id,
75+
span,
76+
errors::RefOfMutStatic { span, sugg, shared },
77+
);
78+
}
8779
}

compiler/rustc_hir_analysis/src/check/region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ fn resolve_local<'tcx>(
654654
// & expression, and its lifetime would be extended to the end of the block (due
655655
// to a different rule, not the below code).
656656
match pat.kind {
657-
PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
657+
PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes(_), _), ..) => true,
658658

659659
PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),
660660

compiler/rustc_hir_pretty/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1721,12 +1721,15 @@ impl<'a> State<'a> {
17211721
PatKind::Wild => self.word("_"),
17221722
PatKind::Never => self.word("!"),
17231723
PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
1724-
if by_ref == ByRef::Yes {
1725-
self.word_nbsp("ref");
1726-
}
17271724
if mutbl.is_mut() {
17281725
self.word_nbsp("mut");
17291726
}
1727+
if let ByRef::Yes(rmutbl) = by_ref {
1728+
self.word_nbsp("ref");
1729+
if rmutbl.is_mut() {
1730+
self.word_nbsp("mut");
1731+
}
1732+
}
17301733
self.print_ident(ident);
17311734
if let Some(p) = sub {
17321735
self.word("@");

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -739,12 +739,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
739739
// In a cases of pattern like `let pat = upvar`, don't use the span
740740
// of the pattern, as this just looks confusing, instead use the span
741741
// of the discriminant.
742-
match bm {
743-
ty::BindByReference(m) => {
742+
match bm.0 {
743+
hir::ByRef::Yes(m) => {
744744
let bk = ty::BorrowKind::from_mutbl(m);
745745
delegate.borrow(place, discr_place.hir_id, bk);
746746
}
747-
ty::BindByValue(..) => {
747+
hir::ByRef::No => {
748748
debug!("walk_pat binding consuming pat");
749749
delegate_consume(mc, *delegate, place, discr_place.hir_id);
750750
}

compiler/rustc_hir_typeck/src/mem_categorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
206206
.get(pat.hir_id)
207207
.expect("missing binding mode");
208208

209-
if let ty::BindByReference(_) = bm {
209+
if matches!(bm.0, hir::ByRef::Yes(_)) {
210210
// a bind-by-ref means that the base_ty will be the type of the ident itself,
211211
// but what we want here is the type of the underlying value being borrowed.
212212
// So peel off one-level, turning the &T into T.

0 commit comments

Comments
 (0)