Add an indirection for closures in hir::ExprKind

This helps bring `hir::Expr` size down, `Closure` was the biggest
variant, especially after `for<>` additions.
This commit is contained in:
Maybe Waffle 2022-07-11 23:39:53 +04:00
parent 3ebb852956
commit df4fee9841
26 changed files with 101 additions and 79 deletions

View File

@ -608,14 +608,18 @@ pub(super) fn make_async_expr(
});
// `static |_task_context| -> <ret_ty> { body }`:
let generator_kind = hir::ExprKind::Closure {
binder: &hir::ClosureBinder::Default,
capture_clause,
bound_generic_params: &[],
fn_decl,
body,
fn_decl_span: self.lower_span(span),
movability: Some(hir::Movability::Static),
let generator_kind = {
let c = self.arena.alloc(hir::Closure {
binder: hir::ClosureBinder::Default,
capture_clause,
bound_generic_params: &[],
fn_decl,
body,
fn_decl_span: self.lower_span(span),
movability: Some(hir::Movability::Static),
});
hir::ExprKind::Closure(c)
};
let generator = hir::Expr {
hir_id: self.lower_node_id(closure_node_id),
@ -864,7 +868,7 @@ fn lower_expr_closure(
// Lower outside new scope to preserve `is_in_loop_condition`.
let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
hir::ExprKind::Closure {
let c = self.arena.alloc(hir::Closure {
binder: binder_clause,
capture_clause,
bound_generic_params,
@ -872,7 +876,9 @@ fn lower_expr_closure(
body: body_id,
fn_decl_span: this.lower_span(fn_decl_span),
movability: generator_option,
}
});
hir::ExprKind::Closure(c)
})
}
@ -917,7 +923,7 @@ fn generator_movability_for_fn(
fn lower_closure_binder<'c>(
&mut self,
binder: &'c ClosureBinder,
) -> (&'hir hir::ClosureBinder, &'c [GenericParam]) {
) -> (hir::ClosureBinder, &'c [GenericParam]) {
let (binder, params) = match binder {
ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
&ClosureBinder::For { span, ref generic_params } => {
@ -926,7 +932,7 @@ fn lower_closure_binder<'c>(
}
};
(self.arena.alloc(binder), params)
(binder, params)
}
fn lower_expr_async_closure(
@ -991,7 +997,7 @@ fn lower_expr_async_closure(
// closure argument types.
let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
hir::ExprKind::Closure {
let c = self.arena.alloc(hir::Closure {
binder: binder_clause,
capture_clause,
bound_generic_params,
@ -999,7 +1005,8 @@ fn lower_expr_async_closure(
body,
fn_decl_span: this.lower_span(fn_decl_span),
movability: None,
}
});
hir::ExprKind::Closure(c)
})
}

View File

@ -891,7 +891,7 @@ fn closure_span(
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure { body, fn_decl_span, .. } = expr {
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
for (captured_place, place) in self
.infcx
.tcx
@ -904,11 +904,11 @@ fn closure_span(
if target_place == place.as_ref() =>
{
debug!("closure_span: found captured local {:?}", place);
let body = self.infcx.tcx.hir().body(*body);
let body = self.infcx.tcx.hir().body(body);
let generator_kind = body.generator_kind();
return Some((
*fn_decl_span,
fn_decl_span,
generator_kind,
captured_place.get_capture_kind_span(self.infcx.tcx),
captured_place.get_path_span(self.infcx.tcx),

View File

@ -325,7 +325,7 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
// Can't have BrEnv in functions, constants or generators.
bug!("BrEnv outside of closure.");
};
let hir::ExprKind::Closure { fn_decl_span, .. }
let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. })
= tcx.hir().expect_expr(self.mir_hir_id()).kind
else {
bug!("Closure is not defined by a closure expr");
@ -701,16 +701,16 @@ fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Opti
let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
..
}) => {
let (mut span, mut hir_ty) = match fn_decl.output {
hir::FnRetTy::DefaultReturn(_) => {
(tcx.sess.source_map().end_point(*fn_decl_span), None)
(tcx.sess.source_map().end_point(fn_decl_span), None)
}
hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
};
let mir_description = match hir.body(*body).generator_kind {
let mir_description = match hir.body(body).generator_kind {
Some(hir::GeneratorKind::Async(gen)) => match gen {
hir::AsyncGeneratorKind::Block => " of async block",
hir::AsyncGeneratorKind::Closure => " of async closure",
@ -841,9 +841,9 @@ fn give_name_if_anonymous_region_appears_in_yield_ty(
let yield_span = match tcx.hir().get(self.mir_hir_id()) {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl_span, .. },
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
}) => (tcx.sess.source_map().end_point(*fn_decl_span)),
}) => (tcx.sess.source_map().end_point(fn_decl_span)),
_ => self.body.span,
};

View File

@ -12,6 +12,7 @@ macro_rules! arena_types {
[] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, rustc_span::Span),
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
[] attribute: rustc_ast::Attribute,
[] closure: rustc_hir::Closure<'tcx>,
[] block: rustc_hir::Block<'tcx>,
[] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
[] body: rustc_hir::Body<'tcx>,

View File

@ -922,6 +922,17 @@ pub struct Crate<'hir> {
pub hir_hash: Fingerprint,
}
#[derive(Debug, HashStable_Generic)]
pub struct Closure<'hir> {
pub binder: ClosureBinder,
pub capture_clause: CaptureBy,
pub bound_generic_params: &'hir [GenericParam<'hir>],
pub fn_decl: &'hir FnDecl<'hir>,
pub body: BodyId,
pub fn_decl_span: Span,
pub movability: Option<Movability>,
}
/// A block of statements `{ .. }`, which may have a label (in this case the
/// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
/// the `rules` being anything but `DefaultBlock`.
@ -1930,15 +1941,7 @@ pub enum ExprKind<'hir> {
///
/// This may also be a generator literal or an `async block` as indicated by the
/// `Option<Movability>`.
Closure {
binder: &'hir ClosureBinder,
capture_clause: CaptureBy,
bound_generic_params: &'hir [GenericParam<'hir>],
fn_decl: &'hir FnDecl<'hir>,
body: BodyId,
fn_decl_span: Span,
movability: Option<Movability>,
},
Closure(&'hir Closure<'hir>),
/// A block (e.g., `'label: { ... }`).
Block(&'hir Block<'hir>, Option<Label>),

