generics: fix method calls

pull/5086/head
Alexander Medvednikov 2020-05-28 05:50:57 +02:00
parent ae8cc2f433
commit d6037cbcf2
4 changed files with 54 additions and 39 deletions

View File

@ -366,7 +366,8 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`', c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
field.pos) field.pos)
} }
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer() && !expr_type.is_number() { if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer() &&
!expr_type.is_number() {
c.error('ref', field.pos) c.error('ref', field.pos)
} }
struct_init.fields[i].typ = expr_type struct_init.fields[i].typ = expr_type
@ -472,13 +473,14 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
if infix_expr.op == .mod { if infix_expr.op == .mod {
c.error('float modulo not allowed, use math.fmod() instead', pos) c.error('float modulo not allowed, use math.fmod() instead', pos)
} else { } else {
c.error('$side type of `${infix_expr.op.str()}` cannot be non-integer type $name', pos) c.error('$side type of `${infix_expr.op.str()}` cannot be non-integer type $name',
pos)
} }
} }
} }
if infix_expr.op in [.div, .mod] { if infix_expr.op in [.div, .mod] {
if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == '0' || if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0 { '0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0 {
oper := if infix_expr.op == .div { 'division' } else { 'modulo' } oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
c.error('$oper by zero', right_pos) c.error('$oper by zero', right_pos)
} }
@ -498,7 +500,8 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
c.type_implements(right_type, left_value_type, right_pos) c.type_implements(right_type, left_value_type, right_pos)
} else { } else {
// []Animal << Cat // []Animal << Cat
c.type_implements(c.table.value_type(right_type), left_value_type, right_pos) c.type_implements(c.table.value_type(right_type), left_value_type,
right_pos)
} }
return table.void_type return table.void_type
} }
@ -700,6 +703,7 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type {
pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
left_type := c.expr(call_expr.left) left_type := c.expr(call_expr.left)
is_generic := left_type == table.t_type
call_expr.left_type = left_type call_expr.left_type = left_type
left_type_sym := c.table.get_type_symbol(c.unwrap_generic(left_type)) left_type_sym := c.table.get_type_symbol(c.unwrap_generic(left_type))
method_name := call_expr.name method_name := call_expr.name
@ -803,7 +807,12 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
call_expr.expected_arg_types << method.args[i].typ call_expr.expected_arg_types << method.args[i].typ
} }
} }
if is_generic {
// We need the receiver to be T in cgen.
call_expr.receiver_type = table.t_type
} else {
call_expr.receiver_type = method.args[0].typ call_expr.receiver_type = method.args[0].typ
}
call_expr.return_type = method.return_type call_expr.return_type = method.return_type
return method.return_type return method.return_type
} }
@ -1167,7 +1176,6 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
mut got_types := []table.Type{} mut got_types := []table.Type{}
for expr in return_stmt.exprs { for expr in return_stmt.exprs {
typ := c.expr(expr) typ := c.expr(expr)
// Unpack multi return types // Unpack multi return types
sym := c.table.get_type_symbol(typ) sym := c.table.get_type_symbol(typ)
if sym.kind == .multi_return { if sym.kind == .multi_return {
@ -1183,12 +1191,10 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
if exp_is_optional && got_types[0].idx() in [table.none_type_idx, c.table.type_idxs['Option']] { if exp_is_optional && got_types[0].idx() in [table.none_type_idx, c.table.type_idxs['Option']] {
return return
} }
if expected_types.len > 0 && expected_types.len != got_types.len { if expected_types.len > 0 && expected_types.len != got_types.len {
c.error('wrong number of return arguments', return_stmt.pos) c.error('wrong number of return arguments', return_stmt.pos)
return return
} }
for i, exp_type in expected_types { for i, exp_type in expected_types {
got_typ := got_types[i] got_typ := got_types[i]
is_generic := exp_type == table.t_type is_generic := exp_type == table.t_type
@ -1875,10 +1881,10 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
// second use // second use
if ident.kind == .variable { if ident.kind == .variable {
info := ident.info as ast.IdentVar info := ident.info as ast.IdentVar
if info.typ == table.t_type { // if info.typ == table.t_type {
// Got a var with type T, return current generic type // Got a var with type T, return current generic type
// return c.cur_generic_type // return c.cur_generic_type
} // }
return info.typ return info.typ
} else if ident.kind == .constant { } else if ident.kind == .constant {
info := ident.info as ast.IdentVar info := ident.info as ast.IdentVar

View File

@ -8,7 +8,9 @@ import v.table
import strings import strings
const ( const (
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t'] tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t',
'\t\t\t\t\t\t\t\t'
]
max_len = 90 max_len = 90
) )
@ -405,7 +407,8 @@ pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {
} }
f.write(')') f.write(')')
if fn_info.return_type.idx() != table.void_type_idx { if fn_info.return_type.idx() != table.void_type_idx {
ret_str := f.table.type_to_str(fn_info.return_type).replace(f.cur_mod + '.', '') ret_str := f.table.type_to_str(fn_info.return_type).replace(f.cur_mod + '.',
'')
f.write(' ' + ret_str) f.write(' ' + ret_str)
} }
} }
@ -592,15 +595,12 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
if it.keys.len == 0 { if it.keys.len == 0 {
mut ktyp := it.key_type mut ktyp := it.key_type
mut vtyp := it.value_type mut vtyp := it.value_type
if vtyp == 0 { if vtyp == 0 {
typ_sym := f.table.get_type_symbol(it.typ) typ_sym := f.table.get_type_symbol(it.typ)
minfo := typ_sym.info as table.Map minfo := typ_sym.info as table.Map
ktyp = minfo.key_type ktyp = minfo.key_type
vtyp = minfo.value_type vtyp = minfo.value_type
} }
f.write('map[') f.write('map[')
f.write(f.type_to_str(ktyp)) f.write(f.type_to_str(ktyp))
f.write(']') f.write(']')

View File

@ -380,6 +380,13 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
} }
} }
pub fn (mut g Gen) unwrap_generic(typ table.Type) table.Type {
if typ == table.t_type {
return g.cur_generic_type
}
return typ
}
fn (mut g Gen) method_call(node ast.CallExpr) { fn (mut g Gen) method_call(node ast.CallExpr) {
// TODO: there are still due to unchecked exprs (opt/some fn arg) // TODO: there are still due to unchecked exprs (opt/some fn arg)
if node.left_type == 0 { if node.left_type == 0 {
@ -387,7 +394,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} }
// mut receiver_type_name := g.cc_type(node.receiver_type) // mut receiver_type_name := g.cc_type(node.receiver_type)
// mut receiver_type_name := g.typ(node.receiver_type) // mut receiver_type_name := g.typ(node.receiver_type)
typ_sym := g.table.get_type_symbol(node.receiver_type) typ_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver_type))
mut receiver_type_name := typ_sym.name.replace('.', '__') mut receiver_type_name := typ_sym.name.replace('.', '__')
if typ_sym.kind == .interface_ { if typ_sym.kind == .interface_ {
// Speaker_name_table[s._interface_idx].speak(s._object) // Speaker_name_table[s._interface_idx].speak(s._object)

View File

@ -40,10 +40,11 @@ fn test_foo() {
fn create<T>() { fn create<T>() {
a := T{} a := T{}
mut b := T{} mut xx := T{}
b.foo = 'foo' xx.foo = 'foo'
println(b.foo) println(xx.foo)
assert b.foo == 'foo' assert xx.foo == 'foo'
xx.init()
} }
struct User { struct User {
@ -65,6 +66,7 @@ fn (c City) init() {
fn test_create() { fn test_create() {
create<User>() create<User>()
create<City>() create<City>()
// create<User>()
} }
/* /*