about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-15 12:13:27 +0000
committerbors <bors@rust-lang.org>2017-04-15 12:13:27 +0000
commitc67cf5fddc1d2807e9942c1f9793c3230367332b (patch)
tree47e19bda06f63dda3841c82d74f60cfa9ae8859f
parent5f13a3b540ab6024665322d716e487c800645f24 (diff)
parent5649b3796fa3f8b32116f13e81b44361169ec686 (diff)
downloadrust-c67cf5fddc1d2807e9942c1f9793c3230367332b.tar.gz
rust-c67cf5fddc1d2807e9942c1f9793c3230367332b.zip
Auto merge of #41316 - suchithjn225:issue-41272, r=eddyb
Do not desugar if-let-else to match arm guards

Fixes #41272
Changed the desugaring code

**Before**
```rust
match <sub_expr> {
     <pat> => <body>,
     [_ if <else_opt_if_cond> => <else_opt_if_body>,]
     _ => [<else_opt> | ()]
}
```

**After**
```rust
match <sub_expr> {
    <pat> => <body>,
     _       => [<else_opt> | ()]
}
```
With this fix, it doesn't cause E0301
-rw-r--r--src/librustc/hir/lowering.rs96
-rw-r--r--src/test/run-pass/issue-41272.rs29
2 files changed, 38 insertions, 87 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index c86aaa7bf67..b7aafa0a9ab 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2041,7 +2041,6 @@ impl<'a> LoweringContext<'a> {
                 //
                 //   match <sub_expr> {
                 //     <pat> => <body>,
-                //     [_ if <else_opt_if_cond> => <else_opt_if_body>,]
                 //     _ => [<else_opt> | ()]
                 //   }
 
@@ -2055,93 +2054,16 @@ impl<'a> LoweringContext<'a> {
                     arms.push(self.arm(hir_vec![pat], body_expr));
                 }
 
-                // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
-                // `_ => [<else_opt> | ()]`
+                // _ => [<else_opt>|()]
                 {
-                    let mut current: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
-                    let mut else_exprs: Vec<Option<&Expr>> = vec![current];
-
-                    // First, we traverse the AST and recursively collect all
-                    // `else` branches into else_exprs, e.g.:
-                    //
-                    // if let Some(_) = x {
-                    //    ...
-                    // } else if ... {  // Expr1
-                    //    ...
-                    // } else if ... {  // Expr2
-                    //    ...
-                    // } else {         // Expr3
-                    //    ...
-                    // }
-                    //
-                    // ... results in else_exprs = [Some(&Expr1),
-                    //                              Some(&Expr2),
-                    //                              Some(&Expr3)]
-                    //
-                    // Because there also the case there is no `else`, these
-                    // entries can also be `None`, as in:
-                    //
-                    // if let Some(_) = x {
-                    //    ...
-                    // } else if ... {  // Expr1
-                    //    ...
-                    // } else if ... {  // Expr2
-                    //    ...
-                    // }
-                    //
-                    // ... results in else_exprs = [Some(&Expr1),
-                    //                              Some(&Expr2),
-                    //                              None]
-                    //
-                    // The last entry in this list is always translated into
-                    // the final "unguard" wildcard arm of the `match`. In the
-                    // case of a `None`, it becomes `_ => ()`.
-                    loop {
-                        if let Some(e) = current {
-                            // There is an else branch at this level
-                            if let ExprKind::If(_, _, ref else_opt) = e.node {
-                                // The else branch is again an if-expr
-                                current = else_opt.as_ref().map(|p| &**p);
-                                else_exprs.push(current);
-                            } else {
-                                // The last item in the list is not an if-expr,
-                                // stop here
-                                break
-                             }
-                        } else {
-                            // We have no more else branch
-                            break
-                         }
-                    }
-
-                    // Now translate the list of nested else-branches into the
-                    // arms of the match statement.
-                    for else_expr in else_exprs {
-                        if let Some(else_expr) = else_expr {
-                            let (guard, body) = if let ExprKind::If(ref cond,
-                                                                    ref then,
-                                                                    _) = else_expr.node {
-                                let then = self.lower_block(then, false);
-                                (Some(cond),
-                                 self.expr_block(then, ThinVec::new()))
-                            } else {
-                                (None,
-                                 self.lower_expr(else_expr))
-                            };
-
-                            arms.push(hir::Arm {
-                                attrs: hir_vec![],
-                                pats: hir_vec![self.pat_wild(e.span)],
-                                guard: guard.map(|e| P(self.lower_expr(e))),
-                                body: P(body),
-                            });
-                        } else {
-                            // There was no else-branch, push a noop
-                            let pat_under = self.pat_wild(e.span);
-                            let unit = self.expr_tuple(e.span, hir_vec![]);
-                            arms.push(self.arm(hir_vec![pat_under], unit));
-                        }
-                    }
+                    let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
+                    let wildcard_pattern = self.pat_wild(e.span);
+                    let body = if let Some(else_expr) = wildcard_arm {
+                        P(self.lower_expr(else_expr))
+                    } else {
+                        self.expr_tuple(e.span, hir_vec![])
+                    };
+                    arms.push(self.arm(hir_vec![wildcard_pattern], body));
                 }
 
                 let contains_else_clause = else_opt.is_some();
diff --git a/src/test/run-pass/issue-41272.rs b/src/test/run-pass/issue-41272.rs
new file mode 100644
index 00000000000..d6a0034690a
--- /dev/null
+++ b/src/test/run-pass/issue-41272.rs
@@ -0,0 +1,29 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo;
+
+impl Foo {
+    fn bar(&mut self) -> bool { true }
+}
+
+fn error(foo: &mut Foo) {
+    if let Some(_) = Some(true) {
+    } else if foo.bar() {}
+}
+
+fn ok(foo: &mut Foo) {
+    if let Some(_) = Some(true) {
+    } else {
+        if foo.bar() {}
+    }
+}
+
+fn main() {}