From 713a0796847362843a382d1275db24e91f7a6366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Wed, 21 Jul 2021 22:43:30 +0200 Subject: [PATCH] cgen: properly support `typeof()`, sizeof(), ... in compile time `for` (#10896) --- vlib/v/gen/c/cgen.v | 28 +++++++++++++++++++--------- vlib/v/tests/comptime_for_test.v | 15 +++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 8027bd9fb7..c11261b945 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -36,8 +36,9 @@ fn string_array_to_map(a []string) map[string]bool { } struct Gen { - pref &pref.Preferences - module_built string + pref &pref.Preferences + module_built string + field_data_type ast.Type // cache her to avoid map lookups mut: table &ast.Table out strings.Builder @@ -225,6 +226,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { module_built: module_built timers: util.new_timers(timers_should_print) inner_loop: &ast.EmptyStmt{} + field_data_type: ast.Type(table.find_type_idx('FieldData')) } g.timers.start('cgen init') for mod in g.table.modules { @@ -3422,7 +3424,8 @@ fn (mut g Gen) expr(node ast.Expr) { g.select_expr(node) } ast.SizeOf { - node_typ := g.unwrap_generic(node.typ) + typ := if node.typ == g.field_data_type { g.comp_for_field_value.typ } else { node.typ } + node_typ := g.unwrap_generic(typ) sym := g.table.get_type_symbol(node_typ) if sym.language == .v && sym.kind in [.placeholder, .any] { g.error('unknown type `$sym.name`', node.pos) @@ -3431,7 +3434,8 @@ fn (mut g Gen) expr(node ast.Expr) { g.write('/*SizeOf*/ sizeof(${util.no_dots(styp)})') } ast.IsRefType { - node_typ := g.unwrap_generic(node.typ) + typ := if node.typ == g.field_data_type { g.comp_for_field_value.typ } else { node.typ } + node_typ := g.unwrap_generic(typ) sym := g.table.get_type_symbol(node_typ) if sym.language == .v && sym.kind in [.placeholder, .any] { g.error('unknown type `$sym.name`', node.pos) @@ -3495,7 +3499,8 @@ fn (mut g Gen) expr(node ast.Expr) { } // T.name, typeof(expr).name -fn (mut g Gen) type_name(typ ast.Type) { +fn (mut g Gen) type_name(raw_type ast.Type) { + typ := if raw_type == g.field_data_type { g.comp_for_field_value.typ } else { raw_type } sym := g.table.get_type_symbol(typ) mut s := '' if sym.kind == .function { @@ -3511,7 +3516,12 @@ fn (mut g Gen) type_name(typ ast.Type) { } fn (mut g Gen) typeof_expr(node ast.TypeOf) { - sym := g.table.get_type_symbol(node.expr_type) + typ := if node.expr_type == g.field_data_type { + g.comp_for_field_value.typ + } else { + node.expr_type + } + sym := g.table.get_type_symbol(typ) if sym.kind == .sum_type { // When encountering a .sum_type, typeof() should be done at runtime, // because the subtype of the expression may change: @@ -3525,11 +3535,11 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) { } else if sym.kind == .function { info := sym.info as ast.FnType g.write('_SLIT("${g.fn_decl_str(info)}")') - } else if node.expr_type.has_flag(.variadic) { - varg_elem_type_sym := g.table.get_type_symbol(g.table.value_type(node.expr_type)) + } else if typ.has_flag(.variadic) { + varg_elem_type_sym := g.table.get_type_symbol(g.table.value_type(typ)) g.write('_SLIT("...${util.strip_main_name(varg_elem_type_sym.name)}")') } else { - x := g.table.type_to_str(node.expr_type) + x := g.table.type_to_str(typ) y := util.strip_main_name(x) g.write('_SLIT("$y")') } diff --git a/vlib/v/tests/comptime_for_test.v b/vlib/v/tests/comptime_for_test.v index 05d20f40ee..4c070fc0c6 100644 --- a/vlib/v/tests/comptime_for_test.v +++ b/vlib/v/tests/comptime_for_test.v @@ -64,6 +64,7 @@ fn test_comptime_for_with_if() { fn test_comptime_for_fields() { println(@FN) + mut fields_found := 0 $for field in App.fields { println(' field: $field.name | ' + no_lines('$field')) $if field.typ is string { @@ -81,5 +82,19 @@ fn test_comptime_for_fields() { if field.is_pub && field.is_mut { assert field.name in ['g', 'h'] } + if field.name == 'f' { + assert sizeof(field) == 8 + assert isreftype(field) == false + // assert typeof(field) == 'u64' + assert typeof(field).name == 'u64' + fields_found++ + } + if field.name == 'g' { + // assert typeof(field) == 'string' + assert typeof(field).name == 'string' + assert isreftype(field) == true + fields_found++ + } } + assert fields_found == 2 }