mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser: implement T.name
for generic types (#6783)
This commit is contained in:
parent
1c257abc23
commit
c76e486765
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 != '' {
|
||||
|
@ -1,19 +0,0 @@
|
||||
fn test_todo() {}
|
||||
|
||||
/*
|
||||
fn simple<T>(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 ()"
|
||||
}
|
||||
*/
|
18
vlib/v/tests/type_name_test.v
Normal file
18
vlib/v/tests/type_name_test.v
Normal file
@ -0,0 +1,18 @@
|
||||
fn simple<T>(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 ()"
|
||||
}
|
Loading…
Reference in New Issue
Block a user