From 5c441e6ce6453863e082ae26508958ffc1966e40 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Fri, 20 Mar 2026 12:31:48 +0300 Subject: [PATCH] ty-aware delayed AST -> HIR lowering --- compiler/rustc_ast_lowering/src/delegation.rs | 244 ++++-------------- .../src/delegation/generics.rs | 77 ++---- compiler/rustc_ast_lowering/src/item.rs | 29 ++- compiler/rustc_ast_lowering/src/lib.rs | 171 +++++++++--- compiler/rustc_hir/src/hir.rs | 13 - compiler/rustc_hir/src/stable_hash_impls.rs | 9 +- compiler/rustc_interface/src/passes.rs | 6 +- compiler/rustc_middle/src/hir/map.rs | 20 +- compiler/rustc_middle/src/hir/mod.rs | 80 +++++- compiler/rustc_middle/src/queries.rs | 13 +- compiler/rustc_middle/src/ty/context.rs | 7 +- compiler/rustc_middle/src/ty/mod.rs | 29 --- compiler/rustc_resolve/src/late.rs | 76 ++---- compiler/rustc_resolve/src/lib.rs | 10 +- tests/pretty/delegation-inherit-attributes.pp | 2 +- .../delegation/generics/free-fn-to-free-fn.rs | 2 +- .../generics/free-fn-to-free-fn.stderr | 19 +- .../generics/free-fn-to-trait-infer.stderr | 1 - .../generics/generics-gen-args-errors.stderr | 12 +- .../trait-impl-wrong-args-count.stderr | 16 +- tests/ui/pin-ergonomics/pin_v2-attr.stderr | 16 +- 21 files changed, 398 insertions(+), 454 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index f2589ed198add..0044913721f1f 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -45,16 +45,15 @@ use hir::{BodyId, HirId}; 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 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[ hir::Attribute::Parsed(AttributeKind::MustUse { span, reason }) }, - flag: DelegationFnSigAttrs::MUST_USE, }, }, AttrAdditionInfo { @@ -108,43 +106,11 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[ }, ]; -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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { ); }; - match ids { - Ok(ids) => { - self.add_attrs_if_needed(span, &ids); - - let delegee_id = ids.delegee_id(); - let root_function_id = ids.root_function_id(); + match sig_id { + Ok(sig_id) => { + self.add_attrs_if_needed(span, sig_id); - // `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 is_method = self.is_method(sig_id, span); - // 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 (param_count, c_variadic) = self.param_count(sig_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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { } } - 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { &self, candidate_additions: &[AttrAdditionInfo], span: Span, - ids: &DelegationIds, + sig_id: DefId, existing_attrs: Option<&&[hir::Attribute]>, ) -> Vec { - let defs_orig_attrs = ids - .path - .iter() - .map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id))) - .collect::>(); - candidate_additions .iter() .filter_map(|addition_info| { @@ -280,83 +218,22 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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::>() } - fn parse_local_original_attrs(&self, def_id: DefId) -> Option> { - 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 { + fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result { let mut visited: FxHashSet = 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { }); } } else { - return Ok(DelegationIds::new(path)); + return Ok(path[0]); } } } @@ -400,15 +277,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 } diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index b4564cc81dfcd..d6d8819d8c474 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -7,10 +7,10 @@ use rustc_middle::ty::GenericParamDefKind; 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 { /// User-specified args are present: `reuse foo::;`. @@ -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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { !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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { }) } - fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option { - 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { }) .collect(), where_clause: Default::default(), - span: DUMMY_SP, + span, }) } @@ -563,18 +541,18 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { span: Span, ) -> Option { // 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, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 87d2483bf4738..fa103099e643f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,6 +3,7 @@ use std::mem; 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 @@ use super::{ 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>), + Map(&'a mut FxIndexMap>), +} + +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>, - pub(super) owners: &'a mut IndexVec>, + 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> { 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 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> { } 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 { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index eafa30b4e86cf..a073b81a0dcb4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -42,9 +42,10 @@ use rustc_ast::node_id::NodeMap; 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_hir::{ }; 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 thin_vec::ThinVec; 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 @@ pub mod stability; 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>, - 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>, - 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 @@ impl SpanLowerer { } } -// 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, + partial_res_map: NodeMap, + 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> { + self.base.legacy_const_generic_args(expr, tcx) + } + + fn get_partial_res(&self, id: NodeId) -> Option { + self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id)) + } + + fn get_import_res(&self, id: NodeId) -> PerNS>> { + self.base.get_import_res(id) + } + + fn get_label_res(&self, id: NodeId) -> Option { + self.base.get_label_res(id) + } + + fn get_lifetime_res(&self, id: NodeId) -> Option { + 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 { + 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> { @@ -309,10 +371,6 @@ impl<'tcx> ResolverAstLowering<'tcx> { 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 @@ impl<'tcx> ResolverAstLowering<'tcx> { #[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 = 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)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 7cce0eda4dda7..9526143fcace5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1667,19 +1667,6 @@ impl<'tcx> MaybeOwner<'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>, - // Only present when incr. comp. is enabled. - pub opt_hir_hash: Option, -} - #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Closure<'hir> { pub def_id: LocalDefId, diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index a3f4415ec343d..58649a694880b 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -3,7 +3,7 @@ use rustc_span::def_id::DefPathHash; 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 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable for AttributeMap } } -impl HashStable 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 HashStable for HashIgnoredAttrId { fn hash_stable(&self, _hcx: &mut HirCtx, _hasher: &mut StableHasher) { /* we don't hash HashIgnoredAttrId, we ignore them */ diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index cf62d4223211a..6b7f31521d441 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -21,7 +21,7 @@ use rustc_hir::attrs::AttributeKind; 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 static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { 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; diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index fc2a7fbd4fa9c..499c6dae060bf 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -7,7 +7,7 @@ use rustc_ast::visit::{VisitorResult, walk_list}; 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 diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 82f8eb4bbc4a1..ad56e462d2934 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -6,19 +6,83 @@ pub mod map; 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>, + // Ids of delayed AST owners which are lowered through `lower_delayed_owner` query. + pub delayed_ids: FxIndexSet, + // 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)>, + // Only present when incr. comp. is enabled. + pub opt_hir_hash: Option, +} + +impl<'hir> Crate<'hir> { + pub fn new( + owners: IndexVec>, + delayed_ids: FxIndexSet, + delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc)>, + opt_hir_hash: Option, + ) -> 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 HashStable 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 @@ impl<'tcx> TyCtxt<'tcx> { 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) }; } diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 4dd68db4f9135..255adf509c693 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -68,7 +68,7 @@ use rustc_hir::def_id::{ 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::def_id::LOCAL_CRATE; 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 @@ rustc_queries! { 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 diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 56428780d22da..58a2edca8ecef 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -36,7 +36,7 @@ use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; 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 @@ impl<'tcx> TyCtxt<'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> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d35b755b3193f..f072b26e26917 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,6 @@ use rustc_abi::{ 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, - /// Information about functions signatures for delegation items expansion - pub delegation_fn_sigs: LocalDefIdMap, // Information about delegations which is used when handling recursive delegations pub delegation_infos: LocalDefIdMap, } -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)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 453fe9d7a8e0e..02412394d657e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -29,10 +29,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par 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 thin_vec::ThinVec; 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; @@ -2989,7 +2986,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { item.id, LifetimeBinderKind::Function, span, - |this| this.resolve_delegation(delegation, item.id, false, &item.attrs), + |this| this.resolve_delegation(delegation, item.id, false), ); } @@ -3335,7 +3332,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { 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 @@ -3649,7 +3646,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // 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); }, ); } @@ -3804,7 +3801,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { delegation: &'ast Delegation, item_id: NodeId, is_in_trait_impl: bool, - attrs: &[Attribute], ) { self.smart_resolve_path( delegation.id, @@ -3822,7 +3818,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { 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 }, }, ); @@ -5433,50 +5428,11 @@ 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 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; - } - } + 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() }); } - - DelegationAttrs { flags, to_inherit: to_inherit_attrs } } fn required_generic_args_suggestion(generics: &ast::Generics) -> Option { @@ -5518,7 +5474,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | 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); @@ -5530,12 +5486,10 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { 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); } } } @@ -5561,7 +5515,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { 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 { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7c942191d467f..c18dfb3e56fe3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -65,8 +65,8 @@ use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; 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. @@ -1856,7 +1861,6 @@ impl<'ra, 'tcx> Resolver<'ra, '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 } diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp index 2525d308553ba..242e7161aa84c 100644 --- a/tests/pretty/delegation-inherit-attributes.pp +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -117,7 +117,7 @@ fn foo(self: _, arg1: _) -> _ { ::foo(self + 1, arg1) } #[attr = MustUse {reason: "some reason"}] #[attr = Inline(Hint)] - fn bar(self: _, arg1: _) -> _ { foo(self + 1, arg1) } + fn bar(arg0: _, arg1: _) -> _ { foo(self + 1, arg1) } } } diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.rs b/tests/ui/delegation/generics/free-fn-to-free-fn.rs index 285059e63a75f..67f7a12d710d5 100644 --- a/tests/ui/delegation/generics/free-fn-to-free-fn.rs +++ b/tests/ui/delegation/generics/free-fn-to-free-fn.rs @@ -16,8 +16,8 @@ reuse to_reuse::late; 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); diff --git a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr index 6b6acfc3afff6..db88b8d4f8b7d 100644 --- a/tests/ui/delegation/generics/free-fn-to-free-fn.stderr +++ b/tests/ui/delegation/generics/free-fn-to-free-fn.stderr @@ -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`. diff --git a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr index ead3c30a6886c..a20b28c16402d 100644 --- a/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr +++ b/tests/ui/delegation/generics/free-fn-to-trait-infer.stderr @@ -23,7 +23,6 @@ LL | reuse >::foo as generic_arguments2; | ^^^ | | | expected `&u8`, found `&Self` - | found this type parameter | arguments to this function are incorrect | = note: expected reference `&u8` diff --git a/tests/ui/delegation/generics/generics-gen-args-errors.stderr b/tests/ui/delegation/generics/generics-gen-args-errors.stderr index 78aefbc6604cc..6c57c3bc8d514 100644 --- a/tests/ui/delegation/generics/generics-gen-args-errors.stderr +++ b/tests/ui/delegation/generics/generics-gen-args-errors.stderr @@ -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 diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr index 00dfedef47b5a..9234771ca11f3 100644 --- a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr @@ -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 >::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() {} - | --- help: remove the unnecessary generic argument -... LL | reuse >::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 diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.stderr b/tests/ui/pin-ergonomics/pin_v2-attr.stderr index 8f8a9f3b3a19a..5c8a455114c42 100644 --- a/tests/ui/pin-ergonomics/pin_v2-attr.stderr +++ b/tests/ui/pin-ergonomics/pin_v2-attr.stderr @@ -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