From 1250ce435337d7544bd0152d3be8b56f939d4e50 Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 15 Apr 2021 07:44:11 +0800 Subject: [PATCH] cgen: fix generics with embed generics (fix #8694) (#9724) --- vlib/v/checker/checker.v | 24 ++++++++++--- vlib/v/gen/c/cgen.v | 2 +- vlib/v/gen/c/fn.v | 2 +- vlib/v/parser/containers.v | 6 +++- vlib/v/parser/parse_type.v | 22 ++++++++++++ .../tests/generics_with_embed_generics_test.v | 36 +++++++++++++++++++ 6 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 vlib/v/tests/generics_with_embed_generics_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 08491987ba..abf4ca9e3a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3353,10 +3353,18 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type { } if array_init.is_fixed { idx := c.table.find_or_register_array_fixed(elem_type, array_init.exprs.len) - array_init.typ = ast.new_type(idx) + if elem_type.has_flag(.generic) { + array_init.typ = ast.new_type(idx).set_flag(.generic) + } else { + array_init.typ = ast.new_type(idx) + } } else { idx := c.table.find_or_register_array(elem_type) - array_init.typ = ast.new_type(idx) + if elem_type.has_flag(.generic) { + array_init.typ = ast.new_type(idx).set_flag(.generic) + } else { + array_init.typ = ast.new_type(idx) + } } array_init.elem_type = elem_type } else if array_init.is_fixed && array_init.exprs.len == 1 @@ -3391,8 +3399,11 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type { c.error('fixed size cannot be zero or negative', init_expr.position()) } idx := c.table.find_or_register_array_fixed(array_init.elem_type, fixed_size) - array_type := ast.new_type(idx) - array_init.typ = array_type + if array_init.elem_type.has_flag(.generic) { + array_init.typ = ast.new_type(idx).set_flag(.generic) + } else { + array_init.typ = ast.new_type(idx) + } if array_init.has_default { c.expr(array_init.default_expr) } @@ -6047,10 +6058,13 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type { c.check_dup_keys(node, i) } } - map_type := ast.new_type(c.table.find_or_register_map(key0_type, val0_type)) + mut map_type := ast.new_type(c.table.find_or_register_map(key0_type, val0_type)) node.typ = map_type node.key_type = key0_type node.value_type = val0_type + if node.key_type.has_flag(.generic) || node.value_type.has_flag(.generic) { + map_type = map_type.set_flag(.generic) + } return map_type } return node.typ diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 1f562ebc37..32189fff1f 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3633,7 +3633,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { // arr << val tmp := g.new_tmp_var() info := left_final_sym.info as ast.Array - if right_final_sym.kind == .array && info.elem_type != node.right_type { + if right_final_sym.kind == .array && info.elem_type != g.unwrap_generic(node.right_type) { // push an array => PUSH_MANY, but not if pushing an array to 2d array (`[][]int << []int`) g.write('_PUSH_MANY(') mut expected_push_many_atype := left_type diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 4677fc0902..a8964514ab 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -605,7 +605,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } // TODO performance, detect `array` method differently if left_sym.kind == .array - && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice'] { + && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'pop', 'clone', 'reverse', 'slice', 'pointers'] { // && rec_sym.name == 'array' { // && rec_sym.name == 'array' && receiver_name.starts_with('array') { // `array_byte_clone` => `array_clone` diff --git a/vlib/v/parser/containers.v b/vlib/v/parser/containers.v index 93dc818c48..870c7d115b 100644 --- a/vlib/v/parser/containers.v +++ b/vlib/v/parser/containers.v @@ -33,7 +33,11 @@ fn (mut p Parser) array_init() ast.ArrayInit { // this is set here because it's a known type, others could be the // result of expr so we do those in checker idx := p.table.find_or_register_array(elem_type) - array_type = ast.new_type(idx) + if elem_type.has_flag(.generic) { + array_type = ast.new_type(idx).set_flag(.generic) + } else { + array_type = ast.new_type(idx) + } has_type = true } last_pos = p.tok.position() diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 2c2efeb5d7..e2619f7dcb 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -43,6 +43,9 @@ pub fn (mut p Parser) parse_array_type() ast.Type { } // sym := p.table.get_type_symbol(elem_type) idx := p.table.find_or_register_array_fixed(elem_type, fixed_size) + if elem_type.has_flag(.generic) { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } // array @@ -61,6 +64,9 @@ pub fn (mut p Parser) parse_array_type() ast.Type { nr_dims++ } idx := p.table.find_or_register_array_with_dims(elem_type, nr_dims) + if elem_type.has_flag(.generic) { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } @@ -101,6 +107,9 @@ pub fn (mut p Parser) parse_map_type() ast.Type { return 0 } idx := p.table.find_or_register_map(key_type, value_type) + if key_type.has_flag(.generic) || value_type.has_flag(.generic) { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } @@ -115,6 +124,9 @@ pub fn (mut p Parser) parse_chan_type() ast.Type { is_mut := p.tok.kind == .key_mut elem_type := p.parse_type() idx := p.table.find_or_register_chan(elem_type, is_mut) + if elem_type.has_flag(.generic) { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } @@ -140,17 +152,24 @@ pub fn (mut p Parser) parse_thread_type() ast.Type { } ret_type := p.parse_type() idx := p.table.find_or_register_thread(ret_type) + if ret_type.has_flag(.generic) { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } pub fn (mut p Parser) parse_multi_return_type() ast.Type { p.check(.lpar) mut mr_types := []ast.Type{} + mut has_generic := false for p.tok.kind != .eof { mr_type := p.parse_type() if mr_type.idx() == 0 { break } + if mr_type.has_flag(.generic) { + has_generic = true + } mr_types << mr_type if p.tok.kind == .comma { p.next() @@ -164,6 +183,9 @@ pub fn (mut p Parser) parse_multi_return_type() ast.Type { return mr_types[0] } idx := p.table.find_or_register_multi_return(mr_types) + if has_generic { + return ast.new_type(idx).set_flag(.generic) + } return ast.new_type(idx) } diff --git a/vlib/v/tests/generics_with_embed_generics_test.v b/vlib/v/tests/generics_with_embed_generics_test.v new file mode 100644 index 0000000000..2ddbed730e --- /dev/null +++ b/vlib/v/tests/generics_with_embed_generics_test.v @@ -0,0 +1,36 @@ +struct Group { + len int + val []T +mut: + index int +} + +fn group_new(val ...T) Group { + mut arr := []T{cap: val.len} + for i in val { + arr << i + } + mut g := Group{ + len: val.len + val: arr + } + + return g +} + +fn (mut it Group) next() ?T { + if it.index >= it.len { + return none + } + v := it.val[it.index] + it.index++ + return v +} + +fn test_generics_with_embed_generics() { + gx := group_new(1, 2, 3) + for x in gx.val { + println(x) + } + assert gx.val == [1, 2, 3] +}