mirror of
https://github.com/vlang/v.git
synced 2025-09-12 17:07:11 -04:00
parser, checker: fix const var below at struct fixed array fields(fix#19593) (#19893)
This commit is contained in:
parent
6d2f79176a
commit
4dff383e35
@ -4,6 +4,7 @@ module checker
|
|||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.util
|
import v.util
|
||||||
|
import v.transformer
|
||||||
|
|
||||||
fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
|
fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
|
||||||
util.timing_start(@METHOD)
|
util.timing_start(@METHOD)
|
||||||
@ -52,6 +53,67 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate the size of the unresolved fixed array
|
||||||
|
for mut field in node.fields {
|
||||||
|
sym := c.table.sym(field.typ)
|
||||||
|
if sym.kind == .array_fixed {
|
||||||
|
info := sym.info as ast.ArrayFixed
|
||||||
|
if info.size > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mut fixed_size := 0
|
||||||
|
match info.size_expr {
|
||||||
|
ast.Ident {
|
||||||
|
if mut const_field := c.table.global_scope.find_const('${c.mod}.${info.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 {
|
||||||
|
mut t := transformer.new_transformer_with_table(c.table,
|
||||||
|
c.pref)
|
||||||
|
folded_expr := t.infix_expr(mut const_field.expr)
|
||||||
|
if folded_expr is ast.IntegerLiteral {
|
||||||
|
fixed_size = folded_expr.val.int()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fixed_size <= 0 {
|
||||||
|
c.error('non-constant array bound `${info.size_expr.name}`',
|
||||||
|
info.size_expr.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.InfixExpr {
|
||||||
|
mut t := transformer.new_transformer_with_table(c.table, c.pref)
|
||||||
|
mut size_expr := unsafe { &info.size_expr }
|
||||||
|
folded_expr := t.infix_expr(mut size_expr)
|
||||||
|
|
||||||
|
if folded_expr is ast.IntegerLiteral {
|
||||||
|
fixed_size = folded_expr.val.int()
|
||||||
|
}
|
||||||
|
if fixed_size <= 0 {
|
||||||
|
c.error('fixed array size cannot use non-constant eval value',
|
||||||
|
info.size_expr.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
if fixed_size <= 0 {
|
||||||
|
c.error('fixed size cannot be zero or negative', info.size_expr.pos())
|
||||||
|
}
|
||||||
|
idx := c.table.find_or_register_array_fixed(info.elem_type, fixed_size,
|
||||||
|
info.size_expr, false)
|
||||||
|
if info.elem_type.has_flag(.generic) {
|
||||||
|
field.typ = ast.new_type(idx).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
field.typ = ast.new_type(idx)
|
||||||
|
}
|
||||||
|
for mut symfield in struct_sym.info.fields {
|
||||||
|
if symfield.name == field.name {
|
||||||
|
symfield.typ = field.typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update .default_expr_typ for all fields in the struct:
|
// Update .default_expr_typ for all fields in the struct:
|
||||||
util.timing_start('Checker.struct setting default_expr_typ')
|
util.timing_start('Checker.struct setting default_expr_typ')
|
||||||
old_expected_type := c.expected_type
|
old_expected_type := c.expected_type
|
||||||
|
@ -1459,7 +1459,7 @@ pub fn (mut g Gen) write_typedef_types() {
|
|||||||
mut def_str := 'typedef ${fixed};'
|
mut def_str := 'typedef ${fixed};'
|
||||||
def_str = def_str.replace_once('(*)', '(*${styp}[${len}])')
|
def_str = def_str.replace_once('(*)', '(*${styp}[${len}])')
|
||||||
g.type_definitions.writeln(def_str)
|
g.type_definitions.writeln(def_str)
|
||||||
} else if !info.is_fn_ret {
|
} else if !info.is_fn_ret && len.int() > 0 {
|
||||||
g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];')
|
g.type_definitions.writeln('typedef ${fixed} ${styp} [${len}];')
|
||||||
base := g.typ(info.elem_type.clear_flags(.option, .result))
|
base := g.typ(info.elem_type.clear_flags(.option, .result))
|
||||||
if info.elem_type.has_flag(.option) && base !in g.options_forward {
|
if info.elem_type.has_flag(.option) && base !in g.options_forward {
|
||||||
@ -6044,7 +6044,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
|
|||||||
mut def_str := 'typedef ${fixed_elem_name};'
|
mut def_str := 'typedef ${fixed_elem_name};'
|
||||||
def_str = def_str.replace_once('(*)', '(*${styp}[${len}])')
|
def_str = def_str.replace_once('(*)', '(*${styp}[${len}])')
|
||||||
g.type_definitions.writeln(def_str)
|
g.type_definitions.writeln(def_str)
|
||||||
} else {
|
} else if len > 0 {
|
||||||
g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];')
|
g.type_definitions.writeln('typedef ${fixed_elem_name} ${styp} [${len}];')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,30 +16,28 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ
|
|||||||
if p.tok.kind in [.number, .name] {
|
if p.tok.kind in [.number, .name] {
|
||||||
mut fixed_size := 0
|
mut fixed_size := 0
|
||||||
mut size_expr := p.expr(0)
|
mut size_expr := p.expr(0)
|
||||||
|
mut size_unresolved := true
|
||||||
if p.pref.is_fmt {
|
if p.pref.is_fmt {
|
||||||
fixed_size = 987654321
|
fixed_size = 987654321
|
||||||
} else {
|
} else {
|
||||||
match mut size_expr {
|
match mut size_expr {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
fixed_size = size_expr.val.int()
|
fixed_size = size_expr.val.int()
|
||||||
|
size_unresolved = false
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
mut show_non_const_error := true
|
|
||||||
if mut const_field := p.table.global_scope.find_const('${p.mod}.${size_expr.name}') {
|
if mut const_field := p.table.global_scope.find_const('${p.mod}.${size_expr.name}') {
|
||||||
if mut const_field.expr is ast.IntegerLiteral {
|
if mut const_field.expr is ast.IntegerLiteral {
|
||||||
fixed_size = const_field.expr.val.int()
|
fixed_size = const_field.expr.val.int()
|
||||||
show_non_const_error = false
|
size_unresolved = false
|
||||||
} else {
|
} else if mut const_field.expr is ast.InfixExpr {
|
||||||
if mut const_field.expr is ast.InfixExpr {
|
// QUESTION: this should most likely no be done in the parser, right?
|
||||||
// QUESTION: this should most likely no be done in the parser, right?
|
mut t := transformer.new_transformer_with_table(p.table, p.pref)
|
||||||
mut t := transformer.new_transformer_with_table(p.table,
|
folded_expr := t.infix_expr(mut const_field.expr)
|
||||||
p.pref)
|
|
||||||
folded_expr := t.infix_expr(mut const_field.expr)
|
|
||||||
|
|
||||||
if folded_expr is ast.IntegerLiteral {
|
if folded_expr is ast.IntegerLiteral {
|
||||||
fixed_size = folded_expr.val.int()
|
fixed_size = folded_expr.val.int()
|
||||||
show_non_const_error = false
|
size_unresolved = false
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -47,26 +45,17 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ
|
|||||||
// for vfmt purposes, pretend the constant does exist
|
// for vfmt purposes, pretend the constant does exist
|
||||||
// it may have been defined in another .v file:
|
// it may have been defined in another .v file:
|
||||||
fixed_size = 1
|
fixed_size = 1
|
||||||
show_non_const_error = false
|
size_unresolved = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if show_non_const_error {
|
|
||||||
p.error_with_pos('non-constant array bound `${size_expr.name}`',
|
|
||||||
size_expr.pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
mut show_non_const_error := true
|
|
||||||
mut t := transformer.new_transformer_with_table(p.table, p.pref)
|
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 size_expr)
|
||||||
|
|
||||||
if folded_expr is ast.IntegerLiteral {
|
if folded_expr is ast.IntegerLiteral {
|
||||||
fixed_size = folded_expr.val.int()
|
fixed_size = folded_expr.val.int()
|
||||||
show_non_const_error = false
|
size_unresolved = false
|
||||||
}
|
|
||||||
if show_non_const_error {
|
|
||||||
p.error_with_pos('fixed array size cannot use non-constant eval value',
|
|
||||||
size_expr.pos)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -85,7 +74,10 @@ fn (mut p Parser) parse_array_type(expecting token.Kind, is_option bool) ast.Typ
|
|||||||
// error is handled by parse_type
|
// error is handled by parse_type
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if fixed_size <= 0 {
|
// TODO:
|
||||||
|
// For now, when a const variable or expression is temporarily unavailable to evaluate,
|
||||||
|
// only pending struct fields are deferred.
|
||||||
|
if fixed_size <= 0 && (!p.inside_struct_field_decl || !size_unresolved) {
|
||||||
p.error_with_pos('fixed size cannot be zero or negative', size_expr.pos())
|
p.error_with_pos('fixed size cannot be zero or negative', size_expr.pos())
|
||||||
}
|
}
|
||||||
idx := p.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr,
|
idx := p.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr,
|
||||||
|
@ -10,3 +10,15 @@ fn test_consant_array_size() {
|
|||||||
mut b := [c_b_s]int{}
|
mut b := [c_b_s]int{}
|
||||||
b = [1, 2]!
|
b = [1, 2]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test const was declared below struct fixed array fields declaration
|
||||||
|
struct Foo {
|
||||||
|
posts [max_posts_count]int
|
||||||
|
}
|
||||||
|
|
||||||
|
const max_posts_count = 5
|
||||||
|
|
||||||
|
fn test_const_below_at_struct_fixed_array_fields() {
|
||||||
|
foo := Foo{}
|
||||||
|
assert foo.posts == [0, 0, 0, 0, 0]!
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user