Skip to content

Commit 6c529de

Browse files
lower let-else in MIR instead
1 parent 38b7215 commit 6c529de

File tree

71 files changed

+421
-264
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+421
-264
lines changed

compiler/rustc_ast_lowering/src/block.rs

+20-71
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
2-
use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
2+
use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
33
use rustc_hir as hir;
44
use rustc_session::parse::feature_err;
5-
use rustc_span::{sym, DesugaringKind};
5+
use rustc_span::sym;
66

77
use smallvec::SmallVec;
88

@@ -36,21 +36,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
3636
match s.kind {
3737
StmtKind::Local(ref local) => {
3838
let hir_id = self.lower_node_id(s.id);
39-
match &local.kind {
40-
LocalKind::InitElse(init, els) => {
41-
let e = self.lower_let_else(hir_id, local, init, els, tail);
42-
expr = Some(e);
43-
// remaining statements are in let-else expression
44-
break;
39+
let els = if let LocalKind::InitElse(_, els) = &local.kind {
40+
if !self.tcx.features().let_else {
41+
feature_err(
42+
&self.tcx.sess.parse_sess,
43+
sym::let_else,
44+
s.span,
45+
"`let...else` statements are unstable",
46+
)
47+
.emit();
4548
}
46-
_ => {
47-
let local = self.lower_local(local);
48-
self.alias_attrs(hir_id, local.hir_id);
49-
let kind = hir::StmtKind::Local(local);
50-
let span = self.lower_span(s.span);
51-
stmts.push(hir::Stmt { hir_id, kind, span });
52-
}
53-
}
49+
Some(self.lower_block(els, false))
50+
} else {
51+
None
52+
};
53+
let local = self.lower_local(local);
54+
self.alias_attrs(hir_id, local.hir_id);
55+
let kind = hir::StmtKind::Local(local, els);
56+
let span = self.lower_span(s.span);
57+
stmts.push(hir::Stmt { hir_id, kind, span });
5458
}
5559
StmtKind::Item(ref it) => {
5660
stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
@@ -115,59 +119,4 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
115119
}
116120
}
117121
}
118-
119-
fn lower_let_else(
120-
&mut self,
121-
stmt_hir_id: hir::HirId,
122-
local: &Local,
123-
init: &Expr,
124-
els: &Block,
125-
tail: &[Stmt],
126-
) -> &'hir hir::Expr<'hir> {
127-
let ty = local
128-
.ty
129-
.as_ref()
130-
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
131-
let span = self.lower_span(local.span);
132-
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
133-
let init = self.lower_expr(init);
134-
let local_hir_id = self.lower_node_id(local.id);
135-
self.lower_attrs(local_hir_id, &local.attrs);
136-
let let_expr = {
137-
let lex = self.arena.alloc(hir::Let {
138-
hir_id: local_hir_id,
139-
pat: self.lower_pat(&local.pat),
140-
ty,
141-
init,
142-
span,
143-
});
144-
self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new()))
145-
};
146-
let then_expr = {
147-
let (stmts, expr) = self.lower_stmts(tail);
148-
let block = self.block_all(span, stmts, expr);
149-
self.arena.alloc(self.expr_block(block, AttrVec::new()))
150-
};
151-
let else_expr = {
152-
let block = self.lower_block(els, false);
153-
self.arena.alloc(self.expr_block(block, AttrVec::new()))
154-
};
155-
self.alias_attrs(let_expr.hir_id, local_hir_id);
156-
self.alias_attrs(else_expr.hir_id, local_hir_id);
157-
let if_expr = self.arena.alloc(hir::Expr {
158-
hir_id: stmt_hir_id,
159-
span,
160-
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
161-
});
162-
if !self.tcx.features().let_else {
163-
feature_err(
164-
&self.tcx.sess.parse_sess,
165-
sym::let_else,
166-
local.span,
167-
"`let...else` statements are unstable",
168-
)
169-
.emit();
170-
}
171-
if_expr
172-
}
173122
}

compiler/rustc_ast_lowering/src/index.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
284284
});
285285
}
286286

287-
fn visit_local(&mut self, l: &'hir Local<'hir>) {
287+
fn visit_local(&mut self, l: &'hir Local<'hir>, e: Option<&'hir Block<'hir>>) {
288288
self.insert(l.span, l.hir_id, Node::Local(l));
289289
self.with_parent(l.hir_id, |this| {
290-
intravisit::walk_local(this, l);
290+
intravisit::walk_local(this, l, e);
291291
})
292292
}
293293

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2147,7 +2147,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21472147
self.attrs.insert(hir_id.local_id, a);
21482148
}
21492149
let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
2150-
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
2150+
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local), None))
21512151
}
21522152

