parser: fix fixed array with eval const size (#19269)

This commit is contained in:
yuyi 2023-09-04 16:57:25 +08:00 committed by GitHub
parent d04a3e52e3
commit e6b7eb3a29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 27 deletions

View file

@ -25,38 +25,49 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ
}
ast.Ident {
mut show_non_const_error := false
if mut const_field := p.table.global_scope.find_const('${p.mod}.${size_expr.name}') {
if mut const_field.expr is ast.IntegerLiteral {
fixed_size = const_field.expr.val.int()
} else {
if mut const_field.expr is ast.InfixExpr {
// QUESTION: this should most likely no be done in the parser, right?
mut t := transformer.new_transformer(p.pref)
folded_expr := t.infix_expr(mut const_field.expr)
if folded_expr is ast.IntegerLiteral {
fixed_size = folded_expr.val.int()
} else {
show_non_const_error = true
}
} else {
show_non_const_error = true
}
}
} 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
} else {
show_non_const_error = true
}
}
fixed_size, show_non_const_error = p.check_and_eval_const_val(size_expr)
if show_non_const_error {
p.error_with_pos('non-constant array bound `${size_expr.name}`',
size_expr.pos)
}
}
ast.InfixExpr {
mut show_non_const_error := false
mut left_val := 1
mut right_val := 1
if size_expr.left is ast.Ident {
left_val, show_non_const_error = p.check_and_eval_const_val(size_expr.left)
if show_non_const_error {
p.error_with_pos('non-constant array bound `${size_expr.left.name}`',
size_expr.left.pos)
}
}
if size_expr.right is ast.Ident && !show_non_const_error {
right_val, show_non_const_error = p.check_and_eval_const_val(size_expr.right)
if show_non_const_error {
p.error_with_pos('non-constant array bound `${size_expr.right.name}`',
size_expr.right.pos)
}
}
match size_expr.op {
.plus {
fixed_size = left_val + right_val
}
.minus {
fixed_size = left_val - right_val
}
.mul {
fixed_size = left_val * right_val
}
.div {
fixed_size = left_val / right_val
}
else {
p.error_with_pos('fixed array size cannot use non-constant value',
size_expr.pos)
}
}
}
else {
p.error_with_pos('fixed array size cannot use non-constant value',
size_expr.pos())
@ -840,3 +851,29 @@ fn (mut p Parser) parse_generic_inst_type(name string) ast.Type {
}
return p.find_type_or_add_placeholder(name, .v).set_flag(.generic)
}
// return value and show_non_const_error
fn (mut p Parser) check_and_eval_const_val(expr ast.Ident) (int, bool) {
if mut const_field := p.table.global_scope.find_const('${p.mod}.${expr.name}') {
if mut const_field.expr is ast.IntegerLiteral {
return const_field.expr.val.int(), false
} else {
if mut const_field.expr is ast.InfixExpr {
// QUESTION: this should most likely no be done in the parser, right?
mut t := transformer.new_transformer(p.pref)
folded_expr := t.infix_expr(mut const_field.expr)
if folded_expr is ast.IntegerLiteral {
return folded_expr.val.int(), false
}
}
}
} else {
if p.pref.is_fmt {
// for vfmt purposes, pretend the constant does exist
// it may have been defined in another .v file:
return 1, false
}
}
return 0, true
}

View file

@ -44,3 +44,18 @@ fn test_int_const_used_as_fixed_array_size() {
dump(bb.len)
assert aa.len == 10_000
}
const (
rows = 4
cols = 4
)
struct Matrix {
data [rows * cols]int
}
fn test_infix_const_expr_used_as_fixed_array_size() {
mat := Matrix{}
println(mat)
assert mat.data.len == 16
}