diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e63e31c8f7bddb..e82870410f1e59 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1641,7 +1641,8 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { else { if node.field_name == 'name' { return ast.string_type - } else if node.field_name in ['idx', 'unaliased_typ'] { + } else if node.field_name in ['idx', 'unaliased_typ', 'key_type', 'value_type', + 'element_type'] { return ast.int_type } else if node.field_name == 'indirections' { return ast.int_type diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 78c619d48aa9fd..6147ef2bb3ac03 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3971,7 +3971,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { g.type_name(name_type) return } else if node.field_name in ['idx', 'unaliased_typ'] { - // `typeof(expr).idx`, // `typeof(expr).unalised_typ` + // `T.idx`, `T.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_field_type(g.type_resolver.typeof_type(node.expr.expr, @@ -3981,6 +3981,13 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { g.write(int(g.unwrap_generic(name_type)).str()) } return + } else if node.field_name in ['key_type', 'value_type', 'element_type'] { + // `T.`, `typeof(expr).` + mut name_type := node.name_type + name_type = g.type_resolver.typeof_field_type(g.type_resolver.typeof_type(node.expr, + name_type), node.field_name) + g.write(int(name_type).str()) + return } else if node.field_name == 'indirections' { mut name_type := node.name_type if node.expr is ast.TypeOf { diff --git a/vlib/v/tests/comptime/comptime_typeof_value_test.v b/vlib/v/tests/comptime/comptime_typeof_value_test.v new file mode 100644 index 00000000000000..a2b15cb5c10a66 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_typeof_value_test.v @@ -0,0 +1,18 @@ +fn t[T](a T) string { + $if a is $map { + mut s := '' + s += '${typeof[T]().name}\n' + s += '${T.key_type == typeof[u8]().idx} | ${typeof(T.key_type).name} | ${typeof[T]().key_type == typeof[u8]().idx} | ${typeof(typeof[T]().key_type).name}\n' + s += '${T.value_type == typeof[string]().idx} | ${typeof(T.value_type).name} | ${typeof[T]().value_type == typeof[string]().idx} | ${typeof(typeof[T]().value_type).name}\n' + s += '${T.idx == typeof[T]().idx} | ${typeof(T.idx).name} | ${typeof(typeof[T]().idx).name}' + return s + } $else $if a is $array { + return '${typeof[T]().name} >> ${T.element_type == typeof[rune]().idx} | ${typeof(T.element_type).name} | ${typeof[T]().element_type == typeof[rune]().idx} | ${typeof(typeof[T]().element_type).name}' + } + return '' +} + +fn test_main() { + assert t(map[u8]string{}) == 'map[u8]string\ntrue | u8 | true | u8\ntrue | string | true | string\ntrue | int | int' + assert t([]rune{}) == '[]rune >> true | rune | true | rune' +} diff --git a/vlib/v/type_resolver/comptime_resolver.v b/vlib/v/type_resolver/comptime_resolver.v index 9bd5a956c4c38a..53de0f5160bc9b 100644 --- a/vlib/v/type_resolver/comptime_resolver.v +++ b/vlib/v/type_resolver/comptime_resolver.v @@ -79,11 +79,20 @@ pub fn (mut t TypeResolver) typeof_type(node ast.Expr, default_type ast.Type) as if f := t.table.find_field_with_embeds(sym, node.field_name) { return f.typ } + } else if node is ast.SelectorExpr && node.name_type != 0 { + if node.field_name in ['value_type', 'element_type'] { + return t.table.value_type(t.resolver.unwrap_generic(node.name_type)) + } else if node.field_name == 'key_type' { + sym := t.table.sym(t.resolver.unwrap_generic(node.name_type)) + if sym.info is ast.Map { + return t.resolver.unwrap_generic(sym.info.key_type) + } + } } return default_type } -// typeof_field_type resolves the typeof[T](). type +// typeof_field_type resolves the T. and typeof[T](). type pub fn (mut t TypeResolver) typeof_field_type(typ ast.Type, field_name string) ast.Type { match field_name { 'name' { @@ -98,6 +107,16 @@ pub fn (mut t TypeResolver) typeof_field_type(typ ast.Type, field_name string) a 'indirections' { return ast.int_type } + 'key_type' { + sym := t.table.final_sym(t.resolver.unwrap_generic(typ)) + if sym.info is ast.Map { + return t.resolver.unwrap_generic(sym.info.key_type) + } + return ast.no_type + } + 'value_type', 'element_type' { + return t.table.value_type(t.resolver.unwrap_generic(typ)) + } else { return typ }