Skip to content

[WIP] Delay def collection for expression-like nodes #128844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_session::parse::feature_err;
use rustc_span::symbol::kw;
use rustc_span::{sym, Span};
use rustc_target::asm;

Expand Down Expand Up @@ -222,18 +221,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};

// Wrap the expression in an AnonConst.
let parent_def_id = self.current_def_id_parent;
let node_id = self.next_node_id();
// HACK(min_generic_const_args): see lower_anon_const
if !expr.is_potential_trivial_const_arg() {
self.create_def(
parent_def_id,
node_id,
kw::Empty,
DefKind::AnonConst,
*op_sp,
);
}
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFn {
anon_const: self.lower_anon_const_to_anon_const(&anon_const),
Expand Down
98 changes: 64 additions & 34 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
_ => (),
}

self.create_def_if_needed_for(e);
let hir_id = self.lower_node_id(e.id);
self.lower_attrs(hir_id, &e.attrs);

Expand Down Expand Up @@ -207,31 +208,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
body,
fn_decl_span,
fn_arg_span,
}) => match coroutine_kind {
Some(coroutine_kind) => self.lower_expr_coroutine_closure(
binder,
*capture_clause,
e.id,
hir_id,
*coroutine_kind,
fn_decl,
body,
*fn_decl_span,
*fn_arg_span,
),
None => self.lower_expr_closure(
binder,
*capture_clause,
e.id,
hir_id,
*constness,
*movability,
fn_decl,
body,
*fn_decl_span,
*fn_arg_span,
),
},
}) => {
let closure_def = self.local_def_id(e.id);
self.with_def_id_parent(closure_def, |this| match coroutine_kind {
Some(coroutine_kind) => this.lower_expr_coroutine_closure(
binder,
*capture_clause,
e.id,
hir_id,
*coroutine_kind,
fn_decl,
body,
*fn_decl_span,
*fn_arg_span,
),
None => this.lower_expr_closure(
binder,
*capture_clause,
e.id,
hir_id,
*constness,
*movability,
fn_decl,
body,
*fn_decl_span,
*fn_arg_span,
),
})
}
ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => {
let desugaring_kind = match genblock_kind {
GenBlockKind::Async => hir::CoroutineDesugaring::Async,
Expand Down Expand Up @@ -356,6 +360,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
})
}

/// HACK(min_generic_const_args): we delay creation of expression defs until ast_lowering
///
/// This only creates a def for the top-level expression. If it has nested expressions that
/// need defs, those are handled by the recursion in the main lowering logic.
fn create_def_if_needed_for(&mut self, e: &Expr) {
match &e.kind {
ExprKind::ConstBlock(c) => {
self.create_def(
self.current_def_id_parent,
c.id,
kw::Empty,
DefKind::InlineConst,
c.value.span,
);
}
ExprKind::Closure(_) => {
self.create_def(
self.current_def_id_parent,
e.id,
kw::Empty,
DefKind::Closure,
e.span,
);
}
_ => {}
}
}

fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
match u {
UnOp::Deref => hir::UnOp::Deref,
Expand Down Expand Up @@ -383,15 +415,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut generic_args = ThinVec::new();
for (idx, arg) in args.into_iter().enumerate() {
if legacy_args_idx.contains(&idx) {
let parent_def_id = self.current_def_id_parent;
let node_id = self.next_node_id();

// HACK(min_generic_const_args): see lower_anon_const
if !arg.is_potential_trivial_const_arg() {
// Add a definition for the in-band const def.
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
}

let anon_const = AnonConst { id: node_id, value: arg };
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
} else {
Expand Down Expand Up @@ -625,7 +649,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
coroutine_source: hir::CoroutineSource,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
let closure_def_id = self.local_def_id(closure_node_id);
let closure_def_id = self.create_def(
self.current_def_id_parent,
closure_node_id,
kw::Empty,
DefKind::Closure,
span,
);
let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);

// The `async` desugaring takes a resume argument and maintains a `task_context`,
Expand Down
23 changes: 10 additions & 13 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2465,19 +2465,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_const_arg`].
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
if c.value.is_potential_trivial_const_arg() {
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
// Over there, we guess if this is a bare param and only create a def if
// we think it's not. However we may can guess wrong (see there for example)
// in which case we have to create the def here.
self.create_def(
self.current_def_id_parent,
c.id,
kw::Empty,
DefKind::AnonConst,
c.value.span,
);
}
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
// We delay creation of defs for expression-like things, including anon consts.
// This is because some anon consts end up as `ConstArgKind::Path`'s instead.
self.create_def(
self.current_def_id_parent,
c.id,
kw::Empty,
DefKind::AnonConst,
c.value.span,
);

self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
Expand Down
76 changes: 17 additions & 59 deletions compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
});
}

fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: Span, _: NodeId) {
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
match sig.header.coroutine_kind {
Some(coroutine_kind) => {
Some(_) => {
self.visit_generics(generics);

// For async functions, we need to create their inner defs inside of a
Expand All @@ -196,17 +196,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
self.visit_param(param);
}
self.visit_fn_ret_ty(&sig.decl.output);
// If this async fn has no body (i.e. it's an async fn signature in a trait)
// then the closure_def will never be used, and we should avoid generating a
// def-id for it.
if let Some(body) = body {
let closure_def = self.create_def(
coroutine_kind.closure_id(),
kw::Empty,
DefKind::Closure,
span,
);
self.with_parent(closure_def, |this| this.visit_block(body));
// HACK(min_generic_const_args): expression-like things (including coroutines)
// have their defs created later, in ast_lowering
self.visit_block(body);
}
return;
}
Expand Down Expand Up @@ -314,64 +307,29 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
}

fn visit_anon_const(&mut self, constant: &'a AnonConst) {
// HACK(min_generic_const_args): don't create defs for anon consts if we think they will
// later be turned into ConstArgKind::Path's. because this is before resolve is done, we
// may accidentally identify a construction of a unit struct as a param and not create a
// def. we'll then create a def later in ast lowering in this case. the parent of nested
// items will be messed up, but that's ok because there can't be any if we're just looking
// for bare idents.
if constant.value.is_potential_trivial_const_arg() {
visit::walk_anon_const(self, constant)
} else {
let def =
self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
}
// HACK(min_generic_const_args): expressions with defs (const blocks,
// anon consts, closures/generators) have their defs created later,
// during ast_lowering
visit::walk_anon_const(self, constant)
}

fn visit_expr(&mut self, expr: &'a Expr) {
let parent_def = match expr.kind {
// HACK(min_generic_const_args): expressions with defs (const blocks,
// anon consts, closures/generators) have their defs created later,
// during ast_lowering
match expr.kind {
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
ExprKind::Closure(ref closure) => {
// Async closures desugar to closures inside of closures, so
// we must create two defs.
let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
match closure.coroutine_kind {
Some(coroutine_kind) => {
self.with_parent(closure_def, |this| {
let coroutine_def = this.create_def(
coroutine_kind.closure_id(),
kw::Empty,
DefKind::Closure,
expr.span,
);
this.with_parent(coroutine_def, |this| visit::walk_expr(this, expr));
});
return;
}
None => closure_def,
}
}
ExprKind::Gen(_, _, _, _) => {
self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
}
ExprKind::ConstBlock(ref constant) => {
for attr in &expr.attrs {
visit::walk_attribute(self, attr);
}
let def = self.create_def(
constant.id,
kw::Empty,
DefKind::InlineConst,
constant.value.span,
);
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
visit::walk_anon_const(self, constant);
return;
}
_ => self.parent_def,
};
_ => {}
}

self.with_parent(parent_def, |this| visit::walk_expr(this, expr));
visit::walk_expr(self, expr);
}

fn visit_ty(&mut self, ty: &'a Ty) {
Expand Down
Loading
Loading