Skip to content

Commit 4a5d475

Browse files
committed
"structural" ruleset: use the "classic" ruleset's diagnostic and fallback for inherited ref mutability mismatches
I think the diagnostic could use some work, but it's more helpful than the alternative. The previous error was misleading, since it ignored the inherited reference altogether.
1 parent 8738f93 commit 4a5d475

File tree

4 files changed

+151
-382
lines changed

4 files changed

+151
-382
lines changed

compiler/rustc_hir_typeck/src/pat.rs

+31-27
Original file line numberDiff line numberDiff line change
@@ -2285,22 +2285,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22852285
// NB: This assumes that `&` patterns can match against mutable references
22862286
// (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E
22872287
// but not Rule 5, we'll need to check that here.
2288-
let err_msg = "mismatched types";
2289-
let err = if let Some(span) = pat_prefix_span {
2290-
let mut err = self.dcx().struct_span_err(span, err_msg);
2291-
err.code(E0308);
2292-
err.note("cannot match inherited `&` with `&mut` pattern");
2293-
err.span_suggestion_verbose(
2294-
span,
2295-
"replace this `&mut` pattern with `&`",
2296-
"&",
2297-
Applicability::MachineApplicable,
2298-
);
2299-
err
2300-
} else {
2301-
self.dcx().struct_span_err(pat.span, err_msg)
2302-
};
2303-
err.emit();
2288+
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
23042289
}
23052290

23062291
pat_info.binding_mode = ByRef::No;
@@ -2319,21 +2304,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23192304
} else {
23202305
// The expected type isn't a reference, so match against the inherited ref.
23212306
if pat_mutbl > inh_mut {
2322-
// We can't match an inherited shared reference with `&mut`. This will
2323-
// be a type error later, since we're matching a reference pattern
2324-
// against a non-reference type.
2307+
// We can't match an inherited shared reference with `&mut`.
23252308
// NB: This assumes that `&` patterns can match against mutable
23262309
// references (RFC 3627, Rule 5). If we implement a pattern typing
23272310
// ruleset with Rule 4 but not Rule 5, we'll need to check that here.
2328-
} else {
2329-
pat_info.binding_mode = ByRef::No;
2330-
self.typeck_results
2331-
.borrow_mut()
2332-
.skipped_ref_pats_mut()
2333-
.insert(pat.hir_id);
2334-
self.check_pat(inner, expected, pat_info);
2335-
return expected;
2311+
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
23362312
}
2313+
2314+
pat_info.binding_mode = ByRef::No;
2315+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2316+
self.check_pat(inner, expected, pat_info);
2317+
return expected;
23372318
}
23382319
}
23392320
InheritedRefMatchRule::EatBoth => {
@@ -2407,6 +2388,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24072388
Ty::new_ref(self.tcx, region, ty, mutbl)
24082389
}
24092390

2391+
fn error_inherited_ref_mutability_mismatch(
2392+
&self,
2393+
pat: &'tcx Pat<'tcx>,
2394+
pat_prefix_span: Option<Span>,
2395+
) -> ErrorGuaranteed {
2396+
let err_msg = "mismatched types";
2397+
let err = if let Some(span) = pat_prefix_span {
2398+
let mut err = self.dcx().struct_span_err(span, err_msg);
2399+
err.code(E0308);
2400+
err.note("cannot match inherited `&` with `&mut` pattern");
2401+
err.span_suggestion_verbose(
2402+
span,
2403+
"replace this `&mut` pattern with `&`",
2404+
"&",
2405+
Applicability::MachineApplicable,
2406+
);
2407+
err
2408+
} else {
2409+
self.dcx().struct_span_err(pat.span, err_msg)
2410+
};
2411+
err.emit()
2412+
}
2413+
24102414
fn try_resolve_slice_ty_to_array_ty(
24112415
&self,
24122416
before: &'tcx [Pat<'tcx>],

tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ LL | if let Some(&Some(x)) = &Some(Some(0)) {
8383
| ~
8484

8585
error[E0308]: mismatched types
86-
--> $DIR/pattern-errors.rs:125:10
86+
--> $DIR/pattern-errors.rs:123:10
8787
|
8888
LL | let [&mut x] = &[&mut 0];
8989
| ^^^^^
@@ -95,7 +95,7 @@ LL | let [&x] = &[&mut 0];
9595
| ~
9696

9797
error[E0308]: mismatched types
98-
--> $DIR/pattern-errors.rs:130:10
98+
--> $DIR/pattern-errors.rs:128:10
9999
|
100100
LL | let [&mut &x] = &[&mut 0];
101101
| ^^^^^
@@ -107,7 +107,7 @@ LL | let [&&x] = &[&mut 0];
107107
| ~
108108

109109
error[E0308]: mismatched types
110-
--> $DIR/pattern-errors.rs:135:10
110+
--> $DIR/pattern-errors.rs:133:10
111111
|
112112
LL | let [&mut &ref x] = &[&mut 0];
113113
| ^^^^^
@@ -119,7 +119,7 @@ LL | let [&&ref x] = &[&mut 0];
119119
| ~
120120

121121
error[E0308]: mismatched types
122-
--> $DIR/pattern-errors.rs:140:10
122+
--> $DIR/pattern-errors.rs:138:10
123123
|
124124
LL | let [&mut &(mut x)] = &[&mut 0];
125125
| ^^^^^

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

+14-16
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,36 @@ pub fn main() {
4545
}
4646
}
4747

