gen: implement type_name method for sum type instances (#6802)

pull/6836/head
Nick Treleaven 2020-11-14 11:59:03 +00:00 committed by GitHub
parent 2dc9a45e06
commit 50163508f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 38 additions and 2 deletions

View File

@ -1634,8 +1634,11 @@ struct Venus {}
type World = Moon | Mars | Venus
sum := World(Moon{})
assert sum.type_name() == 'Moon'
println(sum)
```
The built-in method `type_name` returns the name of the currently held
type.
#### Dynamic casts

View File

@ -294,7 +294,7 @@ pub:
left Expr // `user` in `user.register()`
mod string
pub mut:
name string
name string // left.name()
is_method bool
is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
args []CallArg

View File

@ -1097,6 +1097,9 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
c.error('optional type cannot be called directly', call_expr.left.position())
return table.void_type
}
if left_type_sym.kind == .sum_type && method_name == 'type_name' {
return table.string_type
}
// TODO: remove this for actual methods, use only for compiler magic
// FIXME: Argument count != 1 will break these
if left_type_sym.kind == .array &&
@ -4424,6 +4427,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if sym.kind == .interface_ {
c.error('interfaces cannot be used as method receiver', node.receiver_pos)
}
if sym.kind == .sum_type && node.name == 'type_name' {
c.error('method overrides built-in sum type method', node.pos)
}
// if sym.has_method(node.name) {
// c.warn('duplicate method `$node.name`', node.pos)
// }

View File

@ -1,3 +1,12 @@
vlib/v/checker/tests/incorrect_name_sum_type.vv:1:1: error: sum type `integer` must begin with capital letter
1 | type integer = i8 | i16 | int | i64
| ~~~~~~~~~~~~
| ~~~~~~~~~~~~
2 | type Integer = i8 | i16 | int | i64
3 |
vlib/v/checker/tests/incorrect_name_sum_type.vv:4:1: error: method overrides built-in sum type method
2 | type Integer = i8 | i16 | int | i64
3 |
4 | fn (i Integer) type_name() {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 | }
6 |

View File

@ -1 +1,6 @@
type integer = i8 | i16 | int | i64
type Integer = i8 | i16 | int | i64
fn (i Integer) type_name() {
}

View File

@ -377,6 +377,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
else {}
}
}
if left_sym.kind == .sum_type && node.name == 'type_name' {
g.write('tos3( /* $left_sym.name */ v_typeof_sumtype_${node.receiver_type}( (')
g.expr(node.left)
g.write(').typ ))')
return
}
if node.name == 'str' {
mut styp := g.typ(node.receiver_type)
if node.receiver_type.is_ptr() {

View File

@ -65,6 +65,9 @@ fn test_typeof_on_sumtypes() {
assert typeof(a) == 'int'
assert typeof(b) == 'f32'
assert typeof(c) == 'FooBar'
assert a.type_name() == 'int'
assert b.type_name() == 'f32'
assert c.type_name() == 'FooBar'
// typeof should be known at compile-time for all types
assert typeof(a).name == 'MySumType'
assert typeof(b).name == 'MySumType'
@ -96,6 +99,10 @@ fn test_typeof_on_sumtypes_of_structs() {
assert typeof(b) == 'BinExpr'
assert typeof(c) == 'BoolExpr'
assert typeof(d) == 'UnaryExpr'
assert a.type_name() == 'UnaryExpr'
assert b.type_name() == 'BinExpr'
assert c.type_name() == 'BoolExpr'
assert d.type_name() == 'UnaryExpr'
}
fn myfn(i int) int {