diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 0b2103c83d..016014dfad 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -989,10 +989,10 @@ pub fn (mut t Table) bitsize_to_type(bit_size int) Type { } } -// resolve_generic_by_names resolves generics to real types T => int. +// resolve_generic_to_concrete resolves generics to real types T => int. // Even map[string]map[string]T can be resolved. // This is used for resolving the generic return type of CallExpr white `unwrap_generic` is used to resolve generic usage in FnDecl. -pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names []string, concrete_types []Type) ?Type { +pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_names []string, concrete_types []Type) ?Type { mut sym := t.get_type_symbol(generic_type) if sym.name in generic_names { index := generic_names.index(sym.name) @@ -1008,13 +1008,13 @@ pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names [ elem_sym = t.get_type_symbol(elem_type) dims++ } - if typ := t.resolve_generic_by_names(elem_type, generic_names, concrete_types) { + if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) { idx := t.find_or_register_array_with_dims(typ, dims) return new_type(idx).derive(generic_type).clear_flag(.generic) } } else if sym.kind == .chan { info := sym.info as Chan - if typ := t.resolve_generic_by_names(info.elem_type, generic_names, concrete_types) { + if typ := t.resolve_generic_to_concrete(info.elem_type, generic_names, concrete_types) { idx := t.find_or_register_chan(typ, typ.nr_muls() > 0) return new_type(idx).derive(generic_type).clear_flag(.generic) } @@ -1022,7 +1022,7 @@ pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names [ mut types := []Type{} mut type_changed := false for ret_type in sym.info.types { - if typ := t.resolve_generic_by_names(ret_type, generic_names, concrete_types) { + if typ := t.resolve_generic_to_concrete(ret_type, generic_names, concrete_types) { types << typ type_changed = true } else { @@ -1037,76 +1037,11 @@ pub fn (mut t Table) resolve_generic_by_names(generic_type Type, generic_names [ mut type_changed := false mut unwrapped_key_type := sym.info.key_type mut unwrapped_value_type := sym.info.value_type - if typ := t.resolve_generic_by_names(sym.info.key_type, generic_names, concrete_types) { + if typ := t.resolve_generic_to_concrete(sym.info.key_type, generic_names, concrete_types) { unwrapped_key_type = typ type_changed = true } - if typ := t.resolve_generic_by_names(sym.info.value_type, generic_names, concrete_types) { - unwrapped_value_type = typ - type_changed = true - } - if type_changed { - idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type) - return new_type(idx).derive(generic_type).clear_flag(.generic) - } - } - return none -} - -// resolve_generic_by_types resolves generics to real types T => int. -// Even map[string]map[string]T can be resolved. -// This is used for resolving the generic return type of CallExpr white `unwrap_generic` is used to resolve generic usage in FnDecl. -pub fn (mut t Table) resolve_generic_by_types(generic_type Type, generic_types []Type, concrete_types []Type) ?Type { - mut sym := t.get_type_symbol(generic_type) - gtype := generic_type.set_nr_muls(0) // resolve &T &&T - if gtype in generic_types { - index := generic_types.index(gtype) - typ := concrete_types[index] - return typ.derive(generic_type).clear_flag(.generic) - } else if sym.kind == .array { - info := sym.info as Array - mut elem_type := info.elem_type - mut elem_sym := t.get_type_symbol(elem_type) - mut dims := 1 - for mut elem_sym.info is Array { - elem_type = elem_sym.info.elem_type - elem_sym = t.get_type_symbol(elem_type) - dims++ - } - if typ := t.resolve_generic_by_types(elem_type, generic_types, concrete_types) { - idx := t.find_or_register_array_with_dims(typ, dims) - return new_type(idx).derive(generic_type).clear_flag(.generic) - } - } else if sym.kind == .chan { - info := sym.info as Chan - if typ := t.resolve_generic_by_types(info.elem_type, generic_types, concrete_types) { - idx := t.find_or_register_chan(typ, typ.nr_muls() > 0) - return new_type(idx).derive(generic_type).clear_flag(.generic) - } - } else if mut sym.info is MultiReturn { - mut types := []Type{} - mut type_changed := false - for ret_type in sym.info.types { - if typ := t.resolve_generic_by_types(ret_type, generic_types, concrete_types) { - types << typ - type_changed = true - } else { - types << ret_type - } - } - if type_changed { - idx := t.find_or_register_multi_return(types) - return new_type(idx).derive(generic_type).clear_flag(.generic) - } - } else if mut sym.info is Map { - mut type_changed := false - mut unwrapped_key_type := sym.info.key_type - mut unwrapped_value_type := sym.info.value_type - if typ := t.resolve_generic_by_types(sym.info.key_type, generic_types, concrete_types) { - unwrapped_key_type = typ - type_changed = true - } - if typ := t.resolve_generic_by_types(sym.info.value_type, generic_types, concrete_types) { + if typ := t.resolve_generic_to_concrete(sym.info.value_type, generic_names, concrete_types) { unwrapped_value_type = typ type_changed = true } @@ -1132,8 +1067,9 @@ pub fn (mut t Table) generic_struct_insts_to_concrete() { mut parent_info := parent.info as Struct mut fields := parent_info.fields.clone() if parent_info.generic_types.len == info.generic_types.len { + generic_names := parent_info.generic_types.map(t.get_type_symbol(it).name) for i in 0 .. fields.len { - if t_typ := t.resolve_generic_by_types(fields[i].typ, parent_info.generic_types, + if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names, info.generic_types) { fields[i].typ = t_typ diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7b7fd22dd8..f119c9c26c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1444,9 +1444,10 @@ fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_e } else { mut fields := rts.info.fields.clone() if rts.info.generic_types.len == generic_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_by_types(fields[i].typ, rts.info.generic_types, - generic_types) + if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ, + generic_names, generic_types) { fields[i].typ = t_typ } @@ -1744,7 +1745,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type { c.infer_fn_generic_types(method, mut call_expr) } if call_expr.generic_types.len > 0 && method.return_type != 0 { - if typ := c.table.resolve_generic_by_names(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.return_type = typ @@ -2264,7 +2265,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { 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 unwrap_typ := c.table.resolve_generic_by_names(param.typ, func.generic_names, + if unwrap_typ := c.table.resolve_generic_to_concrete(param.typ, func.generic_names, call_expr.generic_types) { c.check_expected_call_arg(typ, unwrap_typ, call_expr.language) or { @@ -2275,7 +2276,7 @@ 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 typ := c.table.resolve_generic_by_names(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.return_type = typ @@ -4124,7 +4125,7 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) { pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type { if typ.has_flag(.generic) { - if t_typ := c.table.resolve_generic_by_names(typ, c.cur_fn.generic_names, c.cur_fn.cur_generic_types) { + if t_typ := c.table.resolve_generic_to_concrete(typ, c.cur_fn.generic_names, c.cur_fn.cur_generic_types) { return t_typ } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index d798f95dbb..d16777786a 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -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_by_names(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_generic_types) { return t_typ } }