From fb9b2e873cae8d3458e068ca2b33d1c9b4cfd5db Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 8 Jul 2021 21:50:25 +0800 Subject: [PATCH] checker: fix generic fn with assign reference generic struct (fix #10681) (#10695) --- vlib/v/checker/checker.v | 15 ++++++ vlib/v/gen/c/cgen.v | 21 ++++++++- ...ics_assign_reference_generic_struct_test.v | 46 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/generics_assign_reference_generic_struct_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b0a8bc446e..f1582fcdf0 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3390,6 +3390,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { c.expected_type = ast.void_type } right_first := node.right[0] + node.left_types = [] mut right_len := node.right.len mut right_type0 := ast.void_type for i, right in node.right { @@ -3477,6 +3478,16 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } right := if i < node.right.len { node.right[i] } else { node.right[0] } mut right_type := node.right_types[i] + if right is ast.Ident { + right_sym := c.table.get_type_symbol(right_type) + if right_sym.info is ast.Struct { + if right_sym.info.generic_types.len > 0 { + if obj := right.scope.find(right.name) { + right_type = obj.typ + } + } + } + } if is_decl { // check generic struct init and return unwrap generic struct type if right is ast.StructInit { @@ -3484,6 +3495,10 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { c.expr(right) right_type = right.typ } + } else if right is ast.PrefixExpr { + if right.op == .amp && right.right is ast.StructInit { + right_type = c.expr(right) + } } if right.is_auto_deref_var() { left_type = c.table.mktyp(right_type.deref()) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 463344965a..1d6352f476 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2620,8 +2620,27 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { if is_inside_ternary { g.out.write_string(util.tabs(g.indent - g.inside_ternary)) } + mut is_used_var_styp := false if ident.name !in g.defer_vars { - g.write('$styp ') + val_sym := g.table.get_type_symbol(val_type) + if val_sym.info is ast.Struct { + if val_sym.info.generic_types.len > 0 { + if val is ast.StructInit { + var_styp := g.typ(val.typ) + g.write('$var_styp ') + is_used_var_styp = true + } else if val is ast.PrefixExpr { + if val.op == .amp && val.right is ast.StructInit { + var_styp := g.typ(val.right.typ.to_ptr()) + g.write('$var_styp ') + is_used_var_styp = true + } + } + } + } + if !is_used_var_styp { + g.write('$styp ') + } if is_auto_heap { g.write('*') } diff --git a/vlib/v/tests/generics_assign_reference_generic_struct_test.v b/vlib/v/tests/generics_assign_reference_generic_struct_test.v new file mode 100644 index 0000000000..74b2c9a338 --- /dev/null +++ b/vlib/v/tests/generics_assign_reference_generic_struct_test.v @@ -0,0 +1,46 @@ +pub struct List { +pub mut: + head &ListNode = 0 +} + +pub struct ListNode { +pub mut: + value T + next &ListNode = 0 +} + +pub fn list_new() List { + return List{} +} + +pub fn (mut l List) add(value T) { + mut node := &ListNode{value, 0} + if l.head == 0 { + l.head = node + } else { + node.next = l.head + l.head = node + } +} + +fn test_generic_assign_reference_generic_struct() { + mut list1 := list_new() + list1.add('hello') + println(list1.head.value) + assert list1.head.value == 'hello' + + mut list2 := list_new() + list2.add(100) + println(list2.head.value) + assert list2.head.value == 100 + + mut list3 := list_new() + list3.add(22.2) + println(list3.head.value) + assert list3.head.value == 22.2 + + mut list4 := list_new() + list4.add(true) + println(list4.head.value) + assert list4.head.value == true +}