48-
// TODO: these should be mutability mismatches on `structural`
4948
fn structural_errors_0() {
5049
let &[&mut x] = &&mut [0];
5150
//[structural]~^ ERROR: mismatched types
51+
//[structural]~| cannot match inherited `&` with `&mut` pattern
5252
let _: u32 = x;
53-
//[structural]~^ ERROR: mismatched types
5453

5554
let &[&mut x] = &mut &mut [0];
5655
//[structural]~^ ERROR: mismatched types
56+
//[structural]~| cannot match inherited `&` with `&mut` pattern
5757
let _: u32 = x;
58-
//[structural]~^ ERROR: mismatched types
5958

6059
let &[&mut ref x] = &&mut [0];
6160
//[structural]~^ ERROR: mismatched types
61+
//[structural]~| cannot match inherited `&` with `&mut` pattern
6262
let _: &u32 = x;
6363

6464
let &[&mut ref x] = &mut &mut [0];
6565
//[structural]~^ ERROR: mismatched types
66+
//[structural]~| cannot match inherited `&` with `&mut` pattern
6667
let _: &u32 = x;
6768

6869
let &[&mut mut x] = &&mut [0];
6970
//[structural]~^ ERROR: mismatched types
70-
//[structural]~| ERROR: binding cannot be both mutable and by-reference
71+
//[structural]~| cannot match inherited `&` with `&mut` pattern
7172
let _: u32 = x;
72-
//[structural]~^ ERROR: mismatched types
7373

7474
let &[&mut mut x] = &mut &mut [0];
7575
//[structural]~^ ERROR: mismatched types
76-
//[structural]~| ERROR: binding cannot be both mutable and by-reference
76+
//[structural]~| cannot match inherited `&` with `&mut` pattern
7777
let _: u32 = x;
78-
//[structural]~^ ERROR: mismatched types
7978
}
8079

8180
fn structural_errors_1() {
@@ -88,37 +87,36 @@ fn structural_errors_1() {
8887
let _: &u32 = x;
8988
}
9089

91-
// TODO: these should be mutability mismatches on `structural`
9290
fn structural_errors_2() {
9391
let [&&mut x] = &[&mut 0];
9492
//[structural]~^ ERROR: mismatched types
93+
//[structural]~| cannot match inherited `&` with `&mut` pattern
9594
let _: u32 = x;
96-
//[structural]~^ ERROR: mismatched types
9795

9896
let [&&mut x] = &mut [&mut 0];
9997
//[structural]~^ ERROR: mismatched types
98+
//[structural]~| cannot match inherited `&` with `&mut` pattern
10099
let _: u32 = x;
101-
//[structural]~^ ERROR: mismatched types
102100

103101
let [&&mut ref x] = &[&mut 0];
104102
//[structural]~^ ERROR: mismatched types
103+
//[structural]~| cannot match inherited `&` with `&mut` pattern
105104
let _: &u32 = x;
106105

107106
let [&&mut ref x] = &mut [&mut 0];
108107
//[structural]~^ ERROR: mismatched types
108+
//[structural]~| cannot match inherited `&` with `&mut` pattern
109109
let _: &u32 = x;
110110

111111
let [&&mut mut x] = &[&mut 0];
112-
//[structural]~^ ERROR: binding cannot be both mutable and by-reference
113-
//[structural]~| ERROR: mismatched types
114-
let _: u32 = x;
115112
//[structural]~^ ERROR: mismatched types
113+
//[structural]~| cannot match inherited `&` with `&mut` pattern
114+
let _: u32 = x;
116115

117116
let [&&mut mut x] = &mut [&mut 0];
118-
//[structural]~^ ERROR: binding cannot be both mutable and by-reference
119-
//[structural]~| ERROR: mismatched types
120-
let _: u32 = x;
121117
//[structural]~^ ERROR: mismatched types
118+
//[structural]~| cannot match inherited `&` with `&mut` pattern
119+
let _: u32 = x;
122120
}
123121

124122
fn classic_errors_0() {

0 commit comments

Comments
 (0)