cgen: fix generics with multi generics struct receiver (#9853)
parent
49a2de562b
commit
dd2002cc57
|
@ -1075,7 +1075,7 @@ pub fn (mut t Table) generic_struct_insts_to_concrete() {
|
||||||
fields[i].typ = t_typ
|
fields[i].typ = t_typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parent_info.generic_types = []
|
parent_info.is_generic = false
|
||||||
parent_info.concrete_types = info.concrete_types.clone()
|
parent_info.concrete_types = info.concrete_types.clone()
|
||||||
parent_info.fields = fields
|
parent_info.fields = fields
|
||||||
parent_info.parent_type = new_type(info.parent_idx).set_flag(.generic)
|
parent_info.parent_type = new_type(info.parent_idx).set_flag(.generic)
|
||||||
|
|
|
@ -722,6 +722,7 @@ pub mut:
|
||||||
is_typedef bool // C. [typedef]
|
is_typedef bool // C. [typedef]
|
||||||
is_union bool
|
is_union bool
|
||||||
is_heap bool
|
is_heap bool
|
||||||
|
is_generic bool
|
||||||
generic_types []Type
|
generic_types []Type
|
||||||
concrete_types []Type
|
concrete_types []Type
|
||||||
parent_type Type
|
parent_type Type
|
||||||
|
|
|
@ -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
|
mut typ := ast.void_type
|
||||||
for i, param in f.params {
|
for i, param in f.params {
|
||||||
mut to_set := ast.void_type
|
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) {
|
if i == 0 && call_expr.is_method && param.typ.has_flag(.generic) {
|
||||||
sym := c.table.get_type_symbol(call_expr.receiver_type)
|
sym := c.table.get_type_symbol(call_expr.receiver_type)
|
||||||
if sym.kind == .struct_ {
|
if sym.kind == .struct_ {
|
||||||
info := sym.info as ast.Struct
|
info := sym.info as ast.Struct
|
||||||
if info.concrete_types.len > 0 {
|
receiver_generic_names := info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||||
typ = info.concrete_types[0]
|
if gt_name in receiver_generic_names {
|
||||||
|
idx := receiver_generic_names.index(gt_name)
|
||||||
|
typ = info.concrete_types[idx]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
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)
|
rts := c.table.get_type_symbol(return_type)
|
||||||
if rts.info is ast.Struct {
|
if rts.info is ast.Struct {
|
||||||
if rts.info.generic_types.len > 0 {
|
if rts.info.is_generic {
|
||||||
mut nrt := '$rts.name<'
|
mut nrt := '$rts.name<'
|
||||||
mut c_nrt := '${rts.name}_T_'
|
mut c_nrt := '${rts.name}_T_'
|
||||||
for i in 0 .. call_expr.generic_types.len {
|
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
|
mut info := rts.info
|
||||||
info.generic_types = []
|
info.is_generic = false
|
||||||
info.concrete_types = generic_types.clone()
|
info.concrete_types = generic_types.clone()
|
||||||
info.parent_type = return_type
|
info.parent_type = return_type
|
||||||
info.fields = fields
|
info.fields = fields
|
||||||
|
|
|
@ -693,7 +693,7 @@ fn (mut g Gen) cc_type(typ ast.Type, is_prefix_struct bool) string {
|
||||||
mut styp := sym.cname
|
mut styp := sym.cname
|
||||||
// TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker)
|
// TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker)
|
||||||
if mut sym.info is ast.Struct {
|
if mut sym.info is ast.Struct {
|
||||||
if sym.info.generic_types.len > 0 {
|
if sym.info.is_generic {
|
||||||
mut sgtyps := '_T'
|
mut sgtyps := '_T'
|
||||||
for gt in sym.info.generic_types {
|
for gt in sym.info.generic_types {
|
||||||
gts := g.table.get_type_symbol(g.unwrap_generic(gt))
|
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
|
mut name := typ.cname
|
||||||
match mut typ.info {
|
match mut typ.info {
|
||||||
ast.Struct {
|
ast.Struct {
|
||||||
if typ.info.generic_types.len > 0 {
|
if typ.info.is_generic {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if name.contains('_T_') {
|
if name.contains('_T_') {
|
||||||
|
|
|
@ -299,6 +299,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
is_typedef: attrs.contains('typedef')
|
is_typedef: attrs.contains('typedef')
|
||||||
is_union: is_union
|
is_union: is_union
|
||||||
is_heap: attrs.contains('heap')
|
is_heap: attrs.contains('heap')
|
||||||
|
is_generic: generic_types.len > 0
|
||||||
generic_types: generic_types
|
generic_types: generic_types
|
||||||
attrs: attrs
|
attrs: attrs
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
||||||
|
}
|
Loading…
Reference in New Issue