From 8ccdae618898b76c6545ee6eafbd152d0d2e89a9 Mon Sep 17 00:00:00 2001 From: yuyi Date: Sat, 24 Apr 2021 14:44:15 +0800 Subject: [PATCH] all: cleanup generics call_expr (#9856) --- vlib/v/ast/ast.v | 4 +- vlib/v/checker/check_types.v | 6 +-- vlib/v/checker/checker.v | 101 ++++++++++++++++++----------------- vlib/v/fmt/fmt.v | 8 +-- vlib/v/gen/c/cgen.v | 10 ++-- vlib/v/gen/c/fn.v | 32 +++++------ vlib/v/parser/fn.v | 20 +++---- vlib/v/parser/parser.v | 16 +++--- 8 files changed, 99 insertions(+), 98 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 801484919b..018cda88ba 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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. + 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 diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index eb7aca18f8..078c667d35 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -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) } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index e25e71d325..ffc6fb6148 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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() instead of x.foo() - 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() instead of x.foo() + 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() instead of foo() - 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() instead of foo() + 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()', 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 diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index b13e1ce28d..6f46bdb04d 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -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(', ') } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 2d9cc57d17..d3badbda31 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -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()` + cur_concrete_types []ast.Type // current concrete types, e.g. 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 and get_string // `foo()` => `foo_T_int()` if i == 0 { name += '_T' } - name += '_' + g.typ(generic_type) + name += '_' + g.typ(concrete_type) } } if expr.is_method { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 2479eb36d6..0bade0c423 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -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() => foo_T_int(), foo_T_string() etc // Using _T_ to differentiate between get 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 and get_string // `foo()` => `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 and get_string // `foo()` => `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 } } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 6e165fb91d..0f3ab8311a 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -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(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 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 diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 81c43bdb0b..c8116050d8 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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(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 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