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
This commit is contained in:
commit
c67cf5fddc
@ -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();
|
||||
|
29
src/test/run-pass/issue-41272.rs
Normal file
29
src/test/run-pass/issue-41272.rs
Normal file
@ -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() {}
|
Loading…
x
Reference in New Issue
Block a user