Skip to content

Commit

Permalink
lower let-else in MIR instead
Browse files Browse the repository at this point in the history
  • Loading branch information
dingxiangfei2009 committed Jul 11, 2022
1 parent 38b7215 commit 6c529de
Show file tree
Hide file tree
Showing 71 changed files with 421 additions and 264 deletions.
91 changes: 20 additions & 71 deletions compiler/rustc_ast_lowering/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
use rustc_hir as hir;
use rustc_session::parse::feature_err;
use rustc_span::{sym, DesugaringKind};
use rustc_span::sym;

use smallvec::SmallVec;

Expand Down Expand Up @@ -36,21 +36,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match s.kind {
StmtKind::Local(ref local) => {
let hir_id = self.lower_node_id(s.id);
match &local.kind {
LocalKind::InitElse(init, els) => {
let e = self.lower_let_else(hir_id, local, init, els, tail);
expr = Some(e);
// remaining statements are in let-else expression
break;
let els = if let LocalKind::InitElse(_, els) = &local.kind {
if !self.tcx.features().let_else {
feature_err(
&self.tcx.sess.parse_sess,
sym::let_else,
s.span,
"`let...else` statements are unstable",
)
.emit();
}
_ => {
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 });
}
}
Some(self.lower_block(els, false))
} else {
None
};
let local = self.lower_local(local);
self.alias_attrs(hir_id, local.hir_id);
let kind = hir::StmtKind::Local(local, els);
let span = self.lower_span(s.span);
stmts.push(hir::Stmt { hir_id, kind, span });
}
StmtKind::Item(ref it) => {
stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
Expand Down Expand Up @@ -115,59 +119,4 @@ 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 hir::Expr<'hir> {
let ty = local
.ty
.as_ref()
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
let span = self.lower_span(local.span);
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
let init = self.lower_expr(init);
let local_hir_id = self.lower_node_id(local.id);
self.lower_attrs(local_hir_id, &local.attrs);
let let_expr = {
let lex = self.arena.alloc(hir::Let {
hir_id: local_hir_id,
pat: self.lower_pat(&local.pat),
ty,
init,
span,
});
self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), 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(let_expr.hir_id, local_hir_id);
self.alias_attrs(else_expr.hir_id, local_hir_id);
let if_expr = self.arena.alloc(hir::Expr {
hir_id: stmt_hir_id,
span,
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
});
if !self.tcx.features().let_else {
feature_err(
&self.tcx.sess.parse_sess,
sym::let_else,
local.span,
"`let...else` statements are unstable",
)
.emit();
}
if_expr
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_ast_lowering/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}

fn visit_local(&mut self, l: &'hir Local<'hir>) {
fn visit_local(&mut self, l: &'hir Local<'hir>, e: Option<&'hir Block<'hir>>) {
self.insert(l.span, l.hir_id, Node::Local(l));
self.with_parent(l.hir_id, |this| {
intravisit::walk_local(this, l);
intravisit::walk_local(this, l, e);
})
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2147,7 +2147,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.attrs.insert(hir_id.local_id, a);
}
let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local), None))
}

fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,8 @@ pub struct Stmt<'hir> {
#[derive(Debug, HashStable_Generic)]
pub enum StmtKind<'hir> {
/// A local (`let`) binding.
Local(&'hir Local<'hir>),
/// FIXME: bundle the last two components into another `struct`
Local(&'hir Local<'hir>, Option<&'hir Block<'hir>>),

