cgen: fix generics with embed generics (fix #8694) (#9724)

pull/9739/head
yuyi 2021-04-15 07:44:11 +08:00 committed by GitHub
parent f4c8f897fe
commit 1250ce4353
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 8 deletions

View File

@ -3353,11 +3353,19 @@ 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)
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)
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
&& array_init.elem_type != ast.void_type {
@ -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

View File

@ -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

View File

@ -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`

View File

@ -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)
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()

View File

@ -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)
}

View File

@ -0,0 +1,36 @@
struct Group<T> {
len int
val []T
mut:
index int
}
fn group_new<T>(val ...T) Group<T> {
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<T>) next<T>() ?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<int>(1, 2, 3)
for x in gx.val {
println(x)
}
assert gx.val == [1, 2, 3]
}