Skip to content

Commit 8e9f412

Browse files
authored
parser: fix evaluation of fixed array size (fix #25404) (#25409)
1 parent 67d30eb commit 8e9f412

3 files changed

Lines changed: 99 additions & 52 deletions

File tree

‎vlib/v/checker/containers.v‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ fn (mut c Checker) eval_array_fixed_sizes(mut size_expr ast.Expr, size int, elem
388388
ast.IntegerLiteral {
389389
fixed_size = size_expr.expr.val.int()
390390
}
391+
ast.FloatLiteral {
392+
fixed_size = int(size_expr.expr.val.f64())
393+
}
391394
ast.EnumVal {
392395
if val := c.table.find_enum_field_val(size_expr.expr.enum_name,
393396
size_expr.expr.val)

‎vlib/v/parser/parse_type.v‎

Lines changed: 86 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,75 +11,109 @@ import v.token
1111
const maximum_inline_sum_type_variants = 3
1212
const generic_type_level_cutoff_limit = 10 // it is very rarely deeper than 4
1313

14-
fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Type {
15-
p.check(expecting)
16-
// fixed array
17-
if p.tok.kind in [.number, .name, .dollar] {
18-
mut fixed_size := 0
19-
mut size_expr := p.expr(0)
20-
mut size_unresolved := true
21-
if p.pref.is_fmt {
22-
fixed_size = 987654321
23-
} else {
24-
match mut size_expr {
14+
fn (mut p Parser) eval_array_fixed_sizes(mut size_expr ast.Expr) (int, bool) {
15+
mut fixed_size := 0
16+
mut size_unresolved := true
17+
match mut size_expr {
18+
ast.ParExpr {
19+
return p.eval_array_fixed_sizes(mut size_expr.expr)
20+
}
21+
ast.IntegerLiteral {
22+
fixed_size = size_expr.val.int()
23+
size_unresolved = false
24+
}
25+
ast.ComptimeCall {
26+
if size_expr.kind == .d {
27+
size_expr.resolve_compile_value(p.pref.compile_values) or {
28+
p.error_with_pos(err.msg(), size_expr.pos)
29+
}
30+
if size_expr.result_type != ast.i64_type {
31+
p.error_with_pos('value from \$d() can only be positive integers when used as fixed size',
32+
size_expr.pos)
33+
}
34+
fixed_size = size_expr.compile_value.int()
35+
size_unresolved = false
36+
} else {
37+
p.error_with_pos('only \$d() is supported as fixed array size quantifier at compile time',
38+
size_expr.pos)
39+
}
40+
}
41+
ast.CastExpr {
42+
if !size_expr.typ.is_pure_int() {
43+
p.error_with_pos('only integer types are allowed', size_expr.pos)
44+
}
45+
match mut size_expr.expr {
2546
ast.IntegerLiteral {
26-
fixed_size = size_expr.val.int()
47+
fixed_size = size_expr.expr.val.int()
2748
size_unresolved = false
2849
}
29-
ast.ComptimeCall {
30-
if size_expr.kind == .d {
31-
size_expr.resolve_compile_value(p.pref.compile_values) or {
32-
p.error_with_pos(err.msg(), size_expr.pos)
33-
}
34-
if size_expr.result_type != ast.i64_type {
35-
p.error_with_pos('value from \$d() can only be positive integers when used as fixed size',
36-
size_expr.pos)
37-
}
38-
fixed_size = size_expr.compile_value.int()
50+
ast.FloatLiteral {
51+
fixed_size = int(size_expr.expr.val.f64())
52+
size_unresolved = false
53+
}
54+
ast.EnumVal {
55+
if val := p.table.find_enum_field_val(size_expr.expr.enum_name, size_expr.expr.val) {
56+
fixed_size = int(val)
3957
size_unresolved = false
40-
} else {
41-
p.error_with_pos('only \$d() is supported as fixed array size quantifier at compile time',
42-
size_expr.pos)
4358
}
4459
}
45-
ast.Ident {
46-
if mut const_field := p.table.global_scope.find_const(size_expr.full_name()) {
47-
if mut const_field.expr is ast.IntegerLiteral {
48-
fixed_size = const_field.expr.val.int()
49-
size_unresolved = false
50-
} else if mut const_field.expr is ast.InfixExpr {
51-
mut t := transformer.new_transformer_with_table(p.table, p.pref)
52-
folded_expr := t.infix_expr(mut const_field.expr)
53-
54-
if folded_expr is ast.IntegerLiteral {
55-
fixed_size = folded_expr.val.int()
56-
size_unresolved = false
57-
}
58-
}
59-
} else {
60-
if p.pref.is_fmt {
61-
// for vfmt purposes, pretend the constant does exist
62-
// it may have been defined in another .v file:
63-
fixed_size = 1
64-
size_unresolved = false
65-
}
66-
}
60+
else {
61+
size, unresolved := p.eval_array_fixed_sizes(mut size_expr.expr)
62+
return int(size), unresolved
6763
}
68-
ast.InfixExpr {
64+
}
65+
}
66+
ast.Ident {
67+
if mut const_field := p.table.global_scope.find_const(size_expr.full_name().all_after('builtin.')) {
68+
if mut const_field.expr is ast.IntegerLiteral {
69+
fixed_size = const_field.expr.val.int()
70+
size_unresolved = false
71+
} else if mut const_field.expr is ast.InfixExpr {
6972
mut t := transformer.new_transformer_with_table(p.table, p.pref)
70-
folded_expr := t.infix_expr(mut size_expr)
73+
folded_expr := t.infix_expr(mut const_field.expr)
7174

7275
if folded_expr is ast.IntegerLiteral {
7376
fixed_size = folded_expr.val.int()
7477
size_unresolved = false
7578
}
7679
}
77-
else {
78-
p.error_with_pos('fixed array size cannot use non-constant value',
79-
size_expr.pos())
80+
} else {
81+
if p.pref.is_fmt {
82+
// for vfmt purposes, pretend the constant does exist
83+
// it may have been defined in another .v file:
84+
fixed_size = 1
85+
size_unresolved = false
8086
}
8187
}
8288
}
89+
ast.InfixExpr {
90+
mut t := transformer.new_transformer_with_table(p.table, p.pref)
91+
folded_expr := t.infix_expr(mut size_expr)
92+
93+
if folded_expr is ast.IntegerLiteral {
94+
fixed_size = folded_expr.val.int()
95+
size_unresolved = false
96+
}
97+
}
98+
else {
99+
p.error_with_pos('fixed array size cannot use non-constant value', size_expr.pos())
100+
}
101+
}
102+
return fixed_size, size_unresolved
103+
}
104+
105+
fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Type {
106+
p.check(expecting)
107+
// fixed array
108+
if p.tok.kind != .rsbr {
109+
mut fixed_size := 0
110+
mut size_expr := p.expr(0)
111+
mut size_unresolved := true
112+
if p.pref.is_fmt {
113+
fixed_size = 987654321
114+
} else {
115+
fixed_size, size_unresolved = p.eval_array_fixed_sizes(mut size_expr)
116+
}
83117
p.check(.rsbr)
84118
p.fixed_array_dim++
85119
defer {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const k = 2
2+
3+
fn test_complex_dim_fixed_array() {
4+
result := [[0, 0]!, [0, 0]!]!
5+
6+
assert result == [2][k]int{}
7+
assert result == [2][k + 1 - 1]int{}
8+
assert result == [k][(k + 1) * 2 - 4]int{}
9+
assert result == [k][int(k)]int{}
10+
}

0 commit comments

Comments
 (0)