cgen: fix generics with multi generics struct receiver (#9853)

pull/9855/head
yuyi 2021-04-23 20:17:57 +08:00 committed by GitHub
parent 49a2de562b
commit dd2002cc57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 40 additions and 8 deletions

View File

@ -1075,7 +1075,7 @@ pub fn (mut t Table) generic_struct_insts_to_concrete() {
fields[i].typ = t_typ
}
}
parent_info.generic_types = []
parent_info.is_generic = false
parent_info.concrete_types = info.concrete_types.clone()
parent_info.fields = fields
parent_info.parent_type = new_type(info.parent_idx).set_flag(.generic)

View File

@ -722,6 +722,7 @@ pub mut:
is_typedef bool // C. [typedef]
is_union bool
is_heap bool
is_generic bool
generic_types []Type
concrete_types []Type
parent_type Type

View File

@ -486,13 +486,15 @@ pub fn (mut c Checker) infer_fn_generic_types(f ast.Fn, mut call_expr ast.CallEx
mut typ := ast.void_type
for i, param in f.params {
mut to_set := ast.void_type
// resolve generic struct receiver (TODO: multi generic struct)
// resolve generic struct receiver
if i == 0 && call_expr.is_method && param.typ.has_flag(.generic) {
sym := c.table.get_type_symbol(call_expr.receiver_type)
if sym.kind == .struct_ {
info := sym.info as ast.Struct
if info.concrete_types.len > 0 {
typ = info.concrete_types[0]
receiver_generic_names := info.generic_types.map(c.table.get_type_symbol(it).name)
if gt_name in receiver_generic_names {
idx := receiver_generic_names.index(gt_name)
typ = info.concrete_types[idx]
}
}
}

View File

@ -1433,7 +1433,7 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, call_exp
fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_expr ast.CallExpr, generic_types []ast.Type) {
rts := c.table.get_type_symbol(return_type)
if rts.info is ast.Struct {
if rts.info.generic_types.len > 0 {
if rts.info.is_generic {
mut nrt := '$rts.name<'
mut c_nrt := '${rts.name}_T_'
for i in 0 .. call_expr.generic_types.len {
@ -1462,7 +1462,7 @@ fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_e
}
}
mut info := rts.info
info.generic_types = []
info.is_generic = false
info.concrete_types = generic_types.clone()
info.parent_type = return_type
info.fields = fields

View File

@ -693,7 +693,7 @@ fn (mut g Gen) cc_type(typ ast.Type, is_prefix_struct bool) string {
mut styp := sym.cname
// TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker)
if mut sym.info is ast.Struct {
if sym.info.generic_types.len > 0 {
if sym.info.is_generic {
mut sgtyps := '_T'
for gt in sym.info.generic_types {
gts := g.table.get_type_symbol(g.unwrap_generic(gt))
@ -5438,7 +5438,7 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
mut name := typ.cname
match mut typ.info {
ast.Struct {
if typ.info.generic_types.len > 0 {
if typ.info.is_generic {
continue
}
if name.contains('_T_') {

View File

@ -299,6 +299,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
is_typedef: attrs.contains('typedef')
is_union: is_union
is_heap: attrs.contains('heap')
is_generic: generic_types.len > 0
generic_types: generic_types
attrs: attrs
}

View File

@ -0,0 +1,28 @@
struct Foo<A, B> {
a A
b B
}
fn (num Foo<A, B>) get_foo1<A, B>() (A, B) {
return num.a, num.b
}
fn (num Foo<A, B>) get_foo2<B, A>() (A, B) {
return num.a, num.b
}
fn test_generics_with_multi_generics_struct_receiver() {
num := Foo<int,string>{
a: 3
b: 'aaa'
}
a1, b1 := num.get_foo1()
println('$a1, $b1')
assert a1 == 3
assert b1 == 'aaa'
a2, b2 := num.get_foo2()
println('$a2, $b2')
assert a2 == 3
assert b2 == 'aaa'
}