diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 6f8190536c..5151c29679 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -373,7 +373,7 @@ pub: is_builtin bool // this function is defined in builtin/strconv body_pos token.Position // function bodys position file string - generic_params []GenericParam + generic_names []string is_direct_arr bool // direct array access attrs []Attr skip_gen bool // this function doesn't need to be generated (for example [if foo]) @@ -391,11 +391,6 @@ pub mut: pos token.Position // function declaration position } -pub struct GenericParam { -pub: - name string -} - // break, continue pub struct BranchStmt { pub: diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v index 57c915417e..472732e4f4 100644 --- a/vlib/v/ast/str.v +++ b/vlib/v/ast/str.v @@ -62,11 +62,11 @@ pub fn (node &FnDecl) stringify(t &Table, cur_mod string, m2a map[string]string) if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] { f.write_string(' ') } - if node.generic_params.len > 0 { + if node.generic_names.len > 0 { f.write_string('<') - for i, param in node.generic_params { - is_last := i == node.generic_params.len - 1 - f.write_string(param.name) + for i, gname in node.generic_names { + is_last := i == node.generic_names.len - 1 + f.write_string(gname) if !is_last { f.write_string(', ') } diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 5271c0df58..9909696c76 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -360,7 +360,7 @@ pub fn (mut c Checker) symmetric_check(left ast.Type, right ast.Type) bool { return c.check_basic(left, right) } -pub fn (c &Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) byte { +pub fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) byte { if ftyp.has_flag(.optional) { return `s` } else if typ.is_float() { @@ -521,7 +521,7 @@ pub fn (mut c Checker) infer_fn_types(f ast.Fn, mut call_expr ast.CallExpr) { mut param_elem_sym := c.table.get_type_symbol(param_elem_info.elem_type) for { if arg_elem_sym.kind == .array && param_elem_sym.kind == .array - && c.cur_fn.generic_params.filter(it.name == param_elem_sym.name).len == 0 { + && param_elem_sym.name !in c.cur_fn.generic_names { arg_elem_info = arg_elem_sym.info as ast.Array arg_elem_sym = c.table.get_type_symbol(arg_elem_info.elem_type) param_elem_info = param_elem_sym.info as ast.Array diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 55f3ad82f5..64fe23ccab 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -514,7 +514,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { struct_init.pos) } } - if type_sym.name.len == 1 && c.cur_fn.generic_params.len == 0 { + if type_sym.name.len == 1 && c.cur_fn.generic_names.len == 0 { c.error('unknown struct `$type_sym.name`', struct_init.pos) return 0 } @@ -2495,8 +2495,7 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) ast.Typ match mut selector_expr.expr { ast.Ident { name := selector_expr.expr.name - valid_generic := util.is_generic_type_name(name) - && c.cur_fn.generic_params.filter(it.name == name).len != 0 + valid_generic := util.is_generic_type_name(name) && name in c.cur_fn.generic_names if valid_generic { name_type = ast.Type(c.table.find_type_idx(name)).set_flag(.generic) } @@ -4051,13 +4050,10 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) { c.expected_type = ast.void_type } -pub fn (c &Checker) unwrap_generic(typ ast.Type) ast.Type { +pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type { if typ.has_flag(.generic) { - sym := c.table.get_type_symbol(typ) - for i, generic_param in c.cur_fn.generic_params { - if generic_param.name == sym.name { - return c.cur_generic_types[i].derive(typ).clear_flag(.generic) - } + if t_typ := c.table.resolve_generic_by_names(typ, c.cur_fn.generic_names, c.cur_generic_types) { + return t_typ } } return typ @@ -6332,7 +6328,7 @@ fn (mut c Checker) post_process_generic_fns() { fn (mut c Checker) fn_decl(mut node ast.FnDecl) { c.returns = false - if node.generic_params.len > 0 && c.cur_generic_types.len == 0 { + if node.generic_names.len > 0 && c.cur_generic_types.len == 0 { // Just remember the generic function for now. // It will be processed later in c.post_process_generic_fns, // after all other normal functions are processed. diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a4c2412f19..13b7797e90 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -687,7 +687,7 @@ static inline Option_void __Option_${styp}_pushval($styp ch, $el_type e) { } // cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo) -fn (g &Gen) cc_type(typ ast.Type, is_prefix_struct bool) string { +fn (mut g Gen) cc_type(typ ast.Type, is_prefix_struct bool) string { sym := g.table.get_type_symbol(g.unwrap_generic(typ)) mut styp := sym.cname // TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 22d999bcff..21e67e8175 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -64,7 +64,7 @@ fn (mut g Gen) process_fn_decl(node ast.FnDecl) { // We are using prebuilt modules, we do not need to generate // their functions in main.c. if node.mod != 'main' && node.mod != 'help' && !should_bundle_module && !g.pref.is_test - && node.generic_params.len == 0 { + && node.generic_names.len == 0 { skip = true } } @@ -127,7 +127,7 @@ 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_params.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_generic_types.len == 0 { // need the cur_generic_type check to avoid inf. recursion // loop thru each generic type and generate a function for gen_types in g.table.fn_gen_types[node.name] { if g.pref.is_verbose { @@ -475,13 +475,10 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { } } -pub fn (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) { - sym := g.table.get_type_symbol(typ) - for i, generic_param in g.cur_fn.generic_params { - if generic_param.name == sym.name { - return g.cur_generic_types[i].derive(typ).clear_flag(.generic) - } + if t_typ := g.table.resolve_generic_by_names(typ, g.cur_fn.generic_names, g.cur_generic_types) { + return t_typ } } return typ diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 197a339105..1679a48452 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -274,7 +274,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } } // - generic_params := p.parse_generic_params() + generic_names := p.parse_generic_names() // Args args2, are_args_type_only, is_variadic := p.fn_args() params << args2 @@ -338,7 +338,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { params: params return_type: return_type is_variadic: is_variadic - generic_names: generic_params.map(it.name) + generic_names: generic_names is_pub: is_pub is_deprecated: is_deprecated is_unsafe: is_unsafe @@ -367,7 +367,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { params: params return_type: return_type is_variadic: is_variadic - generic_names: generic_params.map(it.name) + generic_names: generic_names is_pub: is_pub is_deprecated: is_deprecated is_unsafe: is_unsafe @@ -422,7 +422,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { name: rec.name typ: rec.typ } - generic_params: generic_params + generic_names: generic_names receiver_pos: rec.pos is_method: is_method method_type_pos: rec.type_pos @@ -517,10 +517,10 @@ fn (mut p Parser) fn_receiver(mut params []ast.Param, mut rec ReceiverParsingInf return } -fn (mut p Parser) parse_generic_params() []ast.GenericParam { +fn (mut p Parser) parse_generic_names() []string { mut param_names := []string{} if p.tok.kind != .lt { - return []ast.GenericParam{} + return param_names } p.check(.lt) mut first_done := false @@ -551,7 +551,7 @@ fn (mut p Parser) parse_generic_params() []ast.GenericParam { count++ } p.check(.gt) - return param_names.map(ast.GenericParam{it}) + return param_names } // is_generic_name returns true if the current token is a generic name.