From a065d014a2d916af36c2066b7ee13a6da19e975d Mon Sep 17 00:00:00 2001
From: Lukas Neubert <serkonda@protonmail.com>
Date: Wed, 28 Apr 2021 21:11:15 +0200
Subject: [PATCH] fmt: keep constant sizes in struct field fixed array types
 (#9910)

---
 cmd/tools/vtest-cleancode.v                    |  2 --
 vlib/v/ast/table.v                             | 17 ++++++++++++-----
 vlib/v/ast/types.v                             |  9 ++++++++-
 vlib/v/checker/checker.v                       |  6 ++++--
 vlib/v/fmt/tests/fixed_size_array_type_keep.vv |  7 +++++++
 vlib/v/parser/parse_type.v                     |  2 +-
 6 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/cmd/tools/vtest-cleancode.v b/cmd/tools/vtest-cleancode.v
index 281e69a949..15bd3908de 100644
--- a/cmd/tools/vtest-cleancode.v
+++ b/cmd/tools/vtest-cleancode.v
@@ -30,8 +30,6 @@ const (
 		// TODOs and unfixed vfmt bugs
 		'vlib/builtin/int.v' /* TODO byteptr: vfmt converts `pub fn (nn byteptr) str() string {` to `nn &byte` and that conflicts with `nn byte` */,
 		'vlib/builtin/string_charptr_byteptr_helpers.v' /* TODO byteptr: a temporary shim to ease the byteptr=>&byte transition */,
-		'vlib/v/tests/array_append_short_struct_test.v', /* extra empty line */
-		'vlib/v/tests/fixed_array_const_size_test.v', /* fixed arr type is changed */
 		'vlib/v/tests/fn_high_test.v', /* param name removed */
 		'vlib/v/tests/fn_test.v', /* bad comment formatting */
 		'vlib/v/tests/generics_return_generics_struct_test.v', /* generic fn param removed */
diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v
index c44a3c8ada..f7973b04a5 100644
--- a/vlib/v/ast/table.v
+++ b/vlib/v/ast/table.v
@@ -577,10 +577,16 @@ pub fn (t &Table) array_cname(elem_type Type) string {
 // array_fixed_source_name generates the original name for the v source.
 // e. g. [16][8]int
 [inline]
-pub fn (t &Table) array_fixed_name(elem_type Type, size int) string {
+pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) string {
 	elem_type_sym := t.get_type_symbol(elem_type)
 	ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
-	return '[$size]$ptr$elem_type_sym.name'
+	mut size_str := size.str()
+	if t.is_fmt {
+		if size_expr is Ident {
+			size_str = size_expr.name
+		}
+	}
+	return '[$size_str]$ptr$elem_type_sym.name'
 }
 
 [inline]
@@ -760,8 +766,8 @@ pub fn (mut t Table) find_or_register_array_with_dims(elem_type Type, nr_dims in
 	return t.find_or_register_array(t.find_or_register_array_with_dims(elem_type, nr_dims - 1))
 }
 
-pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int) int {
-	name := t.array_fixed_name(elem_type, size)
+pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size_expr Expr) int {
+	name := t.array_fixed_name(elem_type, size, size_expr)
 	cname := t.array_fixed_cname(elem_type, size)
 	// existing
 	existing_idx := t.type_idxs[name]
@@ -776,6 +782,7 @@ pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int) int
 		info: ArrayFixed{
 			elem_type: elem_type
 			size: size
+			expr: size_expr
 		}
 	}
 	return t.register_type_symbol(array_fixed_type)
@@ -983,7 +990,7 @@ pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
 			if bit_size % 8 != 0 { // there is no way to do `i2131(32)` so this should never be reached
 				t.panic('compiler bug: bitsizes must be multiples of 8')
 			}
-			return new_type(t.find_or_register_array_fixed(byte_type, bit_size / 8))
+			return new_type(t.find_or_register_array_fixed(byte_type, bit_size / 8, EmptyExpr{}))
 		}
 	}
 }
diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v
index 4db2f51b1e..6d958cd847 100644
--- a/vlib/v/ast/types.v
+++ b/vlib/v/ast/types.v
@@ -792,6 +792,7 @@ pub mut:
 pub struct ArrayFixed {
 pub:
 	size int
+	expr Expr // used by fmt for e.g. ´[my_const]byte´
 pub mut:
 	elem_type Type
 }
@@ -874,7 +875,13 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
 		.array_fixed {
 			info := sym.info as ArrayFixed
 			elem_str := t.type_to_str_using_aliases(info.elem_type, import_aliases)
-			res = '[$info.size]$elem_str'
+			mut size_str := info.size.str()
+			if t.is_fmt {
+				if info.expr is Ident {
+					size_str = info.expr.name
+				}
+			}
+			res = '[$size_str]$elem_str'
 		}
 		.chan {
 			// TODO currently the `chan` struct in builtin is not considered a struct but a chan
diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v
index 9af2d2937c..5d23ec254d 100644
--- a/vlib/v/checker/checker.v
+++ b/vlib/v/checker/checker.v
@@ -3433,7 +3433,8 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
 			}
 		}
 		if array_init.is_fixed {
-			idx := c.table.find_or_register_array_fixed(elem_type, array_init.exprs.len)
+			idx := c.table.find_or_register_array_fixed(elem_type, array_init.exprs.len,
+				ast.EmptyExpr{})
 			if elem_type.has_flag(.generic) {
 				array_init.typ = ast.new_type(idx).set_flag(.generic)
 			} else {
@@ -3479,7 +3480,8 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
 		if fixed_size <= 0 {
 			c.error('fixed size cannot be zero or negative', init_expr.position())
 		}
-		idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size)
+		idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size,
+			init_expr)
 		if array_init.elem_type.has_flag(.generic) {
 			array_init.typ = ast.new_type(idx).set_flag(.generic)
 		} else {
diff --git a/vlib/v/fmt/tests/fixed_size_array_type_keep.vv b/vlib/v/fmt/tests/fixed_size_array_type_keep.vv
index 44537b0030..31639b3245 100644
--- a/vlib/v/fmt/tests/fixed_size_array_type_keep.vv
+++ b/vlib/v/fmt/tests/fixed_size_array_type_keep.vv
@@ -1,3 +1,10 @@
+const size = 5
+
+struct Foo {
+	bar [size]int
+	baz [5]int
+}
+
 fn foo() [1]f32 {
 	return [f32(0.0)]!
 }
diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v
index 7fa520c1dd..42fe40889d 100644
--- a/vlib/v/parser/parse_type.v
+++ b/vlib/v/parser/parse_type.v
@@ -42,7 +42,7 @@ pub fn (mut p Parser) parse_array_type() ast.Type {
 			p.error_with_pos('fixed size cannot be zero or negative', size_expr.position())
 		}
 		// sym := p.table.get_type_symbol(elem_type)
-		idx := p.table.find_or_register_array_fixed(elem_type, fixed_size)
+		idx := p.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr)
 		if elem_type.has_flag(.generic) {
 			return ast.new_type(idx).set_flag(.generic)
 		}