]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #53815 - F001:if-let-guard, r=petrochenkov
authorbors <bors@rust-lang.org>
Sat, 1 Sep 2018 20:31:29 +0000 (20:31 +0000)
committerbors <bors@rust-lang.org>
Sat, 1 Sep 2018 20:31:29 +0000 (20:31 +0000)
refactor match guard

This is the first step to implement RFC 2294: if-let-guard. Tracking issue: https://github.com/rust-lang/rust/issues/51114

The second step should be introducing another variant `IfLet` in the Guard enum. I separated them into 2 PRs for the convenience of reviewers.

r? @petrochenkov

22 files changed:
src/librustc/cfg/construct.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/ich/impls_hir.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/liveness.rs
src/librustc/middle/region.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/hair/pattern/check_match.rs
src/librustc_passes/rvalue_promotion.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_typeck/check/_match.rs
src/libsyntax/ast.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs

index 98cfa094c169a2c250311df96f35919246c1096b..1b97480920321d6fafad010285a19ff258e95394 100644 (file)
@@ -488,8 +488,9 @@ fn match_(&mut self, id: hir::ItemLocalId, discr: &hir::Expr,
                     // expression to target
                     let guard_start = self.add_dummy_node(&[pat_exit]);
                     // Visit the guard expression
-                    let guard_exit = self.expr(&guard, guard_start);
-
+                    let guard_exit = match guard {
+                        hir::Guard::If(ref e) => self.expr(e, guard_start),
+                    };
                     // #47295: We used to have very special case code
                     // here for when a pair of arms are both formed
                     // solely from constants, and if so, not add these
index d853d3d9a7fb4975601bc311b1c538455d131c4d..8129cc18d46c2e08952b0753b8fcd691a90526b1 100644 (file)
@@ -1102,7 +1102,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
 
 pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
     walk_list!(visitor, visit_pat, &arm.pats);
-    walk_list!(visitor, visit_expr, &arm.guard);
+    if let Some(ref g) = arm.guard {
+        match g {
+            Guard::If(ref e) => visitor.visit_expr(e),
+        }
+    }
     visitor.visit_expr(&arm.body);
     walk_list!(visitor, visit_attribute, &arm.attrs);
 }
index 8584b534ff240b4c5cb18781653f66197b04318c..34b3eb0a8c8bf64d1fd595377f2f028d89dcaf3f 100644 (file)
@@ -1054,7 +1054,10 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
         hir::Arm {
             attrs: self.lower_attrs(&arm.attrs),
             pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
-            guard: arm.guard.as_ref().map(|ref x| P(self.lower_expr(x))),
+            guard: match arm.guard {
+                Some(Guard::If(ref x)) => Some(hir::Guard::If(P(self.lower_expr(x)))),
+                _ => None,
+            },
             body: P(self.lower_expr(&arm.body)),
         }
     }
