Introduce tcx.anon_const_kind query

This commit is contained in:
Boxy 2025-03-12 11:23:20 +00:00
parent 356f2d0774
commit 996a185ba7
11 changed files with 86 additions and 46 deletions

View file

@ -89,6 +89,7 @@ pub(crate) fn provide(providers: &mut Providers) {
opaque_ty_origin,
rendered_precise_capturing_args,
const_param_default,
anon_const_kind,
..*providers
};
}
@ -1828,3 +1829,27 @@ fn const_param_default<'tcx>(
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
ty::EarlyBinder::bind(ct)
}
fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
let hir_id = tcx.local_def_id_to_hir_id(def);
let const_arg_id = tcx.parent_hir_id(hir_id);
match tcx.hir_node(const_arg_id) {
hir::Node::ConstArg(_) => {
if tcx.features().generic_const_exprs() {
ty::AnonConstKind::GCEConst
} else if tcx.features().min_generic_const_args() {
ty::AnonConstKind::MCGConst
} else if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Repeat(_, repeat_count),
..
}) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
&& repeat_count.hir_id == const_arg_id
{
ty::AnonConstKind::RepeatExprCount
} else {
ty::AnonConstKind::MCGConst
}
}
_ => ty::AnonConstKind::NonTypeSystem,
}
}

View file

@ -104,19 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
}
if in_param_ty {
// We do not allow generic parameters in anon consts if we are inside
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.features().generic_const_exprs() {
let parent_node = tcx.parent_hir_node(hir_id);
debug!(?parent_node);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
&& constant.hir_id == hir_id
{
// enum variant discriminants are not allowed to use any kind of generics
None
} else if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id)
match tcx.anon_const_kind(def_id) {
// Stable: anon consts are not able to use any generic parameters...
ty::AnonConstKind::MCGConst => None,
// we provide generics to repeat expr counts as a backwards compatibility hack. #76200
ty::AnonConstKind::RepeatExprCount => Some(parent_did),
// Even GCE anon const should not be allowed to use generic parameters as it would be
// trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::<N>]`.
//
// We could potentially mirror the hack done for defaults of generic parameters but
// this case just doesn't come up much compared to `const N: u32 = ...`. Long term the
// hack for defaulted parameters should be removed eventually anyway.
ty::AnonConstKind::GCEConst if in_param_ty => None,
// GCE anon consts as a default for a generic parameter should have their provided generics
// "truncated" up to whatever generic parameter this anon const is within the default of.
//
// FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type
// parameter defaults, e.g. `T = Foo</*defid*/>`.
ty::AnonConstKind::GCEConst
if let Some(param_id) =
tcx.hir_opt_const_param_default_param_def_id(hir_id) =>
{
// If the def_id we are calling generics_of on is an anon ct default i.e:
//
@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions,
};
} else {
// HACK(eddyb) this provides the correct generics when
// `feature(generic_const_expressions)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
// `min_const_generics`.
}
ty::AnonConstKind::GCEConst => Some(parent_did),
// Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/`
ty::AnonConstKind::NonTypeSystem
if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) =>
{
Some(parent_did)
}
} else {
let parent_node = tcx.parent_hir_node(hir_id);
let parent_node = match parent_node {
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
_ => parent_node,
};
match parent_node {
// HACK(eddyb) this provides the correct generics for repeat
// expressions' count (i.e. `N` in `[x; N]`), and explicit
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
// as they shouldn't be able to cause query cycle errors.
Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. })
if ct.anon_const_hir_id() == Some(hir_id) =>
{
Some(parent_did)
}
Node::TyPat(_) => Some(parent_did),
// Field default values inherit the ADT's generics.
Node::Field(_) => Some(parent_did),
_ => None,
}
// Default to no generic parameters for other kinds of anon consts
ty::AnonConstKind::NonTypeSystem => None,
}
}
Node::ConstBlock(_)

View file

@ -425,6 +425,7 @@ provide! { tcx, def_id, other, cdata,
doc_link_traits_in_scope => {
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
}
anon_const_kind => { table }
}
pub(in crate::rmeta) fn provide(providers: &mut Providers) {

View file

@ -1569,6 +1569,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
<- tcx.explicit_implied_const_bounds(def_id).skip_binder());
}
}
if let DefKind::AnonConst = def_kind {
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
}
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
{

View file

@ -480,6 +480,7 @@ define_tables! {
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
}
#[derive(TyEncodable, TyDecodable)]

View file

@ -311,6 +311,7 @@ trivial! {
rustc_middle::ty::Asyncness,
rustc_middle::ty::AsyncDestructor,
rustc_middle::ty::BoundVariableKind,
rustc_middle::ty::AnonConstKind,
rustc_middle::ty::DeducedParamAttrs,
rustc_middle::ty::Destructor,
rustc_middle::ty::fast_reject::SimplifiedType,

View file

@ -2586,6 +2586,12 @@ rustc_queries! {
desc { "estimating codegen size of `{}`", key }
cache_on_disk_if { true }
}
query anon_const_kind(def_id: DefId) -> ty::AnonConstKind {
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
}
rustc_with_all_queries! { define_callbacks! }

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
use rustc_macros::HashStable;
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
@ -259,3 +259,11 @@ impl<'tcx> Const<'tcx> {
TypeWalker::new(self.into())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AnonConstKind {
GCEConst,
MCGConst,
RepeatExprCount,
NonTypeSystem,
}

View file

@ -74,8 +74,8 @@ pub use self::closure::{
place_to_string_for_capture,
};
pub use self::consts::{
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind,
Value,
AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
ValTree, ValTreeKind, Value,
};
pub use self::context::{
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,

View file

@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! {
ty::AsyncDestructor,
ty::AssocItemContainer,
ty::Asyncness,
ty::AnonConstKind,
ty::DeducedParamAttrs,
ty::Destructor,
ty::Generics,

View file

@ -553,7 +553,8 @@ pub fn try_evaluate_const<'tcx>(
//
// FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
// instead of having this logic here
let (args, typing_env) = if tcx.features().generic_const_exprs()
let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst
&& let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def)
&& uv.has_non_region_infer()
{
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
@ -582,7 +583,10 @@ pub fn try_evaluate_const<'tcx>(
(args, typing_env)
}
}
} else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
} else if tcx.def_kind(uv.def) == DefKind::AnonConst
&& let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def)
&& uv.has_non_region_infer()
{
// FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
//
// Diagnostics will sometimes replace the identity args of anon consts in
@ -599,6 +603,7 @@ pub fn try_evaluate_const<'tcx>(
let args = GenericArgs::identity_for_item(tcx, uv.def);
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
(args, typing_env)
} else {
// FIXME: This codepath is reachable under `associated_const_equality` and in the