table: make Table.type_to_str generate proper function type, not fn name (#6716)

pull/6751/head
Nick Treleaven 2020-11-05 05:34:56 +00:00 committed by GitHub
parent a2fc19880a
commit ca8d23acab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 21 deletions

View File

@ -1585,7 +1585,10 @@ fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos tok
for imethod in inter_sym.methods {
if method := typ_sym.find_method(imethod.name) {
if !imethod.is_same_method_as(method) {
c.error('`$styp` incorrectly implements method `$imethod.name` of interface `$inter_sym.source_name`, expected `${c.table.fn_to_str(imethod)}`',
sig := c.table.fn_signature(imethod, {
skip_receiver: true
})
c.error('`$styp` incorrectly implements method `$imethod.name` of interface `$inter_sym.source_name`, expected `$sig`',
pos)
return false
}

View File

@ -0,0 +1,17 @@
vlib/v/checker/tests/fn_var.vv:2:5: error: cannot assign to `f`: expected `fn (int) byte`, not `any_int`
1 | mut f := fn(i int) byte {}
2 | f = 4
| ^
3 | mut p := &f
4 | p = &[f]
vlib/v/checker/tests/fn_var.vv:4:5: error: cannot assign to `p`: expected `&fn (int) byte`, not `&[]fn (int) byte`
2 | f = 4
3 | mut p := &f
4 | p = &[f]
| ^
5 | f = fn(mut a []int) {}
vlib/v/checker/tests/fn_var.vv:5:5: error: cannot assign to `f`: expected `fn (int) byte`, not `fn (mut []int)`
3 | mut p := &f
4 | p = &[f]
5 | f = fn(mut a []int) {}
| ~~

View File

@ -0,0 +1,5 @@
mut f := fn(i int) byte {}
f = 4
mut p := &f
p = &[f]
f = fn(mut a []int) {}

View File

@ -2389,21 +2389,15 @@ 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
if typ.has_flag(.generic) {
typ = g.cur_generic_type
}
sym := g.table.get_type_symbol(typ)
// TODO: fix table.type_to_str and use instead
if sym.kind == .function {
g.typeof_expr(node)
} else {
// Note: typeof() must be known at compile-time
// sum types should not be handled dynamically
s := g.table.type_to_str(typ)
g.write('tos_lit("${util.strip_main_name(s)}")')
}
s := g.table.type_to_str(typ)
g.write('tos_lit("${util.strip_main_name(s)}")')
}
fn (mut g Gen) typeof_expr(node ast.TypeOf) {

View File

@ -839,7 +839,10 @@ pub fn (table &Table) type_to_str(t Type) string {
}
}
.function {
// do nothing, source_name is sufficient
info := sym.info as FnType
res = table.fn_signature(info.func, {
type_only: true
})
}
.map {
if int(t) == map_type_idx {
@ -889,18 +892,37 @@ pub fn (table &Table) type_to_str(t Type) string {
return res
}
pub fn (t &Table) fn_to_str(func &Fn) string {
pub struct FnSignatureOpts {
skip_receiver bool
type_only bool
}
pub fn (t &Table) fn_signature(func &Fn, opts FnSignatureOpts) string {
mut sb := strings.new_builder(20)
sb.write('${func.name}(')
for i in 1 .. func.params.len {
param := func.params[i]
sb.write('$param.name')
if i == func.params.len - 1 || func.params[i + 1].typ != param.typ {
sb.write(' ${t.type_to_str(param.typ)}')
}
if i != func.params.len - 1 {
if !opts.skip_receiver {
sb.write('fn ')
// TODO write receiver
}
if !opts.type_only {
sb.write('$func.name')
}
sb.write('(')
start := int(opts.skip_receiver)
for i in start .. func.params.len {
if i != start {
sb.write(', ')
}
param := func.params[i]
mut typ := param.typ
if param.is_mut {
typ = typ.deref()
sb.write('mut ')
}
if !opts.type_only {
sb.write('$param.name ')
}
styp := t.type_to_str(typ)
sb.write('$styp')
}
sb.write(')')
if func.return_type != void_type {

View File

@ -115,6 +115,7 @@ fn test_typeof_on_fn() {
assert typeof(myfn3) == 'fn (int, string) byte'
assert typeof(myfn4) == 'fn () i8'
assert typeof(myfn).name == typeof(myfn)
assert typeof(&myfn).name == '&fn (int) int'
assert typeof(myfn2).name == typeof(myfn2)
assert typeof(myfn3).name == typeof(myfn3)
assert typeof(myfn4).name == typeof(myfn4)