table: make Table.type_to_str generate proper function type, not fn name (#6716)
parent
a2fc19880a
commit
ca8d23acab
|
@ -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 {
|
for imethod in inter_sym.methods {
|
||||||
if method := typ_sym.find_method(imethod.name) {
|
if method := typ_sym.find_method(imethod.name) {
|
||||||
if !imethod.is_same_method_as(method) {
|
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)
|
pos)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {}
|
||||||
|
| ~~
|
|
@ -0,0 +1,5 @@
|
||||||
|
mut f := fn(i int) byte {}
|
||||||
|
f = 4
|
||||||
|
mut p := &f
|
||||||
|
p = &[f]
|
||||||
|
f = fn(mut a []int) {}
|
|
@ -2389,21 +2389,15 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeof(expr).name
|
// 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) {
|
fn (mut g Gen) typeof_name(node ast.TypeOf) {
|
||||||
mut typ := node.expr_type
|
mut typ := node.expr_type
|
||||||
if typ.has_flag(.generic) {
|
if typ.has_flag(.generic) {
|
||||||
typ = g.cur_generic_type
|
typ = g.cur_generic_type
|
||||||
}
|
}
|
||||||
sym := g.table.get_type_symbol(typ)
|
s := g.table.type_to_str(typ)
|
||||||
// TODO: fix table.type_to_str and use instead
|
g.write('tos_lit("${util.strip_main_name(s)}")')
|
||||||
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)}")')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||||
|
|
|
@ -839,7 +839,10 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.function {
|
.function {
|
||||||
// do nothing, source_name is sufficient
|
info := sym.info as FnType
|
||||||
|
res = table.fn_signature(info.func, {
|
||||||
|
type_only: true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
if int(t) == map_type_idx {
|
if int(t) == map_type_idx {
|
||||||
|
@ -889,18 +892,37 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
return res
|
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)
|
mut sb := strings.new_builder(20)
|
||||||
sb.write('${func.name}(')
|
if !opts.skip_receiver {
|
||||||
for i in 1 .. func.params.len {
|
sb.write('fn ')
|
||||||
param := func.params[i]
|
// TODO write receiver
|
||||||
sb.write('$param.name')
|
}
|
||||||
if i == func.params.len - 1 || func.params[i + 1].typ != param.typ {
|
if !opts.type_only {
|
||||||
sb.write(' ${t.type_to_str(param.typ)}')
|
sb.write('$func.name')
|
||||||
}
|
}
|
||||||
if i != func.params.len - 1 {
|
sb.write('(')
|
||||||
|
start := int(opts.skip_receiver)
|
||||||
|
for i in start .. func.params.len {
|
||||||
|
if i != start {
|
||||||
sb.write(', ')
|
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(')')
|
sb.write(')')
|
||||||
if func.return_type != void_type {
|
if func.return_type != void_type {
|
||||||
|
|
|
@ -115,6 +115,7 @@ fn test_typeof_on_fn() {
|
||||||
assert typeof(myfn3) == 'fn (int, string) byte'
|
assert typeof(myfn3) == 'fn (int, string) byte'
|
||||||
assert typeof(myfn4) == 'fn () i8'
|
assert typeof(myfn4) == 'fn () i8'
|
||||||
assert typeof(myfn).name == typeof(myfn)
|
assert typeof(myfn).name == typeof(myfn)
|
||||||
|
assert typeof(&myfn).name == '&fn (int) int'
|
||||||
assert typeof(myfn2).name == typeof(myfn2)
|
assert typeof(myfn2).name == typeof(myfn2)
|
||||||
assert typeof(myfn3).name == typeof(myfn3)
|
assert typeof(myfn3).name == typeof(myfn3)
|
||||||
assert typeof(myfn4).name == typeof(myfn4)
|
assert typeof(myfn4).name == typeof(myfn4)
|
||||||
|
|
Loading…
Reference in New Issue