]> git.lizzy.rs Git - rust.git/commitdiff
typeck/pat.rs: extract `peel_off_references` and define `def_bm` algorithm more decla...
authorMazdak Farrokhzad <twingoow@gmail.com>
Fri, 23 Aug 2019 13:51:18 +0000 (15:51 +0200)
committerMazdak Farrokhzad <twingoow@gmail.com>
Sat, 24 Aug 2019 17:14:46 +0000 (19:14 +0200)
src/librustc_typeck/check/pat.rs

index 25eefbaa24c6f76bbc6e192011992fb13072e989..625c57356af38e677fa4405063e5cd548e825bd0 100644 (file)
@@ -48,8 +48,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_pat_walk(
         &self,
         pat: &'tcx hir::Pat,
-        mut expected: Ty<'tcx>,
-        mut def_bm: ty::BindingMode,
+        expected: Ty<'tcx>,
+        def_bm: ty::BindingMode,
         discrim_span: Option<Span>,
     ) {
         let tcx = self.tcx;
@@ -62,53 +62,10 @@ pub fn check_pat_walk(
         };
 
         let is_non_ref_pat = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res));
-        if is_non_ref_pat {
+        let (expected, def_bm) = if is_non_ref_pat {
             debug!("pattern is non reference pattern");
-            let mut exp_ty = self.resolve_type_vars_with_obligations(&expected);
-
-            // Peel off as many `&` or `&mut` from the discriminant as possible. For example,
-            // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
-            // the `Some(5)` which is not of type Ref.
-            //
-            // For each ampersand peeled off, update the binding mode and push the original
-            // type into the adjustments vector.
-            //
-            // See the examples in `ui/match-defbm*.rs`.
-            let mut pat_adjustments = vec![];
-            while let ty::Ref(_, inner_ty, inner_mutability) = exp_ty.sty {
-                debug!("inspecting {:?}", exp_ty);
-
-                debug!("current discriminant is Ref, inserting implicit deref");
-                // Preserve the reference type. We'll need it later during HAIR lowering.
-                pat_adjustments.push(exp_ty);
-
-                exp_ty = inner_ty;
-                def_bm = match def_bm {
-                    // If default binding mode is by value, make it `ref` or `ref mut`
-                    // (depending on whether we observe `&` or `&mut`).
-                    ty::BindByValue(_) =>
-                        ty::BindByReference(inner_mutability),
-
-                    // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
-                    // the underlying value.
-                    ty::BindByReference(hir::Mutability::MutImmutable) =>
-                        ty::BindByReference(hir::Mutability::MutImmutable),
-
-                    // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
-                    // (on `&`).
-                    ty::BindByReference(hir::Mutability::MutMutable) =>
-                        ty::BindByReference(inner_mutability),
-                };
-            }
-            expected = exp_ty;
-
-            if pat_adjustments.len() > 0 {
-                debug!("default binding mode is now {:?}", def_bm);
-                self.inh.tables.borrow_mut()
-                    .pat_adjustments_mut()
-                    .insert(pat.hir_id, pat_adjustments);
-            }
-        } else if let PatKind::Ref(..) = pat.node {
+            self.peel_off_references(pat, expected, def_bm)
+        } else {
             // When you encounter a `&pat` pattern, reset to "by
             // value". This is so that `x` and `y` here are by value,
             // as they appear to be:
@@ -120,12 +77,12 @@ pub fn check_pat_walk(
             // ```
             //
             // See issue #46688.
-            def_bm = ty::BindByValue(hir::MutImmutable);
-        }
-
-        // Lose mutability now that we know binding mode and discriminant type.
-        let def_bm = def_bm;
-        let expected = expected;
+            let def_bm = match pat.node {
+                PatKind::Ref(..) => ty::BindByValue(hir::MutImmutable),
+                _ => def_bm,
+            };
+            (expected, def_bm)
+        };
 
         let ty = match pat.node {
             PatKind::Wild => {
@@ -568,6 +525,62 @@ fn is_non_ref_pat(&self, pat: &'tcx hir::Pat, opt_path_res: Option<Res>) -> bool
         }
     }
 
+    /// Peel off as many immediately nested `& mut?` from the expected type as possible
+    /// and return the new expected type and binding default binding mode.
+    /// The adjustments vector, if non-empty is stored in a table.
+    fn peel_off_references(
+        &self,
+        pat: &'tcx hir::Pat,
+        expected: Ty<'tcx>,
+        mut def_bm: ty::BindingMode,
+    ) -> (Ty<'tcx>, ty::BindingMode) {
+        let mut expected = self.resolve_type_vars_with_obligations(&expected);
+
+        // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
+        // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
+        // the `Some(5)` which is not of type Ref.
+        //
+        // For each ampersand peeled off, update the binding mode and push the original
+        // type into the adjustments vector.
+        //
+        // See the examples in `ui/match-defbm*.rs`.
+        let mut pat_adjustments = vec![];
+        while let ty::Ref(_, inner_ty, inner_mutability) = expected.sty {
+            debug!("inspecting {:?}", expected);
+
+            debug!("current discriminant is Ref, inserting implicit deref");
+            // Preserve the reference type. We'll need it later during HAIR lowering.
+            pat_adjustments.push(expected);
+
+            expected = inner_ty;
+            def_bm = match def_bm {
+                // If default binding mode is by value, make it `ref` or `ref mut`
+                // (depending on whether we observe `&` or `&mut`).
+                ty::BindByValue(_) =>
+                    ty::BindByReference(inner_mutability),
+
+                // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
+                // the underlying value.
+                ty::BindByReference(hir::Mutability::MutImmutable) =>
+                    ty::BindByReference(hir::Mutability::MutImmutable),
+
+                // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
+                // (on `&`).
+                ty::BindByReference(hir::Mutability::MutMutable) =>
+                    ty::BindByReference(inner_mutability),
+            };
+        }
+
+        if pat_adjustments.len() > 0 {
+            debug!("default binding mode is now {:?}", def_bm);
+            self.inh.tables.borrow_mut()
+                .pat_adjustments_mut()
+                .insert(pat.hir_id, pat_adjustments);
+        }
+
+        (expected, def_bm)
+    }
+
     fn borrow_pat_suggestion(
         &self,
         err: &mut DiagnosticBuilder<'_>,