Auto merge of #150786 - reddevilmidzy:mgca-array, r=BoxyUwU
mGCA: Support array expression as direct const arguments tracking issue: rust-lang/rust#132980 resolve: rust-lang/rust#150612 Support array expression as direct const arguments (e. g. [1, 2, N]) in min_generic_const_args. todo: * [x] Rebase another mGCA PR * [x] Add more test case * [x] Modify clippy code
This commit is contained in:
commit
137716908d
20 changed files with 235 additions and 1 deletions
|
|
@ -2517,6 +2517,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span,
|
||||
}
|
||||
}
|
||||
ExprKind::Array(elements) => {
|
||||
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
|
||||
let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(element)
|
||||
};
|
||||
&*self.arena.alloc(const_arg)
|
||||
}));
|
||||
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
|
||||
span: self.lower_span(expr.span),
|
||||
elems: lowered_elems,
|
||||
});
|
||||
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Array(array_expr),
|
||||
span,
|
||||
}
|
||||
}
|
||||
ExprKind::Underscore => ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Infer(()),
|
||||
|
|
@ -2532,6 +2554,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| ExprKind::Struct(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Array(..)
|
||||
)
|
||||
{
|
||||
return self.lower_expr_to_const_arg_direct(expr);
|
||||
|
|
|
|||
|
|
@ -513,6 +513,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
|
|||
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
|
||||
/// Tuple constructor variant
|
||||
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
|
||||
/// Array literal argument
|
||||
Array(&'hir ConstArgArrayExpr<'hir>),
|
||||
/// Error const
|
||||
Error(ErrorGuaranteed),
|
||||
/// This variant is not always used to represent inference consts, sometimes
|
||||
|
|
@ -529,6 +531,12 @@ pub struct ConstArgExprField<'hir> {
|
|||
pub expr: &'hir ConstArg<'hir>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub struct ConstArgArrayExpr<'hir> {
|
||||
pub span: Span,
|
||||
pub elems: &'hir [&'hir ConstArg<'hir>],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub struct InferArg {
|
||||
#[stable_hasher(ignore)]
|
||||
|
|
|
|||
|
|
@ -1101,6 +1101,12 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
|
|||
}
|
||||
V::Result::output()
|
||||
}
|
||||
ConstArgKind::Array(array_expr) => {
|
||||
for arg in array_expr.elems {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2389,6 +2389,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::ConstArgKind::TupleCall(qpath, args) => {
|
||||
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span)
|
||||
}
|
||||
hir::ConstArgKind::Array(array_expr) => self.lower_const_arg_array(array_expr, feed),
|
||||
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
|
||||
hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span),
|
||||
hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e),
|
||||
|
|
@ -2402,6 +2403,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_const_arg_array(
|
||||
&self,
|
||||
array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>,
|
||||
feed: FeedConstTy<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let FeedConstTy::WithTy(ty) = feed else {
|
||||
return Const::new_error_with_message(tcx, array_expr.span, "unsupported const array");
|
||||
};
|
||||
|
||||
let ty::Array(elem_ty, _) = ty.kind() else {
|
||||
return Const::new_error_with_message(
|
||||
tcx,
|
||||
array_expr.span,
|
||||
"const array must have an array type",
|
||||
);
|
||||
};
|
||||
|
||||
let elems = array_expr
|
||||
.elems
|
||||
.iter()
|
||||
.map(|elem| self.lower_const_arg(elem, FeedConstTy::WithTy(*elem_ty)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let valtree = ty::ValTree::from_branches(tcx, elems);
|
||||
|
||||
ty::Const::new_value(tcx, valtree, ty)
|
||||
}
|
||||
|
||||
fn lower_const_arg_tuple_call(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
|
|
|
|||
|
|
@ -1153,6 +1153,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields),
|
||||
ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args),
|
||||
ConstArgKind::Array(..) => self.word("/* ARRAY EXPR */"),
|
||||
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::Array(..)
|
||||
| hir::ConstArgKind::TupleCall(..)
|
||||
| hir::ConstArgKind::Tup(..)
|
||||
| hir::ConstArgKind::Path(..)
|
||||
|
|
|
|||
|
|
@ -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(_) | ExprKind::Call(..) | ExprKind::Tup(..) => {
|
||||
ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) | ExprKind::Array(..) => {
|
||||
return visit::walk_expr(self, expr);
|
||||
}
|
||||
// FIXME(mgca): we may want to handle block labels in some manner
|
||||
|
|
|
|||
|
|
@ -330,6 +330,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind
|
|||
// FIXME(mgca): proper printing :3
|
||||
ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() }
|
||||
}
|
||||
hir::ConstArgKind::Array(..) => {
|
||||
ConstantKind::Path { path: "/* ARRAY EXPR */".to_string().into() }
|
||||
}
|
||||
hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
|
||||
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
|
||||
hir::ConstArgKind::Literal(..) => {
|
||||
|
|
@ -1818,6 +1821,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
|||
| hir::ConstArgKind::Path(..)
|
||||
| hir::ConstArgKind::TupleCall(..)
|
||||
| hir::ConstArgKind::Tup(..)
|
||||
| hir::ConstArgKind::Array(..)
|
||||
| hir::ConstArgKind::Literal(..) => {
|
||||
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
|
||||
print_const(cx, ct)
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
},
|
||||
ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"),
|
||||
ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Array(..) => chain!(self, "let ConstArgKind::Array(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"),
|
||||
|
|
|
|||
|
|
@ -1144,6 +1144,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx
|
|||
| ConstArgKind::Tup(..)
|
||||
| ConstArgKind::Literal(..)
|
||||
| ConstArgKind::TupleCall(..)
|
||||
| ConstArgKind::Array(..)
|
||||
| ConstArgKind::Path(_)
|
||||
| ConstArgKind::Error(..)
|
||||
| ConstArgKind::Infer(..) => None,
|
||||
|
|
|
|||
|
|
@ -687,6 +687,11 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
.all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b))
|
||||
},
|
||||
(ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r,
|
||||
(ConstArgKind::Array(l_arr), ConstArgKind::Array(r_arr)) => {
|
||||
l_arr.elems.len() == r_arr.elems.len()
|
||||
&& l_arr.elems.iter().zip(r_arr.elems.iter())
|
||||
.all(|(l_elem, r_elem)| self.eq_const_arg(l_elem, r_elem))
|
||||
}
|
||||
// Use explicit match for now since ConstArg is undergoing flux.
|
||||
(
|
||||
ConstArgKind::Path(..)
|
||||
|
|
@ -696,6 +701,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
| ConstArgKind::Infer(..)
|
||||
| ConstArgKind::Struct(..)
|
||||
| ConstArgKind::Literal(..)
|
||||
| ConstArgKind::Array(..)
|
||||
| ConstArgKind::Error(..),
|
||||
_,
|
||||
) => false,
|
||||
|
|
@ -1575,6 +1581,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
self.hash_const_arg(arg);
|
||||
}
|
||||
},
|
||||
ConstArgKind::Array(array_expr) => {
|
||||
for elem in array_expr.elems {
|
||||
self.hash_const_arg(elem);
|
||||
}
|
||||
},
|
||||
ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {},
|
||||
ConstArgKind::Literal(lit) => lit.hash(&mut self.s),
|
||||
}
|
||||
|
|
|
|||
16
tests/ui/const-generics/mgca/array-expr-complex.rs
Normal file
16
tests/ui/const-generics/mgca/array-expr-complex.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#![expect(incomplete_features)]
|
||||
#![feature(min_generic_const_args, adt_const_params)]
|
||||
|
||||
fn takes_array<const A: [u32; 3]>() {}
|
||||
|
||||
fn generic_caller<const X: u32, const Y: usize>() {
|
||||
// not supported yet
|
||||
takes_array::<{ [1, 2, 1 + 2] }>();
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
takes_array::<{ [X; 3] }>();
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
takes_array::<{ [0; Y] }>();
|
||||
//~^ ERROR: complex const arguments must be placed inside of a `const` block
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
20
tests/ui/const-generics/mgca/array-expr-complex.stderr
Normal file
20
tests/ui/const-generics/mgca/array-expr-complex.stderr
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/array-expr-complex.rs:8:28
|
||||
|
|
||||
LL | takes_array::<{ [1, 2, 1 + 2] }>();
|
||||
| ^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/array-expr-complex.rs:10:19
|
||||
|
|
||||
LL | takes_array::<{ [X; 3] }>();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: complex const arguments must be placed inside of a `const` block
|
||||
--> $DIR/array-expr-complex.rs:12:19
|
||||
|
|
||||
LL | takes_array::<{ [0; Y] }>();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
9
tests/ui/const-generics/mgca/array-expr-empty.rs
Normal file
9
tests/ui/const-generics/mgca/array-expr-empty.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#![expect(incomplete_features)]
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
fn takes_empty_array<const A: []>() {}
|
||||
//~^ ERROR: expected type, found `]`
|
||||
|
||||
fn main() {
|
||||
takes_empty_array::<{ [] }>();
|
||||
}
|
||||
8
tests/ui/const-generics/mgca/array-expr-empty.stderr
Normal file
8
tests/ui/const-generics/mgca/array-expr-empty.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: expected type, found `]`
|
||||
--> $DIR/array-expr-empty.rs:4:32
|
||||
|
|
||||
LL | fn takes_empty_array<const A: []>() {}
|
||||
| ^ expected type
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
25
tests/ui/const-generics/mgca/array-expr-simple.rs
Normal file
25
tests/ui/const-generics/mgca/array-expr-simple.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//@ run-pass
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(min_generic_const_args, adt_const_params)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn takes_array_u32<const A: [u32; 3]>() {}
|
||||
fn takes_array_bool<const A: [bool; 2]>() {}
|
||||
fn takes_nested_array<const A: [[u32; 2]; 2]>() {}
|
||||
fn takes_empty_array<const A: [u32; 0]>() {}
|
||||
|
||||
fn generic_caller<const X: u32, const Y: u32>() {
|
||||
takes_array_u32::<{ [X, Y, X] }>();
|
||||
takes_array_u32::<{ [X, Y, const { 1 }] }>();
|
||||
takes_array_u32::<{ [X, Y, const { 1 + 1 }] }>();
|
||||
takes_array_u32::<{ [2_002, 2u32, 1_u32] }>();
|
||||
|
||||
takes_array_bool::<{ [true, false] }>();
|
||||
|
||||
takes_nested_array::<{ [[X, Y], [3, 4]] }>();
|
||||
takes_nested_array::<{ [[1u32, 2_u32], [const { 3 }, 4]] }>();
|
||||
|
||||
takes_empty_array::<{ [] }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
18
tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs
Normal file
18
tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//@ run-pass
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(min_generic_const_args, adt_const_params)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn takes_array<const A: [u32; 3]>() {}
|
||||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: u32;
|
||||
}
|
||||
|
||||
fn generic_caller<T: Trait, const N: u32>() {
|
||||
takes_array::<{ [T::ASSOC, N, T::ASSOC] }>();
|
||||
takes_array::<{ [1_u32, T::ASSOC, 2] }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
18
tests/ui/const-generics/mgca/array-expr-with-macro.rs
Normal file
18
tests/ui/const-generics/mgca/array-expr-with-macro.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//@ run-pass
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(min_generic_const_args, adt_const_params)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
macro_rules! make_array {
|
||||
($n:expr, $m:expr, $p:expr) => {
|
||||
[N, $m, $p]
|
||||
};
|
||||
}
|
||||
|
||||
fn takes_array<const A: [u32; 3]>() {}
|
||||
|
||||
fn generic_caller<const N: u32>() {
|
||||
takes_array::<{ make_array!(N, 2, 3) }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
20
tests/ui/const-generics/mgca/array-expr-with-struct.rs
Normal file
20
tests/ui/const-generics/mgca/array-expr-with-struct.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//@ run-pass
|
||||
#![feature(min_generic_const_args, adt_const_params)]
|
||||
#![expect(incomplete_features)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::marker::ConstParamTy;
|
||||
|
||||
#[derive(PartialEq, Eq, ConstParamTy)]
|
||||
struct Container {
|
||||
values: [u32; 3],
|
||||
}
|
||||
|
||||
fn takes_container<const C: Container>() {}
|
||||
|
||||
fn generic_caller<const N: u32, const M: u32>() {
|
||||
takes_container::<{ Container { values: [N, M, 1] } }>();
|
||||
takes_container::<{ Container { values: [1, 2, 3] } }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
13
tests/ui/const-generics/mgca/array-expr-with-tuple.rs
Normal file
13
tests/ui/const-generics/mgca/array-expr-with-tuple.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//@ run-pass
|
||||
#![feature(min_generic_const_args, adt_const_params, unsized_const_params)]
|
||||
#![expect(incomplete_features)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn takes_tuple<const T: ([u32; 2], u32, [u32; 2])>() {}
|
||||
|
||||
fn generic_caller<const N: u32, const M: u32>() {
|
||||
takes_tuple::<{ ([N, M], 5, [M, N]) }>();
|
||||
takes_tuple::<{ ([1, 2], 3, [4, 5]) }>();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue