Skip to content

Commit 19950b5

Browse files
committed
Turn the peeling loop into a recursive call
1 parent 9f57903 commit 19950b5

File tree

1 file changed

+46
-34
lines changed
  • compiler/rustc_hir_typeck/src

1 file changed

+46
-34
lines changed

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
318318
/// Conversely, inside this module, `check_pat_top` should never be used.
319319
#[instrument(level = "debug", skip(self, pat_info))]
320320
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
321+
let opt_path_res = match pat.kind {
322+
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
323+
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
324+
}
325+
_ => None,
326+
};
327+
let adjust_mode = self.calc_adjust_mode(pat, opt_path_res.map(|(res, ..)| res));
328+
self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
329+
}
330+
331+
// Helper to avoid resolving the same path pattern several times.
332+
fn check_pat_inner(
333+
&self,
334+
pat: &'tcx Pat<'tcx>,
335+
opt_path_res: Option<(Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>])>,
336+
adjust_mode: AdjustMode,
337+
expected: Ty<'tcx>,
338+
pat_info: PatInfo<'tcx>,
339+
) {
321340
let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
322341
#[cfg(debug_assertions)]
323342
if binding_mode == ByRef::Yes(Mutability::Mut)
@@ -327,34 +346,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
327346
span_bug!(pat.span, "Pattern mutability cap violated!");
328347
}
329348

330-
let path_res = match pat.kind {
331-
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
332-
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
333-
}
334-
_ => None,
335-
};
336-
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
337349
let (expected, binding_mode, max_ref_mutbl) = match adjust_mode {
338350
// When we perform destructuring assignment, we disable default match bindings, which
339351
// are unintuitive in this context.
340352
_ if !pat.default_binding_modes => (expected, ByRef::No, MutblCap::Mut),
341353
AdjustMode::Pass => (expected, binding_mode, max_ref_mutbl),
342-
// Peel off as many immediately nested `& mut?` from the expected type as possible
343-
// and return the new expected type and binding default binding mode.
344-
// The adjustments vector, if non-empty is stored in a table.
354+
// Peel an immediately nested `& mut?` from the expected type if possible and return the
355+
// new expected type and binding default binding mode.
345356
AdjustMode::Peel => {
346-
let mut binding_mode = binding_mode;
347-
let mut max_ref_mutbl = max_ref_mutbl;
348-
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
349-
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
350-
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
351-
// the `Some(5)` which is not of type Ref.
352-
//
353-
// For each ampersand peeled off, update the binding mode and push the original
354-
// type into the adjustments vector.
357+
let expected = self.try_structurally_resolve_type(pat.span, expected);
358+
// Peel off a `&` or `&mut` from the scrutinee type. For each ampersand peeled off,
359+
// update the binding mode and push the original type into the adjustments vector.
355360
//
356-
// See the examples in `ui/match-defbm*.rs`.
357-
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
361+
// See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode`.
362+
if let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
358363
debug!("inspecting {:?}", expected);
359364

360365
debug!("current discriminant is Ref, inserting implicit deref");
@@ -366,8 +371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
366371
.or_default()
367372
.push(expected);
368373

369-
expected = self.try_structurally_resolve_type(pat.span, inner_ty);
370-
binding_mode = ByRef::Yes(match binding_mode {
374+
let mut binding_mode = ByRef::Yes(match binding_mode {
371375
// If default binding mode is by value, make it `ref` or `ref mut`
372376
// (depending on whether we observe `&` or `&mut`).
373377
ByRef::No |
@@ -377,18 +381,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
377381
// This is because a `& &mut` cannot mutate the underlying value.
378382
ByRef::Yes(Mutability::Not) => Mutability::Not,
379383
});
380-
}
381384

382-
if self.downgrade_mut_inside_shared() {
383-
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
384-
}
385-
if binding_mode == ByRef::Yes(Mutability::Not) {
386-
max_ref_mutbl = MutblCap::Not;
385+
if self.downgrade_mut_inside_shared() {
386+
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
387+
}
388+
let mut max_ref_mutbl = max_ref_mutbl;
389+
if binding_mode == ByRef::Yes(Mutability::Not) {
390+
max_ref_mutbl = MutblCap::Not;
391+
}
392+
debug!("default binding mode is now {:?}", binding_mode);
393+
let pat_info = PatInfo { binding_mode, max_ref_mutbl, ..pat_info };
394+
return self.check_pat_inner(
395+
pat,
396+
opt_path_res,
397+
adjust_mode,
398+
inner_ty,
399+
pat_info,
400+
);
401+
} else {
402+
(expected, binding_mode, max_ref_mutbl)
387403
}
388-
389-
debug!("default binding mode is now {:?}", binding_mode);
390-
391-
(expected, binding_mode, max_ref_mutbl)
392404
}
393405
};
394406
let pat_info = PatInfo {
@@ -409,7 +421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
409421
pat.hir_id,
410422
*span,
411423
qpath,
412-
path_res.unwrap(),
424+
opt_path_res.unwrap(),
413425
expected,
414426
&pat_info.top_info,
415427
);

0 commit comments

Comments
 (0)