diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 391437dd88..ba92da4fc7 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1133,7 +1133,7 @@ fn (mut table Table) does_type_implement_interface(typ Type, inter_typ Type) boo // 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_to_concrete(generic_type Type, generic_names []string, concrete_types []Type, is_inst bool) ?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) @@ -1151,24 +1151,18 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name elem_sym = t.get_type_symbol(elem_type) dims++ } - if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types, - is_inst) - { + 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 == .array_fixed { info := sym.info as ArrayFixed - if typ := t.resolve_generic_to_concrete(info.elem_type, generic_names, concrete_types, - is_inst) - { + if typ := t.resolve_generic_to_concrete(info.elem_type, generic_names, concrete_types) { idx := t.find_or_register_array_fixed(typ, info.size, None{}) return new_type(idx).derive(generic_type).clear_flag(.generic) } } else if mut sym.info is Chan { - if typ := t.resolve_generic_to_concrete(sym.info.elem_type, generic_names, concrete_types, - is_inst) - { + if typ := t.resolve_generic_to_concrete(sym.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) } @@ -1176,9 +1170,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name mut types := []Type{} mut type_changed := false for ret_type in sym.info.types { - if typ := t.resolve_generic_to_concrete(ret_type, generic_names, concrete_types, - is_inst) - { + if typ := t.resolve_generic_to_concrete(ret_type, generic_names, concrete_types) { types << typ type_changed = true } else { @@ -1193,15 +1185,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name 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_to_concrete(sym.info.key_type, generic_names, concrete_types, - is_inst) - { + 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_to_concrete(sym.info.value_type, generic_names, concrete_types, - is_inst) - { + if typ := t.resolve_generic_to_concrete(sym.info.value_type, generic_names, concrete_types) { unwrapped_value_type = typ type_changed = true } @@ -1210,11 +1198,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name return new_type(idx).derive(generic_type).clear_flag(.generic) } } else if mut sym.info is Struct { - if sym.info.is_generic && is_inst { + if sym.info.is_generic { mut nrt := '$sym.name<' for i in 0 .. sym.info.generic_types.len { if ct := t.resolve_generic_to_concrete(sym.info.generic_types[i], generic_names, - concrete_types, false) + concrete_types) { gts := t.get_type_symbol(ct) nrt += gts.name @@ -1233,18 +1221,14 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } else if mut sym.info is FnType { mut func := sym.info.func if func.return_type.has_flag(.generic) { - if typ := t.resolve_generic_to_concrete(func.return_type, generic_names, concrete_types, - is_inst) - { + if typ := t.resolve_generic_to_concrete(func.return_type, generic_names, concrete_types) { func.return_type = typ } } func.params = func.params.clone() for mut param in func.params { if param.typ.has_flag(.generic) { - if typ := t.resolve_generic_to_concrete(param.typ, generic_names, concrete_types, - is_inst) - { + if typ := t.resolve_generic_to_concrete(param.typ, generic_names, concrete_types) { param.typ = typ } } @@ -1271,7 +1255,7 @@ pub fn (mut t Table) generic_struct_insts_to_concrete() { 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_to_concrete(fields[i].typ, generic_names, - info.concrete_types, true) + info.concrete_types) { fields[i].typ = t_typ } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index f651eced8f..54395f100f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -637,7 +637,7 @@ fn (mut c Checker) unwrap_generic_struct(struct_type ast.Type, generic_names []s mut c_nrt := '${ts.cname}_T_' for i in 0 .. ts.info.generic_types.len { if ct := c.table.resolve_generic_to_concrete(ts.info.generic_types[i], - generic_names, concrete_types, false) + generic_names, concrete_types) { gts := c.table.get_type_symbol(ct) nrt += gts.name @@ -657,7 +657,7 @@ fn (mut c Checker) unwrap_generic_struct(struct_type ast.Type, generic_names []s mut fields := ts.info.fields.clone() for i in 0 .. fields.len { if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ, generic_names, - concrete_types, true) + concrete_types) { fields[i].typ = t_typ } @@ -666,7 +666,7 @@ fn (mut c Checker) unwrap_generic_struct(struct_type ast.Type, generic_names []s mut info_concrete_types := []ast.Type{} for i in 0 .. ts.info.generic_types.len { if t_typ := c.table.resolve_generic_to_concrete(ts.info.generic_types[i], - generic_names, concrete_types, true) + generic_names, concrete_types) { info_concrete_types << t_typ } @@ -2057,7 +2057,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type { } 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, - concrete_types, false) + concrete_types) { call_expr.return_type = typ return typ @@ -2613,7 +2613,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { 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, - concrete_types, false) + concrete_types) { c.check_expected_call_arg(c.unwrap_generic(typ), unwrap_typ, call_expr.language) or { c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos) @@ -2631,7 +2631,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type { } 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, - concrete_types, false) + concrete_types) { call_expr.return_type = typ return typ @@ -3033,13 +3033,6 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { pub fn (mut c Checker) return_stmt(mut node ast.Return) { c.expected_type = c.table.cur_fn.return_type mut expected_type := c.unwrap_generic(c.expected_type) - if expected_type.has_flag(.generic) && c.table.get_type_symbol(expected_type).kind == .struct_ { - if t_typ := c.table.resolve_generic_to_concrete(expected_type, c.table.cur_fn.generic_names, - c.table.cur_concrete_types, true) - { - expected_type = t_typ - } - } expected_type_sym := c.table.get_type_symbol(expected_type) if node.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type { c.error('unexpected argument, current function does not return anything', node.exprs[0].position()) @@ -4669,7 +4662,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_to_concrete(typ, c.table.cur_fn.generic_names, - c.table.cur_concrete_types, false) + c.table.cur_concrete_types) { return t_typ } diff --git a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out index d2c1933c8b..9ef31efbc2 100644 --- a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out +++ b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out @@ -5,6 +5,20 @@ vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:26:1: error: g | ~~~~~~~~~~~~~~~~~~~~~~~~~ 27 | t := <-g.ch 28 | handle(t) +vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:27:7: error: <- operator can only be used with `chan` types + 25 | + 26 | fn g_worker(g Generic) { + 27 | t := <-g.ch + | ~~ + 28 | handle(t) + 29 | // println("${t.msg}") +vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:28:9: error: cannot use `void` as `T` in argument 1 to `handle` + 26 | fn g_worker(g Generic) { + 27 | t := <-g.ch + 28 | handle(t) + | ^ + 29 | // println("${t.msg}") + 30 | } vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:32:1: error: generic function declaration must specify generic type names, e.g. foo 30 | } 31 | @@ -12,10 +26,3 @@ vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:32:1: error: g | ~~~~~~~~~~~~~~ 33 | println("hi") 34 | } -vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:21:14: error: cannot use `Generic` as `Generic` in argument 1 to `g_worker` - 19 | } - 20 | - 21 | go g_worker(g) - | ^ - 22 | - 23 | return g diff --git a/vlib/v/gen/c/utils.v b/vlib/v/gen/c/utils.v index 2e02a3534b..a4768c8a3f 100644 --- a/vlib/v/gen/c/utils.v +++ b/vlib/v/gen/c/utils.v @@ -8,7 +8,7 @@ import v.ast 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.table.cur_fn.generic_names, - g.table.cur_concrete_types, true) + g.table.cur_concrete_types) { return t_typ } diff --git a/vlib/v/tests/generics_return_generics_struct_test.v b/vlib/v/tests/generics_return_generics_struct_test.v index bcfee98a73..a48ae4da44 100644 --- a/vlib/v/tests/generics_return_generics_struct_test.v +++ b/vlib/v/tests/generics_return_generics_struct_test.v @@ -124,3 +124,22 @@ fn test_generics_return_generic_struct_from_fn() { println(it.next() or { -1 }) assert '$it.next()' == 'Option(1)' } + +struct ListNode { +pub mut: + val T + next &ListNode = 0 +} + +fn (mut node ListNode) test() &ListNode { + return node.next +} + +fn test_generics_return_generic_struct_field() { + mut node1 := &ListNode{100, 0} + mut node2 := &ListNode{200, 0} + node1.next = node2 + ret := node1.test() + println(ret) + assert ret.val == 200 +}