Introduce feature(generic_const_parameter_types)

This commit is contained in:
Boxy 2025-02-25 00:06:38 +00:00
parent 60493b8973
commit df5b279ca9
56 changed files with 419 additions and 154 deletions

View file

@ -966,7 +966,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
let ty = tcx.type_of(param.def_id).instantiate_identity();
if tcx.features().unsized_const_params() {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| {
wfcx.register_bound(
ObligationCause::new(
hir_ty.span,
@ -980,7 +980,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
Ok(())
})
} else if tcx.features().adt_const_params() {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| {
wfcx.register_bound(
ObligationCause::new(
hir_ty.span,

View file

@ -1822,6 +1822,9 @@ fn const_param_default<'tcx>(
),
};
let icx = ItemCtxt::new(tcx, def_id);
let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id()));
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
let ct = icx
.lowerer()
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
ty::EarlyBinder::bind(ct)
}

View file

@ -223,10 +223,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
hir::GenericParamKind::Const { .. } => {
let param_def_id = param.def_id.to_def_id();
let ct_ty = tcx
.type_of(param_def_id)
.no_bound_vars()
.expect("const parameters cannot be generic");
let ct_ty = tcx.type_of(param_def_id).instantiate_identity();
let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id);
predicates
.insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));

View file

@ -273,7 +273,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
// We lower to an infer even when the feature gate is not enabled
// as it is useful for diagnostics to be able to see a `ConstKind::Infer`
args.push(ctx.provided_kind(param, arg));
args.push(ctx.provided_kind(&args, param, arg));
args_iter.next();
params.next();
}

View file

@ -232,12 +232,15 @@ impl AssocItemQSelf {
/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
/// desired behavior.
#[derive(Debug, Clone, Copy)]
pub enum FeedConstTy {
pub enum FeedConstTy<'a, 'tcx> {
/// Feed the type.
///
/// The `DefId` belongs to the const param that we are supplying
/// this (anon) const arg to.
Param(DefId),
///
/// The list of generic args is used to instantiate the parameters
/// used by the type of the const param specified by `DefId`.
Param(DefId, &'a [ty::GenericArg<'tcx>]),
/// Don't feed the type.
No,
}
@ -298,6 +301,7 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
fn provided_kind(
&mut self,
preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx>;
@ -481,6 +485,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn provided_kind(
&mut self,
preceding_args: &[ty::GenericArg<'tcx>],
param: &ty::GenericParamDef,
arg: &GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
@ -526,7 +531,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
.lowerer
// Ambig portions of `ConstArg` are handled in the match arm below
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
.lower_const_arg(
ct.as_unambig_ct(),
FeedConstTy::Param(param.def_id, preceding_args),
)
.into(),
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
self.lowerer.ct_infer(Some(param), inf.span).into()
@ -582,8 +590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let ty = tcx
.at(self.span)
.type_of(param.def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic");
.instantiate(tcx, preceding_args);
if let Err(guar) = ty.error_reported() {
return ty::Const::new_error(tcx, guar).into();
}
@ -2107,14 +2114,50 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn lower_const_arg(
&self,
const_arg: &hir::ConstArg<'tcx>,
feed: FeedConstTy,
feed: FeedConstTy<'_, 'tcx>,
) -> Const<'tcx> {
let tcx = self.tcx();
if let FeedConstTy::Param(param_def_id) = feed
if let FeedConstTy::Param(param_def_id, args) = feed
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
{
tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args);
// We must error if the instantiated type has any inference variables as we will
// use this type to feed the `type_of` and query results must not contain inference
// variables otherwise we will ICE.
//
// We also error if the type contains any regions as effectively any region will wind
// up as a region variable in mir borrowck. It would also be somewhat concerning if
// hir typeck was using equality but mir borrowck wound up using subtyping as that could
// result in a non-infer in hir typeck but a region variable in borrowck.
//
// FIXME(generic_const_parameter_types): Ideally we remove these errors one day when
// we have the ability to intermix typeck of anon const const args with the parent
// bodies typeck.
if tcx.features().generic_const_parameter_types()
&& (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
{
let e = tcx.dcx().span_err(
const_arg.span(),
"anonymous constants with lifetimes in their type are not yet supported",
);
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
return ty::Const::new_error(tcx, e);
}
if anon_const_type.has_non_region_infer() {
let e = tcx.dcx().span_err(
const_arg.span(),
"anonymous constants with inferred types are not yet supported",
);
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
return ty::Const::new_error(tcx, e);
}
tcx.feed_anon_const_type(
anon.def_id,
ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)),
);
}
let hir_id = const_arg.hir_id;
@ -2230,10 +2273,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let expr = &tcx.hir_body(anon.body).value;
debug!(?expr);
let ty = tcx
.type_of(anon.def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic");
// FIXME(generic_const_parameter_types): We should use the proper generic args
// here. It's only used as a hint for literals so doesn't matter too much to use the right
// generic arguments, just weaker type inference.
let ty = tcx.type_of(anon.def_id).instantiate_identity();
match self.try_lower_anon_const_lit(ty, expr) {
Some(v) => v,

View file

@ -260,7 +260,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
pub fn lower_const_arg_for_rustdoc<'tcx>(
tcx: TyCtxt<'tcx>,
hir_ct: &hir::ConstArg<'tcx>,
feed: FeedConstTy,
feed: FeedConstTy<'_, 'tcx>,
) -> Const<'tcx> {
let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)