mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
generics: fix method calls
This commit is contained in:
parent
ae8cc2f433
commit
d6037cbcf2
@ -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`',
|
||||
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)
|
||||
}
|
||||
struct_init.fields[i].typ = expr_type
|
||||
@ -468,17 +469,18 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||
if infix_expr.op in [.mod, .xor, .amp, .pipe] {
|
||||
side := if left_type == promoted_type { 'left' } else { 'right' }
|
||||
pos := if left_type == promoted_type { left_pos } else { right_pos }
|
||||
name := if left_type == promoted_type { left.name } else { right.name }
|
||||
name := if left_type == promoted_type { left.name } else { right.name }
|
||||
if infix_expr.op == .mod {
|
||||
c.error('float modulo not allowed, use math.fmod() instead', pos)
|
||||
} 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.right is ast.IntegerLiteral && infix_expr.right.str() == '0' ||
|
||||
infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0 {
|
||||
if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
|
||||
'0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0 {
|
||||
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||
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)
|
||||
} else {
|
||||
// []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
|
||||
}
|
||||
@ -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 {
|
||||
left_type := c.expr(call_expr.left)
|
||||
is_generic := left_type == table.t_type
|
||||
call_expr.left_type = left_type
|
||||
left_type_sym := c.table.get_type_symbol(c.unwrap_generic(left_type))
|
||||
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.receiver_type = method.args[0].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.return_type = method.return_type
|
||||
return method.return_type
|
||||
}
|
||||
@ -1167,9 +1176,8 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
||||
mut got_types := []table.Type{}
|
||||
for expr in return_stmt.exprs {
|
||||
typ := c.expr(expr)
|
||||
|
||||
// Unpack multi return types
|
||||
sym := c.table.get_type_symbol(typ)
|
||||
sym := c.table.get_type_symbol(typ)
|
||||
if sym.kind == .multi_return {
|
||||
for t in sym.mr_info().types {
|
||||
got_types << t
|
||||
@ -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']] {
|
||||
return
|
||||
}
|
||||
|
||||
if expected_types.len > 0 && expected_types.len != got_types.len {
|
||||
c.error('wrong number of return arguments', return_stmt.pos)
|
||||
return
|
||||
}
|
||||
|
||||
for i, exp_type in expected_types {
|
||||
got_typ := got_types[i]
|
||||
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
|
||||
if ident.kind == .variable {
|
||||
info := ident.info as ast.IdentVar
|
||||
if info.typ == table.t_type {
|
||||
// Got a var with type T, return current generic type
|
||||
// return c.cur_generic_type
|
||||
}
|
||||
// if info.typ == table.t_type {
|
||||
// Got a var with type T, return current generic type
|
||||
// return c.cur_generic_type
|
||||
// }
|
||||
return info.typ
|
||||
} else if ident.kind == .constant {
|
||||
info := ident.info as ast.IdentVar
|
||||
@ -2183,7 +2189,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||
}
|
||||
}
|
||||
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
|
||||
node.pos)
|
||||
node.pos)
|
||||
}
|
||||
} else {
|
||||
c.error('`if` expression requires an expression as the last statement of every branch',
|
||||
@ -2194,7 +2200,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||
// if only untyped literals were given default to int/f64
|
||||
if node.typ == table.any_int_type {
|
||||
node.typ = table.int_type
|
||||
} else if node.typ == table.any_flt_type {
|
||||
} else if node.typ == table.any_flt_type {
|
||||
node.typ = table.f64_type
|
||||
}
|
||||
if expr_required {
|
||||
@ -2410,8 +2416,8 @@ fn (mut c Checker) fn_decl(it ast.FnDecl) {
|
||||
// loop thru each generic type and generate a function
|
||||
for gen_type in c.table.fn_gen_types[it.name] {
|
||||
c.cur_generic_type = gen_type
|
||||
//sym:=c.table.get_type_symbol(gen_type)
|
||||
//println('\ncalling check for $it.name for type $sym.name')
|
||||
// sym:=c.table.get_type_symbol(gen_type)
|
||||
// println('\ncalling check for $it.name for type $sym.name')
|
||||
c.fn_decl(it)
|
||||
}
|
||||
c.cur_generic_type = 0
|
||||
|
@ -8,7 +8,9 @@ import v.table
|
||||
import strings
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
@ -405,7 +407,8 @@ pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {
|
||||
}
|
||||
f.write(')')
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -592,15 +595,12 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||
if it.keys.len == 0 {
|
||||
mut ktyp := it.key_type
|
||||
mut vtyp := it.value_type
|
||||
|
||||
if vtyp == 0 {
|
||||
typ_sym := f.table.get_type_symbol(it.typ)
|
||||
minfo := typ_sym.info as table.Map
|
||||
|
||||
ktyp = minfo.key_type
|
||||
vtyp = minfo.value_type
|
||||
}
|
||||
|
||||
f.write('map[')
|
||||
f.write(f.type_to_str(ktyp))
|
||||
f.write(']')
|
||||
|
@ -48,19 +48,19 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
'irq_handler' {
|
||||
g.write('__IRQHANDLER ')
|
||||
}
|
||||
|
||||
|
||||
// GCC/clang attributes
|
||||
// prefixed by _ to indicate they're for advanced users only and not really supported by V.
|
||||
// source for descriptions: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
|
||||
|
||||
// The cold attribute on functions is used to inform the compiler that the function is unlikely
|
||||
// The cold attribute on functions is used to inform the compiler that the function is unlikely
|
||||
// to be executed. The function is optimized for size rather than speed and on many targets it
|
||||
// is placed into a special subsection of the text section so all cold functions appear close
|
||||
// together, improving code locality of non-cold parts of program.
|
||||
'_cold' {
|
||||
g.write('__attribute__((cold)) ')
|
||||
}
|
||||
// The constructor attribute causes the function to be called automatically before execution
|
||||
// The constructor attribute causes the function to be called automatically before execution
|
||||
// enters main ().
|
||||
'_constructor' {
|
||||
g.write('__attribute__((constructor)) ')
|
||||
@ -70,7 +70,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
'_destructor' {
|
||||
g.write('__attribute__((destructor)) ')
|
||||
}
|
||||
// Generally, inlining into a function is limited. For a function marked with this attribute,
|
||||
// Generally, inlining into a function is limited. For a function marked with this attribute,
|
||||
// every call inside this function is inlined, if possible.
|
||||
'_flatten' {
|
||||
g.write('__attribute__((flatten)) ')
|
||||
@ -80,16 +80,16 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
'_hot' {
|
||||
g.write('__attribute__((hot)) ')
|
||||
}
|
||||
// This tells the compiler that a function is malloc-like, i.e., that the pointer P returned by
|
||||
// the function cannot alias any other pointer valid when the function returns, and moreover no
|
||||
// This tells the compiler that a function is malloc-like, i.e., that the pointer P returned by
|
||||
// the function cannot alias any other pointer valid when the function returns, and moreover no
|
||||
// pointers to valid objects occur in any storage addressed by P.
|
||||
'_malloc' {
|
||||
g.write('__attribute__((malloc)) ')
|
||||
}
|
||||
|
||||
// Calls to functions whose return value is not affected by changes to the observable state
|
||||
// of the program and that have no observable effects on such state other than to return a
|
||||
// value may lend themselves to optimizations such as common subexpression elimination.
|
||||
|
||||
// Calls to functions whose return value is not affected by changes to the observable state
|
||||
// of the program and that have no observable effects on such state other than to return a
|
||||
// value may lend themselves to optimizations such as common subexpression elimination.
|
||||
// Declaring such functions with the const attribute allows GCC to avoid emitting some calls in
|
||||
// repeated invocations of the function with the same argument values.
|
||||
'_pure' {
|
||||
@ -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) {
|
||||
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
||||
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.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('.', '__')
|
||||
if typ_sym.kind == .interface_ {
|
||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||
|
@ -40,10 +40,11 @@ fn test_foo() {
|
||||
|
||||
fn create<T>() {
|
||||
a := T{}
|
||||
mut b := T{}
|
||||
b.foo = 'foo'
|
||||
println(b.foo)
|
||||
assert b.foo == 'foo'
|
||||
mut xx := T{}
|
||||
xx.foo = 'foo'
|
||||
println(xx.foo)
|
||||
assert xx.foo == 'foo'
|
||||
xx.init()
|
||||
}
|
||||
|
||||
struct User {
|
||||
@ -65,6 +66,7 @@ fn (c City) init() {
|
||||
fn test_create() {
|
||||
create<User>()
|
||||
create<City>()
|
||||
// create<User>()
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user