diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index ecc8c94c3f..3ee4345456 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -109,6 +109,7 @@ pub: pub mut: expr_type table.Type // type of `Foo` in `Foo.bar` typ table.Type // type of the entire thing (`Foo.bar`) + name_type table.Type // T in `T.name` or typeof in `typeof(expr).name` } // module declaration diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index f0a935da0e..f472cee813 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1726,19 +1726,34 @@ fn is_expr_panic_or_exit(expr ast.Expr) bool { } pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.Type { + // T.name, typeof(expr).name + mut name_type := 0 + match selector_expr.expr as left { + ast.Ident { + if left.name == 'T' { + name_type = table.Type(c.table.find_type_idx('T')).set_flag(.generic) + } + } + // Note: in future typeof() should be a type known at compile-time + // sum types should not be handled dynamically + ast.TypeOf { + name_type = c.expr(left.expr) + } + else {} + } + if name_type > 0 { + if selector_expr.field_name != 'name' { + c.error('invalid field `.$selector_expr.field_name` for type `$selector_expr.expr`', + selector_expr.pos) + } + selector_expr.name_type = name_type + return table.string_type + } typ := c.expr(selector_expr.expr) if typ == table.void_type_idx { c.error('unknown selector expression', selector_expr.pos) return table.void_type } - if selector_expr.expr is ast.TypeOf as left { - if selector_expr.field_name == 'name' { - return table.string_type - } else { - c.error('expected `.name`, not `.$selector_expr.field_name` after `typeof` expression', - selector_expr.pos) - } - } selector_expr.expr_type = typ sym := c.table.get_type_symbol(c.unwrap_generic(typ)) field_name := selector_expr.field_name diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 0b24a87758..975dad7efb 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2351,8 +2351,8 @@ fn (mut g Gen) expr(node ast.Expr) { g.struct_init(node) } ast.SelectorExpr { - if node.expr is ast.TypeOf as left { - g.typeof_name(left) + if node.name_type > 0 { + g.type_name(node.name_type) return } if node.expr_type == 0 { @@ -2423,11 +2423,9 @@ fn (mut g Gen) expr(node ast.Expr) { } } -// typeof(expr).name -// Note: typeof() should be a type known at compile-time, not a string -// sum types should not be handled dynamically -fn (mut g Gen) typeof_name(node ast.TypeOf) { - mut typ := node.expr_type +// T.name, typeof(expr).name +fn (mut g Gen) type_name(type_ table.Type) { + mut typ := type_ if typ.has_flag(.generic) { typ = g.cur_generic_type } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 236d1fe0de..608dbc96f5 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1109,6 +1109,21 @@ pub fn (mut p Parser) name_expr() ast.Expr { (!p.inside_for || p.inside_select) { // && (p.tok.lit[0].is_capital() || p.builtin_mod) { return p.struct_init(false) // short_syntax: false } else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) { + // T.name + if p.tok.lit == 'T' { + pos := p.tok.position() + name := p.check_name() + p.check(.dot) + field := p.check_name() + pos.extend(p.tok.position()) + return ast.SelectorExpr{ + expr: ast.Ident{ + name: name + } + field_name: field + pos: pos + } + } // `Color.green` mut enum_name := p.check_name() if mod != '' { diff --git a/vlib/v/tests/nameof_test.v b/vlib/v/tests/nameof_test.v deleted file mode 100644 index cd28ce613e..0000000000 --- a/vlib/v/tests/nameof_test.v +++ /dev/null @@ -1,19 +0,0 @@ -fn test_todo() {} - -/* -fn simple(p T) string { - tname := nameof(T) - println("Hello generic, I'm an [$tname]") - return tname -} - -struct FunkyStruct{ } - -fn test_nameof_on_various_types_in_generic() { - assert simple(42) == "int" - assert simple(3.14) == "f64" - assert simple("FuBar") == "string" - assert simple(FunkyStruct{}) == "FunkyStruct" - assert simple(test_nameof_on_various_types_in_generic) == "fn ()" -} -*/ diff --git a/vlib/v/tests/type_name_test.v b/vlib/v/tests/type_name_test.v new file mode 100644 index 0000000000..b069b0c66d --- /dev/null +++ b/vlib/v/tests/type_name_test.v @@ -0,0 +1,18 @@ +fn simple(p T) string { + tname := T.name + assert tname == typeof(p).name + return tname +} + +struct FunkyStruct{ } + +fn test_generic_type_name() { + i := 42 + assert simple(i) == "int" + f := 3.14 + assert simple(f) == "f64" + assert simple("FuBar") == "string" + assert simple(FunkyStruct{}) == "FunkyStruct" + assert simple(fn(){}) == "fn ()" + //assert simple(test_generic_type_name) == "fn ()" +}