index 7ac334d84a9bfdd2401f6f5734a044f4d4f7aad0..1b3103578737190b2c32a3886806940a6022af92 100644 (file)
@@ -1204,10 +1204,15 @@ pub fn is_local(&self) -> bool {
 pub struct Arm {
     pub attrs: HirVec<Attribute>,
     pub pats: HirVec<P<Pat>>,
-    pub guard: Option<P<Expr>>,
+    pub guard: Option<Guard>,
     pub body: P<Expr>,
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum Guard {
+    If(P<Expr>),
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Field {
     pub id: NodeId,
index 8b221f3463ed334d27a2cc39fa7e1b714dc10b18..55357095fb7596f10b6281af5f268493dab500bd 100644 (file)
@@ -1949,10 +1949,14 @@ fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
             self.print_pat(&p)?;
         }
         self.s.space()?;
-        if let Some(ref e) = arm.guard {
-            self.word_space("if")?;
-            self.print_expr(&e)?;
-            self.s.space()?;
+        if let Some(ref g) = arm.guard {
+            match g {
+                hir::Guard::If(e) => {
+                    self.word_space("if")?;
+                    self.print_expr(&e)?;
+                    self.s.space()?;
+                }
+            }
         }
         self.word_space("=>")?;
 
index 2ac195dca82c42278dc7b40a31e3de8196a9dbbe..3f1899bc54fb4c2e1e34b1c548cb51fcc3726e6b 100644 (file)
@@ -493,6 +493,10 @@ fn hash_stable<W: StableHasherResult>(&self,
     body
 });
 
+impl_stable_hash_for!(enum hir::Guard {
+    If(expr),
+});
+
 impl_stable_hash_for!(struct hir::Field {
     id -> _,
     ident,
index 90692bcd30103303fa1df4cecade47c976500d7d..356992b22146d67b02d63c409b07787c93b46774 100644 (file)
@@ -792,7 +792,9 @@ fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode
         }
 
         if let Some(ref guard) = arm.guard {
-            self.consume_expr(&guard);
+            match guard {
+                hir::Guard::If(ref e) => self.consume_expr(e),
+            }
         }
 
         self.consume_expr(&arm.body);
index 2697d62cf467aa0d4cf857cc018db30fb5e0c6db..c34a0a654e6a9f7c1964b39b3fa0c4e411391010 100644 (file)
@@ -1030,7 +1030,12 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
                 let body_succ =
                     self.propagate_through_expr(&arm.body, succ);
                 let guard_succ =
-                    self.propagate_through_opt_expr(arm.guard.as_ref().map(|e| &**e), body_succ);
+                    self.propagate_through_opt_expr(
+                        arm.guard.as_ref().map(|g|
+                            match g {
+                                hir::Guard::If(e) => &**e,
+                            }),
+                        body_succ);
                 // only consider the first pattern; any later patterns must have
                 // the same bindings, and we also consider the first pattern to be
                 // the "authoritative" set of ids
index 20ee5f0b04635fbc8dae8d5ca02c75da6f584da6..e281cbf94889394198e3e8e5d982b70b43bfab81 100644 (file)
@@ -885,8 +885,10 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
 fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
     visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
 
-    if let Some(ref expr) = arm.guard {
-        visitor.terminating_scopes.insert(expr.hir_id.local_id);
+    if let Some(ref g) = arm.guard {
+        match g {
+            hir::Guard::If(ref expr) => visitor.terminating_scopes.insert(expr.hir_id.local_id),
+        };
     }
 
     intravisit::walk_arm(visitor, arm);
index b317bb7cff0e3c9a6e0b720f0dd0b2a63e1123f9..d3e67ea7b7d7153c6a5008848918007900a5d86f 100644 (file)
@@ -453,7 +453,7 @@ pub struct Candidate<'pat, 'tcx:'pat> {
     bindings: Vec<Binding<'tcx>>,
 
     // ...and the guard must be evaluated...
-    guard: Option<ExprRef<'tcx>>,
+    guard: Option<Guard<'tcx>>,
 
     // ...and then we branch to arm with this index.
     arm_index: usize,
@@ -998,7 +998,9 @@ fn bind_and_guard_matched_candidate<'pat>(&mut self,
 
             // the block to branch to if the guard fails; if there is no
             // guard, this block is simply unreachable
-            let guard = self.hir.mirror(guard);
+            let guard = match guard {
+                Guard::If(e) => self.hir.mirror(e),
+            };
             let source_info = self.source_info(guard.span);
             let cond = unpack!(block = self.as_local_operand(block, guard));
             if autoref {
index 8be1f52a9cdfc7d39151dc272fea046ddd3865a6..055f238e5db4ea12f2c03d6a079d7ff2fe70b5ea 100644 (file)
@@ -837,7 +837,10 @@ fn to_borrow_kind(&self) -> BorrowKind {
 fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
     Arm {
         patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
-        guard: arm.guard.to_ref(),
+        guard: match arm.guard {
+                Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
+                _ => None,
+            },
         body: arm.body.to_ref(),
         // BUG: fix this
         lint_level: LintLevel::Inherited,
index d6037adb53bb7a8a5161e626846df7491b38cde0..2ddb810f4914817e7640e6bdf92cd1a78750ae67 100644 (file)
@@ -316,11 +316,16 @@ pub struct FruInfo<'tcx> {
 #[derive(Clone, Debug)]
 pub struct Arm<'tcx> {
     pub patterns: Vec<Pattern<'tcx>>,
-    pub guard: Option<ExprRef<'tcx>>,
+    pub guard: Option<Guard<'tcx>>,
     pub body: ExprRef<'tcx>,
     pub lint_level: LintLevel,
 }
 
+#[derive(Clone, Debug)]
+pub enum Guard<'tcx> {
+    If(ExprRef<'tcx>),
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum LogicalOp {
     And,
index 604cc61a17ecb17073f104a7eb8167793291ddc4..3a518bad8ed7c20aff0b9ee4b90ebad1f97725f6 100644 (file)
@@ -208,7 +208,9 @@ fn check_match(
                     }
                     (pattern, &**pat)
                 }).collect(),
-                arm.guard.as_ref().map(|e| &**e)
+                arm.guard.as_ref().map(|g| match g {
+                    hir::Guard::If(ref e) => &**e,
+                })
             )).collect();
 
             // Bail out early if inlining failed.
@@ -575,12 +577,19 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 /// assign.
 ///
 /// FIXME: this should be done by borrowck.
-fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
+fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Guard) {
     let mut checker = MutationChecker {
         cx,
     };
-    ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
-        .walk_expr(guard);
+    match guard {
+        hir::Guard::If(expr) =>
+            ExprUseVisitor::new(&mut checker,
+                                cx.tcx,
+                                cx.param_env,
+                                cx.region_scope_tree,
+                                cx.tables,
+                                None).walk_expr(expr),
+    };
 }
 
 struct MutationChecker<'a, 'tcx: 'a> {
index 4a091a96ce465b9cb6e092710ea034b625a8438e..ea4fba3e1248182af89e6b6b99149195c9045e0e 100644 (file)
@@ -577,7 +577,7 @@ fn check_expr_kind<'a, 'tcx>(
             for index in hirvec_arm.iter() {
                 let _ = v.check_expr(&*index.body);
                 match index.guard {
-                    Some(ref expr) => {
+                    Some(hir::Guard::If(ref expr)) => {
                         let _ = v.check_expr(&expr);
                     },
                     None => {},
index 95d5fba9668d4a6db5f2f4ec7e6078a6fb6d8c47..0f6a97423091796dc83d97866b4a8d238c99f4bc 100644 (file)
@@ -2701,7 +2701,10 @@ fn resolve_arm(&mut self, arm: &Arm) {
         // This has to happen *after* we determine which pat_idents are variants
         self.check_consistent_bindings(&arm.pats);
 
-        walk_list!(self, visit_expr, &arm.guard);
+        match arm.guard {
+            Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
+            _ => {}
+        }
         self.visit_expr(&arm.body);
 
         self.ribs[ValueNS].pop();
index 6f5655b8cec535be80182279598cb27bcad7d9db..58665b808d98898869ad71570ff6878063599ed7 100644 (file)
@@ -1663,7 +1663,10 @@ fn visit_pat(&mut self, p: &'l ast::Pat) {
 
     fn visit_arm(&mut self, arm: &'l ast::Arm) {
         self.process_var_decl_multi(&arm.pats);
-        walk_list!(self, visit_expr, &arm.guard);
+        match arm.guard {
+            Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
+            _ => {}
+        }
         self.visit_expr(&arm.body);
     }
 
index ae68584f2446f617cf0c4440f273059049ead174..6b5abbfa4a6f75ea00f216596694b489605d3b7c 100644 (file)
@@ -663,9 +663,11 @@ pub fn check_match(&self,
         };
 
         for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
-            if let Some(ref e) = arm.guard {
+            if let Some(ref g) = arm.guard {
                 self.diverges.set(pats_diverge);
-                self.check_expr_has_type_or_error(e, tcx.types.bool);
+                match g {
+                    hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool),
+                };
             }
 
             self.diverges.set(pats_diverge);
index bd0e0d277ee54e932518e45178ba664190a8c3cb..72f1791ef7c0f995d285a3502a9cb4d230820fd8 100644 (file)
@@ -857,10 +857,15 @@ pub struct Local {
 pub struct Arm {
     pub attrs: Vec<Attribute>,
     pub pats: Vec<P<Pat>>,
-    pub guard: Option<P<Expr>>,
+    pub guard: Option<Guard>,
     pub body: P<Expr>,
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum Guard {
+    If(P<Expr>),
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Field {
     pub ident: Ident,
index 660056e15e06b61f669c6d3fc16a4c1d5c089166..dff408d233977b559c99dce845735fba927c8956 100644 (file)
@@ -118,6 +118,10 @@ fn fold_arm(&mut self, a: Arm) -> Arm {
         noop_fold_arm(a, self)
     }
 
+    fn fold_guard(&mut self, g: Guard) -> Guard {
+        noop_fold_guard(g, self)
+    }
+
     fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
         noop_fold_pat(p, self)
     }
@@ -354,11 +358,17 @@ pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm,
     Arm {
         attrs: fold_attrs(attrs, fld),
         pats: pats.move_map(|x| fld.fold_pat(x)),
-        guard: guard.map(|x| fld.fold_expr(x)),
+        guard: guard.map(|x| fld.fold_guard(x)),
         body: fld.fold_expr(body),
     }
 }
 
+pub fn noop_fold_guard<T: Folder>(g: Guard, fld: &mut T) -> Guard {
+    match g {
+        Guard::If(e) => Guard::If(fld.fold_expr(e)),
+    }
+}
+
 pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
     TypeBinding {
         id: fld.new_id(b.id),
index 6c50b9c82f2b8ea138c8ab7231a797c0f43e7d7c..c741bde7c5f24f7d1b4dee695d908ad3f028c4b4 100644 (file)
@@ -12,7 +12,7 @@
 use ast::{AngleBracketedArgs, ParenthesisedArgs, AttrStyle, BareFnTy};
 use ast::{GenericBound, TraitBoundModifier};
 use ast::Unsafety;
-use ast::{Mod, AnonConst, Arg, Arm, Attribute, BindingMode, TraitItemKind};
+use ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
 use ast::Block;
 use ast::{BlockCheckMode, CaptureBy, Movability};
 use ast::{Constness, Crate};
@@ -3533,7 +3533,7 @@ fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<E
         self.eat(&token::BinOp(token::Or));
         let pats = self.parse_pats()?;
         let guard = if self.eat_keyword(keywords::If) {
-            Some(self.parse_expr()?)
+            Some(Guard::If(self.parse_expr()?))
         } else {
             None
         };
index e78e1afe3a4025543dff3f2e856abd82d3edcfae..85d29a5be89db03b1e8303e55d3f9907f41a503f 100644 (file)
@@ -2702,10 +2702,14 @@ fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
         self.print_outer_attributes(&arm.attrs)?;
         self.print_pats(&arm.pats)?;
         self.s.space()?;
-        if let Some(ref e) = arm.guard {
-            self.word_space("if")?;
-            self.print_expr(e)?;
-            self.s.space()?;
+        if let Some(ref g) = arm.guard {
+            match g {
+                ast::Guard::If(ref e) => {
+                    self.word_space("if")?;
+                    self.print_expr(e)?;
+                    self.s.space()?;
+                }
+            }
         }
         self.word_space("=>")?;
 
index e57d692faae53de63a428a61c17342beb98459d9..77311bf53fd1e84e5c0b1e5f9fc190993e0ed133 100644 (file)
@@ -819,7 +819,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
 
 pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
     walk_list!(visitor, visit_pat, &arm.pats);
-    walk_list!(visitor, visit_expr, &arm.guard);
+    if let Some(ref g) = &arm.guard {
+        match g {
+            Guard::If(ref e) => visitor.visit_expr(e),
+        }
+    }
     visitor.visit_expr(&arm.body);
     walk_list!(visitor, visit_attribute, &arm.attrs);
 }