parent
2bc9ee4d88
commit
c3dafad7ef
|
@ -1187,6 +1187,16 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
if left_type_sym.kind == .sum_type && method_name == 'type_name' {
|
||||
return table.string_type
|
||||
}
|
||||
if call_expr.generic_type.has_flag(.generic) {
|
||||
if c.mod != '' {
|
||||
// Need to prepend the module when adding a generic type to a function
|
||||
// `fn_gen_types['mymod.myfn'] == ['string', 'int']`
|
||||
c.table.register_fn_gen_type(c.mod + '.' + call_expr.name, c.cur_generic_type)
|
||||
} else {
|
||||
c.table.register_fn_gen_type(call_expr.name, c.cur_generic_type)
|
||||
}
|
||||
// call_expr.generic_type = c.unwrap_generic(call_expr.generic_type)
|
||||
}
|
||||
// TODO: remove this for actual methods, use only for compiler magic
|
||||
// FIXME: Argument count != 1 will break these
|
||||
if left_type_sym.kind == .array &&
|
||||
|
@ -1351,6 +1361,9 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position())
|
||||
continue
|
||||
}
|
||||
if method.is_generic {
|
||||
continue
|
||||
}
|
||||
c.check_expected_call_arg(got_arg_typ, exp_arg_typ) or {
|
||||
// str method, allow type with str method if fn arg is string
|
||||
// Passing an int or a string array produces a c error here
|
||||
|
@ -1402,6 +1415,36 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
call_expr.receiver_type = method.params[0].typ
|
||||
}
|
||||
call_expr.return_type = method.return_type
|
||||
if method.is_generic && call_expr.generic_type == table.void_type {
|
||||
// no type arguments given in call, attempt implicit instantiation
|
||||
c.infer_fn_types(method, mut call_expr)
|
||||
}
|
||||
if call_expr.generic_type != table.void_type && method.return_type != 0 { // table.t_type {
|
||||
// Handle `foo<T>() T` => `foo<int>() int` => return int
|
||||
return_sym := c.table.get_type_symbol(method.return_type)
|
||||
if return_sym.name == 'T' {
|
||||
mut typ := call_expr.generic_type
|
||||
typ = typ.set_nr_muls(method.return_type.nr_muls())
|
||||
if method.return_type.has_flag(.optional) {
|
||||
typ = typ.set_flag(.optional)
|
||||
}
|
||||
call_expr.return_type = typ
|
||||
return typ
|
||||
} else if return_sym.kind == .array {
|
||||
elem_info := return_sym.info as table.Array
|
||||
elem_sym := c.table.get_type_symbol(elem_info.elem_type)
|
||||
if elem_sym.name == 'T' {
|
||||
idx := c.table.find_or_register_array(call_expr.generic_type, 1)
|
||||
return table.new_type(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
if call_expr.generic_type.is_full() && !method.is_generic {
|
||||
c.error('a non generic function called like a generic one', call_expr.generic_list_pos)
|
||||
}
|
||||
if method.is_generic {
|
||||
return call_expr.return_type
|
||||
}
|
||||
return method.return_type
|
||||
}
|
||||
// TODO: str methods
|
||||
|
|
|
@ -424,6 +424,11 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if node.generic_type != table.void_type && node.generic_type != 0 {
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
// `foo<int>()` => `foo_T_int()`
|
||||
name += '_T_' + g.typ(node.generic_type)
|
||||
}
|
||||
// TODO2
|
||||
// g.generate_tmp_autofree_arg_vars(node, name)
|
||||
//
|
||||
|
|
|
@ -50,7 +50,7 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
|||
}
|
||||
}
|
||||
p.check(.lpar)
|
||||
mut args := p.call_args()
|
||||
args := p.call_args()
|
||||
last_pos := p.tok.position()
|
||||
p.check(.rpar)
|
||||
// ! in mutable methods
|
||||
|
|
|
@ -1427,6 +1427,20 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
|||
}
|
||||
// Method call
|
||||
// TODO move to fn.v call_expr()
|
||||
mut generic_type := table.void_type
|
||||
mut generic_list_pos := p.tok.position()
|
||||
if p.tok.kind == .lt && p.peek_tok.kind == .name && p.peek_tok2.kind == .gt {
|
||||
// `g.foo<int>(10)`
|
||||
p.next() // `<`
|
||||
generic_type = p.parse_type()
|
||||
p.check(.gt) // `>`
|
||||
generic_list_pos = generic_list_pos.extend(p.prev_tok.position())
|
||||
// In case of `foo<T>()`
|
||||
// T is unwrapped and registered in the checker.
|
||||
if !generic_type.has_flag(.generic) {
|
||||
p.table.register_fn_gen_type(field_name, generic_type)
|
||||
}
|
||||
}
|
||||
if p.tok.kind == .lpar {
|
||||
p.next()
|
||||
args := p.call_args()
|
||||
|
@ -1472,6 +1486,8 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
|||
args: args
|
||||
pos: pos
|
||||
is_method: true
|
||||
generic_type: generic_type
|
||||
generic_list_pos: generic_list_pos
|
||||
or_block: ast.OrExpr{
|
||||
stmts: or_stmts
|
||||
kind: or_kind
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
struct Point {
|
||||
mut:
|
||||
x int
|
||||
y int
|
||||
}
|
||||
|
||||
fn (mut p Point) translate<T>(x T, y T) {
|
||||
p.x += x
|
||||
p.y += y
|
||||
}
|
||||
|
||||
fn test_generic_method() {
|
||||
mut pot := Point{}
|
||||
pot.translate<int>(1, 3)
|
||||
pot.translate(1, 3)
|
||||
println(pot)
|
||||
assert pot == Point{
|
||||
x: 2
|
||||
y: 6
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue