1
0
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:
Nick Treleaven 2020-11-09 13:35:26 +00:00 committed by GitHub
parent 1c257abc23
commit c76e486765
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 34 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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 != '' {

View File

@ -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 ()"
}
*/

View 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 ()"
}