Skip to content

Commit ae32e88

Browse files
committed
Lower let-else to HIR
1 parent 120d46e commit ae32e88

File tree

2 files changed

+83
-16
lines changed

2 files changed

+83
-16
lines changed

compiler/rustc_ast_lowering/src/block.rs

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
2-
use rustc_ast::{Block, BlockCheckMode, Local, Stmt, StmtKind};
2+
use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
33
use rustc_hir as hir;
4+
use rustc_span::symbol::Ident;
5+
use rustc_span::{sym, DesugaringKind};
46

57
use smallvec::SmallVec;
68

@@ -32,13 +34,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
3234
let mut expr = None;
3335
while let [s, tail @ ..] = ast_stmts {
3436
match s.kind {
35-
StmtKind::Local(ref l) => {
36-
let l = self.lower_local(l);
37+
StmtKind::Local(ref local) => {
3738
let hir_id = self.lower_node_id(s.id);
38-
self.alias_attrs(hir_id, l.hir_id);
39-
let kind = hir::StmtKind::Local(self.arena.alloc(l));
40-
let span = self.lower_span(s.span);
41-
stmts.push(hir::Stmt { hir_id, kind, span });
39+
match &local.kind {
40+
LocalKind::InitElse(init, els) => {
41+
let (s, e) = self.lower_let_else(hir_id, local, init, els, tail);
42+
stmts.push(s);
43+
expr = Some(e);
44+
// remaining statements are in let-else expression
45+
break;
46+
}
47+
_ => {
48+
let local = self.lower_local(local);
49+
self.alias_attrs(hir_id, local.hir_id);
50+
let kind = hir::StmtKind::Local(local);
51+
let span = self.lower_span(s.span);
52+
stmts.push(hir::Stmt { hir_id, kind, span });
53+
}
54+
}
4255
}
4356
StmtKind::Item(ref it) => {
4457
stmts.extend(self.lower_item_id(it).into_iter().enumerate().map(
@@ -81,22 +94,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
8194
(self.arena.alloc_from_iter(stmts), expr)
8295
}
8396

84-
fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> {
97+
fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
8598
let ty = l
8699
.ty
87100
.as_ref()
88101
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
89102
let init = l.kind.init().map(|init| self.lower_expr(init));
90103
let hir_id = self.lower_node_id(l.id);
104+
let pat = self.lower_pat(&l.pat);
105+
let span = self.lower_span(l.span);
106+
let source = hir::LocalSource::Normal;
91107
self.lower_attrs(hir_id, &l.attrs);
92-
hir::Local {
93-
hir_id,
94-
ty,
95-
pat: self.lower_pat(&l.pat),
96-
init,
97-
span: self.lower_span(l.span),
98-
source: hir::LocalSource::Normal,
99-
}
108+
self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source })
100109
}
101110

102111
fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
@@ -107,4 +116,60 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
107116
}
108117
}
109118
}
119+
120+
fn lower_let_else(
121+
&mut self,
122+
stmt_hir_id: hir::HirId,
123+
local: &Local,
124+
init: &Expr,
125+
els: &Block,
126+
tail: &[Stmt],
127+
) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) {
128+
let ty = local
129+
.ty
130+
.as_ref()
131+
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
132+
let span = self.lower_span(local.span);
133+
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
134+
let init = Some(self.lower_expr(init));
135+
let val = Ident::with_dummy_span(sym::val);
136+
let (pat, val_id) =
137+
self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated);
138+
let local_hir_id = self.lower_node_id(local.id);
139+
self.lower_attrs(local_hir_id, &local.attrs);
140+
// first statement which basically exists for the type annotation
141+
let stmt = {
142+
let local = self.arena.alloc(hir::Local {
143+
hir_id: local_hir_id,
144+
ty,
145+
pat,
146+
init,
147+
span,
148+
source: hir::LocalSource::Normal,
149+
});
150+
let kind = hir::StmtKind::Local(local);
151+
hir::Stmt { hir_id: stmt_hir_id, kind, span }
152+
};
153+
let let_expr = {
154+
let scrutinee = self.expr_ident(span, val, val_id);
155+
let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span);
156+
self.arena.alloc(self.expr(span, let_kind, AttrVec::new()))
157+
};
158+
let then_expr = {
159+
let (stmts, expr) = self.lower_stmts(tail);
160+
let block = self.block_all(span, stmts, expr);
161+
self.arena.alloc(self.expr_block(block, AttrVec::new()))
162+
};
163+
let else_expr = {
164+
let block = self.lower_block(els, false);
165+
self.arena.alloc(self.expr_block(block, AttrVec::new()))
166+
};
167+
self.alias_attrs(else_expr.hir_id, local_hir_id);
168+
let if_expr = self.arena.alloc(hir::Expr {
169+
hir_id: self.next_id(),
170+
span,
171+
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
172+
});
173+
(stmt, if_expr)
174+
}
110175
}

compiler/rustc_span/src/hygiene.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,7 @@ pub enum DesugaringKind {
10971097
Async,
10981098
Await,
10991099
ForLoop(ForLoopLoc),
1100+
LetElse,
11001101
}
11011102

11021103
/// A location in the desugaring of a `for` loop
@@ -1117,6 +1118,7 @@ impl DesugaringKind {
11171118
DesugaringKind::TryBlock => "`try` block",
11181119
DesugaringKind::OpaqueTy => "`impl Trait`",
11191120
DesugaringKind::ForLoop(_) => "`for` loop",
1121+
DesugaringKind::LetElse => "`let...else`",
11201122
}
11211123
}
11221124
}

0 commit comments

Comments
 (0)