Skip to content

Commit a0d4c55

Browse files
varkorfanzier
authored andcommitted
Prevent default match bindings in destructuring assignment
1 parent 8614f44 commit a0d4c55

File tree

9 files changed

+67
-14
lines changed

9 files changed

+67
-14
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -945,19 +945,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
945945
match &lhs.kind {
946946
// Underscore pattern.
947947
ExprKind::Underscore => {
948-
return self.pat(lhs.span, hir::PatKind::Wild);
948+
return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
949949
}
950950
// Slice patterns.
951951
ExprKind::Array(elements) => {
952952
let (pats, rest) =
953953
self.destructure_sequence(elements, "slice", eq_sign_span, assignments);
954954
let slice_pat = if let Some((i, span)) = rest {
955955
let (before, after) = pats.split_at(i);
956-
hir::PatKind::Slice(before, Some(self.pat(span, hir::PatKind::Wild)), after)
956+
hir::PatKind::Slice(
957+
before,
958+
Some(self.pat_without_dbm(span, hir::PatKind::Wild)),
959+
after,
960+
)
957961
} else {
958962
hir::PatKind::Slice(pats, None, &[])
959963
};
960-
return self.pat(lhs.span, slice_pat);
964+
return self.pat_without_dbm(lhs.span, slice_pat);
961965
}
962966
// Tuple structs.
963967
ExprKind::Call(callee, args) => {
@@ -979,7 +983,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
979983
// Destructure like a tuple struct since the path is in fact a constructor.
980984
let tuple_struct_pat =
981985
hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
982-
return self.pat(lhs.span, tuple_struct_pat);
986+
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
983987
}
984988
_ => {
985989
// If the path is not a constructor, lower as an ordinary LHS.
@@ -1028,20 +1032,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
10281032
StructRest::None => false,
10291033
};
10301034
let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);
1031-
return self.pat(lhs.span, struct_pat);
1035+
return self.pat_without_dbm(lhs.span, struct_pat);
10321036
}
10331037
// Tuples.
10341038
ExprKind::Tup(elements) => {
10351039
let (pats, rest) =
10361040
self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
10371041
let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
1038-
return self.pat(lhs.span, tuple_pat);
1042+
return self.pat_without_dbm(lhs.span, tuple_pat);
10391043
}
10401044
// `(..)`. We special-case this for consistency with declarations.
10411045
ExprKind::Paren(e) => {
10421046
if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
10431047
let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
1044-
return self.pat(lhs.span, tuple_pat);
1048+
return self.pat_without_dbm(lhs.span, tuple_pat);
10451049
}
10461050
}
10471051
_ => {}

compiler/rustc_ast_lowering/src/lib.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
25312531
hir_id,
25322532
kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
25332533
span,
2534+
default_binding_modes: true,
25342535
}),
25352536
hir_id,
25362537
)
@@ -2541,7 +2542,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
25412542
}
25422543

25432544
fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
2544-
self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
2545+
self.arena.alloc(hir::Pat {
2546+
hir_id: self.next_id(),
2547+
kind,
2548+
span,
2549+
default_binding_modes: true,
2550+
})
2551+
}
2552+
2553+
fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
2554+
self.arena.alloc(hir::Pat {
2555+
hir_id: self.next_id(),
2556+
kind,
2557+
span,
2558+
default_binding_modes: false,
2559+
})
25452560
}
25462561

25472562
fn ty_path(

compiler/rustc_ast_lowering/src/pat.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
273273

274274
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
275275
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
276-
self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
276+
self.arena.alloc(hir::Pat {
277+
hir_id: self.lower_node_id(p.id),
278+
kind,
279+
span: p.span,
280+
default_binding_modes: true,
281+
})
277282
}
278283

279284
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.

compiler/rustc_hir/src/hir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,9 @@ pub struct Pat<'hir> {
732732
pub hir_id: HirId,
733733
pub kind: PatKind<'hir>,
734734
pub span: Span,
735+
// Whether to use default binding modes.
736+
// At present, this is false only for destructuring assignment.
737+
pub default_binding_modes: bool,
735738
}
736739

737740
impl Pat<'_> {

compiler/rustc_typeck/src/check/pat.rs

+5
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
270270
///
271271
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
272272
fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
273+
// When we perform destructuring assignment, we disable default match bindings, which are
274+
// unintuitive in this context.
275+
if !pat.default_binding_modes {
276+
return AdjustMode::Reset;
277+
}
273278
match &pat.kind {
274279
// Type checking these product-like types successfully always require
275280
// that the expected type be of those types and not reference types.

compiler/rustc_typeck/src/check/regionck.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
577577
fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
578578
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
579579
ignore_err!(self.with_mc(|mc| {
580-
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| {
580+
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| {
581581
// `ref x` pattern
582582
if let PatKind::Binding(..) = kind {
583583
if let Some(ty::BindByReference(mutbl)) =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(destructuring_assignment)]
2+
3+
fn main() {
4+
let mut x = &0;
5+
let mut y = &0;
6+
(x, y) = &(1, 2); //~ ERROR mismatched types
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/default-match-bindings-forbidden.rs:6:5
3+
|
4+
LL | (x, y) = &(1, 2);
5+
| ^^^^^^ ------- this expression has type `&({integer}, {integer})`
6+
| |
7+
| expected reference, found tuple
8+
|
9+
= note: expected type `&({integer}, {integer})`
10+
found tuple `(_, _)`
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ LL | (a, a, b) = (1, 2);
1414
| |
1515
| expected a tuple with 2 elements, found one with 3 elements
1616
|
17-
= note: expected tuple `({integer}, {integer})`
18-
found tuple `(_, _, _)`
17+
= note: expected type `({integer}, {integer})`
18+
found tuple `(_, _, _)`
1919

2020
error[E0308]: mismatched types
2121
--> $DIR/tuple_destructure_fail.rs:7:5
@@ -25,8 +25,8 @@ LL | (_,) = (1, 2);
2525
| |
2626
| expected a tuple with 2 elements, found one with 1 element
2727
|
28-
= note: expected tuple `({integer}, {integer})`
29-
found tuple `(_,)`
28+
= note: expected type `({integer}, {integer})`
29+
found tuple `(_,)`
3030

3131
error: aborting due to 3 previous errors
3232

0 commit comments

Comments
 (0)