init impl

This commit is contained in:
Kivooeo 2026-01-01 02:16:49 +00:00
parent 8d670b93d4
commit 05afcb6d26
24 changed files with 537 additions and 28 deletions

View file

@ -2396,6 +2396,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
match &expr.kind {
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
let qpath = self.lower_qpath(
func.id,
qself,
path,
ParamMode::Explicit,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg_direct(anon_const)
} else {
self.lower_expr_to_const_arg_direct(arg)
};
&*self.arena.alloc(const_arg)
}));
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
}
}
ExprKind::Path(qself, path) => {
let qpath = self.lower_qpath(
expr.id,
@ -2460,7 +2489,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&& let StmtKind::Expr(expr) = &stmt.kind
&& matches!(
expr.kind,
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
ExprKind::Block(..)
| ExprKind::Path(..)
| ExprKind::Struct(..)
| ExprKind::Call(..)
)
{
return self.lower_expr_to_const_arg_direct(expr);

View file

@ -499,6 +499,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
match self.kind {
ConstArgKind::Struct(path, _) => path.span(),
ConstArgKind::Path(path) => path.span(),
ConstArgKind::TupleCall(path, _) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
ConstArgKind::Error(span, _) => span,
ConstArgKind::Infer(span, _) => span,
@ -519,6 +520,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
Anon(&'hir AnonConst),
/// Represents construction of struct/struct variants
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
/// Tuple constructor variant
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
/// Error const
Error(Span, ErrorGuaranteed),
/// This variant is not always used to represent inference consts, sometimes

View file

@ -1090,6 +1090,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
V::Result::output()
}
ConstArgKind::TupleCall(qpath, args) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
for arg in *args {
try_visit!(visitor.visit_const_arg_unambig(*arg));
}
V::Result::output()
}
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important

View file

@ -314,6 +314,7 @@ pub enum PermitVariants {
enum TypeRelativePath<'tcx> {
AssocItem(DefId, GenericArgsRef<'tcx>),
Variant { adt: Ty<'tcx>, variant_did: DefId },
Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> },
}
/// New-typed boolean indicating whether explicit late-bound lifetimes
@ -1261,6 +1262,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
TypeRelativePath::Variant { adt, variant_did } => {
Ok((adt, DefKind::Variant, variant_did))
}
TypeRelativePath::Ctor { .. } => {
let e = tcx.dcx().span_err(span, "expected type, found tuple constructor");
Err(e)
}
}
}
@ -1294,6 +1299,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
(def_id, args)
}
TypeRelativePath::Ctor { ctor_def_id, args } => {
return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)));
}
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
// not just const ctors
TypeRelativePath::Variant { .. } => {
@ -1326,6 +1334,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
// FIXME(mgca): do we want constructor resolutions to take priority over
// other possible resolutions?
if matches!(mode, LowerTypeRelativePathMode::Const)
&& let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor
{
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
slice::from_ref(segment).iter(),
GenericsArgsErrExtend::EnumVariant {
qself: hir_self_ty,
assoc_segment: segment,
adt_def,
},
);
let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() };
return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args });
}
if let PermitVariants::Yes = mode.permit_variants() {
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
@ -2266,12 +2291,106 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::ConstArgKind::Struct(qpath, inits) => {
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span())
}
hir::ConstArgKind::TupleCall(qpath, args) => {
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span())
}
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),
}
}
fn lower_const_arg_tuple_call(
&self,
hir_id: HirId,
qpath: hir::QPath<'tcx>,
args: &'tcx [&'tcx hir::ConstArg<'tcx>],
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();
let non_adt_or_variant_res = || {
let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path");
ty::Const::new_error(tcx, e)
};
let ctor_const = match qpath {
hir::QPath::Resolved(maybe_qself, path) => {
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
self.lower_resolved_const_path(opt_self_ty, path, hir_id)
}
hir::QPath::TypeRelative(hir_self_ty, segment) => {
let self_ty = self.lower_ty(hir_self_ty);
match self.lower_type_relative_const_path(
self_ty,
hir_self_ty,
segment,
hir_id,
span,
) {
Ok(c) => c,
Err(_) => return non_adt_or_variant_res(),
}
}
};
let Some(value) = ctor_const.try_to_value() else {
return non_adt_or_variant_res();
};
let (adt_def, adt_args, variant_did) = match value.ty.kind() {
ty::FnDef(def_id, fn_args)
if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) =>
{
let parent_did = tcx.parent(*def_id);
let enum_did = tcx.parent(parent_did);
(tcx.adt_def(enum_did), fn_args, parent_did)
}
ty::FnDef(def_id, fn_args)
if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) =>
{
let parent_did = tcx.parent(*def_id);
(tcx.adt_def(parent_did), fn_args, parent_did)
}
_ => return non_adt_or_variant_res(),
};
let variant_def = adt_def.variant_with_id(variant_did);
let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32();
if args.len() != variant_def.fields.len() {
let e = tcx.dcx().span_err(
span,
format!(
"tuple constructor has {} arguments but {} were provided",
variant_def.fields.len(),
args.len()
),
);
return ty::Const::new_error(tcx, e);
}
let fields = variant_def
.fields
.iter()
.zip(args)
.map(|(field_def, arg)| {
self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args))
})
.collect::<Vec<_>>();
let opt_discr_const = if adt_def.is_enum() {
let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into());
Some(ty::Const::new_value(tcx, valtree, tcx.types.u32))
} else {
None
};
let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields));
let adt_ty = Ty::new_adt(tcx, adt_def, adt_args);
ty::Const::new_value(tcx, valtree, adt_ty)
}
fn lower_const_arg_struct(
&self,
hir_id: HirId,
@ -2403,6 +2522,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let args = self.lower_generic_args_of_path_segment(span, did, segment);
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
let parent_did = tcx.parent(did);
let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) {
tcx.parent(parent_did)
} else {
parent_did
};
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args))
}
Res::Def(DefKind::AssocConst, did) => {
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
@ -2438,9 +2571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
DefKind::Mod
| DefKind::Enum
| DefKind::Variant
| DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
| DefKind::Struct
| DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
| DefKind::OpaqueTy
| DefKind::TyAlias
| DefKind::TraitAlias

View file

@ -1139,6 +1139,7 @@ impl<'a> State<'a> {
match &const_arg.kind {
// FIXME(mgca): proper printing for struct exprs
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"),
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
ConstArgKind::Error(_, _) => self.word("/*ERROR*/"),

View file

@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Skip encoding defs for these as they should not have had a `DefId` created
hir::ConstArgKind::Error(..)
| hir::ConstArgKind::Struct(..)
| hir::ConstArgKind::TupleCall(..)
| hir::ConstArgKind::Path(..)
| hir::ConstArgKind::Infer(..) => true,
hir::ConstArgKind::Anon(..) => false,

View file

@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
// Avoid overwriting `const_arg_context` as we may want to treat const blocks
// as being anon consts if we are inside a const argument.
ExprKind::Struct(_) => return visit::walk_expr(self, expr),
ExprKind::Struct(_) | ExprKind::Call(..) => return visit::walk_expr(self, expr),
// FIXME(mgca): we may want to handle block labels in some manner
ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind {
// FIXME(mgca): this probably means that mac calls that expand

View file

@ -323,6 +323,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind
// FIXME(mgca): proper printing :3
ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() }
}
hir::ConstArgKind::TupleCall(..) => {
ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() }
}
hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
}
@ -1804,7 +1807,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
let ct = cx.tcx.normalize_erasing_regions(typing_env, ct);
print_const(cx, ct)
}
hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => {
hir::ConstArgKind::Struct(..)
| hir::ConstArgKind::Path(..)
| hir::ConstArgKind::TupleCall(..) => {
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
print_const(cx, ct)
}

View file

@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.body(field!(anon_const.body));
},
ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"),
ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"),
ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"),
ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"),
}

