Skip to content

Commit 461e973

Browse files
committed
Auto merge of #153489 - aerooneqq:two-phase-hir, r=petrochenkov
ty-aware delayed AST -> HIR lowering This PR implements a prototype of ty-aware delayed AST -> HIR lowering. Part of #118212. r? @petrochenkov # Motivation When lowering delegation in perfect scenario we would like to access the ty-level information, in particular, queries like `generics_of`, `type_of`, `fn_sig` for proper HIR generation with less hacks. For example, we do not want to generate more lifetimes than needed, because without ty-level queries we do not know which delegee's lifetimes are late-bound. Next, consider recursive delegations, for their proper support without ty we would have to either duplicate generics inheritance code in AST -> HIR lowering or create stubs for parts of the HIR and materialize them later. We already use those queries when interacting with external crates, however when dealing with compilation of a local crate we should use resolver for similar purposes. Finally, access to ty-level queries is expected to help supporting delegation to inherent impls, as we can not resolve such calls during AST -> HIR stage. # Benefits We eliminate almost all code that uses resolver in delegation lowering: - Attributes inheritance is done without copying attributes from AST at resolve stage - Fn signatures are obtained from `tcx.fn_sig` - Param counts are also obtained from `tcx.fn_sig` - `is_method` function now uses `tcx.associated_item` instead of resolver - Generics are now inherited through `get_external_generics` that uses `tcx.generics_of`. Generics for recursive delegations should also work - `DelegationIds` that stored paths for recursive delegations is removed, we now use only `delegee_id` - Structs that were used for storing delegation-related information in resolver are almost fully removed - `ast_index` is no more used # Next steps - Remove creating generic params through AST cloning, proper const types propagation - Inherent impls # High level design overview ## Queries We store ids of delayed items to lower in `Crate` struct. During first stage of lowering, owners that correspond to delayed items are filled with `MaybeOwner::Phantom`. Next, we define two new queries: `lower_delayed_owner`, `delayed_owner` and a function `force_delayed_owners_lowering`. The first query is used when lowering known (which is in `delayed_ids`) delayed owner. The second is fed with children that were obtained during lowering of a delayed owner (note that the result of lowering of a single `LocalDefId` is not a single `MaybeOwner`, its a list of `(LocalDefId, MaybeOwner)` where the first `MaybeOwner` corresponds to delayed `LocalDefId` and others to children that were obtained during lowering (i.e. generic params)). By default `delayed_owner` returns `MaybeOwner::Phantom`. As we do not want to predict the whole list of children which will be obtained after lowering of a single delayed item, we need to store those children somewhere. There are several options: - Make the return type of `lower_delayed_owner` to be `FxIndexMap<LocalDefId, MaybeOwner>` and search children here. Search will be either linear or we can introduce a map somewhere which will track parent-child relations between a single delayed `LocalDefId` and its children. - Try to make query that will lower all delayed items in a loop and return a complete map of all delayed `LocalDefIds` and their children. In this case there will be problems with delayed items that require information about other delayed items. By using proposed queries we handle the second concern, and in case of acyclic dependencies between delayed ids it automatically works, moreover we use queries as cache for delayed `MaybeOwners`. The only invariant here is that queries which are invoked during delayed AST -> HIR lowering of some `LocalDefId` should not in any way access children of other, yet unlowered, delayed `LocalDefId`, they should firstly materialize it. The `force_delayed_owners_lowering` forces lowering of all delayed items and now integrated in `hir_crate_items` query. ## Resolver for lowering > ~Currently the `resolver_for_lowering` is stolen in `lower_to_hir` function, however we want to prolong its life until all delayed `LocalDefIds` are materialized. For this purpose we borrow `resolver_for_lowering` in `lower_to_hir` and drop it after forcing materialization of all delayed `LocalDefId` in `rustc_interface::run_required_analyses`.~ We split resolver for lowering into two parts: the first part is a readonly part that came to us from resolve, the second part is a mutable part that can be used to add or overwrite values in the readonly part. Such splitted resolver is used during delayed lowering, as we can't steal it. ## AST index Lowering uses an AST index. It is created in `lower_to_hir` function and it references parts of AST. We want to avoid reindexing AST on every delayed `LocalDefId` lowering, however now it is not clear how to properly do it. As delayed HIR lowering is used only for delegation unstable feature it should not affect other use-cases of the compiler. But it will be reworked sooner or later.
2 parents 86c839f + 5c441e6 commit 461e973

