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 rust-lang/rust#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.
This commit is contained in:
bors
2026-03-20 10:56:01 +00:00
21 changed files with 398 additions and 454 deletions
+47 -197
View File
@@ -45,16 +45,15 @@
use rustc_abi::ExternAbi;
use rustc_ast as ast;
use rustc_ast::*;
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::attrs::{AttributeKind, InlineAttr};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs};
use rustc_middle::ty::Asyncness;
use rustc_span::symbol::kw;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
use rustc_span::{Ident, Span, Symbol};
use smallvec::SmallVec;
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
@@ -80,7 +79,7 @@ struct AttrAdditionInfo {
enum AttrAdditionKind {
Default { factory: fn(Span) -> hir::Attribute },
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
}
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
@@ -97,7 +96,6 @@ enum AttrAdditionKind {
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
},
flag: DelegationFnSigAttrs::MUST_USE,
},
},
AttrAdditionInfo {
@@ -108,43 +106,11 @@ enum AttrAdditionKind {
},
];
type DelegationIdsVec = SmallVec<[DefId; 1]>;
// As delegations can now refer to another delegation, we have a delegation path
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
struct DelegationIds {
path: DelegationIdsVec,
}
impl DelegationIds {
fn new(path: DelegationIdsVec) -> Self {
assert!(!path.is_empty());
Self { path }
}
// Id of the first function in (non)local crate that is being reused
fn root_function_id(&self) -> DefId {
*self.path.last().expect("Ids vector can't be empty")
}
// Id of the first definition which is being reused,
// can be either function, in this case `root_id == delegee_id`, or other delegation
fn delegee_id(&self) -> DefId {
*self.path.first().expect("Ids vector can't be empty")
}
}
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
fn is_method(&self, def_id: DefId, span: Span) -> bool {
match self.tcx.def_kind(def_id) {
DefKind::Fn => false,
DefKind::AssocFn => match def_id.as_local() {
Some(local_def_id) => {
self.resolver.delegation_fn_sig(local_def_id).is_some_and(|sig| sig.has_self)
}
None => self.tcx.associated_item(def_id).is_method(),
},
DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
_ => span_bug!(span, "unexpected DefKind for delegation item"),
}
}
@@ -157,10 +123,10 @@ pub(crate) fn lower_delegation(
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
let ids = if let Some(delegation_info) =
let sig_id = if let Some(delegation_info) =
self.resolver.delegation_info(self.local_def_id(item_id))
{
self.get_delegation_ids(delegation_info.resolution_node, span)
self.get_sig_id(delegation_info.resolution_node, span)
} else {
return self.generate_delegation_error(
self.dcx().span_delayed_bug(
@@ -172,28 +138,16 @@ pub(crate) fn lower_delegation(
);
};
match ids {
Ok(ids) => {
self.add_attrs_if_needed(span, &ids);
match sig_id {
Ok(sig_id) => {
self.add_attrs_if_needed(span, sig_id);
let delegee_id = ids.delegee_id();
let root_function_id = ids.root_function_id();
let is_method = self.is_method(sig_id, span);
// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
// if the original function is not a method (without `self`), then it can not be added
// during chain of reuses, so we use `root_function_id` here
let is_method = self.is_method(root_function_id, span);
let (param_count, c_variadic) = self.param_count(sig_id);
// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
// we need a function to extract this information
let (param_count, c_variadic) = self.param_count(root_function_id);
let mut generics = self.lower_delegation_generics(
delegation,
ids.root_function_id(),
item_id,
span,
);
let mut generics =
self.lower_delegation_generics(delegation, sig_id, item_id, span);
let body_id = self.lower_delegation_body(
delegation,
@@ -204,20 +158,10 @@ pub(crate) fn lower_delegation(
span,
);
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
// inheritance, and we want this id to point on a delegee, not on the original
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
let decl = self.lower_delegation_decl(
delegee_id,
param_count,
c_variadic,
span,
&generics,
);
let decl =
self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
// from the root function that started delegation
let sig = self.lower_delegation_sig(root_function_id, decl, span);
let sig = self.lower_delegation_sig(sig_id, decl, span);
let ident = self.lower_ident(delegation.ident);
let generics = self.arena.alloc(hir::Generics {
@@ -236,9 +180,9 @@ pub(crate) fn lower_delegation(
}
}
fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
let new_attrs =
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));
if new_attrs.is_empty() {
return;
@@ -258,15 +202,9 @@ fn create_new_attrs(
&self,
candidate_additions: &[AttrAdditionInfo],
span: Span,
ids: &DelegationIds,
sig_id: DefId,
existing_attrs: Option<&&[hir::Attribute]>,
) -> Vec<hir::Attribute> {
let defs_orig_attrs = ids
.path
.iter()
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
.collect::<Vec<_>>();
candidate_additions
.iter()
.filter_map(|addition_info| {
@@ -280,83 +218,22 @@ fn create_new_attrs(
match addition_info.kind {
AttrAdditionKind::Default { factory } => Some(factory(span)),
AttrAdditionKind::Inherit { flag, factory } => {
for (def_id, orig_attrs) in &defs_orig_attrs {
let original_attr = match def_id.as_local() {
Some(local_id) => self
.get_attrs(local_id)
.flags
.contains(flag)
.then(|| {
orig_attrs
.as_ref()
.map(|attrs| {
attrs.iter().find(|base_attr| {
(addition_info.equals)(base_attr)
})
})
.flatten()
})
.flatten(),
None =>
{
#[allow(deprecated)]
self.tcx
.get_all_attrs(*def_id)
.iter()
.find(|base_attr| (addition_info.equals)(base_attr))
}
};
if let Some(original_attr) = original_attr {
return Some(factory(span, original_attr));
}
}
None
AttrAdditionKind::Inherit { factory, .. } =>
{
#[allow(deprecated)]
self.tcx
.get_all_attrs(sig_id)
.iter()
.find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
}
}
})
.collect::<Vec<_>>()
}
fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
if let Some(local_id) = def_id.as_local() {
let attrs = &self.get_attrs(local_id).to_inherit;
if !attrs.is_empty() {
return Some(AttributeParser::parse_limited_all(
self.tcx.sess,
attrs,
None,
hir::Target::Fn,
DUMMY_SP,
DUMMY_NODE_ID,
Some(self.tcx.features()),
ShouldEmit::Nothing,
));
}
}
None
}
fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
// local_id can correspond either to a function or other delegation
if let Some(fn_sig) = self.resolver.delegation_fn_sig(local_id) {
&fn_sig.attrs
} else {
&self.resolver.delegation_info(local_id).expect("processing delegation").attrs
}
}
fn get_delegation_ids(
&self,
mut node_id: NodeId,
span: Span,
) -> Result<DelegationIds, ErrorGuaranteed> {
fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
let mut visited: FxHashSet<NodeId> = Default::default();
let mut path: DelegationIdsVec = Default::default();
let mut path: SmallVec<[DefId; 1]> = Default::default();
loop {
visited.insert(node_id);
@@ -389,7 +266,7 @@ fn get_delegation_ids(
});
}
} else {
return Ok(DelegationIds::new(path));
return Ok(path[0]);
}
}
}
@@ -400,15 +277,8 @@ fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
// Function parameter count, including C variadic `...` if present.
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
if let Some(local_sig_id) = def_id.as_local() {
match self.resolver.delegation_fn_sig(local_sig_id) {
Some(sig) => (sig.param_count, sig.c_variadic),
None => (0, false),
}
} else {
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
}
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
}
fn lower_delegation_decl(
@@ -455,41 +325,21 @@ fn lower_delegation_sig(
decl: &'hir hir::FnDecl<'hir>,
span: Span,
) -> hir::FnSig<'hir> {
let header = if let Some(local_sig_id) = sig_id.as_local() {
match self.resolver.delegation_fn_sig(local_sig_id) {
Some(sig) => {
let parent = self.tcx.parent(sig_id);
// HACK: we override the default safety instead of generating attributes from the ether.
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
// and here we need the hir attributes.
let default_safety =
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
{
hir::Safety::Unsafe
} else {
hir::Safety::Safe
};
self.lower_fn_header(sig.header, default_safety, &[])
}
None => self.generate_header_error(),
}
} else {
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
let asyncness = match self.tcx.asyncness(sig_id) {
Asyncness::Yes => hir::IsAsync::Async(span),
Asyncness::No => hir::IsAsync::NotAsync,
};
hir::FnHeader {
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
hir::HeaderSafety::SafeTargetFeatures
} else {
hir::HeaderSafety::Normal(sig.safety)
},
constness: self.tcx.constness(sig_id),
asyncness,
abi: sig.abi,
}
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
let asyncness = match self.tcx.asyncness(sig_id) {
Asyncness::Yes => hir::IsAsync::Async(span),
Asyncness::No => hir::IsAsync::NotAsync,
};
let header = hir::FnHeader {
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
hir::HeaderSafety::SafeTargetFeatures
} else {
hir::HeaderSafety::Normal(sig.safety)
},
constness: self.tcx.constness(sig_id),
asyncness,
abi: sig.abi,
};
hir::FnSig { decl, header, span }
@@ -7,10 +7,10 @@
use rustc_middle::{bug, ty};
use rustc_span::sym::{self};
use rustc_span::symbol::kw;
use rustc_span::{DUMMY_SP, Ident, Span};
use rustc_span::{Ident, Span};
use thin_vec::{ThinVec, thin_vec};
use crate::{AstOwner, LoweringContext, ResolverAstLoweringExt};
use crate::{LoweringContext, ResolverAstLoweringExt};
pub(super) enum DelegationGenerics<T> {
/// User-specified args are present: `reuse foo::<String>;`.
@@ -240,7 +240,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
pub(super) fn lower_delegation_generics(
&mut self,
delegation: &Delegation,
root_fn_id: DefId,
sig_id: DefId,
item_id: NodeId,
span: Span,
) -> GenericsGenerationResults<'hir> {
@@ -258,7 +258,7 @@ pub(super) fn lower_delegation_generics(
// we will take those args that are in trait impl header trait ref.
let parent = GenericsGenerationResult::new(DelegationGenerics::Default(None));
let generics = self.get_fn_like_generics(root_fn_id, span);
let generics = self.get_external_generics(sig_id, false, span);
let child = DelegationGenerics::TraitImpl(generics, child_user_specified);
let child = GenericsGenerationResult::new(child);
@@ -269,17 +269,12 @@ pub(super) fn lower_delegation_generics(
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
let root_function_in_trait =
matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait);
matches!(self.tcx.def_kind(self.tcx.parent(sig_id)), DefKind::Trait);
let generate_self = delegation_in_free_ctx && root_function_in_trait;
let parent_generics_factory = |this: &mut Self, user_specified: bool| {
this.get_parent_generics(
this.tcx.parent(root_fn_id),
generate_self,
user_specified,
span,
)
this.get_parent_generics(this.tcx.parent(sig_id), generate_self, user_specified, span)
};
let can_add_generics_to_parent = len >= 2
@@ -304,7 +299,7 @@ pub(super) fn lower_delegation_generics(
let child_generics = if child_user_specified {
DelegationGenerics::UserSpecified
} else {
DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span))
DelegationGenerics::Default(self.get_external_generics(sig_id, false, span))
};
GenericsGenerationResults {
@@ -363,11 +358,9 @@ fn lower_delegation_generic_params(
// FIXME(fn_delegation): proper support for late bound lifetimes.
self.arena.alloc(hir::Generics {
params,
predicates: self.arena.alloc_from_iter(
params
.iter()
.filter_map(|p| p.is_lifetime().then(|| self.generate_lifetime_predicate(p))),
),
predicates: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
})),
has_where_clause_predicates: false,
where_clause_span: span,
span,
@@ -377,6 +370,7 @@ fn lower_delegation_generic_params(
fn generate_lifetime_predicate(
&mut self,
p: &hir::GenericParam<'hir>,
span: Span,
) -> hir::WherePredicate<'hir> {
let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime {
this.arena.alloc(hir::Lifetime {
@@ -392,7 +386,7 @@ fn generate_lifetime_predicate(
hir::WherePredicate {
hir_id: self.next_id(),
span: DUMMY_SP,
span,
kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate(
hir::WhereRegionPredicate {
in_where_clause: true,
@@ -479,22 +473,6 @@ fn create_generics_args_from_params(
})
}
fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option<Generics> {
if let Some(local_id) = id.as_local() {
match self.ast_index.get(local_id) {
Some(AstOwner::Item(item)) if let ItemKind::Fn(f) = &item.kind => {
Some(f.generics.clone())
}
Some(AstOwner::AssocItem(item, _)) if let AssocItemKind::Fn(f) = &item.kind => {
Some(f.generics.clone())
}
_ => None,
}
} else {
self.get_external_generics(id, false, span)
}
}
fn get_external_generics(
&mut self,
id: DefId,
@@ -519,7 +497,7 @@ fn get_external_generics(
bounds: Default::default(),
colon_span: None,
id: self.next_node_id(),
ident: Ident::with_dummy_span(p.name),
ident: Ident::new(p.name, span),
is_placeholder: false,
kind: match p.kind {
GenericParamDefKind::Lifetime => GenericParamKind::Lifetime,
@@ -531,7 +509,7 @@ fn get_external_generics(
})
.collect(),
where_clause: Default::default(),
span: DUMMY_SP,
span,
})
}
@@ -563,18 +541,18 @@ fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericPara
None,
Path {
segments: thin_vec![PathSegment {
ident: Ident::with_dummy_span(type_symbol),
ident: Ident::new(type_symbol, span),
id: self.next_node_id(),
args: None
}],
span: DUMMY_SP,
span,
tokens: None,
},
),
span: DUMMY_SP,
span,
tokens: None,
}),
span: DUMMY_SP,
span,
default: None,
}
}
@@ -587,28 +565,15 @@ fn get_parent_generics(
span: Span,
) -> Option<Generics> {
// If args are user-specified we still maybe need to add self.
let mut generics = if user_specified {
None
} else {
if let Some(local_id) = id.as_local() {
if let Some(AstOwner::Item(item)) = self.ast_index.get(local_id)
&& matches!(item.kind, ItemKind::Trait(..))
{
item.opt_generics().cloned()
} else {
None
}
} else {
self.get_external_generics(id, true, span)
}
};
let mut generics =
if user_specified { None } else { self.get_external_generics(id, true, span) };
if add_self {
generics.get_or_insert_default().params.insert(
0,
GenericParam {
id: self.next_node_id(),
ident: Ident::new(kw::SelfUpper, DUMMY_SP),
ident: Ident::new(kw::SelfUpper, span),
attrs: Default::default(),
bounds: vec![],
is_placeholder: false,
+25 -4
View File
@@ -3,6 +3,7 @@
use rustc_abi::ExternAbi;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
use rustc_hir::def::{DefKind, PerNS, Res};
@@ -27,11 +28,31 @@
RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
};
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
/// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR
/// lowering of delegations (`lower_delayed_owner`),
/// in this case we can not modify already created IndexVec, so we use other map.
pub(super) enum Owners<'a, 'hir> {
IndexVec(&'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>),
Map(&'a mut FxIndexMap<LocalDefId, hir::MaybeOwner<'hir>>),
}
impl<'hir> Owners<'_, 'hir> {
fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
match self {
Owners::IndexVec(index_vec) => {
index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)
}
Owners::Map(map) => map.entry(def_id).or_insert(hir::MaybeOwner::Phantom),
}
}
}
pub(super) struct ItemLowerer<'a, 'hir, R> {
pub(super) tcx: TyCtxt<'hir>,
pub(super) resolver: &'a mut R,
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
pub(super) owners: Owners<'a, 'hir>,
}
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
@@ -59,11 +80,11 @@ fn with_lctx(
owner: NodeId,
f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>,
) {
let mut lctx = LoweringContext::new(self.tcx, self.ast_index, self.resolver);
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
for (def_id, info) in lctx.children {
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
let owner = self.owners.get_or_insert_mut(def_id);
assert!(
matches!(owner, hir::MaybeOwner::Phantom),
"duplicate copy of {def_id:?} in lctx.children"
@@ -73,7 +94,7 @@ fn with_lctx(
}
pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
let owner = self.owners.get_or_insert_mut(def_id);
if let hir::MaybeOwner::Phantom = owner {
let node = self.ast_index[def_id];
match node {
+129 -42
View File
@@ -42,9 +42,10 @@
use rustc_ast::{self as ast, *};
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::spawn;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
@@ -57,8 +58,9 @@
};
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_macros::extension;
use rustc_middle::hir::{self as mid_hir};
use rustc_middle::span_bug;
use rustc_middle::ty::{DelegationFnSig, DelegationInfo, ResolverAstLowering, TyCtxt};
use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt};
use rustc_session::parse::add_feature_diagnostics;
use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
@@ -67,6 +69,7 @@
use tracing::{debug, instrument, trace};
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
use crate::item::Owners;
macro_rules! arena_vec {
($this:expr; $($x:expr),*) => (
@@ -89,15 +92,6 @@ macro_rules! arena_vec {
struct LoweringContext<'a, 'hir, R> {
tcx: TyCtxt<'hir>,
// During lowering of delegation we need to access AST of other functions
// in order to properly propagate generics, we could have done it at resolve
// stage, however it will require either to firstly identify functions that
// are being reused and store their generics, or to store generics of all functions
// in resolver. This approach helps with those problems, as functions that are reused
// will be in AST index.
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
resolver: &'a mut R,
disambiguator: DisambiguatorState,
@@ -159,15 +153,10 @@ struct LoweringContext<'a, 'hir, R> {
}
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
fn new(
tcx: TyCtxt<'hir>,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
resolver: &'a mut R,
) -> Self {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
Self {
tcx,
ast_index,
resolver,
disambiguator: DisambiguatorState::new(),
arena: tcx.hir_arena,
@@ -247,8 +236,81 @@ fn lower(&self, span: Span) -> Span {
}
}
// LoweringContext now uses this trait for #153489, if #153489 is not merged,
// feel free to do whatever you want with this trait.
struct ResolverDelayedAstLowering<'a, 'tcx> {
node_id_to_def_id: NodeMap<LocalDefId>,
partial_res_map: NodeMap<PartialRes>,
next_node_id: NodeId,
base: &'a ResolverAstLowering<'tcx>,
}
// FIXME(fn_delegation): delegate this trait impl to `self.base`
impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> {
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
self.base.legacy_const_generic_args(expr, tcx)
}
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id))
}
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
self.base.get_import_res(id)
}
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
self.base.get_label_res(id)
}
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
self.base.get_lifetime_res(id)
}
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
self.base.extra_lifetime_params(id)
}
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
self.base.delegation_info(id)
}
fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id))
}
fn local_def_id(&self, id: NodeId) -> LocalDefId {
self.opt_local_def_id(id).expect("must have def_id")
}
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
self.base.lifetime_elision_allowed(id)
}
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
self.node_id_to_def_id.insert(node_id, def_id);
}
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
self.partial_res_map.insert(node_id, res);
}
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
self.base.trait_candidates(node_id)
}
#[inline]
fn next_node_id(&mut self) -> NodeId {
next_node_id(&mut self.next_node_id)
}
}
fn next_node_id(current_id: &mut NodeId) -> NodeId {
let start = *current_id;
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
*current_id = ast::NodeId::from_u32(next);
start
}
#[extension(trait ResolverAstLoweringExt<'tcx>)]
impl<'tcx> ResolverAstLowering<'tcx> {
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
@@ -309,10 +371,6 @@ fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>
self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
}
fn delegation_fn_sig(&self, id: LocalDefId) -> Option<&DelegationFnSig> {
self.delegation_fn_sigs.get(&id)
}
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
self.delegation_infos.get(&id)
}
@@ -343,11 +401,7 @@ fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate
#[inline]
fn next_node_id(&mut self) -> NodeId {
let start = self.next_node_id;
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
self.next_node_id = ast::NodeId::from_u32(next);
start
next_node_id(&mut self.next_node_id)
}
}
@@ -555,8 +609,7 @@ fn compute_hir_hash(
})
}
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
let sess = tcx.sess;
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
// Queries that borrow `resolver_for_lowering`.
tcx.ensure_done().output_filenames(());
tcx.ensure_done().early_lint_checks(());
@@ -574,26 +627,60 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
tcx,
resolver: &mut resolver,
ast_index: &ast_index,
owners: &mut owners,
owners: Owners::IndexVec(&mut owners),
};
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
for def_id in ast_index.indices() {
lowerer.lower_node(def_id);
match &ast_index[def_id] {
AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
delayed_ids.insert(def_id);
}
_ => lowerer.lower_node(def_id),
};
}
drop(ast_index);
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
let prof = sess.prof.clone();
spawn(move || {
let _timer = prof.verbose_generic_activity("drop_ast");
drop(krate);
});
// Don't hash unless necessary, because it's expensive.
let opt_hir_hash =
if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
hir::Crate { owners, opt_hir_hash }
let delayed_resolver = Steal::new((resolver, krate));
mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)
}
/// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way.
pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let krate = tcx.hir_crate(());
let (resolver, krate) = &*krate.delayed_resolver.borrow();
// FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
// as it is too bad to reindex whole crate on each delegation lowering.
let ast_index = index_crate(resolver, krate);
let mut resolver = ResolverDelayedAstLowering {
next_node_id: resolver.next_node_id,
partial_res_map: Default::default(),
node_id_to_def_id: Default::default(),
base: resolver,
};
let mut map = Default::default();
let mut lowerer = item::ItemLowerer {
tcx,
resolver: &mut resolver,
ast_index: &ast_index,
owners: Owners::Map(&mut map),
};
lowerer.lower_node(def_id);
for (&child_def_id, &owner) in &map {
tcx.feed_delayed_owner(child_def_id, owner);
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
-13
View File
@@ -1667,19 +1667,6 @@ pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
}
}
/// The top-level data structure that stores the entire contents of
/// the crate currently being compiled.
///
/// For more details, see the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
pub owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
// Only present when incr. comp. is enabled.
pub opt_hir_hash: Option<Fingerprint>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Closure<'hir> {
pub def_id: LocalDefId,
+1 -8
View File
@@ -3,7 +3,7 @@
use crate::HashIgnoredAttrId;
use crate::hir::{
AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
AttributeMap, BodyId, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
};
use crate::hir_id::ItemLocalId;
use crate::lints::DelayedLints;
@@ -94,13 +94,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
let Crate { owners: _, opt_hir_hash } = self;
opt_hir_hash.unwrap().hash_stable(hcx, hasher)
}
}
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HashIgnoredAttrId {
fn hash_stable(&self, _hcx: &mut HirCtx, _hasher: &mut StableHasher) {
/* we don't hash HashIgnoredAttrId, we ignore them */
+5 -1
View File
@@ -21,7 +21,7 @@
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
use rustc_hir::definitions::Definitions;
use rustc_hir::limit::Limit;
use rustc_hir::{Attribute, find_attr};
use rustc_hir::{Attribute, MaybeOwner, find_attr};
use rustc_incremental::setup_dep_graph;
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
use rustc_metadata::EncodedMetadata;
@@ -878,6 +878,10 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
let providers = &mut Providers::default();
providers.queries.analysis = analysis;
providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir;
providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner;
// `delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom,
// as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId.
providers.queries.delayed_owner = |_, _| MaybeOwner::Phantom;
providers.queries.resolver_for_lowering_raw = resolver_for_lowering_raw;
providers.queries.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..];
providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
+19 -1
View File
@@ -7,7 +7,7 @@
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -1245,7 +1245,25 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
}
}
fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
let krate = tcx.hir_crate(());
for &id in &krate.delayed_ids {
tcx.ensure_done().lower_delayed_owner(id);
}
let (_, krate) = krate.delayed_resolver.steal();
let prof = tcx.sess.prof.clone();
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
spawn(move || {
let _timer = prof.verbose_generic_activity("drop_ast");
drop(krate);
});
}
pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
force_delayed_owners_lowering(tcx);
let mut collector = ItemCollector::new(tcx, true);
// A "crate collector" and "module collector" start at a
+73 -7
View File
@@ -6,19 +6,83 @@
pub mod nested_filter;
pub mod place;
use std::sync::Arc;
use rustc_ast::{self as ast};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::lints::DelayedLint;
use rustc_hir::*;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_span::{ErrorGuaranteed, ExpnId, Span};
use crate::query::Providers;
use crate::ty::TyCtxt;
use crate::ty::{ResolverAstLowering, TyCtxt};
/// The top-level data structure that stores the entire contents of
/// the crate currently being compiled.
///
/// For more details, see the [rustc dev guide].
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
// This field is private by intention, access it through `owner` method.
owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
// Ids of delayed AST owners which are lowered through `lower_delayed_owner` query.
pub delayed_ids: FxIndexSet<LocalDefId>,
// The resolver and AST crate which are set in the end of the `hir_crate` query
// and then stolen and dropped in `force_delayed_owners_lowering`.
pub delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
// Only present when incr. comp. is enabled.
pub opt_hir_hash: Option<Fingerprint>,
}
impl<'hir> Crate<'hir> {
pub fn new(
owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
delayed_ids: FxIndexSet<LocalDefId>,
delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
opt_hir_hash: Option<Fingerprint>,
) -> Crate<'hir> {
Crate { owners, delayed_ids, delayed_resolver, opt_hir_hash }
}
/// Serves as an entry point for getting `MaybeOwner`. As owner can either be in
/// `owners` of `hir_crate` or it can be delayed AST owner (i.e., delegations)
/// we need to firstly check in `hir_crate` and then delayed AST owners.
/// This method can be invoked when not all delayed AST owners are lowered.
pub fn owner(&self, tcx: TyCtxt<'hir>, def_id: LocalDefId) -> MaybeOwner<'hir> {
// Delayed LocalDefId can be in `self.owners` if there exists non-delayed LocalDefId
// which is greater than delayed LocalDefId, we use IndexVec for owners,
// so we will call ensure_contains_elem which will grow it.
if let Some(owner) = self.owners.get(def_id)
&& (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom))
{
return *owner;
}
if self.delayed_ids.contains(&def_id) {
tcx.ensure_done().lower_delayed_owner(def_id);
}
tcx.delayed_owner(def_id)
}
}
impl<HirCtx: HashStableContext> HashStable<HirCtx> for Crate<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
let Crate { opt_hir_hash, .. } = self;
opt_hir_hash.unwrap().hash_stable(hcx, hasher)
}
}
/// Gather the LocalDefId for each item-like within a module, including items contained within
/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
@@ -372,7 +436,9 @@ fn hir_owner_parent_impl(self, owner_id: OwnerId) -> HirId {
let parent_owner_id = self.local_def_id_to_hir_id(parent_def_id).owner;
HirId {
owner: parent_owner_id,
local_id: self.hir_crate(()).owners[parent_owner_id.def_id]
local_id: self
.hir_crate(())
.owner(self, parent_owner_id.def_id)
.unwrap()
.parenting
.get(&owner_id.def_id)
@@ -406,19 +472,19 @@ pub fn provide(providers: &mut Providers) {
providers.hir_crate_items = map::hir_crate_items;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) {
MaybeOwner::Owner(_) => HirId::make_owner(def_id),
MaybeOwner::NonOwner(hir_id) => hir_id,
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
};
providers.opt_hir_owner_nodes =
|tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
|tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes);
providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id);
providers.hir_attr_map = |tcx, id| {
tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
};
providers.opt_ast_lowering_delayed_lints =
|tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints);
|tcx, id| tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|o| &o.delayed_lints);
providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
providers.def_ident_span = |tcx, def_id| {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
@@ -459,6 +525,6 @@ pub fn provide(providers: &mut Providers) {
providers.expn_that_defined =
|tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
providers.in_scope_traits_map = |tcx, id| {
tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|owner_info| &owner_info.trait_map)
};
}
+12 -1
View File
@@ -68,7 +68,7 @@
CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
};
use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
use rustc_hir::{ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
use rustc_index::IndexVec;
use rustc_lint_defs::LintId;
use rustc_macros::rustc_queries;
@@ -82,6 +82,7 @@
use rustc_span::{DUMMY_SP, LocalExpnId, Span, Spanned, Symbol};
use rustc_target::spec::PanicStrategy;
use crate::hir::Crate;
use crate::infer::canonical::{self, Canonical};
use crate::lint::LintExpectation;
use crate::metadata::ModChild;
@@ -210,6 +211,16 @@
desc { "getting the crate HIR" }
}
query lower_delayed_owner(def_id: LocalDefId) {
eval_always
desc { "lowering the delayed AST owner `{}`", tcx.def_path_str(def_id) }
}
query delayed_owner(def_id: LocalDefId) -> hir::MaybeOwner<'tcx> {
feedable
desc { "getting child of lowered delayed AST owner `{}`", tcx.def_path_str(def_id) }
}
/// All items in the crate.
query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems {
arena_cache
+6 -1
View File
@@ -36,7 +36,7 @@
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::limit::Limit;
use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr};
use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, MaybeOwner, Node, TraitCandidate, find_attr};
use rustc_index::IndexVec;
use rustc_macros::Diagnostic;
use rustc_session::Session;
@@ -657,6 +657,11 @@ pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx,
debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
TyCtxtFeed { tcx: self, key }.type_of(value)
}
/// Feeds the HIR delayed owner during AST -> HIR delayed lowering.
pub fn feed_delayed_owner(self, key: LocalDefId, owner: MaybeOwner<'tcx>) {
TyCtxtFeed { tcx: self, key }.delayed_owner(owner);
}
}
impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
-29
View File
@@ -27,7 +27,6 @@
Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
};
use rustc_ast as ast;
use rustc_ast::AttrVec;
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
use rustc_ast::node_id::NodeMap;
pub use rustc_ast_ir::{Movability, Mutability, try_visit};
@@ -221,43 +220,15 @@ pub struct ResolverAstLowering<'tcx> {
/// Lints that were emitted by the resolver and early lints.
pub lint_buffer: Steal<LintBuffer>,
/// Information about functions signatures for delegation items expansion
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
// Information about delegations which is used when handling recursive delegations
pub delegation_infos: LocalDefIdMap<DelegationInfo>,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DelegationFnSigAttrs: u8 {
const TARGET_FEATURE = 1 << 0;
const MUST_USE = 1 << 1;
}
}
pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE;
#[derive(Debug)]
pub struct DelegationInfo {
// NodeId (either delegation.id or item_id in case of a trait impl) for signature resolution,
// for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914
pub resolution_node: ast::NodeId,
pub attrs: DelegationAttrs,
}
#[derive(Debug)]
pub struct DelegationAttrs {
pub flags: DelegationFnSigAttrs,
pub to_inherit: AttrVec,
}
#[derive(Debug)]
pub struct DelegationFnSig {
pub header: ast::FnHeader,
pub param_count: usize,
pub has_self: bool,
pub c_variadic: bool,
pub attrs: DelegationAttrs,
}
#[derive(Clone, Copy, Debug, HashStable)]
+15 -61
View File
@@ -29,10 +29,7 @@
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::ty::{
AssocTag, DELEGATION_INHERIT_ATTRS_START, DelegationAttrs, DelegationFnSig,
DelegationFnSigAttrs, DelegationInfo, Visibility,
};
use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CrateType, ResolveDocLinks};
use rustc_session::lint;
@@ -43,9 +40,9 @@
use tracing::{debug, instrument, trace};
use crate::{
BindingError, BindingKey, Decl, Finalize, IdentKey, LateDecl, Module, ModuleOrUniformRoot,
ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used,
errors, path_names_to_string, rustdoc,
BindingError, BindingKey, Decl, DelegationFnSig, Finalize, IdentKey, LateDecl, Module,
ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage,
TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc,
};
mod diagnostics;
@@ -3005,7 +3002,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
item.id,
LifetimeBinderKind::Function,
span,
|this| this.resolve_delegation(delegation, item.id, false, &item.attrs),
|this| this.resolve_delegation(delegation, item.id, false),
);
}
@@ -3351,7 +3348,7 @@ fn resolve_trait_items(&mut self, trait_items: &'ast [Box<AssocItem>]) {
item.id,
LifetimeBinderKind::Function,
delegation.path.segments.last().unwrap().ident.span,
|this| this.resolve_delegation(delegation, item.id, false, &item.attrs),
|this| this.resolve_delegation(delegation, item.id, false),
);
}
AssocItemKind::Type(box TyAlias { generics, .. }) => self
@@ -3665,7 +3662,7 @@ fn resolve_impl_item(
// Here we don't use `trait_id`, as we can process unresolved trait, however
// in this case we are still in a trait impl, https://github.com/rust-lang/rust/issues/150152
this.resolve_delegation(delegation, item.id, is_in_trait_impl, &item.attrs);
this.resolve_delegation(delegation, item.id, is_in_trait_impl);
},
);
}
@@ -3820,7 +3817,6 @@ fn resolve_delegation(
delegation: &'ast Delegation,
item_id: NodeId,
is_in_trait_impl: bool,
attrs: &[Attribute],
) {
self.smart_resolve_path(
delegation.id,
@@ -3838,7 +3834,6 @@ fn resolve_delegation(
self.r.delegation_infos.insert(
self.r.local_def_id(item_id),
DelegationInfo {
attrs: create_delegation_attrs(attrs),
resolution_node: if is_in_trait_impl { item_id } else { delegation.id },
},
);
@@ -5477,52 +5472,13 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
}
impl ItemInfoCollector<'_, '_, '_> {
fn collect_fn_info(
&mut self,
header: FnHeader,
decl: &FnDecl,
id: NodeId,
attrs: &[Attribute],
) {
self.r.delegation_fn_sigs.insert(
self.r.local_def_id(id),
DelegationFnSig {
header,
param_count: decl.inputs.len(),
has_self: decl.has_self(),
c_variadic: decl.c_variadic(),
attrs: create_delegation_attrs(attrs),
},
);
fn collect_fn_info(&mut self, decl: &FnDecl, id: NodeId) {
self.r
.delegation_fn_sigs
.insert(self.r.local_def_id(id), DelegationFnSig { has_self: decl.has_self() });
}
}
fn create_delegation_attrs(attrs: &[Attribute]) -> DelegationAttrs {
static NAMES_TO_FLAGS: &[(Symbol, DelegationFnSigAttrs)] = &[
(sym::target_feature, DelegationFnSigAttrs::TARGET_FEATURE),
(sym::must_use, DelegationFnSigAttrs::MUST_USE),
];
let mut to_inherit_attrs = AttrVec::new();
let mut flags = DelegationFnSigAttrs::empty();
'attrs_loop: for attr in attrs {
for &(name, flag) in NAMES_TO_FLAGS {
if attr.has_name(name) {
flags.set(flag, true);
if flag.bits() >= DELEGATION_INHERIT_ATTRS_START.bits() {
to_inherit_attrs.push(attr.clone());
}
continue 'attrs_loop;
}
}
}
DelegationAttrs { flags, to_inherit: to_inherit_attrs }
}
fn required_generic_args_suggestion(generics: &ast::Generics) -> Option<String> {
let required = generics
.params
@@ -5562,7 +5518,7 @@ fn visit_item(&mut self, item: &'ast Item) {
| ItemKind::Trait(box Trait { generics, .. })
| ItemKind::TraitAlias(box TraitAlias { generics, .. }) => {
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
self.collect_fn_info(&sig.decl, item.id);
}
let def_id = self.r.local_def_id(item.id);
@@ -5574,12 +5530,10 @@ fn visit_item(&mut self, item: &'ast Item) {
self.r.item_generics_num_lifetimes.insert(def_id, count);
}
ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => {
ItemKind::ForeignMod(ForeignMod { items, .. }) => {
for foreign_item in items {
if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind {
let new_header =
FnHeader { ext: Extern::from_abi(*abi, *extern_span), ..sig.header };
self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs);
self.collect_fn_info(&sig.decl, foreign_item.id);
}
}
}
@@ -5605,7 +5559,7 @@ fn visit_item(&mut self, item: &'ast Item) {
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
self.collect_fn_info(&sig.decl, item.id);
}
if let AssocItemKind::Type(box ast::TyAlias { generics, .. }) = &item.kind {
+7 -3
View File
@@ -65,8 +65,8 @@
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, DelegationFnSig, DelegationInfo, Feed, MainDefinition, RegisteredTools,
ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility,
self, DelegationInfo, Feed, MainDefinition, RegisteredTools, ResolverAstLowering,
ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility,
};
use rustc_session::config::CrateType;
use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
@@ -1157,6 +1157,11 @@ pub struct ResolverOutputs<'tcx> {
pub ast_lowering: ResolverAstLowering<'tcx>,
}
#[derive(Debug)]
struct DelegationFnSig {
pub has_self: bool,
}
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
@@ -1860,7 +1865,6 @@ pub fn into_outputs(self) -> ResolverOutputs<'tcx> {
trait_map: self.trait_map,
lifetime_elision_allowed: self.lifetime_elision_allowed,
lint_buffer: Steal::new(self.lint_buffer),
delegation_fn_sigs: self.delegation_fn_sigs,
delegation_infos: self.delegation_infos,
};
ResolverOutputs { global_ctxt, ast_lowering }
@@ -117,7 +117,7 @@ mod recursive {
fn foo<Self>(self: _, arg1: _) -> _ { <X as T>::foo(self + 1, arg1) }
#[attr = MustUse {reason: "some reason"}]
#[attr = Inline(Hint)]
fn bar(self: _, arg1: _) -> _ { foo(self + 1, arg1) }
fn bar<Self>(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) }
}
}
@@ -16,8 +16,8 @@ pub fn bounds<T: Clone>(_: T) {}
reuse to_reuse::bounds;
fn main() {
// FIXME(fn_delegation): proper support for late bound lifetimes.
late::<'static>(&0u8);
//~^ ERROR: function takes 0 lifetime arguments but 1 lifetime argument was supplied
struct S;
bounds(S);
@@ -1,3 +1,17 @@
error[E0107]: function takes 0 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/free-fn-to-free-fn.rs:19:5
|
LL | late::<'static>(&0u8);
| ^^^^----------- help: remove the unnecessary generics
| |
| expected 0 lifetime arguments
|
note: function defined here, with 0 lifetime parameters
--> $DIR/free-fn-to-free-fn.rs:15:17
|
LL | reuse to_reuse::late;
| ^^^^
error[E0277]: the trait bound `S: Clone` is not satisfied
--> $DIR/free-fn-to-free-fn.rs:23:12
|
@@ -20,6 +34,7 @@ LL + #[derive(Clone)]
LL | struct S;
|
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0107, E0277.
For more information about an error, try `rustc --explain E0107`.
@@ -23,7 +23,6 @@ LL | reuse <u8 as Trait<_>>::foo as generic_arguments2;
| ^^^
| |
| expected `&u8`, found `&Self`
| found this type parameter
| arguments to this function are incorrect
|
= note: expected reference `&u8`
@@ -537,10 +537,8 @@ LL | bar::<1, 2, 3, 4, 5, 6>();
note: function defined here, with 3 generic parameters: `T`, `U`, `N`
--> $DIR/generics-gen-args-errors.rs:8:18
|
LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
| - - --------------
LL | reuse foo as bar;
| ^^^
| --- ^^^
error[E0107]: function takes 2 lifetime arguments but 5 lifetime arguments were supplied
--> $DIR/generics-gen-args-errors.rs:17:9
@@ -553,10 +551,8 @@ LL | bar::<'static, 'static, 'static, 'static, 'static>();
note: function defined here, with 2 lifetime parameters: `'a`, `'b`
--> $DIR/generics-gen-args-errors.rs:8:18
|
LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
| -- --
LL | reuse foo as bar;
| ^^^
| --- ^^^
error[E0747]: constant provided when a type was expected
--> $DIR/generics-gen-args-errors.rs:20:23
@@ -575,10 +571,8 @@ LL | bar::<_, _, _, _, _>();
note: function defined here, with 3 generic parameters: `T`, `U`, `N`
--> $DIR/generics-gen-args-errors.rs:8:18
|
LL | fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
| - - --------------
LL | reuse foo as bar;
| ^^^
| --- ^^^
error[E0747]: unresolved item provided when a constant was expected
--> $DIR/generics-gen-args-errors.rs:28:25
@@ -1,11 +1,11 @@
error[E0107]: function takes at most 2 generic arguments but 3 generic arguments were supplied
--> $DIR/trait-impl-wrong-args-count.rs:25:25
|
LL | fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
| ----------------- help: remove the unnecessary generic argument
...
LL | reuse to_reuse::bar;
| ^^^ expected at most 2 generic arguments
| ^^^
| |
| expected at most 2 generic arguments
| help: remove the unnecessary generic argument
|
note: function defined here, with at most 2 generic parameters: `A`, `B`
--> $DIR/trait-impl-wrong-args-count.rs:7:16
@@ -138,11 +138,11 @@ LL | reuse <X as Trait1::<(), ()>>::foo as bar2;
error[E0107]: associated function takes at most 2 generic arguments but 3 generic arguments were supplied
--> $DIR/trait-impl-wrong-args-count.rs:105:40
|
LL | fn bar3<X, Y, Z>() {}
| --- help: remove the unnecessary generic argument
...
LL | reuse <X as Trait1::<(), ()>>::foo as bar3;
| ^^^ expected at most 2 generic arguments
| ^^^
| |
| expected at most 2 generic arguments
| help: remove the unnecessary generic argument
|
note: associated function defined here, with at most 2 generic parameters: `X`, `Y`
--> $DIR/trait-impl-wrong-args-count.rs:88:12
+8 -8
View File
@@ -116,14 +116,6 @@ LL | #[pin_v2]
|
= help: `#[pin_v2]` can only be applied to data types
error: `#[pin_v2]` attribute cannot be used on delegations
--> $DIR/pin_v2-attr.rs:58:5
|
LL | #[pin_v2]
| ^^^^^^^^^
|
= help: `#[pin_v2]` can only be applied to data types
error: `#[pin_v2]` attribute cannot be used on inherent methods
--> $DIR/pin_v2-attr.rs:61:5
|
@@ -308,5 +300,13 @@ LL | #[pin_v2]
|
= help: `#[pin_v2]` can only be applied to data types
error: `#[pin_v2]` attribute cannot be used on delegations
--> $DIR/pin_v2-attr.rs:58:5
|
LL | #[pin_v2]
| ^^^^^^^^^
|
= help: `#[pin_v2]` can only be applied to data types
error: aborting due to 39 previous errors