View file

@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx
ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value),
ConstItemRhs::TypeConst(const_arg) => match const_arg.kind {
ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value),
ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
None
},
},

View file

@ -671,11 +671,19 @@ impl HirEqInterExpr<'_, '_, '_> {
.iter()
.zip(*inits_b)
.all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr))
},
}
(ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => {
self.eq_qpath(path_a, path_b)
&& args_a
.iter()
.zip(*args_b)
.all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b))
}
// Use explicit match for now since ConstArg is undergoing flux.
(
ConstArgKind::Path(..)
| ConstArgKind::Anon(..)
| ConstArgKind::TupleCall(..)
| ConstArgKind::Infer(..)
| ConstArgKind::Struct(..)
| ConstArgKind::Error(..),
@ -1546,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_const_arg(init.expr);
}
},
ConstArgKind::TupleCall(path, args) => {
self.hash_qpath(path);
for arg in *args {
self.hash_const_arg(arg);
}
},
ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {},
}
}

View file

@ -1,11 +0,0 @@
//@ known-bug: #136379
#![feature(min_generic_const_args)]
pub struct S();
impl S {
pub fn f() -> [u8; S] {
[]
}
}
pub fn main() {}

View file

@ -1,10 +0,0 @@
//@ known-bug: #138132
#![feature(min_generic_const_args)]
struct b(Box<[u8; c]>);
impl b {
fn d(self) {
self.0.e()
}
}
struct c<'a>(&'a u8);
fn main() {}

View file

