Skip to content

Commit

Permalink
Delay def collection for expression-like nodes
Browse files Browse the repository at this point in the history
These expression-like nodes are anon const args, const blocks, closures,
and generators. They need to have their def collection delayed because
some anon const args turn into `ConstArgKind::Path`, which has no DefId.
Thus defs that could have an anon const as their parent must be delayed
as well.
  • Loading branch information
camelid committed Aug 8, 2024
1 parent 86e7875 commit 73be83c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 118 deletions.
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
81 changes: 47 additions & 34 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(c) => {
let c = self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
let def_id = this.create_def(
this.current_def_id_parent,
c.id,
kw::Empty,
DefKind::InlineConst,
c.value.span,
);
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
Expand Down Expand Up @@ -207,31 +213,40 @@ 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,
}) => {
let closure_def = self.create_def(
self.current_def_id_parent,
e.id,
hir_id,
*constness,
*movability,
fn_decl,
body,
*fn_decl_span,
*fn_arg_span,
),
},
kw::Empty,
DefKind::Closure,
e.span,
);
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 @@ -383,15 +398,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 +632,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

0 comments on commit 73be83c

Please sign in to comment.