From 8e9f412f747556faa26a46afb5542a8f31c5262f Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Mon, 29 Sep 2025 01:35:57 +0800 Subject: [PATCH] parser: fix evaluation of fixed array size (fix #25404) (#25409) --- vlib/v/checker/containers.v | 3 + vlib/v/parser/parse_type.v | 138 ++++++++++++-------- vlib/v/tests/complex_dim_fixed_array_test.v | 10 ++ 3 files changed, 99 insertions(+), 52 deletions(-) create mode 100644 vlib/v/tests/complex_dim_fixed_array_test.v diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index e9571af0a..d79a8b6bc 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -388,6 +388,9 @@ fn (mut c Checker) eval_array_fixed_sizes(mut size_expr ast.Expr, size int, elem ast.IntegerLiteral { fixed_size = size_expr.expr.val.int() } + ast.FloatLiteral { + fixed_size = int(size_expr.expr.val.f64()) + } ast.EnumVal { if val := c.table.find_enum_field_val(size_expr.expr.enum_name, size_expr.expr.val) diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 774e18d73..215df7219 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -11,75 +11,109 @@ import v.token const maximum_inline_sum_type_variants = 3 const generic_type_level_cutoff_limit = 10 // it is very rarely deeper than 4 -fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Type { - p.check(expecting) - // fixed array - if p.tok.kind in [.number, .name, .dollar] { - mut fixed_size := 0 - mut size_expr := p.expr(0) - mut size_unresolved := true - if p.pref.is_fmt { - fixed_size = 987654321 - } else { - match mut size_expr { +fn (mut p Parser) eval_array_fixed_sizes(mut size_expr ast.Expr) (int, bool) { + mut fixed_size := 0 + mut size_unresolved := true + match mut size_expr { + ast.ParExpr { + return p.eval_array_fixed_sizes(mut size_expr.expr) + } + ast.IntegerLiteral { + fixed_size = size_expr.val.int() + size_unresolved = false + } + ast.ComptimeCall { + if size_expr.kind == .d { + size_expr.resolve_compile_value(p.pref.compile_values) or { + p.error_with_pos(err.msg(), size_expr.pos) + } + if size_expr.result_type != ast.i64_type { + p.error_with_pos('value from \$d() can only be positive integers when used as fixed size', + size_expr.pos) + } + fixed_size = size_expr.compile_value.int() + size_unresolved = false + } else { + p.error_with_pos('only \$d() is supported as fixed array size quantifier at compile time', + size_expr.pos) + } + } + ast.CastExpr { + if !size_expr.typ.is_pure_int() { + p.error_with_pos('only integer types are allowed', size_expr.pos) + } + match mut size_expr.expr { ast.IntegerLiteral { - fixed_size = size_expr.val.int() + fixed_size = size_expr.expr.val.int() size_unresolved = false } - ast.ComptimeCall { - if size_expr.kind == .d { - size_expr.resolve_compile_value(p.pref.compile_values) or { - p.error_with_pos(err.msg(), size_expr.pos) - } - if size_expr.result_type != ast.i64_type { - p.error_with_pos('value from \$d() can only be positive integers when used as fixed size', - size_expr.pos) - } - fixed_size = size_expr.compile_value.int() + ast.FloatLiteral { + fixed_size = int(size_expr.expr.val.f64()) + size_unresolved = false + } + ast.EnumVal { + if val := p.table.find_enum_field_val(size_expr.expr.enum_name, size_expr.expr.val) { + fixed_size = int(val) size_unresolved = false - } else { - p.error_with_pos('only \$d() is supported as fixed array size quantifier at compile time', - size_expr.pos) } } - ast.Ident { - if mut const_field := p.table.global_scope.find_const(size_expr.full_name()) { - if mut const_field.expr is ast.IntegerLiteral { - fixed_size = const_field.expr.val.int() - size_unresolved = false - } else if mut const_field.expr is ast.InfixExpr { - mut t := transformer.new_transformer_with_table(p.table, p.pref) - folded_expr := t.infix_expr(mut const_field.expr) - - if folded_expr is ast.IntegerLiteral { - fixed_size = folded_expr.val.int() - size_unresolved = false - } - } - } else { - if p.pref.is_fmt { - // for vfmt purposes, pretend the constant does exist - // it may have been defined in another .v file: - fixed_size = 1 - size_unresolved = false - } - } + else { + size, unresolved := p.eval_array_fixed_sizes(mut size_expr.expr) + return int(size), unresolved } - ast.InfixExpr { + } + } + ast.Ident { + if mut const_field := p.table.global_scope.find_const(size_expr.full_name().all_after('builtin.')) { + if mut const_field.expr is ast.IntegerLiteral { + fixed_size = const_field.expr.val.int() + size_unresolved = false + } else if mut const_field.expr is ast.InfixExpr { mut t := transformer.new_transformer_with_table(p.table, p.pref) - folded_expr := t.infix_expr(mut size_expr) + folded_expr := t.infix_expr(mut const_field.expr) if folded_expr is ast.IntegerLiteral { fixed_size = folded_expr.val.int() size_unresolved = false } } - else { - p.error_with_pos('fixed array size cannot use non-constant value', - size_expr.pos()) + } else { + if p.pref.is_fmt { + // for vfmt purposes, pretend the constant does exist + // it may have been defined in another .v file: + fixed_size = 1 + size_unresolved = false } } } + ast.InfixExpr { + mut t := transformer.new_transformer_with_table(p.table, p.pref) + folded_expr := t.infix_expr(mut size_expr) + + if folded_expr is ast.IntegerLiteral { + fixed_size = folded_expr.val.int() + size_unresolved = false + } + } + else { + p.error_with_pos('fixed array size cannot use non-constant value', size_expr.pos()) + } + } + return fixed_size, size_unresolved +} + +fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Type { + p.check(expecting) + // fixed array + if p.tok.kind != .rsbr { + mut fixed_size := 0 + mut size_expr := p.expr(0) + mut size_unresolved := true + if p.pref.is_fmt { + fixed_size = 987654321 + } else { + fixed_size, size_unresolved = p.eval_array_fixed_sizes(mut size_expr) + } p.check(.rsbr) p.fixed_array_dim++ defer { diff --git a/vlib/v/tests/complex_dim_fixed_array_test.v b/vlib/v/tests/complex_dim_fixed_array_test.v new file mode 100644 index 000000000..c58936d28 --- /dev/null +++ b/vlib/v/tests/complex_dim_fixed_array_test.v @@ -0,0 +1,10 @@ +const k = 2 + +fn test_complex_dim_fixed_array() { + result := [[0, 0]!, [0, 0]!]! + + assert result == [2][k]int{} + assert result == [2][k + 1 - 1]int{} + assert result == [k][(k + 1) * 2 - 4]int{} + assert result == [k][int(k)]int{} +} -- 2.39.5