diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 9e78530590..d731bae40d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3549,6 +3549,22 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) { } } +fn (mut g Gen) comptime_typeof(node ast.TypeOf, default_type ast.Type) ast.Type { + if node.expr is ast.ComptimeSelector { + if node.expr.field_expr is ast.SelectorExpr { + if node.expr.field_expr.expr is ast.Ident { + key_str := '${node.expr.field_expr.expr.name}.typ' + return g.comptime_var_type_map[key_str] or { default_type } + } + } + } else if g.inside_comptime_for_field && node.expr is ast.Ident + && (node.expr as ast.Ident).obj is ast.Var && ((node.expr as ast.Ident).obj as ast.Var).is_comptime_field == true { + // typeof(var) from T.fields + return g.comptime_for_field_type + } + return default_type +} + fn (mut g Gen) selector_expr(node ast.SelectorExpr) { prevent_sum_type_unwrapping_once := g.prevent_sum_type_unwrapping_once g.prevent_sum_type_unwrapping_once = false @@ -3568,20 +3584,17 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { // typeof(expr).name mut name_type := node.name_type if node.expr is ast.TypeOf { - if node.expr.expr is ast.ComptimeSelector { - if node.expr.expr.field_expr is ast.SelectorExpr { - if node.expr.expr.field_expr.expr is ast.Ident { - key_str := '${node.expr.expr.field_expr.expr.name}.typ' - name_type = g.comptime_var_type_map[key_str] or { name_type } - } - } - } + name_type = g.comptime_typeof(node.expr, name_type) } g.type_name(name_type) return } else if node.field_name == 'idx' { + mut name_type := node.name_type + if node.expr is ast.TypeOf { + name_type = g.comptime_typeof(node.expr, name_type) + } // `typeof(expr).idx` - g.write(int(g.unwrap_generic(node.name_type)).str()) + g.write(int(g.unwrap_generic(name_type)).str()) return } g.error('unknown generic field', node.pos) diff --git a/vlib/v/tests/comptime_for_in_field_typeof_test.v b/vlib/v/tests/comptime_for_in_field_typeof_test.v new file mode 100644 index 0000000000..6eec1234c4 --- /dev/null +++ b/vlib/v/tests/comptime_for_in_field_typeof_test.v @@ -0,0 +1,41 @@ +struct Ab { + a []int +} + +struct ComplexStruct { + a int + b []Ab + c string + d map[string]int +} + +fn test_typeof_in_comptime_for_in_fields() { + out := encode_struct(ComplexStruct{}) + dump(out) + assert out[0] == 'a' + assert out[1] == typeof[int]().idx.str() + assert out[2] == 'int' + + assert out[3] == 'b' + assert out[4] == typeof[[]Ab]().idx.str() + assert out[5] == '[]Ab' + + assert out[6] == 'c' + assert out[7] == typeof[string]().idx.str() + assert out[8] == 'string' + + assert out[9] == 'd' + assert out[10] == typeof[map[string]int]().idx.str() + assert out[11] == 'map[string]int' +} + +fn encode_struct[T](val T) []string { + mut out := []string{} + $for field in T.fields { + value := val.$(field.name) + out << field.name + out << typeof(value).idx.str() + out << typeof(value).name + } + return out +}