@ -0,0 +1,52 @@
//@ run-pass
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
#![allow(dead_code)]
use std::marker::ConstParamTy;
#[derive(Debug, Eq, PartialEq, ConstParamTy)]
struct Point(u32, u32);
#[derive(Debug, Eq, PartialEq, ConstParamTy)]
enum MyEnum<T> {
Variant(T),
Other,
}
trait Trait {
#[type_const]
const ASSOC: u32;
}
fn with_point<const P: Point>() -> Point {
P
}
fn with_enum<const E: MyEnum<u32>>() -> MyEnum<u32> {
E
}
fn test<T: Trait, const N: u32>() {
with_point::<{ Point(<T as Trait>::ASSOC, N) }>();
}
fn test_basic<const N: u32>() {
with_point::<{ Point(N, N) }>();
with_point::<{ Point(const { 5 }, const { 10 }) }>();
with_enum::<{ MyEnum::Variant::<u32>(N) }>();
with_enum::<{ MyEnum::Variant::<u32>(const { 42 }) }>();
with_enum::<{ <MyEnum<u32>>::Variant(N) }>();
}
fn main() {
test_basic::<5>();
let p = with_point::<{ Point(const { 1 }, const { 2 }) }>();
assert_eq!(p, Point(1, 2));
let e = with_enum::<{ MyEnum::Variant::<u32>(const { 10 }) }>();
assert_eq!(e, MyEnum::Variant(10));
}

View file

@ -0,0 +1,19 @@
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(Eq, PartialEq, ConstParamTy)]
struct Point(u32, u32);
fn with_point<const P: Point>() {}
fn test<const N: u32>() {
with_point::<{ Point(N + 1, N) }>();
//~^ ERROR complex const arguments must be placed inside of a `const` block
with_point::<{ Point(const { N + 1 }, N) }>();
//~^ ERROR generic parameters may not be used in const operations
}
fn main() {}

View file

@ -0,0 +1,14 @@
error: complex const arguments must be placed inside of a `const` block
--> $DIR/tuple_ctor_complex_args.rs:12:26
|
LL | with_point::<{ Point(N + 1, N) }>();
| ^^^^^
error: generic parameters may not be used in const operations
--> $DIR/tuple_ctor_complex_args.rs:15:34
|
LL | with_point::<{ Point(const { N + 1 }, N) }>();
| ^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,46 @@
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(Eq, PartialEq, ConstParamTy)]
struct Point(u32, u32);
#[derive(Eq, PartialEq, ConstParamTy)]
enum MyEnum<T> {
Variant(T),
Unit,
}
const CONST_ITEM: u32 = 42;
fn accepts_point<const P: Point>() {}
fn accepts_enum<const E: MyEnum<u32>>() {}
fn non_ctor() {}
fn test_errors<const N: usize>() {
accepts_point::<{ Point(N) }>();
//~^ ERROR tuple constructor has 2 arguments but 1 were provided
accepts_point::<{ Point(N, N, N) }>();
//~^ ERROR tuple constructor has 2 arguments but 3 were provided
accepts_point::<{ UnresolvedIdent(N, N) }>();
//~^ ERROR cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope
//~| ERROR tuple constructor with invalid base path
accepts_point::<{ non_ctor(N, N) }>();
//~^ ERROR tuple constructor with invalid base path
accepts_point::<{ CONST_ITEM(N, N) }>();
//~^ ERROR tuple constructor with invalid base path
accepts_point::<{ Point }>();
//~^ ERROR the constant `Point` is not of type `Point`
accepts_enum::<{ MyEnum::Variant::<u32> }>();
//~^ ERROR the constant `MyEnum::<u32>::Variant` is not of type `MyEnum<u32>`
}
fn main() {}

View file

