@@ -80,6 +80,7 @@ struct TopInfo<'tcx> {
80
80
#[derive(Copy, Clone)]
81
81
struct PatInfo<'tcx, 'a> {
82
82
binding_mode: BindingAnnotation,
83
+ max_ref_mutbl: Mutability,
83
84
top_info: TopInfo<'tcx>,
84
85
decl_origin: Option<DeclOrigin<'a>>,
85
86
@@ -161,8 +162,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161
162
decl_origin: Option<DeclOrigin<'tcx>>,
162
163
) {
163
164
let info = TopInfo { expected, origin_expr, span };
164
- let pat_info =
165
- PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin, current_depth: 0 };
165
+ let pat_info = PatInfo {
166
+ binding_mode: INITIAL_BM,
167
+ max_ref_mutbl: Mutability::Mut,
168
+ top_info: info,
169
+ decl_origin,
170
+ current_depth: 0,
171
+ };
166
172
self.check_pat(pat, expected, pat_info);
167
173
}
168
174
@@ -173,7 +179,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
173
179
/// Conversely, inside this module, `check_pat_top` should never be used.
174
180
#[instrument(level = "debug", skip(self, pat_info))]
175
181
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
176
- let PatInfo { binding_mode: def_bm, top_info: ti, current_depth, .. } = pat_info;
182
+ let PatInfo { binding_mode: def_bm, max_ref_mutbl, top_info: ti, current_depth, .. } =
183
+ pat_info;
177
184
178
185
let path_res = match &pat.kind {
179
186
PatKind::Path(qpath) => Some(
@@ -182,10 +189,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182
189
_ => None,
183
190
};
184
191
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
185
- let (expected, def_bm, ref_pattern_already_consumed) =
186
- self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
192
+ let (expected, def_bm, max_ref_mutbl, ref_pattern_already_consumed) =
193
+ self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl );
187
194
let pat_info = PatInfo {
188
195
binding_mode: def_bm,
196
+ max_ref_mutbl,
189
197
top_info: ti,
190
198
decl_origin: pat_info.decl_origin,
191
199
current_depth: current_depth + 1,
@@ -290,16 +298,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290
298
expected: Ty<'tcx>,
291
299
def_bm: BindingAnnotation,
292
300
adjust_mode: AdjustMode,
293
- ) -> (Ty<'tcx>, BindingAnnotation, bool) {
301
+ max_ref_mutbl: Mutability,
302
+ ) -> (Ty<'tcx>, BindingAnnotation, Mutability, bool) {
303
+ if let ByRef::Yes(mutbl) = def_bm.0 {
304
+ debug_assert!(mutbl <= max_ref_mutbl);
305
+ }
294
306
match adjust_mode {
295
- AdjustMode::Pass => (expected, def_bm, false),
296
- AdjustMode::Reset => (expected, INITIAL_BM, false),
297
- AdjustMode::ResetAndConsumeRef(mutbl) => {
298
- (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl))
307
+ AdjustMode::Pass => (expected, def_bm, max_ref_mutbl, false),
308
+ AdjustMode::Reset => (expected, INITIAL_BM, Mutability::Mut, false),
309
+ AdjustMode::ResetAndConsumeRef(ref_pat_mutbl) => {
310
+ let mutbls_match = def_bm.0 == ByRef::Yes(ref_pat_mutbl);
311
+ if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
312
+ if mutbls_match {
313
+ debug!("consuming inherited reference");
314
+ (expected, INITIAL_BM, cmp::min(max_ref_mutbl, ref_pat_mutbl), true)
315
+ } else {
316
+ let (new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability::Mut {
317
+ self.peel_off_references(
318
+ pat,
319
+ expected,
320
+ def_bm,
321
+ Mutability::Not,
322
+ max_ref_mutbl,
323
+ )
324
+ } else {
325
+ (expected, def_bm.cap_ref_mutability(Mutability::Not), Mutability::Not)
326
+ };
327
+ (new_ty, new_bm, max_ref_mutbl, false)
328
+ }
329
+ } else {
330
+ (expected, INITIAL_BM, max_ref_mutbl, mutbls_match)
331
+ }
299
332
}
300
333
AdjustMode::Peel => {
301
- let peeled = self.peel_off_references(pat, expected, def_bm);
302
- (peeled.0, peeled.1, false)
334
+ let peeled =
335
+ self.peel_off_references(pat, expected, def_bm, Mutability::Mut, max_ref_mutbl);
336
+ (peeled.0, peeled.1, peeled.2, false)
303
337
}
304
338
}
305
339
}
@@ -380,7 +414,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
380
414
pat: &'tcx Pat<'tcx>,
381
415
expected: Ty<'tcx>,
382
416
mut def_bm: BindingAnnotation,
383
- ) -> (Ty<'tcx>, BindingAnnotation) {
417
+ max_peelable_mutability: Mutability,
418
+ mut max_ref_mutability: Mutability,
419
+ ) -> (Ty<'tcx>, BindingAnnotation, Mutability) {
384
420
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
385
421
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
386
422
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
@@ -391,7 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391
427
//
392
428
// See the examples in `ui/match-defbm*.rs`.
393
429
let mut pat_adjustments = vec![];
394
- while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
430
+ while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
431
+ && inner_mutability <= max_peelable_mutability
432
+ {
395
433
debug!("inspecting {:?}", expected);
396
434
397
435
debug!("current discriminant is Ref, inserting implicit deref");
@@ -411,6 +449,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
411
449
});
412
450
}
413
451
452
+ if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
453
+ def_bm = def_bm.cap_ref_mutability(max_ref_mutability);
454
+ if def_bm.0 == ByRef::Yes(Mutability::Not) {
455
+ max_ref_mutability = Mutability::Not;
456
+ }
457
+ }
458
+
414
459
if !pat_adjustments.is_empty() {
415
460
debug!("default binding mode is now {:?}", def_bm);
416
461
self.typeck_results
@@ -419,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
419
464
.insert(pat.hir_id, pat_adjustments);
420
465
}
421
466
422
- (expected, def_bm)
467
+ (expected, def_bm, max_ref_mutability )
423
468
}
424
469
425
470
fn check_pat_lit(
@@ -1109,15 +1154,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1109
1154
expected: Ty<'tcx>,
1110
1155
pat_info: PatInfo<'tcx, '_>,
1111
1156
) -> Ty<'tcx> {
1112
- let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth } = pat_info;
1113
1157
let tcx = self.tcx;
1114
1158
let on_error = |e| {
1115
1159
for pat in subpats {
1116
- self.check_pat(
1117
- pat,
1118
- Ty::new_error(tcx, e),
1119
- PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
1120
- );
1160
+ self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
1121
1161
}
1122
1162
};
1123
1163
let report_unexpected_res = |res: Res| {
@@ -1162,7 +1202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1162
1202
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
1163
1203
1164
1204
// Type-check the tuple struct pattern against the expected type.
1165
- let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti );
1205
+ let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info );
1166
1206
let had_err = if let Some(err) = diag {
1167
1207
err.emit();
1168
1208
true
@@ -1180,11 +1220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1180
1220
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
1181
1221
let field = &variant.fields[FieldIdx::from_usize(i)];
1182
1222
let field_ty = self.field_ty(subpat.span, field, args);
1183
- self.check_pat(
1184
- subpat,
1185
- field_ty,
1186
- PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
1187
- );
1223
+ self.check_pat(subpat, field_ty, pat_info);
1188
1224
1189
1225
self.tcx.check_stability(
1190
1226
variant.fields[FieldIdx::from_usize(i)].did,
@@ -2071,61 +2107,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2071
2107
pat_info: PatInfo<'tcx, '_>,
2072
2108
consumed_inherited_ref: bool,
2073
2109
) -> Ty<'tcx> {
2074
- let tcx = self.tcx;
2075
- let expected = self.shallow_resolve(expected);
2076
- let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2077
- Ok(()) => {
2078
- // `demand::subtype` would be good enough, but using `eqtype` turns
2079
- // out to be equally general. See (note_1) for details.
2080
-
2081
- // Take region, inner-type from expected type if we can,
2082
- // to avoid creating needless variables. This also helps with
2083
- // the bad interactions of the given hack detailed in (note_1).
2084
- debug!("check_pat_ref: expected={:?}", expected);
2085
- match *expected.kind() {
2086
- ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
2087
- _ => {
2088
- if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
2089
- // We already matched against a match-ergonmics inserted reference,
2090
- // so we don't need to match against a reference from the original type.
2091
- // Save this infor for use in lowering later
2092
- self.typeck_results
2093
- .borrow_mut()
2094
- .skipped_ref_pats_mut()
2095
- .insert(pat.hir_id);
2096
- (expected, expected)
2097
- } else {
2098
- let inner_ty = self.next_ty_var(TypeVariableOrigin {
2099
- param_def_id: None,
2100
- span: inner.span,
2101
- });
2102
- let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
2103
- debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2104
- let err = self.demand_eqtype_pat_diag(
2105
- pat.span,
2106
- expected,
2107
- ref_ty,
2108
- pat_info.top_info,
2109
- );
2110
+ if consumed_inherited_ref
2111
+ && pat.span.at_least_rust_2024()
2112
+ && self.tcx.features().ref_pat_eat_one_layer_2024
2113
+ {
2114
+ self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2115
+ self.check_pat(inner, expected, pat_info);
2116
+ expected
2117
+ } else {
2118
+ let tcx = self.tcx;
2119
+ let expected = self.shallow_resolve(expected);
2120
+ let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
2121
+ Ok(()) => {
2122
+ // `demand::subtype` would be good enough, but using `eqtype` turns
2123
+ // out to be equally general. See (note_1) for details.
2124
+
2125
+ // Take region, inner-type from expected type if we can,
2126
+ // to avoid creating needless variables. This also helps with
2127
+ // the bad interactions of the given hack detailed in (note_1).
2128
+ debug!("check_pat_ref: expected={:?}", expected);
2129
+ match *expected.kind() {
2130
+ ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
2131
+ _ => {
2132
+ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
2133
+ // We already matched against a match-ergonmics inserted reference,
2134
+ // so we don't need to match against a reference from the original type.
2135
+ // Save this infor for use in lowering later
2136
+ self.typeck_results
2137
+ .borrow_mut()
2138
+ .skipped_ref_pats_mut()
2139
+ .insert(pat.hir_id);
2140
+ (expected, expected)
2141
+ } else {
2142
+ let inner_ty = self.next_ty_var(TypeVariableOrigin {
2143
+ param_def_id: None,
2144
+ span: inner.span,
2145
+ });
2146
+ let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
2147
+ debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2148
+ let err = self.demand_eqtype_pat_diag(
2149
+ pat.span,
2150
+ expected,
2151
+ ref_ty,
2152
+ pat_info.top_info,
2153
+ );
2110
2154
2111
- // Look for a case like `fn foo(&foo: u32)` and suggest
2112
- // `fn foo(foo: &u32)`
2113
- if let Some(mut err) = err {
2114
- self.borrow_pat_suggestion(&mut err, pat);
2115
- err.emit();
2155
+ // Look for a case like `fn foo(&foo: u32)` and suggest
2156
+ // `fn foo(foo: &u32)`
2157
+ if let Some(mut err) = err {
2158
+ self.borrow_pat_suggestion(&mut err, pat);
2159
+ err.emit();
2160
+ }
2161
+ (ref_ty, inner_ty)
2116
2162
}
2117
- (ref_ty, inner_ty)
2118
2163
}
2119
2164
}
2120
2165
}
2121
- }
2122
- Err(guar) => {
2123
- let err = Ty::new_error(tcx, guar);
2124
- (err, err)
2125
- }
2126
- } ;
2127
- self.check_pat(inner, inner_ty, pat_info);
2128
- ref_ty
2166
+ Err(guar) => {
2167
+ let err = Ty::new_error(tcx, guar);
2168
+ (err, err)
2169
+ }
2170
+ };
2171
+ self.check_pat(inner, inner_ty, pat_info) ;
2172
+ ref_ty
2173
+ }
2129
2174
}
2130
2175
2131
2176
/// Create a reference type with a fresh region variable.
0 commit comments