View File

@ -1144,23 +1144,17 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
visitor.visit_expr(subexpression);
walk_list!(visitor, visit_arm, arms);
}
ExprKind::Closure {
ExprKind::Closure(&Closure {
binder: _,
bound_generic_params,
ref fn_decl,
fn_decl,
body,
capture_clause: _,
fn_decl_span: _,
movability: _,
} => {
}) => {
walk_list!(visitor, visit_generic_param, bound_generic_params);
visitor.visit_fn(
FnKind::Closure,
fn_decl,
body,
expression.span,
expression.hir_id,
)
visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
}
ExprKind::Block(ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);

View File

@ -1441,7 +1441,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
}
self.bclose(expr.span);
}
hir::ExprKind::Closure {
hir::ExprKind::Closure(&hir::Closure {
binder,
capture_clause,
bound_generic_params,
@ -1449,7 +1449,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
body,
fn_decl_span: _,
movability: _,
} => {
}) => {
self.print_closure_binder(binder, bound_generic_params);
self.print_capture_clause(capture_clause);
@ -2037,7 +2037,7 @@ pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
pub fn print_closure_binder(
&mut self,
binder: &hir::ClosureBinder,
binder: hir::ClosureBinder,
generic_params: &[GenericParam<'_>],
) {
let generic_params = generic_params

View File

@ -6,7 +6,7 @@
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, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@ -1051,7 +1051,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
if let (
&ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
&ExprKind::Closure(&Closure { fn_decl, body, fn_decl_span, .. }),
ty::Closure(_, substs),
) = (&expr.kind, node_ty.kind())
{

View File

@ -22,7 +22,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
Node::Expr(Expr { kind: ExprKind::Closure { fn_decl, .. }, .. })
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. })
| Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
Some(fn_decl)
}
@ -54,7 +54,7 @@ pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
..
})
| Node::Expr(Expr { kind: ExprKind::Closure { body, .. }, .. }) => Some(*body),
| Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body),
Node::AnonConst(constant) => Some(constant.body),
@ -279,8 +279,8 @@ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
}
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure { movability: None, .. } => DefKind::Closure,
ExprKind::Closure { movability: Some(_), .. } => DefKind::Generator,
ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure,
ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator,
_ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
},
Node::GenericParam(param) => match param.kind {
@ -1021,7 +1021,9 @@ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) ->
_ => named_span(item.span, item.ident, None),
},
Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
Node::Expr(Expr { kind: ExprKind::Closure { fn_decl_span, .. }, .. }) => *fn_decl_span,
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
*fn_decl_span
}
_ => self.span_with_body(hir_id),
};
Some(span)

View File