21532153
fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {

compiler/rustc_hir/src/hir.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,8 @@ pub struct Stmt<'hir> {
12961296
#[derive(Debug, HashStable_Generic)]
12971297
pub enum StmtKind<'hir> {
12981298
/// A local (`let`) binding.
1299-
Local(&'hir Local<'hir>),
1299+
/// FIXME: bundle the last two components into another `struct`
1300+
Local(&'hir Local<'hir>, Option<&'hir Block<'hir>>),
13001301

13011302
/// An item binding.
13021303
Item(ItemId),

compiler/rustc_hir/src/intravisit.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ pub trait Visitor<'v>: Sized {
310310
fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) {
311311
walk_foreign_item(self, i)
312312
}
313-
fn visit_local(&mut self, l: &'v Local<'v>) {
314-
walk_local(self, l)
313+
fn visit_local(&mut self, l: &'v Local<'v>, els: Option<&'v Block<'v>>) {
314+
walk_local(self, l, els)
315315
}
316316
fn visit_block(&mut self, b: &'v Block<'v>) {
317317
walk_block(self, b)
@@ -466,12 +466,19 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
466466
visitor.visit_expr(&body.value);
467467
}
468468

469-
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
469+
pub fn walk_local<'v, V: Visitor<'v>>(
470+
visitor: &mut V,
471+
local: &'v Local<'v>,
472+
els: Option<&'v Block<'v>>,
473+
) {
470474
// Intentionally visiting the expr first - the initialization expr
471475
// dominates the local's definition.
472476
walk_list!(visitor, visit_expr, &local.init);
473477
visitor.visit_id(local.hir_id);
474478
visitor.visit_pat(&local.pat);
479+
if let Some(els) = els {
480+
visitor.visit_block(els);
481+
}
475482
walk_list!(visitor, visit_ty, &local.ty);
476483
}
477484

@@ -1055,9 +1062,9 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
10551062

10561063
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
10571064
visitor.visit_id(statement.hir_id);
1058-
match statement.kind {
1059-
StmtKind::Local(ref local) => visitor.visit_local(local),
1060-
StmtKind::Item(item) => visitor.visit_nested_item(item),
1065+
match &statement.kind {
1066+
StmtKind::Local(ref local, els) => visitor.visit_local(local, *els),
1067+
StmtKind::Item(item) => visitor.visit_nested_item(*item),
10611068
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
10621069
visitor.visit_expr(expression)
10631070
}

compiler/rustc_hir_pretty/src/lib.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,12 @@ impl<'a> State<'a> {
883883
self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
884884
}
885885

886-
pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) {
886+
pub fn print_local(
887+
&mut self,
888+
init: Option<&hir::Expr<'_>>,
889+
els: Option<&hir::Block<'_>>,
890+
decl: impl Fn(&mut Self),
891+
) {
887892
self.space_if_not_bol();
888893
self.ibox(INDENT_UNIT);
889894
self.word_nbsp("let");
@@ -897,14 +902,21 @@ impl<'a> State<'a> {
897902
self.word_space("=");
898903
self.print_expr(init);
899904
}
905+
906+
if let Some(els) = els {
907+
self.nbsp();
908+
self.word_space("else");
909+
self.print_block(els);
910+
}
911+
900912
self.end()
901913
}
902914

903915
pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
904916
self.maybe_print_comment(st.span.lo());
905917
match st.kind {
906-
hir::StmtKind::Local(loc) => {
907-
self.print_local(loc.init, |this| this.print_local_decl(loc));
918+
hir::StmtKind::Local(loc, els) => {
919+
self.print_local(loc.init, els, |this| this.print_local_decl(loc));
908920
}
909921
hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
910922
hir::StmtKind::Expr(expr) => {
@@ -1404,7 +1416,7 @@ impl<'a> State<'a> {
14041416

14051417
// Print `let _t = $init;`:
14061418
let temp = Ident::from_str("_t");
1407-
self.print_local(Some(init), |this| this.print_ident(temp));
1419+
self.print_local(Some(init), None, |this| this.print_ident(temp));
14081420
self.word(";");
14091421

14101422
// Print `_t`:
@@ -2293,7 +2305,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool {
22932305
/// seen the semicolon, and thus don't need another.
22942306
fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
22952307
match *stmt {
2296-
hir::StmtKind::Local(_) => true,
2308+
hir::StmtKind::Local(_, _) => true,
22972309
hir::StmtKind::Item(_) => false,
22982310
hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e),
22992311
hir::StmtKind::Semi(..) => false,

compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::infer::type_variable::TypeVariableOriginKind;
22
use crate::infer::InferCtxt;
3+
use hir::{Block, LocalSource};
34
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
45
use rustc_hir as hir;
56
use rustc_hir::def::Res;
67
use rustc_hir::def::{CtorOf, DefKind, Namespace};
78
use rustc_hir::def_id::DefId;
89
use rustc_hir::intravisit::{self, Visitor};
9-
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
10+
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local};
1011
use rustc_middle::hir::nested_filter;
1112
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
1213
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@@ -952,8 +953,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
952953
self.infcx.tcx.hir()
953954
}
954955

955-
fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
956-
intravisit::walk_local(self, local);
956+
fn visit_local(&mut self, local: &'tcx Local<'tcx>, els: Option<&'tcx Block<'tcx>>) {
957+
intravisit::walk_local(self, local, els);
957958

958959
if let Some(ty) = self.opt_node_type(local.hir_id) {
959960
if self.generic_arg_contains_target(ty.into()) {

compiler/rustc_lint/src/late.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
251251
}
252252
}
253253

254-
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
254+
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) {
255255
self.with_lint_attrs(l.hir_id, |cx| {
256-
lint_callback!(cx, check_local, l);
257-
hir_visit::walk_local(cx, l);
256+
lint_callback!(cx, check_local, l, e);
257+
hir_visit::walk_local(cx, l, e);
258258
})
259259
}
260260

compiler/rustc_lint/src/levels.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -783,9 +783,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
783783
})
784784
}
785785

786-
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
786+
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) {
787787
self.with_lint_attrs(l.hir_id, |builder| {
788-
intravisit::walk_local(builder, l);
788+
intravisit::walk_local(builder, l, e);
789789
})
790790
}
791791

compiler/rustc_lint/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ macro_rules! late_lint_methods {
2424
fn check_foreign_item_post(a: &$hir hir::ForeignItem<$hir>);
2525
fn check_item(a: &$hir hir::Item<$hir>);
2626
fn check_item_post(a: &$hir hir::Item<$hir>);
27-
fn check_local(a: &$hir hir::Local<$hir>);
27+
fn check_local(a: &$hir hir::Local<$hir>, b: Option<&$hir hir::Block<$hir>>);
2828
fn check_block(a: &$hir hir::Block<$hir>);
2929
fn check_block_post(a: &$hir hir::Block<$hir>);
3030
fn check_stmt(a: &$hir hir::Stmt<$hir>);

compiler/rustc_middle/src/hir/map/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ impl<'hir> Map<'hir> {
789789
| Node::ForeignItem(_)
790790
| Node::TraitItem(_)
791791
| Node::ImplItem(_)
792-
| Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
792+
| Node::Stmt(Stmt { kind: StmtKind::Local(_, _), .. }) => break,
793793
Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
794794
return Some(expr);
795795
}

compiler/rustc_middle/src/thir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ pub enum StmtKind<'tcx> {
182182
/// `let pat: ty = <INIT>`
183183
initializer: Option<ExprId>,
184184

185+
/// `let pat: ty = <INIT> else { <ELSE> }
186+
else_block: Option<Block>,
187+
185188
/// The lint level for this `let` statement.
186189
lint_level: LintLevel,
187190
},

compiler/rustc_middle/src/thir/visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,15 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm
167167
init_scope: _,
168168
ref pattern,
169169
lint_level: _,
170+
else_block,
170171
} => {
171172
if let Some(init) = initializer {
172173
visitor.visit_expr(&visitor.thir()[*init]);
173174
}
174175
visitor.visit_pat(pattern);
176+
if let Some(block) = else_block {
177+
visitor.visit_block(block)
178+
}
175179
}
176180
}
177181
}

