about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2021-04-25 23:15:12 +0200
committerGitHub <noreply@github.com>2021-04-25 23:15:12 +0200
commita0dcbdf7fd826bac839fc7c8097f807812cc02a0 (patch)
tree1187ea3811adf2f61839db58b5247af3e886502c
parent379a55c64ef72df1c8272ac33ba730244d1395d4 (diff)
parentfc97ce6daed320027a47c1a0ddb86c9242ebde0c (diff)
downloadrust-a0dcbdf7fd826bac839fc7c8097f807812cc02a0.tar.gz
rust-a0dcbdf7fd826bac839fc7c8097f807812cc02a0.zip
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.
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs24
-rw-r--r--src/test/ui/match/issue-82392.rs9
-rw-r--r--src/test/ui/match/issue-82392.stdout20
-rw-r--r--src/test/ui/match/issue-84434.rs18
4 files changed, 69 insertions, 2 deletions
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 5820e7a2612..77d083fc5e9 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -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");
diff --git a/src/test/ui/match/issue-82392.rs b/src/test/ui/match/issue-82392.rs
new file mode 100644
index 00000000000..d26d883040b
--- /dev/null
+++ b/src/test/ui/match/issue-82392.rs
@@ -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) {
+    }
+}
diff --git a/src/test/ui/match/issue-82392.stdout b/src/test/ui/match/issue-82392.stdout
new file mode 100644
index 00000000000..8ff76c64fc7
--- /dev/null
+++ b/src/test/ui/match/issue-82392.stdout
@@ -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 ())
diff --git a/src/test/ui/match/issue-84434.rs b/src/test/ui/match/issue-84434.rs
new file mode 100644
index 00000000000..423481fd5f0
--- /dev/null
+++ b/src/test/ui/match/issue-84434.rs
@@ -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() {}