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