all: cleanup generics call_expr (#9856)
parent
a832bb609a
commit
8ccdae6188
|
@ -420,8 +420,8 @@ pub mut:
|
|||
receiver_type Type // User
|
||||
return_type Type
|
||||
should_be_skipped bool
|
||||
generic_types []Type
|
||||
generic_list_pos token.Position
|
||||
concrete_types []Type // concrete types, e.g. <int, string>
|
||||
concrete_list_pos token.Position
|
||||
free_receiver bool // true if the receiver expression needs to be freed
|
||||
scope &Scope
|
||||
from_embed_type Type // holds the type of the embed that the method is called from
|
||||
|
|
|
@ -479,8 +479,8 @@ pub fn (mut c Checker) infer_fn_generic_types(f ast.Fn, mut call_expr ast.CallEx
|
|||
mut inferred_types := []ast.Type{}
|
||||
for gi, gt_name in f.generic_names {
|
||||
// skip known types
|
||||
if gi < call_expr.generic_types.len {
|
||||
inferred_types << call_expr.generic_types[gi]
|
||||
if gi < call_expr.concrete_types.len {
|
||||
inferred_types << call_expr.concrete_types[gi]
|
||||
continue
|
||||
}
|
||||
mut typ := ast.void_type
|
||||
|
@ -569,7 +569,7 @@ pub fn (mut c Checker) infer_fn_generic_types(f ast.Fn, mut call_expr ast.CallEx
|
|||
println('inferred `$f.name<$s>`')
|
||||
}
|
||||
inferred_types << typ
|
||||
call_expr.generic_types << typ
|
||||
call_expr.concrete_types << typ
|
||||
}
|
||||
c.table.register_fn_generic_types(f.name, inferred_types)
|
||||
}
|
||||
|
|
|
@ -1430,17 +1430,17 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, call_exp
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_expr ast.CallExpr, generic_types []ast.Type) {
|
||||
fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_expr ast.CallExpr, concrete_types []ast.Type) {
|
||||
rts := c.table.get_type_symbol(return_type)
|
||||
if rts.info is ast.Struct {
|
||||
if rts.info.is_generic {
|
||||
mut nrt := '$rts.name<'
|
||||
mut c_nrt := '${rts.name}_T_'
|
||||
for i in 0 .. call_expr.generic_types.len {
|
||||
gts := c.table.get_type_symbol(call_expr.generic_types[i])
|
||||
for i in 0 .. call_expr.concrete_types.len {
|
||||
gts := c.table.get_type_symbol(call_expr.concrete_types[i])
|
||||
nrt += gts.name
|
||||
c_nrt += gts.name
|
||||
if i != call_expr.generic_types.len - 1 {
|
||||
if i != call_expr.concrete_types.len - 1 {
|
||||
nrt += ','
|
||||
c_nrt += '_'
|
||||
}
|
||||
|
@ -1452,18 +1452,18 @@ fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_e
|
|||
call_expr.return_type = ast.new_type(idx).derive(return_type)
|
||||
} else {
|
||||
mut fields := rts.info.fields.clone()
|
||||
if rts.info.generic_types.len == generic_types.len {
|
||||
if rts.info.generic_types.len == concrete_types.len {
|
||||
generic_names := rts.info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
for i, _ in fields {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, generic_types)
|
||||
generic_names, concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
mut info := rts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = generic_types.clone()
|
||||
info.concrete_types = concrete_types.clone()
|
||||
info.parent_type = return_type
|
||||
info.fields = fields
|
||||
stru_idx := c.table.register_type_symbol(ast.TypeSymbol{
|
||||
|
@ -1499,18 +1499,18 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
if left_type_sym.kind in [.sum_type, .interface_] && method_name == 'type_name' {
|
||||
return ast.string_type
|
||||
}
|
||||
mut has_generic_generic := false // x.foo<T>() instead of x.foo<int>()
|
||||
mut generic_types := []ast.Type{}
|
||||
for generic_type in call_expr.generic_types {
|
||||
if generic_type.has_flag(.generic) {
|
||||
has_generic_generic = true
|
||||
generic_types << c.unwrap_generic(generic_type)
|
||||
mut has_generic := false // x.foo<T>() instead of x.foo<int>()
|
||||
mut concrete_types := []ast.Type{}
|
||||
for concrete_type in call_expr.concrete_types {
|
||||
if concrete_type.has_flag(.generic) {
|
||||
has_generic = true
|
||||
concrete_types << c.unwrap_generic(concrete_type)
|
||||
} else {
|
||||
generic_types << generic_type
|
||||
concrete_types << concrete_type
|
||||
}
|
||||
}
|
||||
if has_generic_generic {
|
||||
c.table.register_fn_generic_types(call_expr.name, generic_types)
|
||||
if has_generic {
|
||||
c.table.register_fn_generic_types(call_expr.name, concrete_types)
|
||||
}
|
||||
// TODO: remove this for actual methods, use only for compiler magic
|
||||
// FIXME: Argument count != 1 will break these
|
||||
|
@ -1625,7 +1625,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
return method.return_type
|
||||
}
|
||||
if method.generic_names.len > 0 && method.return_type.has_flag(.generic) {
|
||||
c.check_return_generics_struct(method.return_type, mut call_expr, generic_types)
|
||||
c.check_return_generics_struct(method.return_type, mut call_expr, concrete_types)
|
||||
} else {
|
||||
call_expr.return_type = method.return_type
|
||||
}
|
||||
|
@ -1749,24 +1749,24 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
} else {
|
||||
call_expr.receiver_type = method.params[0].typ
|
||||
}
|
||||
if method.generic_names.len != call_expr.generic_types.len {
|
||||
if method.generic_names.len != call_expr.concrete_types.len {
|
||||
// no type arguments given in call, attempt implicit instantiation
|
||||
c.infer_fn_generic_types(method, mut call_expr)
|
||||
}
|
||||
if call_expr.generic_types.len > 0 && method.return_type != 0 {
|
||||
if call_expr.concrete_types.len > 0 && method.return_type != 0 {
|
||||
if typ := c.table.resolve_generic_to_concrete(method.return_type, method.generic_names,
|
||||
call_expr.generic_types)
|
||||
call_expr.concrete_types)
|
||||
{
|
||||
call_expr.return_type = typ
|
||||
return typ
|
||||
}
|
||||
}
|
||||
if call_expr.generic_types.len > 0 && method.generic_names.len == 0 {
|
||||
c.error('a non generic function called like a generic one', call_expr.generic_list_pos)
|
||||
if call_expr.concrete_types.len > 0 && method.generic_names.len == 0 {
|
||||
c.error('a non generic function called like a generic one', call_expr.concrete_list_pos)
|
||||
}
|
||||
if call_expr.generic_types.len > method.generic_names.len {
|
||||
c.error('too many generic parameters got $call_expr.generic_types.len, expected $method.generic_names.len',
|
||||
call_expr.generic_list_pos)
|
||||
if call_expr.concrete_types.len > method.generic_names.len {
|
||||
c.error('too many generic parameters got $call_expr.concrete_types.len, expected $method.generic_names.len',
|
||||
call_expr.concrete_list_pos)
|
||||
}
|
||||
if method.generic_names.len > 0 {
|
||||
return call_expr.return_type
|
||||
|
@ -1960,22 +1960,22 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
// TODO: impl typeof properly (probably not going to be a fn call)
|
||||
return ast.string_type
|
||||
}
|
||||
mut has_generic_generic := false // foo<T>() instead of foo<int>()
|
||||
mut generic_types := []ast.Type{}
|
||||
for generic_type in call_expr.generic_types {
|
||||
if generic_type.has_flag(.generic) {
|
||||
has_generic_generic = true
|
||||
generic_types << c.unwrap_generic(generic_type)
|
||||
mut has_generic := false // foo<T>() instead of foo<int>()
|
||||
mut concrete_types := []ast.Type{}
|
||||
for concrete_type in call_expr.concrete_types {
|
||||
if concrete_type.has_flag(.generic) {
|
||||
has_generic = true
|
||||
concrete_types << c.unwrap_generic(concrete_type)
|
||||
} else {
|
||||
generic_types << generic_type
|
||||
concrete_types << concrete_type
|
||||
}
|
||||
}
|
||||
if has_generic_generic {
|
||||
if has_generic {
|
||||
if c.mod != '' && !fn_name.starts_with('${c.mod}.') {
|
||||
// Need to prepend the module when adding a generic type to a function
|
||||
c.table.register_fn_generic_types(c.mod + '.' + fn_name, generic_types)
|
||||
c.table.register_fn_generic_types(c.mod + '.' + fn_name, concrete_types)
|
||||
} else {
|
||||
c.table.register_fn_generic_types(fn_name, generic_types)
|
||||
c.table.register_fn_generic_types(fn_name, concrete_types)
|
||||
}
|
||||
}
|
||||
if fn_name == 'json.encode' {
|
||||
|
@ -2061,7 +2061,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
if c.pref.is_script && !found {
|
||||
os_name := 'os.$fn_name'
|
||||
if f := c.table.find_fn(os_name) {
|
||||
if f.generic_names.len == call_expr.generic_types.len {
|
||||
if f.generic_names.len == call_expr.concrete_types.len {
|
||||
c.table.fn_generic_types[os_name] = c.table.fn_generic_types['${call_expr.mod}.$call_expr.name']
|
||||
}
|
||||
call_expr.name = os_name
|
||||
|
@ -2111,16 +2111,16 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
&& !func.is_unsafe {
|
||||
c.error('cannot call a function that does not have a body', call_expr.pos)
|
||||
}
|
||||
for generic_type in call_expr.generic_types {
|
||||
c.ensure_type_exists(generic_type, call_expr.generic_list_pos) or {}
|
||||
for concrete_type in call_expr.concrete_types {
|
||||
c.ensure_type_exists(concrete_type, call_expr.concrete_list_pos) or {}
|
||||
}
|
||||
if func.generic_names.len > 0 && call_expr.args.len == 0 && call_expr.generic_types.len == 0 {
|
||||
if func.generic_names.len > 0 && call_expr.args.len == 0 && call_expr.concrete_types.len == 0 {
|
||||
c.error('no argument generic function must add concrete types, e.g. foo<int>()',
|
||||
call_expr.pos)
|
||||
return func.return_type
|
||||
}
|
||||
if func.generic_names.len > 0 && func.return_type.has_flag(.generic) {
|
||||
c.check_return_generics_struct(func.return_type, mut call_expr, generic_types)
|
||||
c.check_return_generics_struct(func.return_type, mut call_expr, concrete_types)
|
||||
} else {
|
||||
call_expr.return_type = func.return_type
|
||||
}
|
||||
|
@ -2259,7 +2259,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
call_arg.pos)
|
||||
}
|
||||
}
|
||||
if func.generic_names.len != call_expr.generic_types.len {
|
||||
if func.generic_names.len != call_expr.concrete_types.len {
|
||||
// no type arguments given in call, attempt implicit instantiation
|
||||
c.infer_fn_generic_types(func, mut call_expr)
|
||||
}
|
||||
|
@ -2273,9 +2273,10 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
c.expected_type = param.typ
|
||||
typ := c.check_expr_opt_call(call_arg.expr, c.expr(call_arg.expr))
|
||||
|
||||
if param.typ.has_flag(.generic) && func.generic_names.len == call_expr.generic_types.len {
|
||||
if param.typ.has_flag(.generic)
|
||||
&& func.generic_names.len == call_expr.concrete_types.len {
|
||||
if unwrap_typ := c.table.resolve_generic_to_concrete(param.typ, func.generic_names,
|
||||
call_expr.generic_types)
|
||||
call_expr.concrete_types)
|
||||
{
|
||||
c.check_expected_call_arg(typ, unwrap_typ, call_expr.language) or {
|
||||
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
|
||||
|
@ -2284,21 +2285,21 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
}
|
||||
}
|
||||
}
|
||||
if call_expr.generic_types.len > 0 && func.return_type != 0 {
|
||||
if call_expr.concrete_types.len > 0 && func.return_type != 0 {
|
||||
if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
|
||||
call_expr.generic_types)
|
||||
call_expr.concrete_types)
|
||||
{
|
||||
call_expr.return_type = typ
|
||||
return typ
|
||||
}
|
||||
}
|
||||
if call_expr.generic_types.len > 0 && func.generic_names.len == 0 {
|
||||
c.error('a non generic function called like a generic one', call_expr.generic_list_pos)
|
||||
if call_expr.concrete_types.len > 0 && func.generic_names.len == 0 {
|
||||
c.error('a non generic function called like a generic one', call_expr.concrete_list_pos)
|
||||
}
|
||||
|
||||
if call_expr.generic_types.len > func.generic_names.len {
|
||||
c.error('too many generic parameters got $call_expr.generic_types.len, expected $func.generic_names.len',
|
||||
call_expr.generic_list_pos)
|
||||
if call_expr.concrete_types.len > func.generic_names.len {
|
||||
c.error('too many generic parameters got $call_expr.concrete_types.len, expected $func.generic_names.len',
|
||||
call_expr.concrete_list_pos)
|
||||
}
|
||||
if func.generic_names.len > 0 {
|
||||
return call_expr.return_type
|
||||
|
|
|
@ -1599,11 +1599,11 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||
}
|
||||
|
||||
fn (mut f Fmt) write_generic_if_require(node ast.CallExpr) {
|
||||
if node.generic_types.len > 0 {
|
||||
if node.concrete_types.len > 0 {
|
||||
f.write('<')
|
||||
for i, generic_type in node.generic_types {
|
||||
is_last := i == node.generic_types.len - 1
|
||||
f.write(f.table.type_to_str(generic_type))
|
||||
for i, concrete_type in node.concrete_types {
|
||||
is_last := i == node.concrete_types.len - 1
|
||||
f.write(f.table.type_to_str(concrete_type))
|
||||
if !is_last {
|
||||
f.write(', ')
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ mut:
|
|||
hotcode_fn_names []string
|
||||
embedded_files []ast.EmbeddedFile
|
||||
cur_fn ast.FnDecl
|
||||
cur_generic_types []ast.Type // `int`, `string`, etc in `foo<T>()`
|
||||
cur_concrete_types []ast.Type // current concrete types, e.g. <int, string>
|
||||
sql_i int
|
||||
sql_stmt_name string
|
||||
sql_bind_name string
|
||||
|
@ -3202,7 +3202,7 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
fn (mut g Gen) type_name(type_ ast.Type) {
|
||||
mut typ := type_
|
||||
if typ.has_flag(.generic) {
|
||||
typ = g.cur_generic_types[0]
|
||||
typ = g.cur_concrete_types[0]
|
||||
}
|
||||
s := g.table.type_to_str(typ)
|
||||
g.write('_SLIT("${util.strip_main_name(s)}")')
|
||||
|
@ -5945,14 +5945,14 @@ fn (mut g Gen) go_expr(node ast.GoExpr) {
|
|||
mut expr := node.call_expr
|
||||
mut name := expr.name // util.no_dots(expr.name)
|
||||
// TODO: fn call is duplicated. merge with fn_call().
|
||||
for i, generic_type in expr.generic_types {
|
||||
if generic_type != ast.void_type && generic_type != 0 {
|
||||
for i, concrete_type in expr.concrete_types {
|
||||
if concrete_type != ast.void_type && concrete_type != 0 {
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
// `foo<int>()` => `foo_T_int()`
|
||||
if i == 0 {
|
||||
name += '_T'
|
||||
}
|
||||
name += '_' + g.typ(generic_type)
|
||||
name += '_' + g.typ(concrete_type)
|
||||
}
|
||||
}
|
||||
if expr.is_method {
|
||||
|
|
|
@ -127,18 +127,18 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
|||
// if g.fileis('vweb.v') {
|
||||
// println('\ngen_fn_decl() $node.name $node.is_generic $g.cur_generic_type')
|
||||
// }
|
||||
if node.generic_names.len > 0 && g.cur_generic_types.len == 0 { // need the cur_generic_type check to avoid inf. recursion
|
||||
if node.generic_names.len > 0 && g.cur_concrete_types.len == 0 { // need the cur_concrete_type check to avoid inf. recursion
|
||||
// loop thru each generic type and generate a function
|
||||
for generic_types in g.table.fn_generic_types[node.name] {
|
||||
for concrete_types in g.table.fn_generic_types[node.name] {
|
||||
if g.pref.is_verbose {
|
||||
syms := generic_types.map(g.table.get_type_symbol(it))
|
||||
syms := concrete_types.map(g.table.get_type_symbol(it))
|
||||
the_type := syms.map(node.name).join(', ')
|
||||
println('gen fn `$node.name` for type `$the_type`')
|
||||
}
|
||||
g.cur_generic_types = generic_types
|
||||
g.cur_concrete_types = concrete_types
|
||||
g.gen_fn_decl(node, skip)
|
||||
}
|
||||
g.cur_generic_types = []
|
||||
g.cur_concrete_types = []
|
||||
return
|
||||
}
|
||||
cur_fn_save := g.cur_fn
|
||||
|
@ -173,12 +173,12 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
|||
name = c_name(name)
|
||||
}
|
||||
mut type_name := g.typ(node.return_type)
|
||||
if g.cur_generic_types.len > 0 {
|
||||
if g.cur_concrete_types.len > 0 {
|
||||
// foo<T>() => foo_T_int(), foo_T_string() etc
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
name += '_T'
|
||||
for generic_type in g.cur_generic_types {
|
||||
gen_name := g.typ(generic_type)
|
||||
for concrete_type in g.cur_concrete_types {
|
||||
gen_name := g.typ(concrete_type)
|
||||
name += '_' + gen_name
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +477,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||
|
||||
pub fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
|
||||
if typ.has_flag(.generic) {
|
||||
if t_typ := g.table.resolve_generic_to_concrete(typ, g.cur_fn.generic_names, g.cur_generic_types) {
|
||||
if t_typ := g.table.resolve_generic_to_concrete(typ, g.cur_fn.generic_names, g.cur_concrete_types) {
|
||||
return t_typ
|
||||
}
|
||||
}
|
||||
|
@ -654,14 +654,14 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
}
|
||||
}
|
||||
}
|
||||
for i, generic_type in node.generic_types {
|
||||
if generic_type != ast.void_type && generic_type != 0 {
|
||||
for i, concrete_type in node.concrete_types {
|
||||
if concrete_type != ast.void_type && concrete_type != 0 {
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
// `foo<int>()` => `foo_T_int()`
|
||||
if i == 0 {
|
||||
name += '_T'
|
||||
}
|
||||
name += '_' + g.typ(generic_type)
|
||||
name += '_' + g.typ(concrete_type)
|
||||
}
|
||||
}
|
||||
// TODO2
|
||||
|
@ -832,13 +832,13 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
panic('cgen: obf name "$key" not found, this should never happen')
|
||||
}
|
||||
}
|
||||
for i, generic_type in node.generic_types {
|
||||
for i, concrete_type in node.concrete_types {
|
||||
// Using _T_ to differentiate between get<string> and get_string
|
||||
// `foo<int>()` => `foo_T_int()`
|
||||
if i == 0 {
|
||||
name += '_T'
|
||||
}
|
||||
name += '_' + g.typ(generic_type)
|
||||
name += '_' + g.typ(concrete_type)
|
||||
}
|
||||
// TODO2
|
||||
// cgen shouldn't modify ast nodes, this should be moved
|
||||
|
@ -1072,7 +1072,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
|||
g.write('/*af arg*/' + name)
|
||||
}
|
||||
} else {
|
||||
if node.generic_types.len > 0 && arg.expr.is_auto_deref_var() && !arg.is_mut
|
||||
if node.concrete_types.len > 0 && arg.expr.is_auto_deref_var() && !arg.is_mut
|
||||
&& !expected_types[i].is_ptr() {
|
||||
g.write('*')
|
||||
}
|
||||
|
@ -1104,7 +1104,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
|||
varg_type_name := g.table.type_to_str(varg_type)
|
||||
for i, fn_gen_name in fn_def.generic_names {
|
||||
if fn_gen_name == varg_type_name {
|
||||
arr_info.elem_type = node.generic_types[i]
|
||||
arr_info.elem_type = node.concrete_types[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,27 +26,27 @@ pub fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr
|
|||
p.expecting_type = true // Makes name_expr() parse the type `User` in `json.decode(User, txt)`
|
||||
or_kind = .block
|
||||
}
|
||||
//
|
||||
|
||||
old_expr_mod := p.expr_mod
|
||||
defer {
|
||||
p.expr_mod = old_expr_mod
|
||||
}
|
||||
p.expr_mod = ''
|
||||
//
|
||||
mut generic_types := []ast.Type{}
|
||||
mut generic_list_pos := p.tok.position()
|
||||
|
||||
mut concrete_types := []ast.Type{}
|
||||
mut concrete_list_pos := p.tok.position()
|
||||
if p.tok.kind == .lt {
|
||||
// `foo<int>(10)`
|
||||
p.expr_mod = ''
|
||||
generic_types = p.parse_generic_type_list()
|
||||
generic_list_pos = generic_list_pos.extend(p.prev_tok.position())
|
||||
concrete_types = p.parse_generic_type_list()
|
||||
concrete_list_pos = concrete_list_pos.extend(p.prev_tok.position())
|
||||
// In case of `foo<T>()`
|
||||
// T is unwrapped and registered in the checker.
|
||||
full_generic_fn_name := if fn_name.contains('.') { fn_name } else { p.prepend_mod(fn_name) }
|
||||
has_generic_generic := generic_types.filter(it.has_flag(.generic)).len > 0
|
||||
has_generic_generic := concrete_types.filter(it.has_flag(.generic)).len > 0
|
||||
if !has_generic_generic {
|
||||
// will be added in checker
|
||||
p.table.register_fn_generic_types(full_generic_fn_name, generic_types)
|
||||
p.table.register_fn_generic_types(full_generic_fn_name, concrete_types)
|
||||
}
|
||||
}
|
||||
p.check(.lpar)
|
||||
|
@ -95,8 +95,8 @@ pub fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr
|
|||
mod: p.mod
|
||||
pos: pos
|
||||
language: language
|
||||
generic_types: generic_types
|
||||
generic_list_pos: generic_list_pos
|
||||
concrete_types: concrete_types
|
||||
concrete_list_pos: concrete_list_pos
|
||||
or_block: ast.OrExpr{
|
||||
stmts: or_stmts
|
||||
kind: or_kind
|
||||
|
|
|
@ -2229,18 +2229,18 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
|||
}
|
||||
// Method call
|
||||
// TODO move to fn.v call_expr()
|
||||
mut generic_types := []ast.Type{}
|
||||
mut generic_list_pos := p.tok.position()
|
||||
mut concrete_types := []ast.Type{}
|
||||
mut concrete_list_pos := p.tok.position()
|
||||
if is_generic_call {
|
||||
// `g.foo<int>(10)`
|
||||
generic_types = p.parse_generic_type_list()
|
||||
generic_list_pos = generic_list_pos.extend(p.prev_tok.position())
|
||||
concrete_types = p.parse_generic_type_list()
|
||||
concrete_list_pos = concrete_list_pos.extend(p.prev_tok.position())
|
||||
// In case of `foo<T>()`
|
||||
// T is unwrapped and registered in the checker.
|
||||
has_generic_generic := generic_types.filter(it.has_flag(.generic)).len > 0
|
||||
has_generic_generic := concrete_types.filter(it.has_flag(.generic)).len > 0
|
||||
if !has_generic_generic {
|
||||
// will be added in checker
|
||||
p.table.register_fn_generic_types(field_name, generic_types)
|
||||
p.table.register_fn_generic_types(field_name, concrete_types)
|
||||
}
|
||||
}
|
||||
if p.tok.kind == .lpar {
|
||||
|
@ -2280,8 +2280,8 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
|||
name_pos: name_pos
|
||||
pos: pos
|
||||
is_method: true
|
||||
generic_types: generic_types
|
||||
generic_list_pos: generic_list_pos
|
||||
concrete_types: concrete_types
|
||||
concrete_list_pos: concrete_list_pos
|
||||
or_block: ast.OrExpr{
|
||||
stmts: or_stmts
|
||||
kind: or_kind
|
||||
|
|
Loading…
Reference in New Issue