Auto merge of #150603 - Kivooeo:tuple-struct, r=BoxyUwU
MGCA: Support for tuple constructors r? BoxyUwU part of https://github.com/rust-lang/rust/issues/132980 fixes rust-lang/rust#136379 fixes rust-lang/rust#138132 i tried to keep implementation very minimal and it's very similar to how structs was implemented with small adjustments this does not make const constructor like None works, just something like Some(n) todo: * ~~tests~~ * write a better description (not sure if needed) * add more comments and FIXMEs from structs code
This commit is contained in:
commit
6885bdf1af
24 changed files with 537 additions and 28 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1375,6 +1376,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let adt = self.check_param_uses_if_mcg(adt, span, false);
|
||||
Ok((adt, DefKind::Variant, variant_did))
|
||||
}
|
||||
TypeRelativePath::Ctor { .. } => {
|
||||
let e = tcx.dcx().span_err(span, "expected type, found tuple constructor");
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1410,6 +1415,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let ct = self.check_param_uses_if_mcg(ct, span, false);
|
||||
Ok(ct)
|
||||
}
|
||||
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 { .. } => {
|
||||
|
|
@ -1441,6 +1449,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(
|
||||
|
|
@ -2349,12 +2374,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,
|
||||
|
|
@ -2486,6 +2605,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);
|
||||
|
|
@ -2521,9 +2654,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
|
||||
|
|
|
|||
|
|
@ -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*/"),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(..) => {},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
@ -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() {}
|
||||
52
tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs
Normal file
52
tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs
Normal 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));
|
||||
}
|
||||
19
tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs
Normal file
19
tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs
Normal 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() {}
|
||||
14
tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr
Normal file
14
tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr
Normal 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
|
||||
|
||||
46
tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs
Normal file
46
tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs
Normal 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() {}
|
||||
68
tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr
Normal file
68
tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr
Normal 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`.
|
||||
16
tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs
Normal file
16
tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs
Normal 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() {}
|
||||
23
tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr
Normal file
23
tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr
Normal 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`.
|
||||
38
tests/ui/const-generics/mgca/tuple_ctor_nested.rs
Normal file
38
tests/ui/const-generics/mgca/tuple_ctor_nested.rs
Normal 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)));
|
||||
}
|
||||
26
tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs
Normal file
26
tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs
Normal 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));
|
||||
}
|
||||
14
tests/ui/const-generics/mgca/type_as_const_in_array_len.rs
Normal file
14
tests/ui/const-generics/mgca/type_as_const_in_array_len.rs
Normal 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() {}
|
||||
|
|
@ -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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue