table,checker,cgen: fix generics with recursive generics struct (#9862)
parent
21d1f86ead
commit
3877522ee3
|
@ -993,7 +993,7 @@ pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
|
|||
// resolve_generic_to_concrete resolves generics to real types T => int.
|
||||
// Even map[string]map[string]T can be resolved.
|
||||
// This is used for resolving the generic return type of CallExpr white `unwrap_generic` is used to resolve generic usage in FnDecl.
|
||||
pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_names []string, concrete_types []Type) ?Type {
|
||||
pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_names []string, concrete_types []Type, is_inst bool) ?Type {
|
||||
mut sym := t.get_type_symbol(generic_type)
|
||||
if sym.name in generic_names {
|
||||
index := generic_names.index(sym.name)
|
||||
|
@ -1009,13 +1009,17 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
|||
elem_sym = t.get_type_symbol(elem_type)
|
||||
dims++
|
||||
}
|
||||
if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) {
|
||||
if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types,
|
||||
is_inst)
|
||||
{
|
||||
idx := t.find_or_register_array_with_dims(typ, dims)
|
||||
return new_type(idx).derive(generic_type).clear_flag(.generic)
|
||||
}
|
||||
} else if sym.kind == .chan {
|
||||
info := sym.info as Chan
|
||||
if typ := t.resolve_generic_to_concrete(info.elem_type, generic_names, concrete_types) {
|
||||
if typ := t.resolve_generic_to_concrete(info.elem_type, generic_names, concrete_types,
|
||||
is_inst)
|
||||
{
|
||||
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
|
||||
return new_type(idx).derive(generic_type).clear_flag(.generic)
|
||||
}
|
||||
|
@ -1023,7 +1027,9 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
|||
mut types := []Type{}
|
||||
mut type_changed := false
|
||||
for ret_type in sym.info.types {
|
||||
if typ := t.resolve_generic_to_concrete(ret_type, generic_names, concrete_types) {
|
||||
if typ := t.resolve_generic_to_concrete(ret_type, generic_names, concrete_types,
|
||||
is_inst)
|
||||
{
|
||||
types << typ
|
||||
type_changed = true
|
||||
} else {
|
||||
|
@ -1038,11 +1044,15 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
|||
mut type_changed := false
|
||||
mut unwrapped_key_type := sym.info.key_type
|
||||
mut unwrapped_value_type := sym.info.value_type
|
||||
if typ := t.resolve_generic_to_concrete(sym.info.key_type, generic_names, concrete_types) {
|
||||
if typ := t.resolve_generic_to_concrete(sym.info.key_type, generic_names, concrete_types,
|
||||
is_inst)
|
||||
{
|
||||
unwrapped_key_type = typ
|
||||
type_changed = true
|
||||
}
|
||||
if typ := t.resolve_generic_to_concrete(sym.info.value_type, generic_names, concrete_types) {
|
||||
if typ := t.resolve_generic_to_concrete(sym.info.value_type, generic_names, concrete_types,
|
||||
is_inst)
|
||||
{
|
||||
unwrapped_value_type = typ
|
||||
type_changed = true
|
||||
}
|
||||
|
@ -1050,6 +1060,23 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
|||
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
||||
return new_type(idx).derive(generic_type).clear_flag(.generic)
|
||||
}
|
||||
} else if mut sym.info is Struct {
|
||||
if sym.info.is_generic && is_inst {
|
||||
mut nrt := '$sym.name<'
|
||||
for i in 0 .. concrete_types.len {
|
||||
gts := t.get_type_symbol(concrete_types[i])
|
||||
nrt += gts.name
|
||||
if i != concrete_types.len - 1 {
|
||||
nrt += ','
|
||||
}
|
||||
}
|
||||
nrt += '>'
|
||||
mut idx := t.type_idxs[nrt]
|
||||
if idx == 0 {
|
||||
idx = t.add_placeholder_type(nrt, .v)
|
||||
}
|
||||
return new_type(idx).derive(generic_type).clear_flag(.generic)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
@ -1070,7 +1097,7 @@ pub fn (mut t Table) generic_struct_insts_to_concrete() {
|
|||
generic_names := parent_info.generic_types.map(t.get_type_symbol(it).name)
|
||||
for i in 0 .. fields.len {
|
||||
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names,
|
||||
info.concrete_types)
|
||||
info.concrete_types, true)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
|
|
|
@ -1464,7 +1464,7 @@ fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_e
|
|||
generic_names := rts.info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
for i, _ in fields {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, concrete_types)
|
||||
generic_names, concrete_types, false)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
|
@ -1764,7 +1764,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
}
|
||||
if call_expr.concrete_types.len > 0 && method.return_type != 0 {
|
||||
if typ := c.table.resolve_generic_to_concrete(method.return_type, method.generic_names,
|
||||
call_expr.concrete_types)
|
||||
call_expr.concrete_types, false)
|
||||
{
|
||||
call_expr.return_type = typ
|
||||
return typ
|
||||
|
@ -2280,7 +2280,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
if param.typ.has_flag(.generic)
|
||||
&& func.generic_names.len == call_expr.concrete_types.len {
|
||||
if unwrap_typ := c.table.resolve_generic_to_concrete(param.typ, func.generic_names,
|
||||
call_expr.concrete_types)
|
||||
call_expr.concrete_types, false)
|
||||
{
|
||||
c.check_expected_call_arg(typ, unwrap_typ, call_expr.language) or {
|
||||
c.error('$err.msg in argument ${i + 1} to `$fn_name`', call_arg.pos)
|
||||
|
@ -2297,7 +2297,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
}
|
||||
if call_expr.concrete_types.len > 0 && func.return_type != 0 {
|
||||
if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
|
||||
call_expr.concrete_types)
|
||||
call_expr.concrete_types, false)
|
||||
{
|
||||
call_expr.return_type = typ
|
||||
return typ
|
||||
|
@ -4158,7 +4158,9 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
|
|||
|
||||
pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
|
||||
if typ.has_flag(.generic) {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(typ, c.cur_fn.generic_names, c.cur_fn.cur_generic_types) {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(typ, c.cur_fn.generic_names, c.cur_fn.cur_generic_types,
|
||||
false)
|
||||
{
|
||||
return t_typ
|
||||
}
|
||||
}
|
||||
|
|
|
@ -479,7 +479,9 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||
|
||||
pub fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
|
||||
if typ.has_flag(.generic) {
|
||||
if t_typ := g.table.resolve_generic_to_concrete(typ, g.cur_fn.generic_names, g.cur_concrete_types) {
|
||||
if t_typ := g.table.resolve_generic_to_concrete(typ, g.cur_fn.generic_names, g.cur_concrete_types,
|
||||
false)
|
||||
{
|
||||
return t_typ
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
pub struct Node<T> {
|
||||
value T
|
||||
points_to []&Node<T>
|
||||
}
|
||||
|
||||
fn test_generics_with_recursive_generics_struct() {
|
||||
mid := &Node<string>{
|
||||
value: 'Middle'
|
||||
}
|
||||
finish := &Node<string>{
|
||||
value: 'Finish'
|
||||
}
|
||||
|
||||
graph := &Node<string>{
|
||||
value: 'Start'
|
||||
points_to: [
|
||||
&Node<string>{
|
||||
value: 'TopLeft'
|
||||
points_to: [
|
||||
finish,
|
||||
mid,
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
println(graph.points_to[0].value)
|
||||
assert graph.points_to[0].value == 'TopLeft'
|
||||
}
|
Loading…
Reference in New Issue