From b010f2dfbb841a45c4f4c342826ad882042274f9 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 17 Mar 2025 09:37:04 -0300 Subject: [PATCH 1/3] new feature --- vlib/v/checker/checker.v | 3 ++- vlib/v/gen/c/cgen.v | 9 +++++++- .../comptime/comptime_typeof_value_test.v | 18 ++++++++++++++++ vlib/v/type_resolver/comptime_resolver.v | 21 ++++++++++++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/comptime/comptime_typeof_value_test.v 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..a26e880c73e86a --- /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(T.key_type).name} | ${typeof[T]().key_type} | ${typeof(typeof[T]().key_type).name}\n' + s += '${T.value_type} | ${typeof(T.value_type).name} | ${typeof[T]().value_type} | ${typeof(typeof[T]().value_type).name}\n' + s += '${T.idx} | ${typeof(T.idx).name} | ${typeof[T]().idx} | ${typeof(typeof[T]().idx).name}' + return s + } $else $if a is $array { + return '${typeof[T]().name} >> ${T.element_type} | ${typeof(T.element_type).name} | ${typeof[T]().element_type} | ${typeof(typeof[T]().element_type).name}' + } + return '' +} + +fn test_main() { + assert t(map[u8]string{}) == 'map[u8]string\n11 | u8 | 11 | u8\n21 | string | 21 | string\n105 | int | 105 | int' + assert t([]rune{}) == '[]rune >> 22 | rune | 22 | 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 } From f0b8e185bc1a345e2325ce655090c0a05cde6922 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 17 Mar 2025 10:23:42 -0300 Subject: [PATCH 2/3] fix --- vlib/v/tests/comptime/comptime_typeof_value_test.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlib/v/tests/comptime/comptime_typeof_value_test.v b/vlib/v/tests/comptime/comptime_typeof_value_test.v index a26e880c73e86a..3f281010fa9b5e 100644 --- a/vlib/v/tests/comptime/comptime_typeof_value_test.v +++ b/vlib/v/tests/comptime/comptime_typeof_value_test.v @@ -13,6 +13,6 @@ fn t[T](a T) string { } fn test_main() { - assert t(map[u8]string{}) == 'map[u8]string\n11 | u8 | 11 | u8\n21 | string | 21 | string\n105 | int | 105 | int' + assert t(map[u8]string{}) == 'map[u8]string\n11 | u8 | 11 | u8\n21 | string | 21 | string\n111 | int | 111 | int' assert t([]rune{}) == '[]rune >> 22 | rune | 22 | rune' } From 67dd9f313cf0e18e0ddaaeaf63d3fef2fedb6bb5 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 18 Mar 2025 08:56:45 -0300 Subject: [PATCH 3/3] fix --- vlib/v/tests/comptime/comptime_typeof_value_test.v | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vlib/v/tests/comptime/comptime_typeof_value_test.v b/vlib/v/tests/comptime/comptime_typeof_value_test.v index 3f281010fa9b5e..a2b15cb5c10a66 100644 --- a/vlib/v/tests/comptime/comptime_typeof_value_test.v +++ b/vlib/v/tests/comptime/comptime_typeof_value_test.v @@ -2,17 +2,17 @@ fn t[T](a T) string { $if a is $map { mut s := '' s += '${typeof[T]().name}\n' - s += '${T.key_type} | ${typeof(T.key_type).name} | ${typeof[T]().key_type} | ${typeof(typeof[T]().key_type).name}\n' - s += '${T.value_type} | ${typeof(T.value_type).name} | ${typeof[T]().value_type} | ${typeof(typeof[T]().value_type).name}\n' - s += '${T.idx} | ${typeof(T.idx).name} | ${typeof[T]().idx} | ${typeof(typeof[T]().idx).name}' + 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(T.element_type).name} | ${typeof[T]().element_type} | ${typeof(typeof[T]().element_type).name}' + 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\n11 | u8 | 11 | u8\n21 | string | 21 | string\n111 | int | 111 | int' - assert t([]rune{}) == '[]rune >> 22 | rune | 22 | rune' + 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' }