@ -68,9 +68,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
// Figure out what primary body this item has.
let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { fn_decl, body, .. }, .. }) => {
(*body, fn_decl.output.span(), None)
}
Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(hir::Closure { fn_decl, body, .. }),
..
}) => (*body, fn_decl.output.span(), None),
Node::Item(hir::Item {
kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
span,

View File

@ -57,7 +57,13 @@ fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
hir::ExprKind::Loop(ref b, _, source, _) => {
self.with_context(Loop(source), |v| v.visit_block(&b));
}
hir::ExprKind::Closure { ref fn_decl, body, fn_decl_span, movability, .. } => {
hir::ExprKind::Closure(&hir::Closure {
ref fn_decl,
body,
fn_decl_span,
movability,
..
}) => {
let cx = if let Some(Movability::Static) = movability {
AsyncClosure(fn_decl_span)
} else {

View File

@ -273,7 +273,10 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
}
hir::ImplItemKind::TyAlias(_) => {}
},
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) => {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
..
}) => {
self.visit_nested_body(body);
}
// Nothing to recurse on for these

View File

@ -571,7 +571,10 @@ fn visit_nested_body(&mut self, body: hir::BodyId) {
}
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Closure { binder, bound_generic_params, fn_decl, .. } = e.kind {
if let hir::ExprKind::Closure(hir::Closure {
binder, bound_generic_params, fn_decl, ..
}) = e.kind
{
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
struct V(Option<Span>);

View File

@ -1360,7 +1360,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
}
}
}
hir::ExprKind::Closure { ref fn_decl, body, .. } => {
hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => {
let id = format!("${}", ex.hir_id);
// walk arg and return types

View File

@ -1084,7 +1084,7 @@ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>
let hir = self.tcx.hir();
Some(match node {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure { body, fn_decl_span, .. },
kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
..
}) => (
sm.guess_head_span(fn_decl_span),

View File

@ -103,7 +103,7 @@ fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
})
}),
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { body, movability, .. },
kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
..
}) => self.describe_generator(*body).or_else(|| {
Some(if movability.is_some() { "an async closure" } else { "a closure" })

View File

@ -785,7 +785,7 @@ fn suggest_fn_call(
// Get the name of the callable and the arguments to be used in the suggestion.
let (snippet, sugg) = match hir.get_if_local(def_id) {
Some(hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl, fn_decl_span, .. },
kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
..
})) => {
err.span_label(*fn_decl_span, "consider calling this closure");

View File

@ -285,29 +285,29 @@ fn identify_bad_closure_def_and_call(
let parent_node = hir.get(parent_hir_id);
if let (
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl_span, body, .. },
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }),
..
}),
hir::ExprKind::Block(..),
) = (parent_node, callee_node)
{
let fn_decl_span = if hir.body(*body).generator_kind
let fn_decl_span = if hir.body(body).generator_kind
== Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
{
// Actually need to unwrap a few more layers of HIR to get to
// the _real_ closure...
let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl_span, .. },
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
}) = hir.get(async_closure)
{
*fn_decl_span
fn_decl_span
} else {
return;
}
} else {
*fn_decl_span
fn_decl_span
};
let start = fn_decl_span.shrink_to_lo();

View File

@ -1577,8 +1577,8 @@ fn report_return_mismatched_types<'a>(
let parent_id = fcx.tcx.hir().get_parent_node(id);
let parent = fcx.tcx.hir().get(parent_id);
if let Some(expr) = expression
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) = parent
&& !matches!(fcx.tcx.hir().body(*body).value.kind, hir::ExprKind::Block(..))
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent
&& !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
{
fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
}

View File

@ -483,7 +483,7 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
let Some(Node::Expr(hir::Expr {
hir_id: expr_hir_id,
kind: hir::ExprKind::Closure { fn_decl: closure_fn_decl, .. },
kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
..
})) = self.tcx.hir().find(param_parent) else {
return None;

View File

@ -35,7 +35,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, HirId, QPath};
use rustc_hir::{Closure, ExprKind, HirId, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
@ -319,7 +319,7 @@ pub(super) fn check_expr_kind(
ExprKind::Match(discrim, arms, match_src) => {
self.check_match(expr, &discrim, arms, expected, match_src)
}
ExprKind::Closure { capture_clause, fn_decl, body, movability, .. } => {
ExprKind::Closure(&Closure { capture_clause, fn_decl, body, movability, .. }) => {
self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected)
}
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),

View File

@ -1821,7 +1821,7 @@ fn label_fn_like<'tcx>(
} else {
match tcx.hir().get_if_local(def_id) {
Some(hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl_span, .. },
kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
..
})) => {
let spans: MultiSpan = (*fn_decl_span).into();

View File

@ -335,7 +335,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
match expr.kind {
// Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
hir::ExprKind::Closure { body, .. }
hir::ExprKind::Closure(&hir::Closure { body, .. })
| hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);

View File

@ -142,7 +142,7 @@ struct InferBorrowKindVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
match expr.kind {
hir::ExprKind::Closure { capture_clause, body: body_id, .. } => {
hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => {
let body = self.fcx.tcx.hir().body(body_id);
self.visit_body(body);
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);

View File

@ -263,7 +263,7 @@ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
self.fix_index_builtin_expr(e);
match e.kind {
hir::ExprKind::Closure { body, .. } => {
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let body = self.fcx.tcx.hir().body(body);
for param in body.params {
self.visit_node_id(e.span, param.hir_id);

View File

@ -1717,8 +1717,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
// provide junk type parameter defs - the only place that
// cares about anything but the length is instantiation,
// and we don't do that for closures.
if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { movability: gen, .. }, .. }) =
node
if let Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
..
}) = node
{
let dummy_args = if gen.is_some() {
&["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
@ -2564,7 +2566,7 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> {
match tcx.hir().get_if_local(def_id) {
Some(Node::Expr(&rustc_hir::Expr {
kind: rustc_hir::ExprKind::Closure { body, .. },
kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
..
})) => tcx.hir().body(body).generator_kind(),
Some(_) => None,