1
Fork 0

Remove hir::StmtKind::Decl.

It's a level of indirection that hurts far more than it helps. The code
is simpler without it. (This commit cuts more than 120 lines of code.)

In particular, this commit removes some unnecessary `Span`s within
`DeclKind` that were always identical to those in the enclosing `Stmt`,
and some unnecessary allocations via `P`.
This commit is contained in:
Nicholas Nethercote 2019-01-17 10:39:24 +11:00
parent b2ce5a9099
commit afbd004d69
16 changed files with 152 additions and 274 deletions

View file

@ -100,29 +100,20 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex {
let hir_id = self.tcx.hir().node_to_hir_id(stmt.id);
match stmt.node {
hir::StmtKind::Decl(ref decl) => {
let exit = self.decl(&decl, pred);
self.add_ast_node(hir_id.local_id, &[exit])
}
hir::StmtKind::Expr(ref expr) |
hir::StmtKind::Semi(ref expr) => {
let exit = self.expr(&expr, pred);
self.add_ast_node(hir_id.local_id, &[exit])
}
}
}
fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex {
match decl.node {
hir::DeclKind::Local(ref local) => {
let exit = match stmt.node {
hir::StmtKind::Local(ref local) => {
let init_exit = self.opt_expr(&local.init, pred);
self.pat(&local.pat, init_exit)
}
hir::DeclKind::Item(_) => pred,
}
hir::StmtKind::Item(_) => {
pred
}
hir::StmtKind::Expr(ref expr) |
hir::StmtKind::Semi(ref expr) => {
self.expr(&expr, pred)
}
};
self.add_ast_node(hir_id.local_id, &[exit])
}
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {

View file

@ -298,8 +298,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
fn check_stmt_attributes(&self, stmt: &hir::Stmt) {
// When checking statements ignore expressions, they will be checked later
if let hir::StmtKind::Decl(..) = stmt.node {
for attr in stmt.node.attrs() {
if let hir::StmtKind::Local(ref l) = stmt.node {
for attr in l.attrs.iter() {
if attr.check_name("inline") {
self.check_inline(attr, &stmt.span, Target::Statement);
}

View file

@ -260,9 +260,6 @@ pub trait Visitor<'v> : Sized {
fn visit_pat(&mut self, p: &'v Pat) {
walk_pat(self, p)
}
fn visit_decl(&mut self, d: &'v Decl) {
walk_decl(self, d)
}
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
@ -955,9 +952,8 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) {
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
visitor.visit_id(statement.id);
match statement.node {
StmtKind::Decl(ref declaration) => {
visitor.visit_decl(declaration)
}
StmtKind::Local(ref local) => visitor.visit_local(local),
StmtKind::Item(ref item) => visitor.visit_nested_item(**item),
StmtKind::Expr(ref expression) |
StmtKind::Semi(ref expression) => {
visitor.visit_expr(expression)
@ -965,13 +961,6 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
}
}
pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
match declaration.node {
DeclKind::Local(ref local) => visitor.visit_local(local),
DeclKind::Item(item) => visitor.visit_nested_item(item),
}
}
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
visitor.visit_id(constant.id);
visitor.visit_nested_body(constant.body);

View file

@ -1957,7 +1957,7 @@ impl<'a> LoweringContext<'a> {
)
}
fn lower_local(&mut self, l: &Local) -> (P<hir::Local>, SmallVec<[hir::ItemId; 1]>) {
fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[hir::ItemId; 1]>) {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id);
let mut ids = SmallVec::<[hir::ItemId; 1]>::new();
if self.sess.features_untracked().impl_trait_in_bindings {
@ -1967,7 +1967,7 @@ impl<'a> LoweringContext<'a> {
}
}
let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0);
(P(hir::Local {
(hir::Local {
id: node_id,
hir_id,
ty: l.ty
@ -1984,7 +1984,7 @@ impl<'a> LoweringContext<'a> {
span: l.span,
attrs: l.attrs.clone(),
source: hir::LocalSource::Normal,
}), ids)
}, ids)
}
fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
@ -4537,23 +4537,13 @@ impl<'a> LoweringContext<'a> {
.into_iter()
.map(|item_id| hir::Stmt {
id: self.next_id().node_id,
node: hir::StmtKind::Decl(
P(Spanned {
node: hir::DeclKind::Item(item_id),
span: s.span,
}),
),
node: hir::StmtKind::Item(P(item_id)),
span: s.span,
})
.collect();
ids.push(hir::Stmt {
id: self.lower_node_id(s.id).node_id,
node: hir::StmtKind::Decl(
P(Spanned {
node: hir::DeclKind::Local(l),
span: s.span,
}),
),
node: hir::StmtKind::Local(P(l)),
span: s.span,
});
return ids;
@ -4567,12 +4557,7 @@ impl<'a> LoweringContext<'a> {
id: id.take()
.map(|id| self.lower_node_id(id).node_id)
.unwrap_or_else(|| self.next_id().node_id),
node: hir::StmtKind::Decl(
P(Spanned {
node: hir::DeclKind::Item(item_id),
span: s.span,
}),
),
node: hir::StmtKind::Item(P(item_id)),
span: s.span,
})
.collect();
@ -4799,7 +4784,7 @@ impl<'a> LoweringContext<'a> {
) -> hir::Stmt {
let LoweredNodeId { node_id, hir_id } = self.next_id();
let local = P(hir::Local {
let local = hir::Local {
pat,
ty: None,
init: ex,
@ -4808,11 +4793,10 @@ impl<'a> LoweringContext<'a> {
span: sp,
attrs: ThinVec::new(),
source,
});
let decl = respan(sp, hir::DeclKind::Local(local));
};
hir::Stmt {
id: self.next_id().node_id,
node: hir::StmtKind::Decl(P(decl)),
node: hir::StmtKind::Local(P(local)),
span: sp
}
}

View file

@ -1160,8 +1160,10 @@ impl fmt::Debug for Stmt {
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum StmtKind {
/// Could be an item or a local (let) binding:
Decl(P<Decl>),
/// A local (let) binding:
Local(P<Local>),
/// An item binding:
Item(P<ItemId>),
/// Expr without trailing semi-colon (must have unit type):
Expr(P<Expr>),
@ -1173,7 +1175,8 @@ pub enum StmtKind {
impl StmtKind {
pub fn attrs(&self) -> &[Attribute] {
match *self {
StmtKind::Decl(ref d) => d.node.attrs(),
StmtKind::Local(ref l) => &l.attrs,
StmtKind::Item(_) => &[],
StmtKind::Expr(ref e) |
StmtKind::Semi(ref e) => &e.attrs,
}
@ -1194,32 +1197,6 @@ pub struct Local {
pub source: LocalSource,
}
pub type Decl = Spanned<DeclKind>;
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum DeclKind {
/// A local (let) binding:
Local(P<Local>),
/// An item binding:
Item(ItemId),
}
impl DeclKind {
pub fn attrs(&self) -> &[Attribute] {
match *self {
DeclKind::Local(ref l) => &l.attrs,
DeclKind::Item(_) => &[]
}
}
pub fn is_local(&self) -> bool {
match *self {
DeclKind::Local(_) => true,
_ => false,
}
}
}
/// represents one arm of a 'match'
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Arm {

View file

@ -992,8 +992,23 @@ impl<'a> State<'a> {
pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
self.maybe_print_comment(st.span.lo())?;
match st.node {
hir::StmtKind::Decl(ref decl) => {
self.print_decl(&decl)?;
hir::StmtKind::Local(ref loc) => {
self.space_if_not_bol()?;
self.ibox(indent_unit)?;
self.word_nbsp("let")?;
self.ibox(indent_unit)?;
self.print_local_decl(&loc)?;
self.end()?;
if let Some(ref init) = loc.init {
self.nbsp()?;
self.word_space("=")?;
self.print_expr(&init)?;
}
self.end()?
}
hir::StmtKind::Item(ref item) => {
self.ann.nested(self, Nested::Item(**item))?
}
hir::StmtKind::Expr(ref expr) => {
self.space_if_not_bol()?;
@ -1562,30 +1577,6 @@ impl<'a> State<'a> {
Ok(())
}
pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> {
self.maybe_print_comment(decl.span.lo())?;
match decl.node {
hir::DeclKind::Local(ref loc) => {
self.space_if_not_bol()?;
self.ibox(indent_unit)?;
self.word_nbsp("let")?;
self.ibox(indent_unit)?;
self.print_local_decl(&loc)?;
self.end()?;
if let Some(ref init) = loc.init {
self.nbsp()?;
self.word_space("=")?;
self.print_expr(&init)?;
}
self.end()
}
hir::DeclKind::Item(item) => {
self.ann.nested(self, Nested::Item(item))
}
}
}
pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
self.s.word(i.to_string())
}
@ -2401,18 +2392,10 @@ 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::Decl(ref d) => {
match d.node {
hir::DeclKind::Local(_) => true,
hir::DeclKind::Item(_) => false,
}
}
hir::StmtKind::Expr(ref e) => {
expr_requires_semi_to_be_stmt(&e)
}
hir::StmtKind::Semi(..) => {
false
}
hir::StmtKind::Local(_) => true,
hir::StmtKind::Item(_) => false,
hir::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(&e),
hir::StmtKind::Semi(..) => false,
}
}

View file

@ -501,12 +501,6 @@ impl_stable_hash_for!(struct hir::Local {
source
});
impl_stable_hash_for_spanned!(hir::DeclKind);
impl_stable_hash_for!(enum hir::DeclKind {
Local(local),
Item(item_id)
});
impl_stable_hash_for!(struct hir::Arm {
attrs,
pats,
@ -946,7 +940,8 @@ impl_stable_hash_for!(enum hir::ForeignItemKind {
});
impl_stable_hash_for!(enum hir::StmtKind {
Decl(decl),
Local(local),
Item(item_id),
Expr(expr),
Semi(expr)
});

View file

@ -941,11 +941,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
hir_visit::walk_arm(self, a);
}
fn visit_decl(&mut self, d: &'tcx hir::Decl) {
run_lints!(self, check_decl, d);
hir_visit::walk_decl(self, d);
}
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
run_lints!(self, check_generic_param, p);
hir_visit::walk_generic_param(self, p);

View file

@ -191,7 +191,6 @@ macro_rules! late_lint_methods {
fn check_stmt(a: &$hir hir::Stmt);
fn check_arm(a: &$hir hir::Arm);
fn check_pat(a: &$hir hir::Pat);
fn check_decl(a: &$hir hir::Decl);
fn check_expr(a: &$hir hir::Expr);
fn check_expr_post(a: &$hir hir::Expr);
fn check_ty(a: &$hir hir::Ty);

View file

@ -589,17 +589,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
fn walk_stmt(&mut self, stmt: &hir::Stmt) {
match stmt.node {
hir::StmtKind::Decl(ref decl) => {
match decl.node {
hir::DeclKind::Local(ref local) => {
self.walk_local(&local);
}
hir::StmtKind::Local(ref local) => {
self.walk_local(&local);
}
hir::DeclKind::Item(_) => {
// we don't visit nested items in this visitor,
// only the fn body we were given.
}
}
hir::StmtKind::Item(_) => {
// we don't visit nested items in this visitor,
// only the fn body we were given.
}
hir::StmtKind::Expr(ref expr) |

View file

@ -956,46 +956,31 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode)
-> LiveNode {
match stmt.node {
hir::StmtKind::Decl(ref decl) => {
self.propagate_through_decl(&decl, succ)
}
hir::StmtKind::Local(ref local) => {
// Note: we mark the variable as defined regardless of whether
// there is an initializer. Initially I had thought to only mark
// the live variable as defined if it was initialized, and then we
// could check for uninit variables just by scanning what is live
// at the start of the function. But that doesn't work so well for
// immutable variables defined in a loop:
// loop { let x; x = 5; }
// because the "assignment" loops back around and generates an error.
//
// So now we just check that variables defined w/o an
// initializer are not live at the point of their
// initialization, which is mildly more complex than checking
// once at the func header but otherwise equivalent.
let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
self.define_bindings_in_pat(&local.pat, succ)
}
hir::StmtKind::Item(..) => succ,
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
self.propagate_through_expr(&expr, succ)
}
}
}
fn propagate_through_decl(&mut self, decl: &hir::Decl, succ: LiveNode)
-> LiveNode {
match decl.node {
hir::DeclKind::Local(ref local) => {
self.propagate_through_local(&local, succ)
}
hir::DeclKind::Item(_) => succ,
}
}
fn propagate_through_local(&mut self, local: &hir::Local, succ: LiveNode)
-> LiveNode {
// Note: we mark the variable as defined regardless of whether
// there is an initializer. Initially I had thought to only mark
// the live variable as defined if it was initialized, and then we
// could check for uninit variables just by scanning what is live
// at the start of the function. But that doesn't work so well for
// immutable variables defined in a loop:
// loop { let x; x = 5; }
// because the "assignment" loops back around and generates an error.
//
// So now we just check that variables defined w/o an
// initializer are not live at the point of their
// initialization, which is mildly more complex than checking
// once at the func header but otherwise equivalent.
let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
self.define_bindings_in_pat(&local.pat, succ)
}
fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
-> LiveNode {
exprs.iter().rev().fold(succ, |succ, expr| {

View file

@ -784,20 +784,25 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
// index information.)
for (i, statement) in blk.stmts.iter().enumerate() {
if let hir::StmtKind::Decl(..) = statement.node {
// Each StmtKind::Decl introduces a subscope for bindings
// introduced by the declaration; this subscope covers
// a suffix of the block . Each subscope in a block
// has the previous subscope in the block as a parent,
// except for the first such subscope, which has the
// block itself as a parent.
visitor.enter_scope(
Scope {
id: blk.hir_id.local_id,
data: ScopeData::Remainder(FirstStatementIndex::new(i))
}
);
visitor.cx.var_parent = visitor.cx.parent;
match statement.node {
hir::StmtKind::Local(..) |
hir::StmtKind::Item(..) => {
// Each declaration introduces a subscope for bindings
// introduced by the declaration; this subscope covers a
// suffix of the block. Each subscope in a block has the
// previous subscope in the block as a parent, except for
// the first such subscope, which has the block itself as a
// parent.
visitor.enter_scope(
Scope {
id: blk.hir_id.local_id,
data: ScopeData::Remainder(FirstStatementIndex::new(i))
}
);
visitor.cx.var_parent = visitor.cx.parent;
}
hir::StmtKind::Expr(..) |
hir::StmtKind::Semi(..) => {}
}
visitor.visit_stmt(statement)
}

View file

@ -64,52 +64,48 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
span: stmt_span,
})))
}
hir::StmtKind::Decl(ref decl) => {
match decl.node {
hir::DeclKind::Item(..) => {
// ignore for purposes of the MIR
}
hir::DeclKind::Local(ref local) => {
let remainder_scope = region::Scope {
id: block_id,
data: region::ScopeData::Remainder(
region::FirstStatementIndex::new(index)),
hir::StmtKind::Item(..) => {
// ignore for purposes of the MIR
}
hir::StmtKind::Local(ref local) => {
let remainder_scope = region::Scope {
id: block_id,
data: region::ScopeData::Remainder(
region::FirstStatementIndex::new(index)),
};
let mut pattern = cx.pattern_from_hir(&local.pat);
if let Some(ty) = &local.ty {
if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
debug!("mirror_stmts: user_ty={:?}", user_ty);
pattern = Pattern {
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatternKind::AscribeUserType {
user_ty: PatternTypeProjection::from_user_type(user_ty),
user_ty_span: ty.span,
subpattern: pattern,
variance: ty::Variance::Covariant,
})
};
let mut pattern = cx.pattern_from_hir(&local.pat);
if let Some(ty) = &local.ty {
if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
debug!("mirror_stmts: user_ty={:?}", user_ty);
pattern = Pattern {
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatternKind::AscribeUserType {
user_ty: PatternTypeProjection::from_user_type(user_ty),
user_ty_span: ty.span,
subpattern: pattern,
variance: ty::Variance::Covariant,
})
};
}
}
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Let {
remainder_scope: remainder_scope,
init_scope: region::Scope {
id: hir_id.local_id,
data: region::ScopeData::Node
},
pattern,
initializer: local.init.to_ref(),
lint_level: cx.lint_level_of(local.id),
},
opt_destruction_scope: opt_dxn_ext,
span: stmt_span,
})));
}
}
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Let {
remainder_scope: remainder_scope,
init_scope: region::Scope {
id: hir_id.local_id,
data: region::ScopeData::Node
},
pattern,
initializer: local.init.to_ref(),
lint_level: cx.lint_level_of(local.id),
},
opt_destruction_scope: opt_dxn_ext,
span: stmt_span,
})));
}
}
}

View file

@ -158,11 +158,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
hir_visit::walk_pat(self, p)
}
fn visit_decl(&mut self, d: &'v hir::Decl) {
self.record("Decl", Id::None, d);
hir_visit::walk_decl(self, d)
}
fn visit_expr(&mut self, ex: &'v hir::Expr) {
self.record("Expr", Id::Node(ex.id), ex);
hir_visit::walk_expr(self, ex)

View file

@ -220,24 +220,20 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
fn check_stmt(&mut self, stmt: &'tcx hir::Stmt) -> Promotability {
match stmt.node {
hir::StmtKind::Decl(ref decl) => {
match &decl.node {
hir::DeclKind::Local(local) => {
if self.remove_mut_rvalue_borrow(&local.pat) {
if let Some(init) = &local.init {
self.mut_rvalue_borrows.insert(init.id);
}
}
if let Some(ref expr) = local.init {
let _ = self.check_expr(&expr);
}
NotPromotable
hir::StmtKind::Local(ref local) => {
if self.remove_mut_rvalue_borrow(&local.pat) {
if let Some(init) = &local.init {
self.mut_rvalue_borrows.insert(init.id);
}
// Item statements are allowed
hir::DeclKind::Item(_) => Promotable
}
if let Some(ref expr) = local.init {
let _ = self.check_expr(&expr);
}
NotPromotable
}
// Item statements are allowed
hir::StmtKind::Item(..) => Promotable,
hir::StmtKind::Expr(ref box_expr) |
hir::StmtKind::Semi(ref box_expr) => {
let _ = self.check_expr(box_expr);

View file

@ -4840,12 +4840,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
// Don't do all the complex logic below for `DeclItem`.
match stmt.node {
hir::StmtKind::Decl(ref decl) => {
if let hir::DeclKind::Item(_) = decl.node {
return
}
}
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
hir::StmtKind::Item(..) => return,
hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
}
self.warn_if_unreachable(stmt.id, stmt.span, "statement");
@ -4857,15 +4853,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.has_errors.set(false);
match stmt.node {
hir::StmtKind::Decl(ref decl) => {
match decl.node {
hir::DeclKind::Local(ref l) => {
self.check_decl_local(&l);
}
// Ignore for now.
hir::DeclKind::Item(_) => ()
}
hir::StmtKind::Local(ref l) => {
self.check_decl_local(&l);
}
// Ignore for now.
hir::StmtKind::Item(_) => {}
hir::StmtKind::Expr(ref expr) => {
// Check with expected type of `()`.
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit());