From 50163508f8a08771e247187949df9ba8b254d0cc Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 14 Nov 2020 11:59:03 +0000 Subject: [PATCH] gen: implement type_name method for sum type instances (#6802) --- doc/docs.md | 3 +++ vlib/v/ast/ast.v | 2 +- vlib/v/checker/checker.v | 6 ++++++ vlib/v/checker/tests/incorrect_name_sum_type.out | 11 ++++++++++- vlib/v/checker/tests/incorrect_name_sum_type.vv | 5 +++++ vlib/v/gen/fn.v | 6 ++++++ vlib/v/tests/typeof_test.v | 7 +++++++ 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/doc/docs.md b/doc/docs.md index 3e07720cd3..609774c1b1 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -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 diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5c469d56d1..05619e4be0 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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 diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index fd7e17b35e..9347a56c2d 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) // } diff --git a/vlib/v/checker/tests/incorrect_name_sum_type.out b/vlib/v/checker/tests/incorrect_name_sum_type.out index 25bf0f0ad2..91a04121b8 100644 --- a/vlib/v/checker/tests/incorrect_name_sum_type.out +++ b/vlib/v/checker/tests/incorrect_name_sum_type.out @@ -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 - | ~~~~~~~~~~~~ \ No newline at end of file + | ~~~~~~~~~~~~ + 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 | diff --git a/vlib/v/checker/tests/incorrect_name_sum_type.vv b/vlib/v/checker/tests/incorrect_name_sum_type.vv index 8a3098fec8..e73300d599 100644 --- a/vlib/v/checker/tests/incorrect_name_sum_type.vv +++ b/vlib/v/checker/tests/incorrect_name_sum_type.vv @@ -1 +1,6 @@ type integer = i8 | i16 | int | i64 +type Integer = i8 | i16 | int | i64 + +fn (i Integer) type_name() { +} + diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 8ab567c8f0..c1d343393d 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -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() { diff --git a/vlib/v/tests/typeof_test.v b/vlib/v/tests/typeof_test.v index bbe3acefef..a86e307ccf 100644 --- a/vlib/v/tests/typeof_test.v +++ b/vlib/v/tests/typeof_test.v @@ -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 {