compiler/rustc_mir_build/src/build/block.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
9999
ref pattern,
100100
initializer,
101101
lint_level,
102+
else_block,
102103
} => {
103104
let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
104105
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
@@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
124125
|this| {
125126
let scope = (*init_scope, source_info);
126127
this.in_scope(scope, *lint_level, |this| {
127-
this.declare_bindings(
128-
visibility_scope,
129-
remainder_span,
130-
pattern,
131-
ArmHasGuard(false),
132-
Some((None, initializer_span)),
133-
);
134-
this.expr_into_pattern(block, pattern.clone(), init)
128+
if let Some(else_block) = else_block {
129+
this.ast_let_else(
130+
block,
131+
init,
132+
initializer_span,
133+
else_block,
134+
visibility_scope,
135+
remainder_span,
136+
pattern,
137+
)
138+
} else {
139+
this.declare_bindings(
140+
visibility_scope,
141+
remainder_span,
142+
pattern,
143+
ArmHasGuard(false),
144+
Some((None, initializer_span)),
145+
);
146+
this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
147+
}
135148
})
136-
}
149+
},
137150
)
138-
);
151+
)
139152
} else {
140153
let scope = (*init_scope, source_info);
141154
unpack!(this.in_scope(scope, *lint_level, |this| {

0 commit comments

Comments
 (0)