Skip to content

Commit 415b207

Browse files
authored
Rollup merge of #137617 - BoxyUwU:generic_const_parameter_types, r=lcnr
Introduce `feature(generic_const_parameter_types)` Allows to define const generic parameters whose type depends on other generic parameters, e.g. `Foo<const N: usize, const ARR: [u8; N]>;` Wasn't going to implement for this for a while until we could implement it with `bad_inference.rs` resolved but apparently the project simd folks would like to be able to use this for some intrinsics and the inference issue isn't really a huge problem there aiui. (cc ``@workingjubilee`` )
2 parents 11ddd56 + df5b279 commit 415b207

File tree

56 files changed

+419
-154
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+419
-154
lines changed

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,8 @@ declare_features! (
508508
(incomplete, generic_const_exprs, "1.56.0", Some(76560)),
509509
/// Allows generic parameters and where-clauses on free & associated const items.
510510
(incomplete, generic_const_items, "1.73.0", Some(113521)),
511+
/// Allows the type of const generics to depend on generic parameters
512+
(incomplete, generic_const_parameter_types, "CURRENT_RUSTC_VERSION", Some(137626)),
511513
/// Allows any generic constants being used as pattern type range ends
512514
(incomplete, generic_pattern_types, "1.86.0", Some(136574)),
513515
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
966966
let ty = tcx.type_of(param.def_id).instantiate_identity();
967967

968968
if tcx.features().unsized_const_params() {
969-
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
969+
enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| {
970970
wfcx.register_bound(
971971
ObligationCause::new(
972972
hir_ty.span,
@@ -980,7 +980,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
980980
Ok(())
981981
})
982982
} else if tcx.features().adt_const_params() {
983-
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
983+
enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| {
984984
wfcx.register_bound(
985985
ObligationCause::new(
986986
hir_ty.span,

compiler/rustc_hir_analysis/src/collect.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1822,6 +1822,9 @@ fn const_param_default<'tcx>(
18221822
),
18231823
};
18241824
let icx = ItemCtxt::new(tcx, def_id);
1825-
let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id()));
1825+
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
1826+
let ct = icx
1827+
.lowerer()
1828+
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
18261829
ty::EarlyBinder::bind(ct)
18271830
}

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
223223
}
224224
hir::GenericParamKind::Const { .. } => {
225225
let param_def_id = param.def_id.to_def_id();
226-
let ct_ty = tcx
227-
.type_of(param_def_id)
228-
.no_bound_vars()
229-
.expect("const parameters cannot be generic");
226+
let ct_ty = tcx.type_of(param_def_id).instantiate_identity();
230227
let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id);
231228
predicates
232229
.insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));

compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
273273

274274
// We lower to an infer even when the feature gate is not enabled
275275
// as it is useful for diagnostics to be able to see a `ConstKind::Infer`
276-
args.push(ctx.provided_kind(param, arg));
276+
args.push(ctx.provided_kind(&args, param, arg));
277277
args_iter.next();
278278
params.next();
279279
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+55-12
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,15 @@ impl AssocItemQSelf {
232232
/// Use this enum with `<dyn HirTyLowerer>::lower_const_arg` to instruct it with the
233233
/// desired behavior.
234234
#[derive(Debug, Clone, Copy)]
235-
pub enum FeedConstTy {
235+
pub enum FeedConstTy<'a, 'tcx> {
236236
/// Feed the type.
237237
///
238238
/// The `DefId` belongs to the const param that we are supplying
239239
/// this (anon) const arg to.
240-
Param(DefId),
240+
///
241+
/// The list of generic args is used to instantiate the parameters
242+
/// used by the type of the const param specified by `DefId`.
243+
Param(DefId, &'a [ty::GenericArg<'tcx>]),
241244
/// Don't feed the type.
242245
No,
243246
}
@@ -298,6 +301,7 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
298301

299302
fn provided_kind(
300303
&mut self,
304+
preceding_args: &[ty::GenericArg<'tcx>],
301305
param: &ty::GenericParamDef,
302306
arg: &GenericArg<'tcx>,
303307
) -> ty::GenericArg<'tcx>;
@@ -481,6 +485,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
481485

482486
fn provided_kind(
483487
&mut self,
488+
preceding_args: &[ty::GenericArg<'tcx>],
484489
param: &ty::GenericParamDef,
485490
arg: &GenericArg<'tcx>,
486491
) -> ty::GenericArg<'tcx> {
@@ -526,7 +531,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
526531
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
527532
.lowerer
528533
// Ambig portions of `ConstArg` are handled in the match arm below
529-
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
534+
.lower_const_arg(
535+
ct.as_unambig_ct(),
536+
FeedConstTy::Param(param.def_id, preceding_args),
537+
)
530538
.into(),
531539
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
532540
self.lowerer.ct_infer(Some(param), inf.span).into()
@@ -582,8 +590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
582590
let ty = tcx
583591
.at(self.span)
584592
.type_of(param.def_id)
585-
.no_bound_vars()
586-
.expect("const parameter types cannot be generic");
593+
.instantiate(tcx, preceding_args);
587594
if let Err(guar) = ty.error_reported() {
588595
return ty::Const::new_error(tcx, guar).into();
589596
}
@@ -2107,14 +2114,50 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21072114
pub fn lower_const_arg(
21082115
&self,
21092116
const_arg: &hir::ConstArg<'tcx>,
2110-
feed: FeedConstTy,
2117+
feed: FeedConstTy<'_, 'tcx>,
21112118
) -> Const<'tcx> {
21122119
let tcx = self.tcx();
21132120

2114-
if let FeedConstTy::Param(param_def_id) = feed
2121+
if let FeedConstTy::Param(param_def_id, args) = feed
21152122
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
21162123
{
2117-
tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id));
2124+
let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args);
2125+
2126+
// We must error if the instantiated type has any inference variables as we will
2127+
// use this type to feed the `type_of` and query results must not contain inference
2128+
// variables otherwise we will ICE.
2129+
//
2130+
// We also error if the type contains any regions as effectively any region will wind
2131+
// up as a region variable in mir borrowck. It would also be somewhat concerning if
2132+
// hir typeck was using equality but mir borrowck wound up using subtyping as that could
2133+
// result in a non-infer in hir typeck but a region variable in borrowck.
2134+
//
2135+
// FIXME(generic_const_parameter_types): Ideally we remove these errors one day when
2136+
// we have the ability to intermix typeck of anon const const args with the parent
2137+
// bodies typeck.
2138+
if tcx.features().generic_const_parameter_types()
2139+
&& (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
2140+
{
2141+
let e = tcx.dcx().span_err(
2142+
const_arg.span(),
2143+
"anonymous constants with lifetimes in their type are not yet supported",
2144+
);
2145+
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
2146+
return ty::Const::new_error(tcx, e);
2147+
}
2148+
if anon_const_type.has_non_region_infer() {
2149+
let e = tcx.dcx().span_err(
2150+
const_arg.span(),
2151+
"anonymous constants with inferred types are not yet supported",
2152+
);
2153+
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
2154+
return ty::Const::new_error(tcx, e);
2155+
}
2156+
2157+
tcx.feed_anon_const_type(
2158+
anon.def_id,
2159+
ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)),
2160+
);
21182161
}
21192162