@ -0,0 +1,68 @@
error[E0425]: cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope
--> $DIR/tuple_ctor_erroneous.rs:29:23
|
LL | accepts_point::<{ UnresolvedIdent(N, N) }>();
| ^^^^^^^^^^^^^^^ not found in this scope
|
help: you might be missing a const parameter
|
LL | fn test_errors<const N: usize, const UnresolvedIdent: /* Type */>() {
| +++++++++++++++++++++++++++++++++++
error: tuple constructor has 2 arguments but 1 were provided
--> $DIR/tuple_ctor_erroneous.rs:23:23
|
LL | accepts_point::<{ Point(N) }>();
| ^^^^^
error: tuple constructor has 2 arguments but 3 were provided
--> $DIR/tuple_ctor_erroneous.rs:26:23
|
LL | accepts_point::<{ Point(N, N, N) }>();
| ^^^^^
error: tuple constructor with invalid base path
--> $DIR/tuple_ctor_erroneous.rs:29:23
|
LL | accepts_point::<{ UnresolvedIdent(N, N) }>();
| ^^^^^^^^^^^^^^^
error: tuple constructor with invalid base path
--> $DIR/tuple_ctor_erroneous.rs:33:23
|
LL | accepts_point::<{ non_ctor(N, N) }>();
| ^^^^^^^^
error: tuple constructor with invalid base path
--> $DIR/tuple_ctor_erroneous.rs:36:23
|
LL | accepts_point::<{ CONST_ITEM(N, N) }>();
| ^^^^^^^^^^
error: the constant `Point` is not of type `Point`
--> $DIR/tuple_ctor_erroneous.rs:39:23
|
LL | accepts_point::<{ Point }>();
| ^^^^^ expected `Point`, found struct constructor
|
note: required by a const generic parameter in `accepts_point`
--> $DIR/tuple_ctor_erroneous.rs:17:18
|
LL | fn accepts_point<const P: Point>() {}
| ^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_point`
error: the constant `MyEnum::<u32>::Variant` is not of type `MyEnum<u32>`
--> $DIR/tuple_ctor_erroneous.rs:42:22
|
LL | accepts_enum::<{ MyEnum::Variant::<u32> }>();
| ^^^^^^^^^^^^^^^^^^^^^^ expected `MyEnum<u32>`, found enum constructor
|
note: required by a const generic parameter in `accepts_enum`
--> $DIR/tuple_ctor_erroneous.rs:18:17
|
LL | fn accepts_enum<const E: MyEnum<u32>>() {}
| ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_enum`
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0425`.

View file

@ -0,0 +1,16 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/136379>
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
pub struct S();
impl S {
pub fn f() -> [u8; S] {
//~^ ERROR the constant `S` is not of type `usize`
[]
//~^ ERROR mismatched types [E0308]
}
}
pub fn main() {}

View file

@ -0,0 +1,23 @@
error: the constant `S` is not of type `usize`
--> $DIR/tuple_ctor_in_array_len.rs:9:19
|
LL | pub fn f() -> [u8; S] {
| ^^^^^^^ expected `usize`, found struct constructor
|
= note: the length of array `[u8; S]` must be type `usize`
error[E0308]: mismatched types
--> $DIR/tuple_ctor_in_array_len.rs:11:9
|
LL | pub fn f() -> [u8; S] {
| ------- expected `[u8; S]` because of return type
LL |
LL | []
| ^^ expected an array with a size of S, found one with a size of 0
|
= note: expected array `[u8; S]`
found array `[_; 0]`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,38 @@
//@ run-pass
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(Debug, Eq, PartialEq, ConstParamTy)]
struct Inner(u32);
#[derive(Debug, Eq, PartialEq, ConstParamTy)]
struct Outer(Inner);
#[derive(Debug, Eq, PartialEq, ConstParamTy)]
enum Container<T> {
Wrap(T),
}
fn with_outer<const O: Outer>() -> Outer {
O
}
fn with_container<const C: Container<Inner>>() -> Container<Inner> {
C
}
fn test<const N: u32>() {
with_outer::<{ Outer(Inner(N)) }>();
with_outer::<{ Outer(Inner(const { 42 })) }>();
with_container::<{ Container::Wrap::<Inner>(Inner(N)) }>();
}
fn main() {
test::<5>();
let o = with_outer::<{ Outer(Inner(const { 10 })) }>();
assert_eq!(o, Outer(Inner(10)));
}

View file

@ -0,0 +1,26 @@
//@ run-pass
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(Debug, Eq, PartialEq, ConstParamTy)]
enum Option<T> {
Some(T),
}
fn with_option<const O: Option<u32>>() -> Option<u32> {
O
}
fn test<const N: u32>() {
with_option::<{ <Option<u32>>::Some(N) }>();
with_option::<{ <Option<u32>>::Some(const { 42 }) }>();
}
fn main() {
test::<5>();
let o = with_option::<{ <Option<u32>>::Some(const { 10 }) }>();
assert_eq!(o, Option::Some(10));
}

View file

@ -0,0 +1,14 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/138132>
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
struct B(Box<[u8; C]>);
//~^ ERROR missing generics for struct `C`
impl B {
fn d(self) {
self.0.e()
}
}
struct C<'a>(&'a u8);
fn main() {}

View file

@ -0,0 +1,19 @@
error[E0107]: missing generics for struct `C`
--> $DIR/type_as_const_in_array_len.rs:6:19
|
LL | struct B(Box<[u8; C]>);
| ^ expected 1 lifetime argument
|
note: struct defined here, with 1 lifetime parameter: `'a`
--> $DIR/type_as_const_in_array_len.rs:13:8
|
LL | struct C<'a>(&'a u8);
| ^ --
help: add missing lifetime argument
|
LL | struct B(Box<[u8; C<'a>]>);
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0107`.