Rollup merge of #154142 - aerooneqq:dont-create-ast-generics-2, r=petrochenkov

Delegation: eliminate usage of AST from generics creation

This PR eliminates all interaction with AST during creation of generics, then it supports proper const param types propagation. Fixes rust-lang/rust#153433. Fixes rust-lang/rust#153499. Part of rust-lang/rust#118212.

r? @petrochenkov
This commit is contained in:
Jonathan Brouwer
2026-03-24 16:22:49 +01:00
committed by GitHub
10 changed files with 249 additions and 316 deletions
+22 -28
View File
@@ -146,12 +146,10 @@ pub(crate) fn lower_delegation(
let (param_count, c_variadic) = self.param_count(sig_id);
let mut generics =
self.lower_delegation_generics(delegation, sig_id, item_id, span);
let mut generics = self.uplift_delegation_generics(delegation, sig_id, item_id);
let body_id = self.lower_delegation_body(
delegation,
item_id,
is_method,
param_count,
&mut generics,
@@ -166,10 +164,8 @@ pub(crate) fn lower_delegation(
let generics = self.arena.alloc(hir::Generics {
has_where_clause_predicates: false,
params: self.arena.alloc_from_iter(generics.all_params(item_id, span, self)),
predicates: self
.arena
.alloc_from_iter(generics.all_predicates(item_id, span, self)),
params: self.arena.alloc_from_iter(generics.all_params(span, self)),
predicates: self.arena.alloc_from_iter(generics.all_predicates(span, self)),
span,
where_clause_span: span,
});
@@ -294,19 +290,22 @@ fn lower_delegation_decl(
let decl_param_count = param_count - c_variadic as usize;
let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
sig_id,
hir::InferDelegationSig::Input(arg),
)),
span,
}));
let output = self.arena.alloc(hir::Ty {
hir_id: self.next_id(),
kind: hir::TyKind::InferDelegation(
kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
sig_id,
hir::InferDelegationKind::Output(self.arena.alloc(hir::DelegationGenerics {
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationGenerics {
child_args_segment_id: generics.child.args_segment_id,
parent_args_segment_id: generics.parent.args_segment_id,
})),
),
)),
span,
});
@@ -399,7 +398,6 @@ fn generate_arg(
fn lower_delegation_body(
&mut self,
delegation: &Delegation,
item_id: NodeId,
is_method: bool,
param_count: usize,
generics: &mut GenericsGenerationResults<'hir>,
@@ -434,7 +432,7 @@ fn lower_delegation_body(
args.push(arg);
}
let final_expr = this.finalize_body_lowering(delegation, item_id, args, generics, span);
let final_expr = this.finalize_body_lowering(delegation, args, generics, span);
(this.arena.alloc_from_iter(parameters), final_expr)
})
@@ -471,7 +469,6 @@ fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
fn finalize_body_lowering(
&mut self,
delegation: &Delegation,
item_id: NodeId,
args: Vec<hir::Expr<'hir>>,
generics: &mut GenericsGenerationResults<'hir>,
span: Span,
@@ -501,7 +498,7 @@ fn finalize_body_lowering(
// FIXME(fn_delegation): proper support for parent generics propagation
// in method call scenario.
let segment = self.process_segment(item_id, span, &segment, &mut generics.child, false);
let segment = self.process_segment(span, &segment, &mut generics.child, false);
let segment = self.arena.alloc(segment);
self.arena.alloc(hir::Expr {
@@ -528,7 +525,7 @@ fn finalize_body_lowering(
new_path.segments = self.arena.alloc_from_iter(
new_path.segments.iter().enumerate().map(|(idx, segment)| {
let mut process_segment = |result, add_lifetimes| {
self.process_segment(item_id, span, segment, result, add_lifetimes)
self.process_segment(span, segment, result, add_lifetimes)
};
if idx + 2 == len {
@@ -544,8 +541,7 @@ fn finalize_body_lowering(
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
}
hir::QPath::TypeRelative(ty, segment) => {
let segment =
self.process_segment(item_id, span, segment, &mut generics.child, false);
let segment = self.process_segment(span, segment, &mut generics.child, false);
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
}
@@ -569,7 +565,6 @@ fn finalize_body_lowering(
fn process_segment(
&mut self,
item_id: NodeId,
span: Span,
segment: &hir::PathSegment<'hir>,
result: &mut GenericsGenerationResult<'hir>,
@@ -577,15 +572,14 @@ fn process_segment(
) -> hir::PathSegment<'hir> {
let details = result.generics.args_propagation_details();
// The first condition is needed when there is SelfAndUserSpecified case,
// we don't want to propagate generics params in this situation.
let segment = if details.should_propagate
&& let Some(args) = result
.generics
.into_hir_generics(self, item_id, span)
.into_generic_args(self, add_lifetimes, span)
{
hir::PathSegment { args: Some(args), ..segment.clone() }
let segment = if details.should_propagate {
let generics = result.generics.into_hir_generics(self, span);
let args = generics.into_generic_args(self, add_lifetimes, span);
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
let args = if args.is_empty() { None } else { Some(args) };
hir::PathSegment { args, ..segment.clone() }
} else {
segment.clone()
};
@@ -5,10 +5,8 @@
use rustc_hir::def_id::DefId;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::{bug, ty};
use rustc_span::sym::{self};
use rustc_span::symbol::kw;
use rustc_span::{Ident, Span};
use thin_vec::{ThinVec, thin_vec};
use crate::{LoweringContext, ResolverAstLoweringExt};
@@ -16,34 +14,33 @@ pub(super) enum DelegationGenerics<T> {
/// User-specified args are present: `reuse foo::<String>;`.
UserSpecified,
/// The default case when no user-specified args are present: `reuse Trait::foo;`.
Default(Option<T>),
Default(T),
/// In free-to-trait reuse, when user specified args for trait `reuse Trait::<i32>::foo;`
/// in this case we need to both generate `Self` and process user args.
SelfAndUserSpecified(Option<T>),
SelfAndUserSpecified(T),
/// In delegations from trait impl to other entities like free functions or trait functions,
/// we want to generate a function whose generics matches generics of signature function
/// in trait.
TraitImpl(Option<T>, bool /* Has user-specified args */),
TraitImpl(T, bool /* Has user-specified args */),
}
/// Used for storing either AST generics or their lowered HIR version. Firstly we obtain
/// AST generics either from local function from AST index or from external function
/// through `tcx`. Next, at some point of generics processing we need to lower those
/// generics to HIR, for this purpose we use `into_hir_generics` that lowers AST generics
/// and replaces Ast variant with Hir. Such approach is useful as we can call this method
/// at any time knowing that lowering will occur at most only once. Then, in order to obtain generic
/// Used for storing either ty generics or their uplifted HIR version. First we obtain
/// ty generics. Next, at some point of generics processing we need to uplift those
/// generics to HIR, for this purpose we use `into_hir_generics` that uplifts ty generics
/// and replaces Ty variant with Hir. Such approach is useful as we can call this method
/// at any time knowing that uplifting will occur at most only once. Then, in order to obtain generic
/// params or args we use `hir_generics_or_empty` or `into_generic_args` functions.
/// There also may be situations when we obtained AST generics but never lowered them to HIR,
/// There also may be situations when we obtained ty generics but never uplifted them to HIR,
/// meaning we did not propagate them and thus we do not need to generate generic params
/// (i.e., method call scenarios), in such a case this approach helps
/// a lot as if `into_hir_generics` will not be called then lowering will not happen.
pub(super) enum HirOrAstGenerics<'hir> {
Ast(DelegationGenerics<Generics>),
/// a lot as if `into_hir_generics` will not be called then uplifting will not happen.
pub(super) enum HirOrTyGenerics<'hir> {
Ty(DelegationGenerics<&'hir [ty::GenericParamDef]>),
Hir(DelegationGenerics<&'hir hir::Generics<'hir>>),
}
pub(super) struct GenericsGenerationResult<'hir> {
pub(super) generics: HirOrAstGenerics<'hir>,
pub(super) generics: HirOrTyGenerics<'hir>,
pub(super) args_segment_id: Option<HirId>,
}
@@ -78,35 +75,31 @@ fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
}
}
impl<'hir> HirOrAstGenerics<'hir> {
impl<'hir> HirOrTyGenerics<'hir> {
pub(super) fn into_hir_generics(
&mut self,
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
item_id: NodeId,
span: Span,
) -> &mut HirOrAstGenerics<'hir> {
if let HirOrAstGenerics::Ast(generics) = self {
let process_params = |generics: &mut Generics| {
ctx.lower_delegation_generic_params(item_id, span, &mut generics.params)
) -> &mut HirOrTyGenerics<'hir> {
if let HirOrTyGenerics::Ty(params) = self {
let mut uplift_params = |generics: &'hir [ty::GenericParamDef]| {
ctx.uplift_delegation_generic_params(span, generics)
};
let hir_generics = match generics {
let hir_generics = match params {
DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified,
DelegationGenerics::Default(generics) => {
DelegationGenerics::Default(generics.as_mut().map(process_params))
DelegationGenerics::Default(params) => {
DelegationGenerics::Default(uplift_params(params))
}
DelegationGenerics::SelfAndUserSpecified(generics) => {
DelegationGenerics::SelfAndUserSpecified(generics.as_mut().map(process_params))
DelegationGenerics::SelfAndUserSpecified(params) => {
DelegationGenerics::SelfAndUserSpecified(uplift_params(params))
}
DelegationGenerics::TraitImpl(generics, user_specified) => {
DelegationGenerics::TraitImpl(
generics.as_mut().map(process_params),
*user_specified,
)
DelegationGenerics::TraitImpl(params, user_specified) => {
DelegationGenerics::TraitImpl(uplift_params(params), *user_specified)
}
};
*self = HirOrAstGenerics::Hir(hir_generics);
*self = HirOrTyGenerics::Hir(hir_generics);
}
self
@@ -114,14 +107,12 @@ pub(super) fn into_hir_generics(
fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
match self {
HirOrAstGenerics::Ast(_) => hir::Generics::empty(),
HirOrAstGenerics::Hir(hir_generics) => match hir_generics {
HirOrTyGenerics::Ty(_) => hir::Generics::empty(),
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
DelegationGenerics::UserSpecified => hir::Generics::empty(),
DelegationGenerics::Default(generics)
| DelegationGenerics::SelfAndUserSpecified(generics)
| DelegationGenerics::TraitImpl(generics, _) => {
generics.unwrap_or(hir::Generics::empty())
}
| DelegationGenerics::TraitImpl(generics, _) => generics,
},
}
}
@@ -131,43 +122,41 @@ pub(super) fn into_generic_args(
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
add_lifetimes: bool,
span: Span,
) -> Option<&'hir hir::GenericArgs<'hir>> {
) -> &'hir hir::GenericArgs<'hir> {
match self {
HirOrAstGenerics::Ast(_) => {
bug!("Attempting to get generic args before lowering to HIR")
HirOrTyGenerics::Ty(_) => {
bug!("Attempting to get generic args before uplifting to HIR")
}
HirOrAstGenerics::Hir(hir_generics) => match hir_generics {
DelegationGenerics::UserSpecified => None,
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
DelegationGenerics::UserSpecified => hir::GenericArgs::NONE,
DelegationGenerics::Default(generics)
| DelegationGenerics::SelfAndUserSpecified(generics)
| DelegationGenerics::TraitImpl(generics, _) => generics.map(|generics| {
| DelegationGenerics::TraitImpl(generics, _) => {
ctx.create_generics_args_from_params(generics.params, add_lifetimes, span)
}),
}
},
}
}
pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
match self {
HirOrAstGenerics::Ast(ast_generics) => ast_generics.args_propagation_details(),
HirOrAstGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(),
HirOrTyGenerics::Ty(ty_generics) => ty_generics.args_propagation_details(),
HirOrTyGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(),
}
}
}
impl<'a> GenericsGenerationResult<'a> {
fn new(generics: DelegationGenerics<Generics>) -> GenericsGenerationResult<'a> {
GenericsGenerationResult {
generics: HirOrAstGenerics::Ast(generics),
args_segment_id: None,
}
impl<'hir> GenericsGenerationResult<'hir> {
fn new(
generics: DelegationGenerics<&'hir [ty::GenericParamDef]>,
) -> GenericsGenerationResult<'hir> {
GenericsGenerationResult { generics: HirOrTyGenerics::Ty(generics), args_segment_id: None }
}
}
impl<'hir> GenericsGenerationResults<'hir> {
pub(super) fn all_params(
&mut self,
item_id: NodeId,
span: Span,
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
) -> impl Iterator<Item = hir::GenericParam<'hir>> {
@@ -176,21 +165,14 @@ pub(super) fn all_params(
// method call will be supported (if HIR generics were not obtained
// then it means that we did not propagated them, thus we do not need
// to generate params).
let parent = self
.parent
.generics
.into_hir_generics(ctx, item_id, span)
.hir_generics_or_empty()
.params;
let mut create_params = |result: &mut GenericsGenerationResult<'hir>| {
result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().params
};
let child = self
.child
.generics
.into_hir_generics(ctx, item_id, span)
.hir_generics_or_empty()
.params;
let parent = create_params(&mut self.parent);
let child = create_params(&mut self.child);
// Order generics, firstly we have parent and child lifetimes,
// Order generics, first we have parent and child lifetimes,
// then parent and child types and consts.
// `generics_of` in `rustc_hir_analysis` will order them anyway,
// however we want the order to be consistent in HIR too.
@@ -203,13 +185,12 @@ pub(super) fn all_params(
.copied()
}
/// As we add hack predicates(`'a: 'a`) for all lifetimes (see `lower_delegation_generic_params`
/// As we add hack predicates(`'a: 'a`) for all lifetimes (see `uplift_delegation_generic_params`
/// and `generate_lifetime_predicate` functions) we need to add them to delegation generics.
/// Those predicates will not affect resulting predicate inheritance and folding
/// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature.
pub(super) fn all_predicates(
&mut self,
item_id: NodeId,
span: Span,
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
@@ -218,31 +199,23 @@ pub(super) fn all_predicates(
// method call will be supported (if HIR generics were not obtained
// then it means that we did not propagated them, thus we do not need
// to generate predicates).
self.parent
.generics
.into_hir_generics(ctx, item_id, span)
.hir_generics_or_empty()
.predicates
.into_iter()
.chain(
self.child
.generics
.into_hir_generics(ctx, item_id, span)
.hir_generics_or_empty()
.predicates
.into_iter(),
)
.copied()
let mut create_predicates = |result: &mut GenericsGenerationResult<'hir>| {
result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().predicates
};
let parent = create_predicates(&mut self.parent);
let child = create_predicates(&mut self.child);
parent.into_iter().chain(child).copied()
}
}
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
pub(super) fn lower_delegation_generics(
pub(super) fn uplift_delegation_generics(
&mut self,
delegation: &Delegation,
sig_id: DefId,
item_id: NodeId,
span: Span,
) -> GenericsGenerationResults<'hir> {
let delegation_parent_kind =
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)));
@@ -251,15 +224,16 @@ pub(super) fn lower_delegation_generics(
let len = segments.len();
let child_user_specified = segments[len - 1].args.is_some();
let sig_params = &self.tcx.generics_of(sig_id).own_params[..];
// If we are in trait impl always generate function whose generics matches
// those that are defined in trait.
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
// Considering parent generics, during signature inheritance
// we will take those args that are in trait impl header trait ref.
let parent = GenericsGenerationResult::new(DelegationGenerics::Default(None));
let parent = GenericsGenerationResult::new(DelegationGenerics::TraitImpl(&[], true));
let generics = self.get_external_generics(sig_id, false, span);
let child = DelegationGenerics::TraitImpl(generics, child_user_specified);
let child = DelegationGenerics::TraitImpl(sig_params, child_user_specified);
let child = GenericsGenerationResult::new(child);
return GenericsGenerationResults { parent, child };
@@ -268,38 +242,37 @@ pub(super) fn lower_delegation_generics(
let delegation_in_free_ctx =
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
let root_function_in_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(sig_id), generate_self, user_specified, span)
};
let sig_parent = self.tcx.parent(sig_id);
let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait);
let can_add_generics_to_parent = len >= 2
&& self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)
});
let generate_self = delegation_in_free_ctx && sig_in_trait;
let parent_generics = if can_add_generics_to_parent {
let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];
if segments[len - 2].args.is_some() {
if generate_self {
DelegationGenerics::SelfAndUserSpecified(parent_generics_factory(self, true))
// Take only first Self parameter, it is trait so Self must be present.
DelegationGenerics::SelfAndUserSpecified(&sig_parent_params[..1])
} else {
DelegationGenerics::UserSpecified
}
} else {
DelegationGenerics::Default(parent_generics_factory(self, false))
let skip_self = usize::from(!generate_self);
DelegationGenerics::Default(&sig_parent_params[skip_self..])
}
} else {
DelegationGenerics::Default(None)
DelegationGenerics::<&'hir [ty::GenericParamDef]>::Default(&[])
};
let child_generics = if child_user_specified {
DelegationGenerics::UserSpecified
} else {
DelegationGenerics::Default(self.get_external_generics(sig_id, false, span))
DelegationGenerics::Default(sig_params)
};
GenericsGenerationResults {
@@ -308,59 +281,71 @@ pub(super) fn lower_delegation_generics(
}
}
fn lower_delegation_generic_params(
fn uplift_delegation_generic_params(
&mut self,
item_id: NodeId,
span: Span,
params: &mut ThinVec<GenericParam>,
params: &'hir [ty::GenericParamDef],
) -> &'hir hir::Generics<'hir> {
for p in params.iter_mut() {
// We want to create completely new params, so we generate
// a new id, otherwise assertions will be triggered.
p.id = self.next_node_id();
let params = self.arena.alloc_from_iter(params.iter().map(|p| {
let def_kind = match p.kind {
GenericParamDefKind::Lifetime => DefKind::LifetimeParam,
GenericParamDefKind::Type { .. } => DefKind::TyParam,
GenericParamDefKind::Const { .. } => DefKind::ConstParam,
};
// Remove default params, as they are not supported on functions
// and there will duplicate DefId when we try to lower them later.
match &mut p.kind {
GenericParamKind::Lifetime => {}
GenericParamKind::Type { default } => *default = None,
GenericParamKind::Const { default, .. } => *default = None,
let param_ident = Ident::new(p.name, span);
let def_name = Some(param_ident.name);
let path_data = def_kind.def_path_data(def_name);
let node_id = self.next_node_id();
let def_id = self.create_def(node_id, def_name, def_kind, path_data, span);
let kind = match p.kind {
GenericParamDefKind::Lifetime => {
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
}
GenericParamDefKind::Type { synthetic, .. } => {
hir::GenericParamKind::Type { default: None, synthetic }
}
GenericParamDefKind::Const { .. } => {
let hir_id = self.next_id();
let kind = hir::TyKind::InferDelegation(hir::InferDelegation::DefId(p.def_id));
hir::GenericParamKind::Const {
ty: self.arena.alloc(hir::Ty { kind, hir_id, span }),
default: None,
}
}
};
// Important: we don't use `self.next_id()` as we want to execute
// `lower_node_id` routine so param's id is added to `self.children`.
let hir_id = self.lower_node_id(node_id);
hir::GenericParam {
hir_id,
colon_span: Some(span),
def_id,
kind,
name: hir::ParamName::Plain(param_ident),
pure_wrt_drop: p.pure_wrt_drop,
source: hir::GenericParamSource::Generics,
span,
}
// Note that we use self.disambiguator here, if we will create new every time
// we will get ICE if params have the same name.
self.resolver.insert_new_def_id(
p.id,
self.tcx
.create_def(
self.local_def_id(item_id),
Some(p.ident.name),
match p.kind {
GenericParamKind::Lifetime => DefKind::LifetimeParam,
GenericParamKind::Type { .. } => DefKind::TyParam,
GenericParamKind::Const { .. } => DefKind::ConstParam,
},
None,
&mut self.disambiguator,
)
.def_id(),
);
}
// Fallback to default generic param lowering, we modified them in the loop above.
let params = self.arena.alloc_from_iter(
params.iter().map(|p| self.lower_generic_param(p, hir::GenericParamSource::Generics)),
);
}));
// HACK: for now we generate predicates such that all lifetimes are early bound,
// we can not not generate early-bound lifetimes, but we can't know which of them
// are late-bound at this level of compilation.
// FIXME(fn_delegation): proper support for late bound lifetimes.
let predicates =
self.arena.alloc_from_iter(params.iter().filter_map(|p| {
p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
}));
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, span))
})),
predicates,
has_where_clause_predicates: false,
where_clause_span: span,
span,
@@ -376,11 +361,9 @@ fn generate_lifetime_predicate(
this.arena.alloc(hir::Lifetime {
hir_id: this.next_id(),
ident: p.name.ident(),
kind: rustc_hir::LifetimeKind::Param(p.def_id),
source: rustc_hir::LifetimeSource::Path {
angle_brackets: rustc_hir::AngleBrackets::Full,
},
syntax: rustc_hir::LifetimeSyntax::ExplicitBound,
kind: hir::LifetimeKind::Param(p.def_id),
source: hir::LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full },
syntax: hir::LifetimeSyntax::ExplicitBound,
})
};
@@ -472,117 +455,4 @@ fn create_generics_args_from_params(
span_ext: span,
})
}
fn get_external_generics(
&mut self,
id: DefId,
processing_parent: bool,
span: Span,
) -> Option<Generics> {
let generics = self.tcx.generics_of(id);
if generics.own_params.is_empty() {
return None;
}
// Skip first Self parameter if we are in trait, it will be added later.
let to_skip = (processing_parent && generics.has_self) as usize;
Some(Generics {
params: generics
.own_params
.iter()
.skip(to_skip)
.map(|p| GenericParam {
attrs: Default::default(),
bounds: Default::default(),
colon_span: None,
id: self.next_node_id(),
ident: Ident::new(p.name, span),
is_placeholder: false,
kind: match p.kind {
GenericParamDefKind::Lifetime => GenericParamKind::Lifetime,
GenericParamDefKind::Type { .. } => {
GenericParamKind::Type { default: None }
}
GenericParamDefKind::Const { .. } => self.map_const_kind(p, span),
},
})
.collect(),
where_clause: Default::default(),
span,
})
}
fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericParamKind {
let const_type = self.tcx.type_of(p.def_id).instantiate_identity();
let (type_symbol, res) = match const_type.kind() {
ty::Bool => (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
ty::Uint(uint) => (uint.name(), Res::PrimTy(hir::PrimTy::Uint(*uint))),
ty::Int(int) => (int.name(), Res::PrimTy(hir::PrimTy::Int(*int))),
ty::Char => (sym::char, Res::PrimTy(hir::PrimTy::Char)),
_ => {
self.tcx
.dcx()
.span_delayed_bug(span, format!("Unexpected const type: {}", const_type));
(sym::dummy, Res::Err)
}
};
let node_id = self.next_node_id();
self.resolver.insert_partial_res(node_id, hir::def::PartialRes::new(res));
GenericParamKind::Const {
ty: Box::new(Ty {
id: node_id,
kind: TyKind::Path(
None,
Path {
segments: thin_vec![PathSegment {
ident: Ident::new(type_symbol, span),
id: self.next_node_id(),
args: None
}],
span,
tokens: None,
},
),
span,
tokens: None,
}),
span,
default: None,
}
}
fn get_parent_generics(
&mut self,
id: DefId,
add_self: bool,
user_specified: bool,
span: Span,
) -> Option<Generics> {
// If args are user-specified we still maybe need to add self.
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, span),
attrs: Default::default(),
bounds: vec![],
is_placeholder: false,
kind: GenericParamKind::Type { default: None },
colon_span: None,
},
);
}
generics
}
}
+2 -2
View File
@@ -678,7 +678,7 @@ pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
lowerer.lower_node(def_id);
for (&child_def_id, &owner) in &map {
for (child_def_id, owner) in map {
tcx.feed_delayed_owner(child_def_id, owner);
}
}
@@ -1265,7 +1265,7 @@ fn lower_assoc_item_constraint(
};
gen_args_ctor.into_generic_args(self)
} else {
self.arena.alloc(hir::GenericArgs::none())
hir::GenericArgs::NONE
};
let kind = match &constraint.kind {
AssocItemConstraintKind::Equality { term } => {
+21 -19
View File
@@ -397,12 +397,7 @@ pub fn invalid() -> Self {
}
pub fn args(&self) -> &GenericArgs<'hir> {
if let Some(ref args) = self.args {
args
} else {
const DUMMY: &GenericArgs<'_> = &GenericArgs::none();
DUMMY
}
if let Some(ref args) = self.args { args } else { GenericArgs::NONE }
}
}
@@ -643,14 +638,12 @@ pub struct GenericArgs<'hir> {
}
impl<'hir> GenericArgs<'hir> {
pub const fn none() -> Self {
Self {
args: &[],
constraints: &[],
parenthesized: GenericArgsParentheses::No,
span_ext: DUMMY_SP,
}
}
pub const NONE: &'hir GenericArgs<'hir> = &GenericArgs {
args: &[],
constraints: &[],
parenthesized: GenericArgsParentheses::No,
span_ext: DUMMY_SP,
};
/// Obtain the list of input types and the output type if the generic arguments are parenthesized.
///
@@ -3767,12 +3760,21 @@ pub struct DelegationGenerics {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
pub enum InferDelegationKind<'hir> {
pub enum InferDelegationSig<'hir> {
Input(usize),
// Place generics info here, as we always specify output type for delegations.
Output(&'hir DelegationGenerics),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable_Generic)]
pub enum InferDelegation<'hir> {
/// Infer the type of this `DefId` through `tcx.type_of(def_id).instantiate_identity()`,
/// used for const types propagation.
DefId(DefId),
/// Used during signature inheritance, `DefId` corresponds to the signature function.
Sig(DefId, InferDelegationSig<'hir>),
}
/// The various kinds of types recognized by the compiler.
///
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
@@ -3782,7 +3784,7 @@ pub enum InferDelegationKind<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir, Unambig = ()> {
/// Actual type should be inherited from `DefId` signature
InferDelegation(DefId, InferDelegationKind<'hir>),
InferDelegation(InferDelegation<'hir>),
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).
@@ -3933,7 +3935,7 @@ pub struct FnDecl<'hir> {
impl<'hir> FnDecl<'hir> {
pub fn opt_delegation_sig_id(&self) -> Option<DefId> {
if let FnRetTy::Return(ty) = self.output
&& let TyKind::InferDelegation(sig_id, _) = ty.kind
&& let TyKind::InferDelegation(InferDelegation::Sig(sig_id, _)) = ty.kind
{
return Some(sig_id);
}
@@ -3942,8 +3944,8 @@ pub fn opt_delegation_sig_id(&self) -> Option<DefId> {
pub fn opt_delegation_generics(&self) -> Option<&'hir DelegationGenerics> {
if let FnRetTy::Return(ty) = self.output
&& let TyKind::InferDelegation(_, kind) = ty.kind
&& let InferDelegationKind::Output(generics) = kind
&& let TyKind::InferDelegation(InferDelegation::Sig(_, kind)) = ty.kind
&& let InferDelegationSig::Output(generics) = kind
{
return Some(generics);
}
@@ -925,7 +925,7 @@ fn visit_fn(
hir::FnRetTy::Return(ty) => Some(ty),
};
if let Some(ty) = output
&& let hir::TyKind::InferDelegation(sig_id, _) = ty.kind
&& let hir::TyKind::InferDelegation(hir::InferDelegation::Sig(sig_id, _)) = ty.kind
{
let bound_vars: Vec<_> =
self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
@@ -2960,12 +2960,19 @@ fn require_type_const_attribute(
}
}
fn lower_delegation_ty(&self, idx: hir::InferDelegationKind<'tcx>) -> Ty<'tcx> {
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
fn lower_delegation_ty(&self, infer: hir::InferDelegation<'tcx>) -> Ty<'tcx> {
match infer {
hir::InferDelegation::DefId(def_id) => {
self.tcx().type_of(def_id).instantiate_identity()
}
rustc_hir::InferDelegation::Sig(_, idx) => {
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
match idx {
hir::InferDelegationKind::Input(idx) => delegation_sig[idx],
hir::InferDelegationKind::Output { .. } => *delegation_sig.last().unwrap(),
match idx {
hir::InferDelegationSig::Input(idx) => delegation_sig[idx],
hir::InferDelegationSig::Output { .. } => *delegation_sig.last().unwrap(),
}
}
}
}
@@ -2975,7 +2982,7 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
let tcx = self.tcx();
let result_ty = match &hir_ty.kind {
hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx),
hir::TyKind::InferDelegation(infer) => self.lower_delegation_ty(*infer),
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
hir::TyKind::Ref(region, mt) => {
@@ -0,0 +1,8 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
fn main() {
fn foo<const N: dyn for<'a> Foo>() {}
//~^ ERROR: cannot find trait `Foo` in this scope
reuse foo as bar;
}
@@ -0,0 +1,9 @@
error[E0405]: cannot find trait `Foo` in this scope
--> $DIR/const-type-ice-153433.rs:5:33
|
LL | fn foo<const N: dyn for<'a> Foo>() {}
| ^^^ not found in this scope
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0405`.
@@ -0,0 +1,13 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait<'a, T, const F: fn(&CStr) -> usize> {
//~^ ERROR: cannot find type `CStr` in this scope
//~| ERROR: using function pointers as const generic parameters is forbidden
fn foo<'x: 'x, A, B>(&self) {}
}
reuse Trait::foo;
//~^ ERROR: using function pointers as const generic parameters is forbidden
fn main() {}
@@ -0,0 +1,30 @@
error[E0425]: cannot find type `CStr` in this scope
--> $DIR/const-type-ice-153499.rs:4:33
|
LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> {
| ^^^^ not found in this scope
|
help: consider importing this struct
|
LL + use std::ffi::CStr;
|
error: using function pointers as const generic parameters is forbidden
--> $DIR/const-type-ice-153499.rs:4:29
|
LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> {
| ^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool`, and `char`
error: using function pointers as const generic parameters is forbidden
--> $DIR/const-type-ice-153499.rs:10:14
|
LL | reuse Trait::foo;
| ^^^
|
= note: the only supported types are integers, `bool`, and `char`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0425`.