21 files changed

Lines changed: 398 additions & 454 deletions

File tree

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 47 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,15 @@ use hir::{BodyId, HirId};
4545
use rustc_abi::ExternAbi;
4646
use rustc_ast as ast;
4747
use rustc_ast::*;
48-
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
4948
use rustc_data_structures::fx::FxHashSet;
5049
use rustc_errors::ErrorGuaranteed;
5150
use rustc_hir as hir;
5251
use rustc_hir::attrs::{AttributeKind, InlineAttr};
53-
use rustc_hir::def_id::{DefId, LocalDefId};
52+
use rustc_hir::def_id::DefId;
5453
use rustc_middle::span_bug;
55-
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs};
54+
use rustc_middle::ty::Asyncness;
5655
use rustc_span::symbol::kw;
57-
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
56+
use rustc_span::{Ident, Span, Symbol};
5857
use smallvec::SmallVec;
5958

6059
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
@@ -80,7 +79,7 @@ struct AttrAdditionInfo {
8079

8180
enum AttrAdditionKind {
8281
Default { factory: fn(Span) -> hir::Attribute },
83-
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
82+
Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
8483
}
8584

8685
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
@@ -97,7 +96,6 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
9796

9897
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
9998
},
100-
flag: DelegationFnSigAttrs::MUST_USE,
10199
},
102100
},
103101
AttrAdditionInfo {
@@ -108,43 +106,11 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
108106
},
109107
];
110108

111-
type DelegationIdsVec = SmallVec<[DefId; 1]>;
112-
113-
// As delegations can now refer to another delegation, we have a delegation path
114-
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
115-
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
116-
struct DelegationIds {
117-
path: DelegationIdsVec,
118-
}
119-
120-
impl DelegationIds {
121-
fn new(path: DelegationIdsVec) -> Self {
122-
assert!(!path.is_empty());
123-
Self { path }
124-
}
125-
126-
// Id of the first function in (non)local crate that is being reused
127-
fn root_function_id(&self) -> DefId {
128-
*self.path.last().expect("Ids vector can't be empty")
129-
}
130-
131-
// Id of the first definition which is being reused,
132-
// can be either function, in this case `root_id == delegee_id`, or other delegation
133-
fn delegee_id(&self) -> DefId {
134-
*self.path.first().expect("Ids vector can't be empty")
135-
}
136-
}
137-
138109
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
139110
fn is_method(&self, def_id: DefId, span: Span) -> bool {
140111
match self.tcx.def_kind(def_id) {
141112
DefKind::Fn => false,
142-
DefKind::AssocFn => match def_id.as_local() {
143-
Some(local_def_id) => {
144-
self.resolver.delegation_fn_sig(local_def_id).is_some_and(|sig| sig.has_self)
145-
}
146-
None => self.tcx.associated_item(def_id).is_method(),
147-
},
113+
DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
148114
_ => span_bug!(span, "unexpected DefKind for delegation item"),
149115
}
150116
}
@@ -157,10 +123,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
157123
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
158124

