diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 3416b5efc32c8d..9cb05a9e9b096b 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -1453,6 +1453,7 @@ fn (t Tree) selector_expr(node ast.SelectorExpr) &Node { obj.add_terse('from_embed_types', t.array_node_type(node.from_embed_types)) obj.add_terse('has_hidden_receiver', t.bool_node(node.has_hidden_receiver)) obj.add_terse('next_token', t.token_node(node.next_token)) + obj.add_terse('is_field_typ', t.bool_node(node.is_field_typ)) obj.add('pos', t.pos(node.pos)) obj.add('scope', t.number_node(int(node.scope))) return obj diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 972c262dd85402..de368f234237e8 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -311,6 +311,7 @@ pub mut: from_embed_types []Type // holds the type of the embed that the method is called from generic_from_embed_types [][]Type // holds the types of the embeds for each generic instance when the same generic method is called. has_hidden_receiver bool + is_field_typ bool // var.typ for comptime $for var } // root_ident returns the origin ident where the selector started. diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e7feb1f9cb94ae..87d7958e08266a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1645,6 +1645,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { return node.expr_type } } + node.is_field_typ = node.is_field_typ || c.comptime.is_comptime_selector_type(node) old_selector_expr := c.inside_selector_expr c.inside_selector_expr = true mut typ := c.expr(mut node.expr) diff --git a/vlib/v/gen/c/assert.v b/vlib/v/gen/c/assert.v index 87a970e2b5d50e..20948a3b62aca7 100644 --- a/vlib/v/gen/c/assert.v +++ b/vlib/v/gen/c/assert.v @@ -151,12 +151,12 @@ fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt, kind AssertMetainfoKind) g.writeln('\t${metaname}.op = ${expr_op_str};') g.writeln('\t${metaname}.llabel = ${expr_left_str};') g.writeln('\t${metaname}.rlabel = ${expr_right_str};') - left_type := if g.comptime.is_comptime_expr(node.expr.left) { - g.type_resolver.get_type(node.expr.left) + left_type := if node.expr.left_ct_expr { + g.type_resolver.get_type_or_default(node.expr.left, node.expr.left_type) } else { node.expr.left_type } - right_type := if g.comptime.is_comptime_expr(node.expr.right) { + right_type := if node.expr.right_ct_expr { g.type_resolver.get_type(node.expr.right) } else { node.expr.right_type diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 9d1a9b39c0bd5b..e90d7ccffbdfcd 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3584,7 +3584,7 @@ fn (mut g Gen) expr(node_ ast.Expr) { } } ast.IsRefType { - typ := g.resolve_comptime_type(node.expr, g.get_type(node.typ)) + typ := g.type_resolver.typeof_type(node.expr, g.get_type(node.typ)) node_typ := g.unwrap_generic(typ) sym := g.table.sym(node_typ) if sym.language == .v && sym.kind in [.placeholder, .any] { @@ -3669,7 +3669,7 @@ fn (mut g Gen) expr(node_ ast.Expr) { g.writeln2('\tpanic_option_not_set(_SLIT("none"));', '}') g.write(cur_line) if is_unwrapped { - typ := g.resolve_comptime_type(node.expr, node.typ) + typ := g.type_resolver.typeof_type(node.expr, node.typ) g.write('*(${g.base_type(typ)}*)&') g.expr(node.expr) g.write('.data') @@ -3844,7 +3844,7 @@ fn (mut g Gen) type_name(raw_type ast.Type) { } fn (mut g Gen) typeof_expr(node ast.TypeOf) { - typ := g.resolve_comptime_type(node.expr, g.get_type(node.typ)) + typ := g.type_resolver.typeof_type(node.expr, g.get_type(node.typ)) sym := g.table.sym(typ) if sym.kind == .sum_type { // When encountering a .sum_type, typeof() should be done at runtime, @@ -3894,14 +3894,14 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { // typeof(expr).name mut name_type := node.name_type if node.expr is ast.TypeOf { - name_type = g.resolve_comptime_type(node.expr.expr, name_type) + name_type = g.type_resolver.typeof_type(node.expr.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.resolve_comptime_type(node.expr.expr, name_type) + name_type = g.type_resolver.typeof_type(node.expr.expr, name_type) } // `typeof(expr).idx` g.write(int(g.unwrap_generic(name_type)).str()) @@ -3909,7 +3909,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } else if node.field_name == 'unaliased_typ' { mut name_type := node.name_type if node.expr is ast.TypeOf { - name_type = g.resolve_comptime_type(node.expr.expr, name_type) + name_type = g.type_resolver.typeof_type(node.expr.expr, name_type) } // `typeof(expr).unaliased_typ` g.write(int(g.table.unaliased_type(g.unwrap_generic(name_type))).str()) @@ -3917,7 +3917,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } else if node.field_name == 'indirections' { mut name_type := node.name_type if node.expr is ast.TypeOf { - name_type = g.resolve_comptime_type(node.expr.expr, name_type) + name_type = g.type_resolver.typeof_type(node.expr.expr, name_type) } // `typeof(expr).indirections` g.write(int(g.unwrap_generic(name_type).nr_muls()).str()) @@ -5224,7 +5224,7 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) { node_typ := g.unwrap_generic(node.typ) mut expr_type := node.expr_type sym := g.table.sym(node_typ) - if g.comptime.is_comptime_expr(node.expr) { + if g.comptime.is_comptime(node.expr) { expr_type = g.unwrap_generic(g.type_resolver.get_type(node.expr)) } node_typ_is_option := node.typ.has_flag(.option) @@ -7231,7 +7231,7 @@ fn (mut g Gen) get_type(typ ast.Type) ast.Type { } fn (mut g Gen) size_of(node ast.SizeOf) { - typ := g.resolve_comptime_type(node.expr, g.get_type(node.typ)) + typ := g.type_resolver.typeof_type(node.expr, g.get_type(node.typ)) node_typ := g.unwrap_generic(typ) sym := g.table.sym(node_typ) if sym.language == .v && sym.kind in [.placeholder, .any] { diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 725b8f3550dc48..6d22b2fd79fddc 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -801,21 +801,6 @@ fn (mut g Gen) pop_comptime_info() { g.comptime.comptime_for_method_ret_type = old.comptime_for_method_ret_type } -fn (mut g Gen) resolve_comptime_type(node ast.Expr, default_type ast.Type) ast.Type { - if g.comptime.is_comptime_expr(node) { - return g.type_resolver.get_type(node) - } else if node is ast.SelectorExpr && node.expr_type != 0 { - if node.expr is ast.Ident && g.comptime.is_comptime_selector_type(node) { - return g.type_resolver.get_type_from_comptime_var(node.expr) - } - sym := g.table.sym(g.unwrap_generic(node.expr_type)) - if f := g.table.find_field_with_embeds(sym, node.field_name) { - return f.typ - } - } - return default_type -} - fn (mut g Gen) comptime_for(node ast.ComptimeFor) { sym := if node.typ != g.field_data_type { g.table.final_sym(g.unwrap_generic(node.typ)) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 7e021b1744bc37..da866b58b42e25 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1324,7 +1324,7 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool { return true } } else if left_node is ast.PostfixExpr { - rec_type = g.resolve_comptime_type(left_node.expr, rec_type) + rec_type = g.type_resolver.get_type_or_default(left_node.expr, rec_type) if left_node.op == .question { rec_type = rec_type.clear_flag(.option) } diff --git a/vlib/v/type_resolver/comptime_resolver.v b/vlib/v/type_resolver/comptime_resolver.v index 633f907eab6ffc..a93f756267fa7f 100644 --- a/vlib/v/type_resolver/comptime_resolver.v +++ b/vlib/v/type_resolver/comptime_resolver.v @@ -75,6 +75,22 @@ pub fn (t &ResolverInfo) is_comptime_variant_var(node ast.Ident) bool { return node.name == t.comptime_for_variant_var } +// typeof_type resolves type for typeof() expr where field.typ is resolved to real type instead of int type to make type(field.typ).name working +pub fn (mut t TypeResolver) typeof_type(node ast.Expr, default_type ast.Type) ast.Type { + if t.info.is_comptime(node) { + return t.get_type(node) + } else if node is ast.SelectorExpr && node.expr_type != 0 { + if node.expr is ast.Ident && node.is_field_typ { + return t.get_type_from_comptime_var(node.expr) + } + sym := t.table.sym(t.resolver.unwrap_generic(node.expr_type)) + if f := t.table.find_field_with_embeds(sym, node.field_name) { + return f.typ + } + } + return default_type +} + // get_ct_type_var gets the comptime type of the variable (.generic_param, .key_var, etc) @[inline] pub fn (t &ResolverInfo) get_ct_type_var(node ast.Expr) ast.ComptimeVarKind { diff --git a/vlib/v/type_resolver/type_resolver.v b/vlib/v/type_resolver/type_resolver.v index d6d36c98aa61d3..b4372973a88e05 100644 --- a/vlib/v/type_resolver/type_resolver.v +++ b/vlib/v/type_resolver/type_resolver.v @@ -207,7 +207,7 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type { } return ctyp } else if node is ast.SelectorExpr { - if t.info.is_comptime_selector_type(node) { + if node.is_field_typ { return t.get_type_from_comptime_var(node.expr as ast.Ident) } if node.expr is ast.Ident && node.expr.ct_expr { @@ -216,8 +216,18 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type { // Struct[T] can have field with generic type if struct_sym.info is ast.Struct && struct_sym.info.generic_types.len > 0 { if field := t.table.find_field(struct_sym, node.field_name) { + if f_unwrap := node.scope.find_struct_field(ast.Expr(node.expr).str(), + t.get_type_or_default(node.expr, node.expr_type), node.field_name) + { + return f_unwrap.smartcasts.last() + } return field.typ } + } else { + sym := t.table.sym(t.resolver.unwrap_generic(node.expr_type)) + if f := t.table.find_field_with_embeds(sym, node.field_name) { + return f.typ + } } } return node.typ