diff options
| author | bors <bors@rust-lang.org> | 2017-04-15 12:13:27 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-04-15 12:13:27 +0000 |
| commit | c67cf5fddc1d2807e9942c1f9793c3230367332b (patch) | |
| tree | 47e19bda06f63dda3841c82d74f60cfa9ae8859f | |
| parent | 5f13a3b540ab6024665322d716e487c800645f24 (diff) | |
| parent | 5649b3796fa3f8b32116f13e81b44361169ec686 (diff) | |
| download | rust-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.rs | 96 | ||||
| -rw-r--r-- | src/test/run-pass/issue-41272.rs | 29 |
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() {} |