21202163
let hir_id = const_arg.hir_id;
@@ -2230,10 +2273,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22302273
let expr = &tcx.hir_body(anon.body).value;
22312274
debug!(?expr);
22322275

2233-
let ty = tcx
2234-
.type_of(anon.def_id)
2235-
.no_bound_vars()
2236-
.expect("const parameter types cannot be generic");
2276+
// FIXME(generic_const_parameter_types): We should use the proper generic args
2277+
// here. It's only used as a hint for literals so doesn't matter too much to use the right
2278+
// generic arguments, just weaker type inference.
2279+
let ty = tcx.type_of(anon.def_id).instantiate_identity();
22372280

22382281
match self.try_lower_anon_const_lit(ty, expr) {
22392282
Some(v) => v,

compiler/rustc_hir_analysis/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
260260
pub fn lower_const_arg_for_rustdoc<'tcx>(
261261
tcx: TyCtxt<'tcx>,
262262
hir_ct: &hir::ConstArg<'tcx>,
263-
feed: FeedConstTy,
263+
feed: FeedConstTy<'_, 'tcx>,
264264
) -> Const<'tcx> {
265265
let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id);
266266
collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed)

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
522522
pub(crate) fn lower_const_arg(
523523
&self,
524524
const_arg: &'tcx hir::ConstArg<'tcx>,
525-
feed: FeedConstTy,
525+
feed: FeedConstTy<'_, 'tcx>,
526526
) -> ty::Const<'tcx> {
527527
let ct = self.lowerer().lower_const_arg(const_arg, feed);
528528
self.register_wf_obligation(
@@ -1138,7 +1138,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11381138
.last()
11391139
.is_some_and(|GenericPathSegment(def_id, _)| tcx.generics_of(*def_id).has_self);
11401140

1141-
let (res, self_ctor_args) = if let Res::SelfCtor(impl_def_id) = res {
1141+
let (res, implicit_args) = if let Res::Def(DefKind::ConstParam, def) = res {
1142+
// types of const parameters are somewhat special as they are part of
1143+
// the same environment as the const parameter itself. this means that
1144+
// unlike most paths `type-of(N)` can return a type naming parameters
1145+
// introduced by the containing item, rather than provided through `N`.
1146+
//
1147+
// for example given `<T, const M: usize, const N: [T; M]>` and some
1148+
// `let a = N;` expression. The path to `N` would wind up with no args
1149+
// (as it has no args), but instantiating the early binder on `typeof(N)`
1150+
// requires providing generic arguments for `[T, M, N]`.
1151+
(res, Some(ty::GenericArgs::identity_for_item(tcx, tcx.parent(def))))
1152+
} else if let Res::SelfCtor(impl_def_id) = res {
11421153
let ty = LoweredTy::from_raw(
11431154
self,
11441155
span,
@@ -1264,6 +1275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12641275

12651276
fn provided_kind(
12661277
&mut self,
1278+
preceding_args: &[ty::GenericArg<'tcx>],
12671279
param: &ty::GenericParamDef,
12681280
arg: &GenericArg<'tcx>,
12691281
) -> ty::GenericArg<'tcx> {
@@ -1283,7 +1295,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12831295
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
12841296
.fcx
12851297
// Ambiguous parts of `ConstArg` are handled in the match arms below
1286-
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
1298+
.lower_const_arg(
1299+
ct.as_unambig_ct(),
1300+
FeedConstTy::Param(param.def_id, preceding_args),
1301+
)
12871302
.into(),
12881303
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
12891304
self.fcx.ct_infer(Some(param), inf.span).into()
@@ -1323,7 +1338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13231338
}
13241339
}
13251340

1326-
let args_raw = self_ctor_args.unwrap_or_else(|| {
1341+
let args_raw = implicit_args.unwrap_or_else(|| {
13271342
lower_generic_args(
13281343
self,
13291344
def_id,

compiler/rustc_hir_typeck/src/method/confirm.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
426426

427427
fn provided_kind(
428428
&mut self,
429+
preceding_args: &[ty::GenericArg<'tcx>],
429430
param: &ty::GenericParamDef,
430431
arg: &GenericArg<'tcx>,
431432
) -> ty::GenericArg<'tcx> {
@@ -446,7 +447,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
446447
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self
447448
.cfcx
448449
// We handle the ambig portions of `ConstArg` in the match arms below
449-
.lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id))
450+
.lower_const_arg(
451+
ct.as_unambig_ct(),
452+
FeedConstTy::Param(param.def_id, preceding_args),
453+
)
450454
.into(),
451455
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
452456
self.cfcx.ct_infer(Some(param), inf.span).into()

compiler/rustc_middle/src/ty/sty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ impl ParamConst {
342342
ParamConst::new(def.index, def.name)
343343
}
344344

345+
#[instrument(level = "debug")]
345346
pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
346347
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
347348
// `ConstArgHasType` are never desugared to be higher ranked.

compiler/rustc_resolve/messages.ftl

-9
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ resolve_const_param_in_enum_discriminant =
125125
resolve_const_param_in_non_trivial_anon_const =
126126
const parameters may only be used as standalone arguments, i.e. `{$name}`
127127
128-
resolve_const_param_in_ty_of_const_param =
129-
const parameters may not be used in the type of const parameters
130-
131128
resolve_constructor_private_if_any_field_private =
132129
a constructor is private if any of the fields is private
133130
@@ -250,9 +247,6 @@ resolve_lifetime_param_in_enum_discriminant =
250247
resolve_lifetime_param_in_non_trivial_anon_const =
251248
lifetime parameters may not be used in const expressions
252249
253-
resolve_lifetime_param_in_ty_of_const_param =
254-
lifetime parameters may not be used in the type of const parameters
255-
256250
resolve_lowercase_self =
257251
attempt to use a non-constant value in a constant
258252
.suggestion = try using `Self`
@@ -437,9 +431,6 @@ resolve_type_param_in_enum_discriminant =
437431
resolve_type_param_in_non_trivial_anon_const =
438432
type parameters may not be used in const expressions
439433
440-
resolve_type_param_in_ty_of_const_param =
441-
type parameters may not be used in the type of const parameters
442-
443434
resolve_undeclared_label =
444435
use of undeclared label `{$name}`
445436
.label = undeclared label `{$name}`

compiler/rustc_resolve/src/diagnostics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -890,9 +890,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
890890
ResolutionError::ForwardDeclaredGenericParam => {
891891
self.dcx().create_err(errs::ForwardDeclaredGenericParam { span })
892892
}
893-
ResolutionError::ParamInTyOfConstParam { name, param_kind: is_type } => self
894-
.dcx()
895-
.create_err(errs::ParamInTyOfConstParam { span, name, param_kind: is_type }),
893+
ResolutionError::ParamInTyOfConstParam { name } => {
894+
self.dcx().create_err(errs::ParamInTyOfConstParam { span, name })
895+
}
896896
ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
897897
self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
898898
span,

compiler/rustc_resolve/src/errors.rs

-13
Original file line numberDiff line numberDiff line change
@@ -347,19 +347,6 @@ pub(crate) struct ParamInTyOfConstParam {
347347
#[label]
348348
pub(crate) span: Span,
349349
pub(crate) name: Symbol,
350-
#[subdiagnostic]
351-
pub(crate) param_kind: Option<ParamKindInTyOfConstParam>,
352-
}
353-
354-
#[derive(Debug)]
355-
#[derive(Subdiagnostic)]
356-
pub(crate) enum ParamKindInTyOfConstParam {
357-
#[note(resolve_type_param_in_ty_of_const_param)]
358-
Type,
359-
#[note(resolve_const_param_in_ty_of_const_param)]
360-
Const,
361-
#[note(resolve_lifetime_param_in_ty_of_const_param)]
362-
Lifetime,
363350
}
364351

365352
#[derive(Diagnostic)]

0 commit comments

Comments
 (0)