Skip to content

Commit 8b4114b

Browse files
committed
typeck/pat.rs: extract peel_off_references and define def_bm algorithm more declaratively.
1 parent d1580ee commit 8b4114b

File tree

1 file changed

+67
-54
lines changed
  • src/librustc_typeck/check

1 file changed

+67
-54
lines changed

src/librustc_typeck/check/pat.rs

Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4848
pub fn check_pat_walk(
4949
&self,
5050
pat: &'tcx hir::Pat,
51-
mut expected: Ty<'tcx>,
52-
mut def_bm: ty::BindingMode,
51+
expected: Ty<'tcx>,
52+
def_bm: ty::BindingMode,
5353
discrim_span: Option<Span>,
5454
) {
5555
let tcx = self.tcx;
@@ -62,53 +62,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6262
};
6363

6464
let is_non_ref_pat = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res));
65-
if is_non_ref_pat {
65+
let (expected, def_bm) = if is_non_ref_pat {
6666
debug!("pattern is non reference pattern");
67-
let mut exp_ty = self.resolve_type_vars_with_obligations(&expected);
68-
69-
// Peel off as many `&` or `&mut` from the discriminant as possible. For example,
70-
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
71-
// the `Some(5)` which is not of type Ref.
72-
//
73-
// For each ampersand peeled off, update the binding mode and push the original
74-
// type into the adjustments vector.
75-
//
76-
// See the examples in `ui/match-defbm*.rs`.
77-
let mut pat_adjustments = vec![];
78-
while let ty::Ref(_, inner_ty, inner_mutability) = exp_ty.sty {
79-
debug!("inspecting {:?}", exp_ty);
80-
81-
debug!("current discriminant is Ref, inserting implicit deref");
82-
// Preserve the reference type. We'll need it later during HAIR lowering.
83-
pat_adjustments.push(exp_ty);
84-
85-
exp_ty = inner_ty;
86-
def_bm = match def_bm {
87-
// If default binding mode is by value, make it `ref` or `ref mut`
88-
// (depending on whether we observe `&` or `&mut`).
89-
ty::BindByValue(_) =>
90-
ty::BindByReference(inner_mutability),
91-
92-
// Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
93-
// the underlying value.
94-
ty::BindByReference(hir::Mutability::MutImmutable) =>
95-
ty::BindByReference(hir::Mutability::MutImmutable),
96-
97-
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
98-
// (on `&`).
99-
ty::BindByReference(hir::Mutability::MutMutable) =>
100-
ty::BindByReference(inner_mutability),
101-
};
102-
}
103-
expected = exp_ty;
104-
105-
if pat_adjustments.len() > 0 {
106-
debug!("default binding mode is now {:?}", def_bm);
107-
self.inh.tables.borrow_mut()
108-
.pat_adjustments_mut()
109-
.insert(pat.hir_id, pat_adjustments);
110-
}
111-
} else if let PatKind::Ref(..) = pat.node {
67+
self.peel_off_references(pat, expected, def_bm)
68+
} else {
11269
// When you encounter a `&pat` pattern, reset to "by
11370
// value". This is so that `x` and `y` here are by value,
11471
// as they appear to be:
@@ -120,12 +77,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12077
// ```
12178
//
12279
// See issue #46688.
123-
def_bm = ty::BindByValue(hir::MutImmutable);
124-
}
125-
126-
// Lose mutability now that we know binding mode and discriminant type.
127-
let def_bm = def_bm;
128-
let expected = expected;
80+
let def_bm = match pat.node {
81+
PatKind::Ref(..) => ty::BindByValue(hir::MutImmutable),
82+
_ => def_bm,
83+
};
84+
(expected, def_bm)
85+
};
12986

13087
let ty = match pat.node {
13188
PatKind::Wild => {
@@ -568,6 +525,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
568525
}
569526
}
570527

528+
/// Peel off as many immediately nested `& mut?` from the expected type as possible
529+
/// and return the new expected type and binding default binding mode.
530+
/// The adjustments vector, if non-empty is stored in a table.
531+
fn peel_off_references(
532+
&self,
533+
pat: &'tcx hir::Pat,
534+
expected: Ty<'tcx>,
535+
mut def_bm: ty::BindingMode,
536+
) -> (Ty<'tcx>, ty::BindingMode) {
537+
let mut expected = self.resolve_type_vars_with_obligations(&expected);
538+
539+
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
540+
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
541+
// the `Some(5)` which is not of type Ref.
542+
//
543+
// For each ampersand peeled off, update the binding mode and push the original
544+
// type into the adjustments vector.
545+
//
546+
// See the examples in `ui/match-defbm*.rs`.
547+
let mut pat_adjustments = vec![];
548+
while let ty::Ref(_, inner_ty, inner_mutability) = expected.sty {
549+
debug!("inspecting {:?}", expected);
550+
551+
debug!("current discriminant is Ref, inserting implicit deref");
552+
// Preserve the reference type. We'll need it later during HAIR lowering.
553+
pat_adjustments.push(expected);
554+
555+
expected = inner_ty;
556+
def_bm = match def_bm {
557+
// If default binding mode is by value, make it `ref` or `ref mut`
558+
// (depending on whether we observe `&` or `&mut`).
559+
ty::BindByValue(_) =>
560+
ty::BindByReference(inner_mutability),
561+
562+
// Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
563+
// the underlying value.
564+
ty::BindByReference(hir::Mutability::MutImmutable) =>
565+
ty::BindByReference(hir::Mutability::MutImmutable),
566+
567+
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
568+
// (on `&`).
569+
ty::BindByReference(hir::Mutability::MutMutable) =>
570+
ty::BindByReference(inner_mutability),
571+
};
572+
}
573+
574+
if pat_adjustments.len() > 0 {
575+
debug!("default binding mode is now {:?}", def_bm);
576+
self.inh.tables.borrow_mut()
577+
.pat_adjustments_mut()
578+
.insert(pat.hir_id, pat_adjustments);
579+
}
580+
581+
(expected, def_bm)
582+
}
583+
571584
fn borrow_pat_suggestion(
572585
&self,
573586
err: &mut DiagnosticBuilder<'_>,

0 commit comments

Comments
 (0)