159125
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
160-
let ids = if let Some(delegation_info) =
126+
let sig_id = if let Some(delegation_info) =
161127
self.resolver.delegation_info(self.local_def_id(item_id))
162128
{
163-
self.get_delegation_ids(delegation_info.resolution_node, span)
129+
self.get_sig_id(delegation_info.resolution_node, span)
164130
} else {
165131
return self.generate_delegation_error(
166132
self.dcx().span_delayed_bug(
@@ -172,28 +138,16 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
172138
);
173139
};
174140

175-
match ids {
176-
Ok(ids) => {
177-
self.add_attrs_if_needed(span, &ids);
178-
179-
let delegee_id = ids.delegee_id();
180-
let root_function_id = ids.root_function_id();
141+
match sig_id {
142+
Ok(sig_id) => {
143+
self.add_attrs_if_needed(span, sig_id);
181144

182-
// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
183-
// if the original function is not a method (without `self`), then it can not be added
184-
// during chain of reuses, so we use `root_function_id` here
185-
let is_method = self.is_method(root_function_id, span);
145+
let is_method = self.is_method(sig_id, span);
186146

187-
// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
188-
// we need a function to extract this information
189-
let (param_count, c_variadic) = self.param_count(root_function_id);
147+
let (param_count, c_variadic) = self.param_count(sig_id);
190148

191-
let mut generics = self.lower_delegation_generics(
192-
delegation,
193-
ids.root_function_id(),
194-
item_id,
195-
span,
196-
);
149+
let mut generics =
150+
self.lower_delegation_generics(delegation, sig_id, item_id, span);
197151

198152
let body_id = self.lower_delegation_body(
199153
delegation,
@@ -204,20 +158,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
204158
span,
205159
);
206160

207-
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
208-
// inheritance, and we want this id to point on a delegee, not on the original
209-
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
210-
let decl = self.lower_delegation_decl(
211-
delegee_id,
212-
param_count,
213-
c_variadic,
214-
span,
215-
&generics,
216-
);
161+
let decl =
162+
self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);
217163

218-
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
219-
// from the root function that started delegation
220-
let sig = self.lower_delegation_sig(root_function_id, decl, span);
164+
let sig = self.lower_delegation_sig(sig_id, decl, span);
221165
let ident = self.lower_ident(delegation.ident);
222166

223167
let generics = self.arena.alloc(hir::Generics {
@@ -236,9 +180,9 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
236180
}
237181
}
238182

239-
fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
183+
fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
240184
let new_attrs =
241-
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
185+
self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));
242186

243187
if new_attrs.is_empty() {
244188
return;
@@ -258,15 +202,9 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
258202
&self,
259203
candidate_additions: &[AttrAdditionInfo],
260204
span: Span,
261-
ids: &DelegationIds,
205+
sig_id: DefId,
262206
existing_attrs: Option<&&[hir::Attribute]>,
263207
) -> Vec<hir::Attribute> {
264-
let defs_orig_attrs = ids
265-
.path
266-
.iter()
267-
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
268-
.collect::<Vec<_>>();
269-
270208
candidate_additions
271209
.iter()
272210
.filter_map(|addition_info| {
@@ -280,83 +218,22 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
280218

281219
match addition_info.kind {
282220
AttrAdditionKind::Default { factory } => Some(factory(span)),
283-
AttrAdditionKind::Inherit { flag, factory } => {
284-
for (def_id, orig_attrs) in &defs_orig_attrs {
285-
let original_attr = match def_id.as_local() {
286-
Some(local_id) => self
287-
.get_attrs(local_id)
288-
.flags
289-
.contains(flag)
290-
.then(|| {
291-
orig_attrs
292-
.as_ref()
293-
.map(|attrs| {
294-
attrs.iter().find(|base_attr| {
295-
(addition_info.equals)(base_attr)
296-
})
297-
})
298-
.flatten()
299-
})
300-
.flatten(),
301-
None =>
302-
{
303-
#[allow(deprecated)]
304-
self.tcx
305-
.get_all_attrs(*def_id)
306-
.iter()
307-
.find(|base_attr| (addition_info.equals)(base_attr))
308-
}
309-
};
310-
311-
if let Some(original_attr) = original_attr {
312-
return Some(factory(span, original_attr));
313-
}
314-
}
315-
316-
None
221+
AttrAdditionKind::Inherit { factory, .. } =>
222+
{
223+
#[allow(deprecated)]
224+
self.tcx
225+
.get_all_attrs(sig_id)
226+
.iter()
227+
.find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
317228
}
318229
}
319230
})
320231
.collect::<Vec<_>>()
321232
}
322233

323-
fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
324-
if let Some(local_id) = def_id.as_local() {
325-
let attrs = &self.get_attrs(local_id).to_inherit;
326-
327-
if !attrs.is_empty() {
328-
return Some(AttributeParser::parse_limited_all(
329-
self.tcx.sess,
330-
attrs,
331-
None,
332-
hir::Target::Fn,
333-
DUMMY_SP,
334-
DUMMY_NODE_ID,
335-
Some(self.tcx.features()),
336-
ShouldEmit::Nothing,
337-
));
338-
}
339-
}
340-
341-
None
342-
}
343-
344-
fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
345-
// local_id can correspond either to a function or other delegation
346-
if let Some(fn_sig) = self.resolver.delegation_fn_sig(local_id) {
347-
&fn_sig.attrs
348-
} else {
349-
&self.resolver.delegation_info(local_id).expect("processing delegation").attrs
350-
}
351-
}
352-
353-
fn get_delegation_ids(
354-
&self,
355-
mut node_id: NodeId,
356-
span: Span,
357-
) -> Result<DelegationIds, ErrorGuaranteed> {
234+
fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
358235
let mut visited: FxHashSet<NodeId> = Default::default();
359-
let mut path: DelegationIdsVec = Default::default();
236+
let mut path: SmallVec<[DefId; 1]> = Default::default();
360237

361238
loop {
362239
visited.insert(node_id);
@@ -389,7 +266,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
389266
});
390267
}
391268
} else {
392-
return Ok(DelegationIds::new(path));
269+
return Ok(path[0]);
393270
}
394271
}
395272
}
@@ -400,15 +277,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
400277

