Rollup merge of #84486 - Smittyvb:else-if-let-hir-pretty-print, r=petrochenkov

Handle pretty printing of `else if let` clauses without ICEing

When pretty printing the HIR of `if ... {} else if let ... {}` clauses, this displays it the `else if let` part as `match` it gets desugared to, the same way normal `if let` statements are currently displayed, instead of ICEing.

```rust
pub fn main() {
    if true {
        // 1
    } else if let a = 1 {
        // 2
    } else {
        // 3
    }
}
```

now gets desugared (via `rustc -Zunpretty=hir,typed src/x.rs`) to:

```rust
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
pub fn main() ({
                   (if (true as bool)
                       ({
                            // 1
                        } as
                           ()) else {match (1 as i32) {
                                         a => {
                                             // 2
                                         }
                                         _ => {
                                             // 3
                                         }
                                     }} as ())
                    } as ())
```

For comparison, this code gets HIR prettyprinted the same way before and after this change:

```rust
pub fn main() {
    if let a = 1 {
        // 2
    } else {
        // 3
    }
}
```
turns into
```rust
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
pub fn main() ({
                   (match (1 as i32) {
                        a => {
                            // 2
                        }
                        _ => {
                            // 3
                        }
                    } as ())
               } as ())
```

This closes #82329. It closes #84434 as well, due to having the same root cause.
This commit is contained in:
Dylan DPC 2021-04-25 23:15:12 +02:00 committed by GitHub
commit a0dcbdf7fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 2 deletions

View File

@ -1095,8 +1095,8 @@ impl<'a> State<'a> {
fn print_else(&mut self, els: Option<&hir::Expr<'_>>) {
match els {
Some(_else) => {
match _else.kind {
Some(else_) => {
match else_.kind {
// "another else-if"
hir::ExprKind::If(ref i, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1);
@ -1114,6 +1114,26 @@ impl<'a> State<'a> {
self.s.word(" else ");
self.print_block(&b)
}
hir::ExprKind::Match(ref expr, arms, _) => {
// else if let desugared to match
assert!(arms.len() == 2, "if let desugars to match with two arms");
self.s.word(" else ");
self.s.word("{");
self.cbox(INDENT_UNIT);
self.ibox(INDENT_UNIT);
self.word_nbsp("match");
self.print_expr_as_cond(&expr);
self.s.space();
self.bopen();
for arm in arms {
self.print_arm(arm);
}
self.bclose(expr.span);
self.s.word("}");
}
// BLEAH, constraints would be great here
_ => {
panic!("print_if saw if with weird alternative");

View File

@ -0,0 +1,9 @@
// https://github.com/rust-lang/rust/issues/82329
// compile-flags: -Zunpretty=hir,typed
// check-pass
pub fn main() {
if true {
} else if let Some(a) = Some(3) {
}
}

View File

@ -0,0 +1,20 @@
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
// https://github.com/rust-lang/rust/issues/82329
// compile-flags: -Zunpretty=hir,typed
// check-pass
pub fn main() ({
(if (true as bool)
({ } as
()) else {match ((Some as
fn(i32) -> Option<i32> {Option::<i32>::Some})((3
as
i32))
as Option<i32>) {
Some(a) => { }
_ => { }
}} as ())
} as ())

View File

@ -0,0 +1,18 @@
// https://github.com/rust-lang/rust/issues/84434
// check-pass
use std::path::Path;
struct A {
pub func: fn(check: bool, a: &Path, b: Option<&Path>),
}
const MY_A: A = A {
func: |check, a, b| {
if check {
let _ = ();
} else if let Some(parent) = b.and_then(|p| p.parent()) {
let _ = ();
}
},
};
fn main() {}