diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index fd3f8156be..1512c05952 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3908,21 +3908,16 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { } g.type_name(name_type) return - } else if node.field_name == 'idx' { + } else if node.field_name in ['idx', 'unaliased_typ'] { + // `typeof(expr).idx`, // `typeof(expr).unalised_typ` mut name_type := node.name_type if node.expr is ast.TypeOf { - name_type = g.type_resolver.typeof_type(node.expr.expr, name_type) + name_type = g.type_resolver.typeof_field_type(g.type_resolver.typeof_type(node.expr.expr, + name_type), node.field_name) + g.write(int(name_type).str()) + } else { + g.write(int(g.unwrap_generic(name_type)).str()) } - // `typeof(expr).idx` - g.write(int(g.unwrap_generic(name_type)).str()) - return - } else if node.field_name == 'unaliased_typ' { - mut name_type := node.name_type - if node.expr is ast.TypeOf { - 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()) return } else if node.field_name == 'indirections' { mut name_type := node.name_type diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 4f567b7b3f..524422ee4c 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -455,6 +455,10 @@ fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type { } else if cond.gkind_field == .indirections { return ast.int_type } else { + if cond.expr is ast.TypeOf { + return g.type_resolver.typeof_field_type(g.type_resolver.typeof_type(cond.expr.expr, + cond.name_type), cond.field_name) + } name := '${cond.expr}.${cond.field_name}' if name in g.type_resolver.type_map { return g.type_resolver.get_ct_type_or_default(name, ast.void_type) diff --git a/vlib/v/tests/generics/generic_typeof_idx_test.v b/vlib/v/tests/generics/generic_typeof_idx_test.v new file mode 100644 index 0000000000..89c529f6d8 --- /dev/null +++ b/vlib/v/tests/generics/generic_typeof_idx_test.v @@ -0,0 +1,37 @@ +type MyInt = int +type MyString = string + +struct Foo { + a []int + b MyInt + c MyString +} + +fn unaliased_typ[T](a T) int { + $if typeof[T]().unaliased_typ is $int { + return 1 + } $else $if typeof[T]().unaliased_typ is $string { + return 2 + } + return 0 +} + +fn idx[T](a [][]T) int { + $if typeof[T]().idx is $int { + return 1 + } $else $if typeof[T]().idx is $string { + return 2 + } + return 0 +} + +fn test_main() { + a := Foo{ + a: [1, 2, 3] + } + assert idx([a.a]) == 1 + assert idx([['']]) == 2 + + assert unaliased_typ(1) == 1 + assert unaliased_typ('') == 2 +} diff --git a/vlib/v/type_resolver/comptime_resolver.v b/vlib/v/type_resolver/comptime_resolver.v index 0b2dca8d8d..8dc0ce49dc 100644 --- a/vlib/v/type_resolver/comptime_resolver.v +++ b/vlib/v/type_resolver/comptime_resolver.v @@ -82,6 +82,27 @@ pub fn (mut t TypeResolver) typeof_type(node ast.Expr, default_type ast.Type) as return default_type } +// typeof_field_type resolves the typeof[T](). type +pub fn (mut t TypeResolver) typeof_field_type(typ ast.Type, field_name string) ast.Type { + match field_name { + 'name' { + return ast.string_type + } + 'idx' { + return t.resolver.unwrap_generic(typ) + } + 'unaliased_typ' { + return t.table.unaliased_type(t.resolver.unwrap_generic(typ)) + } + 'indirections' { + return ast.int_type + } + else { + return typ + } + } +} + // 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 {