/// An item binding.
Item(ItemId),
Expand Down
19 changes: 13 additions & 6 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ pub trait Visitor<'v>: Sized {
fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) {
walk_foreign_item(self, i)
}
fn visit_local(&mut self, l: &'v Local<'v>) {
walk_local(self, l)
fn visit_local(&mut self, l: &'v Local<'v>, els: Option<&'v Block<'v>>) {
walk_local(self, l, els)
}
fn visit_block(&mut self, b: &'v Block<'v>) {
walk_block(self, b)
Expand Down Expand Up @@ -466,12 +466,19 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
visitor.visit_expr(&body.value);
}

pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
pub fn walk_local<'v, V: Visitor<'v>>(
visitor: &mut V,
local: &'v Local<'v>,
els: Option<&'v Block<'v>>,
) {
// Intentionally visiting the expr first - the initialization expr
// dominates the local's definition.
walk_list!(visitor, visit_expr, &local.init);
visitor.visit_id(local.hir_id);
visitor.visit_pat(&local.pat);
if let Some(els) = els {
visitor.visit_block(els);
}
walk_list!(visitor, visit_ty, &local.ty);
}

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

pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
visitor.visit_id(statement.hir_id);
match statement.kind {
StmtKind::Local(ref local) => visitor.visit_local(local),
StmtKind::Item(item) => visitor.visit_nested_item(item),
match &statement.kind {
StmtKind::Local(ref local, els) => visitor.visit_local(local, *els),
StmtKind::Item(item) => visitor.visit_nested_item(*item),
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
visitor.visit_expr(expression)
}
Expand Down
22 changes: 17 additions & 5 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,12 @@ impl<'a> State<'a> {
self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
}

pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) {
pub fn print_local(
&mut self,
init: Option<&hir::Expr<'_>>,
els: Option<&hir::Block<'_>>,
decl: impl Fn(&mut Self),
) {
self.space_if_not_bol();
self.ibox(INDENT_UNIT);
self.word_nbsp("let");
Expand All @@ -897,14 +902,21 @@ impl<'a> State<'a> {
self.word_space("=");
self.print_expr(init);
}

if let Some(els) = els {
self.nbsp();
self.word_space("else");
self.print_block(els);
}

self.end()
}

pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
self.maybe_print_comment(st.span.lo());
match st.kind {
hir::StmtKind::Local(loc) => {
self.print_local(loc.init, |this| this.print_local_decl(loc));
hir::StmtKind::Local(loc, els) => {
self.print_local(loc.init, els, |this| this.print_local_decl(loc));
}
hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
hir::StmtKind::Expr(expr) => {
Expand Down Expand Up @@ -1404,7 +1416,7 @@ impl<'a> State<'a> {

// Print `let _t = $init;`:
let temp = Ident::from_str("_t");
self.print_local(Some(init), |this| this.print_ident(temp));
self.print_local(Some(init), None, |this| this.print_ident(temp));
self.word(";");

// Print `_t`:
Expand Down Expand Up @@ -2293,7 +2305,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool {
/// seen the semicolon, and thus don't need another.
fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
match *stmt {
hir::StmtKind::Local(_) => true,
hir::StmtKind::Local(_, _) => true,
hir::StmtKind::Item(_) => false,
hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e),
hir::StmtKind::Semi(..) => false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::infer::type_variable::TypeVariableOriginKind;
use crate::infer::InferCtxt;
use hir::{Block, LocalSource};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local};
use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
Expand Down Expand Up @@ -952,8 +953,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
self.infcx.tcx.hir()
}

fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
intravisit::walk_local(self, local);
fn visit_local(&mut self, local: &'tcx Local<'tcx>, els: Option<&'tcx Block<'tcx>>) {
intravisit::walk_local(self, local, els);

if let Some(ty) = self.opt_node_type(local.hir_id) {
if self.generic_arg_contains_target(ty.into()) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_lint/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
}
}

fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) {
self.with_lint_attrs(l.hir_id, |cx| {
lint_callback!(cx, check_local, l);
hir_visit::walk_local(cx, l);
lint_callback!(cx, check_local, l, e);
hir_visit::walk_local(cx, l, e);
})
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,9 +783,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
})
}

fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) {
self.with_lint_attrs(l.hir_id, |builder| {
intravisit::walk_local(builder, l);
intravisit::walk_local(builder, l, e);
})
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ macro_rules! late_lint_methods {
fn check_foreign_item_post(a: &$hir hir::ForeignItem<$hir>);
fn check_item(a: &$hir hir::Item<$hir>);
fn check_item_post(a: &$hir hir::Item<$hir>);
fn check_local(a: &$hir hir::Local<$hir>);
fn check_local(a: &$hir hir::Local<$hir>, b: Option<&$hir hir::Block<$hir>>);
fn check_block(a: &$hir hir::Block<$hir>);
fn check_block_post(a: &$hir hir::Block<$hir>);
fn check_stmt(a: &$hir hir::Stmt<$hir>);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ impl<'hir> Map<'hir> {
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::ImplItem(_)
| Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
| Node::Stmt(Stmt { kind: StmtKind::Local(_, _), .. }) => break,
Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
return Some(expr);
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ pub enum StmtKind<'tcx> {
/// `let pat: ty = <INIT>`
initializer: Option<ExprId>,

/// `let pat: ty = <INIT> else { <ELSE> }
else_block: Option<Block>,

/// The lint level for this `let` statement.
lint_level: LintLevel,
},
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,15 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm
init_scope: _,
ref pattern,
lint_level: _,
else_block,
} => {
if let Some(init) = initializer {
visitor.visit_expr(&visitor.thir()[*init]);
}
visitor.visit_pat(pattern);
if let Some(block) = else_block {
visitor.visit_block(block)
}
}
}
}
Expand Down
33 changes: 23 additions & 10 deletions compiler/rustc_mir_build/src/build/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref pattern,
initializer,
lint_level,
else_block,
} => {
let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
Expand All @@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|this| {
let scope = (*init_scope, source_info);
this.in_scope(scope, *lint_level, |this| {
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
this.expr_into_pattern(block, pattern.clone(), init)
if let Some(else_block) = else_block {
this.ast_let_else(
block,
init,
initializer_span,
else_block,
visibility_scope,
remainder_span,
pattern,
)
} else {
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
}
})
}
},
)
);
)
} else {
let scope = (*init_scope, source_info);
unpack!(this.in_scope(scope, *lint_level, |this| {
Expand Down
Loading

0 comments on commit 6c529de

Please sign in to comment.