From cfd891578241fce69b7f37ec40005ba89e9030e4 Mon Sep 17 00:00:00 2001 From: shove Date: Fri, 12 Jan 2024 22:02:52 +0800 Subject: [PATCH] checker: cleanup the const variable evaluate for fixed array fields of structs (#20503) --- vlib/v/checker/containers.v | 30 ++++++++++++-- vlib/v/checker/struct.v | 54 ++----------------------- vlib/v/tests/constant_array_size_test.v | 18 +++++---- 3 files changed, 41 insertions(+), 61 deletions(-) diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index be6af09942..f3aa960a23 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -247,9 +247,13 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { node.elem_type = elem_type } else if node.is_fixed && node.exprs.len == 1 && node.elem_type != ast.void_type { // `[50]u8` - mut init_expr := node.exprs[0] - node.typ = c.eval_array_fixed_sizes(mut init_expr, 0, node.elem_type) - node.elem_type = (c.table.sym(node.typ).info as ast.ArrayFixed).elem_type + sym := c.table.sym(node.typ) + if sym.info !is ast.ArrayFixed + || c.array_fixed_has_unresolved_size(sym.info as ast.ArrayFixed) { + mut size_expr := node.exprs[0] + node.typ = c.eval_array_fixed_sizes(mut size_expr, 0, node.elem_type) + node.elem_type = (c.table.sym(node.typ).info as ast.ArrayFixed).elem_type + } if node.has_init { c.check_array_init_default_expr(mut node) } @@ -381,6 +385,26 @@ fn (mut c Checker) eval_array_fixed_sizes(mut size_expr ast.Expr, size int, elem } } +fn (mut c Checker) array_fixed_has_unresolved_size(info &ast.ArrayFixed) bool { + if info.size <= 0 { + return true + } + mut elem_type := info.elem_type + mut elem_sym := c.table.sym(elem_type) + for { + if mut elem_sym.info is ast.ArrayFixed { + if elem_sym.info.size <= 0 { + return true + } + elem_type = elem_sym.info.elem_type + elem_sym = c.table.sym(elem_type) + } else { + break + } + } + return false +} + fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type { // `map = {}` if node.keys.len == 0 && node.vals.len == 0 && node.typ == 0 { diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 9173d15f2c..cb49a86198 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -5,7 +5,6 @@ module checker import v.ast import v.util import v.token -import v.transformer fn (mut c Checker) struct_decl(mut node ast.StructDecl) { util.timing_start(@METHOD) @@ -57,56 +56,9 @@ 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) - } + if sym.info is ast.ArrayFixed && c.array_fixed_has_unresolved_size(sym.info) { + mut size_expr := unsafe { sym.info.size_expr } + field.typ = c.eval_array_fixed_sizes(mut size_expr, 0, sym.info.elem_type) for mut symfield in struct_sym.info.fields { if symfield.name == field.name { symfield.typ = field.typ diff --git a/vlib/v/tests/constant_array_size_test.v b/vlib/v/tests/constant_array_size_test.v index c06648676d..0e2c3f8457 100644 --- a/vlib/v/tests/constant_array_size_test.v +++ b/vlib/v/tests/constant_array_size_test.v @@ -9,21 +9,24 @@ fn test_consant_array_size() { b = [1, 2]! } +// for 19593 // test const was declared below struct fixed array fields declaration struct Foo { - posts [max_posts_count]int + arr [width][2][width + 1]f64 } -const max_posts_count = 5 - fn test_const_below_at_struct_fixed_array_fields() { foo := Foo{} - assert foo.posts == [0, 0, 0, 0, 0]! + assert foo.arr.len == 2 + assert foo.arr[0].len == 2 + assert foo.arr[0][0].len == 3 + assert foo.arr == [[[0.0, 0.0, 0.0]!, [0.0, 0.0, 0.0]!]!, + [[0.0, 0.0, 0.0]!, [0.0, 0.0, 0.0]!]!]! } // for issue 20311 -// When using a static variable to define a fixed array size, -// if the static variable is defined below or in another module, the size value will not be calculated correctly. +// when using a const variable to define a fixed array size, +// if the const variable is defined below or in another module, the size value will not be calculated correctly. fn test_const_below_at_fixed_array() { arr := [width][2][width + 1]f64{} assert arr.len == 2 @@ -33,5 +36,6 @@ fn test_const_below_at_fixed_array() { [0.0, 0.0, 0.0]!]!]! } -// Do not move this definition; it must be below `fn test_const_below_at_fixed_array()`. +// do not move this definition, +// it must be below `struct Foo {...}` and `fn test_const_below_at_fixed_array()`. const width = 2