401278
// Function parameter count, including C variadic `...` if present.
402279
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
403-
if let Some(local_sig_id) = def_id.as_local() {
404-
match self.resolver.delegation_fn_sig(local_sig_id) {
405-
Some(sig) => (sig.param_count, sig.c_variadic),
406-
None => (0, false),
407-
}
408-
} else {
409-
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
410-
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
411-
}
280+
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
281+
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
412282
}
413283

414284
fn lower_delegation_decl(
@@ -455,41 +325,21 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
455325
decl: &'hir hir::FnDecl<'hir>,
456326
span: Span,
457327
) -> hir::FnSig<'hir> {
458-
let header = if let Some(local_sig_id) = sig_id.as_local() {
459-
match self.resolver.delegation_fn_sig(local_sig_id) {
460-
Some(sig) => {
461-
let parent = self.tcx.parent(sig_id);
462-
// HACK: we override the default safety instead of generating attributes from the ether.
463-
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
464-
// and here we need the hir attributes.
465-
let default_safety =
466-
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
467-
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
468-
{
469-
hir::Safety::Unsafe
470-
} else {
471-
hir::Safety::Safe
472-
};
473-
self.lower_fn_header(sig.header, default_safety, &[])
474-
}
475-
None => self.generate_header_error(),
476-
}
477-
} else {
478-
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
479-
let asyncness = match self.tcx.asyncness(sig_id) {
480-
Asyncness::Yes => hir::IsAsync::Async(span),
481-
Asyncness::No => hir::IsAsync::NotAsync,
482-
};
483-
hir::FnHeader {
484-
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
485-
hir::HeaderSafety::SafeTargetFeatures
486-
} else {
487-
hir::HeaderSafety::Normal(sig.safety)
488-
},
489-
constness: self.tcx.constness(sig_id),
490-
asyncness,
491-
abi: sig.abi,
492-
}
328+
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
329+
let asyncness = match self.tcx.asyncness(sig_id) {
330+
Asyncness::Yes => hir::IsAsync::Async(span),
331+
Asyncness::No => hir::IsAsync::NotAsync,
332+
};
333+
334+
let header = hir::FnHeader {
335+
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
336+
hir::HeaderSafety::SafeTargetFeatures
337+
} else {
338+
hir::HeaderSafety::Normal(sig.safety)
339+
},
340+
constness: self.tcx.constness(sig_id),
341+
asyncness,
342+
abi: sig.abi,
493343
};
494344

495345
hir::FnSig { decl, header, span }

0 commit comments

Comments
 (0)