1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

generics: generic methods, cast to T

This commit is contained in:
Simon Heuser 2019-10-25 20:32:27 +02:00 committed by Alexander Medvednikov
parent 7d02eccbce
commit 280c7d396c
4 changed files with 75 additions and 26 deletions

View File

@ -392,8 +392,23 @@ fn (p mut Parser) fn_decl() {
if f.is_generic {
if p.first_pass() {
f.body_idx = p.cur_tok_index()+1
p.table.register_fn(f)
if f.is_method {
rcv := p.table.find_type(receiver_typ)
if p.first_pass() && rcv.name == '' {
r := Type {
name: rcv.name.replace('*', '')
mod: p.mod
is_placeholder: true
}
p.table.register_type2(r)
}
// println('added generic method $rcv.name $f.name')
p.add_method(rcv.name, f)
} else {
p.table.register_fn(f)
}
}
if f.is_method { p.mark_var_changed(f.args[0]) }
p.check_unused_variables()
p.set_current_fn( EmptyFn )
p.returns = false
@ -692,9 +707,6 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
// If we have a method placeholder,
// we need to preappend "method(receiver, ...)"
if f.is_method {
if f.is_generic {
p.error('generic methods are not yet implemented')
}
receiver := f.args.first()
//println('r=$receiver.typ RT=$receiver_type')
if receiver.is_mut && !p.expr_var.is_mut {
@ -709,8 +721,8 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s
if !p.expr_var.is_changed {
p.mark_var_changed(p.expr_var)
}
met_name := if f.is_generic { f.name } else { cgen_name }
p.gen_method_call(receiver_type, f.typ, met_name, receiver, method_ph)
met_call := p.gen_method_call(receiver, receiver_type, cgen_name, f.typ)
p.cgen.set_placeholder(method_ph, met_call)
} else {
// Normal function call
p.gen('$cgen_name (')
@ -1082,8 +1094,8 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
mut r := TypeInst{}
mut i := 0
mut args := args_
args << f.typ
for ai, e in args {
if f.typ != 'void' { args << f.typ }
for e in args {
if e == '' { continue }
tp := f.type_pars[i]
mut ti := e
@ -1118,6 +1130,11 @@ fn (p mut Parser) extract_type_inst(f &Fn, args_ []string) TypeInst {
if r.inst[f.typ] == '' && f.typ in f.type_pars {
r.inst[f.typ] = '_ANYTYPE_'
}
for tp in f.type_pars {
if r.inst[tp] == '' {
p.error_with_token_index('unused type parameter `$tp`', f.body_idx-2)
}
}
return r
}
@ -1257,6 +1274,9 @@ fn (p mut Parser) register_multi_return_stuct(types []string) string {
}
fn (p mut Parser) rename_generic_fn_instance(f mut Fn, ti TypeInst) {
if f.is_method {
f.name = f.receiver_typ + '_' + f.name
}
f.name = f.name + '_T'
for k in ti.inst.keys() {
f.name = f.name + '_' + type_to_safe_str(ti.inst[k].replace('...', ''))
@ -1326,7 +1346,12 @@ fn (p mut Parser) dispatch_generic_fn_instance(f mut Fn, ti TypeInst) {
if f.typ in ti.inst {
f.typ = ti.inst[f.typ]
}
p.table.register_fn(f)
if f.is_method {
p.add_method(f.args[0].name, f)
} else {
p.table.register_fn(f)
}
// println("generating gen inst $f.name(${f.str_args(p.table)}) $f.typ : $ti.inst")
p.cgen.is_tmp = false

View File

@ -247,11 +247,9 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
return name
}
fn (p mut Parser) gen_method_call(receiver_type, ftyp string, cgen_name string,
receiver Var,method_ph int)
{
fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string, cgen_name string, ftyp string) string {
//mut cgen_name := p.table.fn_gen_name(f)
mut method_call := cgen_name + '('
mut method_call := cgen_name + ' ('
// if receiver is key_mut or a ref (&), generate & for the first arg
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
method_call += '& /* ? */'
@ -268,12 +266,11 @@ fn (p mut Parser) gen_method_call(receiver_type, ftyp string, cgen_name string,
// array_int => int
cast = receiver_type.all_after('array_')
cast = '*($cast*) '
}else{
} else {
cast = '(voidptr) '
}
}
p.cgen.set_placeholder(method_ph, '$cast $method_call')
//return method_call
return '$cast $method_call'
}
fn (p mut Parser) gen_array_at(typ_ string, is_arr0 bool, fn_ph int) {

View File

@ -1617,7 +1617,10 @@ fn (p mut Parser) name_expr() string {
}
p.gen('(')
mut typ := name
p.cast(name)
if typ in p.cur_fn.dispatch_of.inst.keys() {
typ = p.cur_fn.dispatch_of.inst[typ]
}
p.cast(typ)
p.gen(')')
for p.tok == .dot {
typ = p.dot(typ, ph)

View File

@ -2,15 +2,15 @@ fn simple<T>(p T) T {
return p
}
fn sum<T>(l []T, nil T) T {
mut r := nil
fn sum<T>(l []T) T {
mut r := T(0)
for e in l {
r += e
}
return r
}
fn map_f<T,U,R>(l []T, f fn(T)U) []U {
fn map_f<T,U>(l []T, f fn(T)U) []U {
mut r := []U
for e in l {
r << f(e)
@ -44,15 +44,39 @@ fn assert_eq<T>(a, b T) {
assert r
}
fn print_nice<T>(x T, indent int) {
mut space := ''
for i in 0..indent {
space = space + ' '
}
println('$space$x')
}
fn test_generic_fn() {
assert_eq(simple(0+1), 1)
assert_eq(simple('g') + 'h', 'gh')
assert_eq(sum([5.1,6.2,7.0], 0.0), 18.3)
assert_eq(sum([5.1,6.2,7.0]), 18.3)
assert_eq(plus(i64(4), i64(6)), i64(10))
a := [1,2,3,4]
$if !windows {
b := map_f(a, square)
assert_eq(sum(b, 0), 30) // 1+4+9+16 = 30
assert_eq(foldl(b, 1, mul_int), 576) // 1*4*9*16 = 576
}
b := map_f(a, square)
assert_eq(sum(b), 30) // 1+4+9+16 = 30
assert_eq(foldl(b, 1, mul_int), 576) // 1*4*9*16 = 576
print_nice('str', 8)
}
struct Point {
mut:
x f64
y f64
}
fn (p mut Point) translate<T>(x, y T) {
p.x += x
p.y += y
}
fn test_generic_method() {
mut p := Point{}
p.translate(2, 1.0)
assert p.x == 2.0 && p.y == 1.0
}