about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs97
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
2 files changed, 83 insertions, 16 deletions
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 4c650ad3dcb..f4584e8bbdf 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -1,6 +1,8 @@
 use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
-use rustc_ast::{Block, BlockCheckMode, Local, Stmt, StmtKind};
+use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
 use rustc_hir as hir;
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, DesugaringKind};
 
 use smallvec::SmallVec;
 
@@ -32,13 +34,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut expr = None;
         while let [s, tail @ ..] = ast_stmts {
             match s.kind {
-                StmtKind::Local(ref l) => {
-                    let l = self.lower_local(l);
+                StmtKind::Local(ref local) => {
                     let hir_id = self.lower_node_id(s.id);
-                    self.alias_attrs(hir_id, l.hir_id);
-                    let kind = hir::StmtKind::Local(self.arena.alloc(l));
-                    let span = self.lower_span(s.span);
-                    stmts.push(hir::Stmt { hir_id, kind, span });
+                    match &local.kind {
+                        LocalKind::InitElse(init, els) => {
+                            let (s, e) = self.lower_let_else(hir_id, local, init, els, tail);
+                            stmts.push(s);
+                            expr = Some(e);
+                            // remaining statements are in let-else expression
+                            break;
+                        }
+                        _ => {
+                            let local = self.lower_local(local);
+                            self.alias_attrs(hir_id, local.hir_id);
+                            let kind = hir::StmtKind::Local(local);
+                            let span = self.lower_span(s.span);
+                            stmts.push(hir::Stmt { hir_id, kind, span });
+                        }
+                    }
                 }
                 StmtKind::Item(ref it) => {
                     stmts.extend(self.lower_item_id(it).into_iter().enumerate().map(
@@ -81,22 +94,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         (self.arena.alloc_from_iter(stmts), expr)
     }
 
-    fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> {
+    fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
         let ty = l
             .ty
             .as_ref()
             .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
         let init = l.kind.init().map(|init| self.lower_expr(init));
         let hir_id = self.lower_node_id(l.id);
+        let pat = self.lower_pat(&l.pat);
+        let span = self.lower_span(l.span);
+        let source = hir::LocalSource::Normal;
         self.lower_attrs(hir_id, &l.attrs);
-        hir::Local {
-            hir_id,
-            ty,
-            pat: self.lower_pat(&l.pat),
-            init,
-            span: self.lower_span(l.span),
-            source: hir::LocalSource::Normal,
-        }
+        self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source })
     }
 
     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
@@ -107,4 +116,60 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
     }
+
+    fn lower_let_else(
+        &mut self,
+        stmt_hir_id: hir::HirId,
+        local: &Local,
+        init: &Expr,
+        els: &Block,
+        tail: &[Stmt],
+    ) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) {
+        let ty = local
+            .ty
+            .as_ref()
+            .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
+        let span = self.lower_span(local.span);
+        let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
+        let init = Some(self.lower_expr(init));
+        let val = Ident::with_dummy_span(sym::val);
+        let (pat, val_id) =
+            self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated);
+        let local_hir_id = self.lower_node_id(local.id);
+        self.lower_attrs(local_hir_id, &local.attrs);
+        // first statement which basically exists for the type annotation
+        let stmt = {
+            let local = self.arena.alloc(hir::Local {
+                hir_id: local_hir_id,
+                ty,
+                pat,
+                init,
+                span,
+                source: hir::LocalSource::Normal,
+            });
+            let kind = hir::StmtKind::Local(local);
+            hir::Stmt { hir_id: stmt_hir_id, kind, span }
+        };
+        let let_expr = {
+            let scrutinee = self.expr_ident(span, val, val_id);
+            let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span);
+            self.arena.alloc(self.expr(span, let_kind, AttrVec::new()))
+        };
+        let then_expr = {
+            let (stmts, expr) = self.lower_stmts(tail);
+            let block = self.block_all(span, stmts, expr);
+            self.arena.alloc(self.expr_block(block, AttrVec::new()))
+        };
+        let else_expr = {
+            let block = self.lower_block(els, false);
+            self.arena.alloc(self.expr_block(block, AttrVec::new()))
+        };
+        self.alias_attrs(else_expr.hir_id, local_hir_id);
+        let if_expr = self.arena.alloc(hir::Expr {
+            hir_id: self.next_id(),
+            span,
+            kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
+        });
+        (stmt, if_expr)
+    }
 }
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index e44a2e96598..c22093c5a42 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1097,6 +1097,7 @@ pub enum DesugaringKind {
     Async,
     Await,
     ForLoop(ForLoopLoc),
+    LetElse,
 }
 
 /// A location in the desugaring of a `for` loop
@@ -1117,6 +1118,7 @@ impl DesugaringKind {
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop(_) => "`for` loop",
+            DesugaringKind::LetElse => "`let...else`",
         }
     }
 }