table, builder, checker: cleanup unwrap_generic (#12241)
parent
57c79770b3
commit
ff02c19827
|
@ -1476,3 +1476,323 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
|||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concrete_types []Type) Type {
|
||||
mut final_concrete_types := []Type{}
|
||||
mut fields := []StructField{}
|
||||
mut nrt := ''
|
||||
mut c_nrt := ''
|
||||
ts := t.get_type_symbol(typ)
|
||||
match mut ts.info {
|
||||
Array {
|
||||
mut elem_type := ts.info.elem_type
|
||||
mut elem_sym := t.get_type_symbol(elem_type)
|
||||
mut dims := 1
|
||||
for mut elem_sym.info is Array {
|
||||
info := elem_sym.info as Array
|
||||
elem_type = info.elem_type
|
||||
elem_sym = t.get_type_symbol(elem_type)
|
||||
dims++
|
||||
}
|
||||
unwrap_typ := t.unwrap_generic_type(elem_type, generic_names, concrete_types)
|
||||
idx := t.find_or_register_array_with_dims(unwrap_typ, dims)
|
||||
return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
ArrayFixed {
|
||||
unwrap_typ := t.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
|
||||
idx := t.find_or_register_array_fixed(unwrap_typ, ts.info.size, None{})
|
||||
return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
Chan {
|
||||
unwrap_typ := t.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
|
||||
idx := t.find_or_register_chan(unwrap_typ, unwrap_typ.nr_muls() > 0)
|
||||
return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
Map {
|
||||
unwrap_key_type := t.unwrap_generic_type(ts.info.key_type, generic_names,
|
||||
concrete_types)
|
||||
unwrap_value_type := t.unwrap_generic_type(ts.info.value_type, generic_names,
|
||||
concrete_types)
|
||||
idx := t.find_or_register_map(unwrap_key_type, unwrap_value_type)
|
||||
return new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
Struct, Interface, SumType {
|
||||
if !ts.info.is_generic {
|
||||
return typ
|
||||
}
|
||||
nrt = '$ts.name<'
|
||||
c_nrt = '${ts.cname}_T_'
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
gts := t.get_type_symbol(ct)
|
||||
nrt += gts.name
|
||||
c_nrt += gts.cname
|
||||
if i != ts.info.generic_types.len - 1 {
|
||||
nrt += ', '
|
||||
c_nrt += '_'
|
||||
}
|
||||
}
|
||||
}
|
||||
nrt += '>'
|
||||
idx := t.type_idxs[nrt]
|
||||
if idx != 0 && t.type_symbols[idx].kind != .placeholder {
|
||||
return new_type(idx).derive(typ).clear_flag(.generic)
|
||||
} else {
|
||||
// fields type translate to concrete type
|
||||
fields = ts.info.fields.clone()
|
||||
for i in 0 .. fields.len {
|
||||
if fields[i].typ.has_flag(.generic) {
|
||||
sym := t.get_type_symbol(fields[i].typ)
|
||||
if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() {
|
||||
fields[i].typ = t.unwrap_generic_type(fields[i].typ, generic_names,
|
||||
concrete_types)
|
||||
} else {
|
||||
if t_typ := t.resolve_generic_to_concrete(fields[i].typ, generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// update concrete types
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
if t_typ := t.resolve_generic_to_concrete(ts.info.generic_types[i],
|
||||
generic_names, concrete_types)
|
||||
{
|
||||
final_concrete_types << t_typ
|
||||
}
|
||||
}
|
||||
if final_concrete_types.len > 0 {
|
||||
for method in ts.methods {
|
||||
t.register_fn_concrete_types(method.name, final_concrete_types)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
match mut ts.info {
|
||||
Struct {
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = final_concrete_types
|
||||
info.parent_type = typ
|
||||
info.fields = fields
|
||||
new_idx := t.register_type_symbol(
|
||||
kind: .struct_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: ts.mod
|
||||
info: info
|
||||
)
|
||||
return new_type(new_idx).derive(typ).clear_flag(.generic)
|
||||
}
|
||||
Interface {
|
||||
// resolve generic types inside methods
|
||||
mut imethods := ts.info.methods.clone()
|
||||
for mut method in imethods {
|
||||
if unwrap_typ := t.resolve_generic_to_concrete(method.return_type, generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
method.return_type = unwrap_typ
|
||||
}
|
||||
for mut param in method.params {
|
||||
if unwrap_typ := t.resolve_generic_to_concrete(param.typ, generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
param.typ = unwrap_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
mut all_methods := ts.methods
|
||||
for imethod in imethods {
|
||||
for mut method in all_methods {
|
||||
if imethod.name == method.name {
|
||||
method = imethod
|
||||
}
|
||||
}
|
||||
}
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = final_concrete_types
|
||||
info.parent_type = typ
|
||||
info.fields = fields
|
||||
info.methods = imethods
|
||||
new_idx := t.register_type_symbol(
|
||||
kind: .interface_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: ts.mod
|
||||
info: info
|
||||
)
|
||||
mut ts_copy := t.get_type_symbol(new_idx)
|
||||
for method in all_methods {
|
||||
ts_copy.register_method(method)
|
||||
}
|
||||
return new_type(new_idx).derive(typ).clear_flag(.generic)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// generic struct instantiations to concrete types
|
||||
pub fn (mut t Table) generic_insts_to_concrete() {
|
||||
for mut typ in t.type_symbols {
|
||||
if typ.kind == .generic_inst {
|
||||
info := typ.info as GenericInst
|
||||
parent := t.type_symbols[info.parent_idx]
|
||||
if parent.kind == .placeholder {
|
||||
typ.kind = .placeholder
|
||||
continue
|
||||
}
|
||||
match parent.info {
|
||||
Struct {
|
||||
mut parent_info := parent.info as Struct
|
||||
if !parent_info.is_generic {
|
||||
util.verror('generic error', 'struct `$parent.name` is not a generic struct, cannot instantiate to the concrete types')
|
||||
continue
|
||||
}
|
||||
mut fields := parent_info.fields.clone()
|
||||
if parent_info.generic_types.len == info.concrete_types.len {
|
||||
generic_names := parent_info.generic_types.map(t.get_type_symbol(it).name)
|
||||
for i in 0 .. fields.len {
|
||||
if fields[i].typ.has_flag(.generic) {
|
||||
sym := t.get_type_symbol(fields[i].typ)
|
||||
if sym.kind == .struct_ && fields[i].typ.idx() != info.parent_idx {
|
||||
fields[i].typ = t.unwrap_generic_type(fields[i].typ,
|
||||
generic_names, info.concrete_types)
|
||||
} else {
|
||||
if t_typ := t.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
typ.info = Struct{
|
||||
...parent_info
|
||||
is_generic: false
|
||||
concrete_types: info.concrete_types.clone()
|
||||
fields: fields
|
||||
parent_type: new_type(info.parent_idx).set_flag(.generic)
|
||||
}
|
||||
typ.is_public = true
|
||||
typ.kind = parent.kind
|
||||
|
||||
parent_sym := t.get_type_symbol(parent_info.parent_type)
|
||||
for method in parent_sym.methods {
|
||||
t.register_fn_concrete_types(method.name, info.concrete_types)
|
||||
}
|
||||
} else {
|
||||
util.verror('generic error', 'the number of generic types of struct `$parent.name` is inconsistent with the concrete types')
|
||||
}
|
||||
}
|
||||
Interface {
|
||||
mut parent_info := parent.info as Interface
|
||||
if !parent_info.is_generic {
|
||||
util.verror('generic error', 'interface `$parent.name` is not a generic interface, cannot instantiate to the concrete types')
|
||||
continue
|
||||
}
|
||||
if parent_info.generic_types.len == info.concrete_types.len {
|
||||
mut fields := parent_info.fields.clone()
|
||||
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)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
mut imethods := parent_info.methods.clone()
|
||||
for mut method in imethods {
|
||||
method.generic_names.clear()
|
||||
if pt := t.resolve_generic_to_concrete(method.return_type,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
method.return_type = pt
|
||||
}
|
||||
method.params = method.params.clone()
|
||||
for mut param in method.params {
|
||||
if pt := t.resolve_generic_to_concrete(param.typ, generic_names,
|
||||
info.concrete_types)
|
||||
{
|
||||
param.typ = pt
|
||||
}
|
||||
}
|
||||
typ.register_method(method)
|
||||
}
|
||||
mut all_methods := parent.methods
|
||||
for imethod in imethods {
|
||||
for mut method in all_methods {
|
||||
if imethod.name == method.name {
|
||||
method = imethod
|
||||
}
|
||||
}
|
||||
}
|
||||
typ.info = Interface{
|
||||
...parent_info
|
||||
is_generic: false
|
||||
concrete_types: info.concrete_types.clone()
|
||||
fields: fields
|
||||
methods: imethods
|
||||
parent_type: new_type(info.parent_idx).set_flag(.generic)
|
||||
}
|
||||
typ.is_public = true
|
||||
typ.kind = parent.kind
|
||||
typ.methods = all_methods
|
||||
} else {
|
||||
util.verror('generic error', 'the number of generic types of interface `$parent.name` is inconsistent with the concrete types')
|
||||
}
|
||||
}
|
||||
SumType {
|
||||
mut parent_info := parent.info as SumType
|
||||
if !parent_info.is_generic {
|
||||
util.verror('generic error', 'sumtype `$parent.name` is not a generic sumtype, cannot instantiate to the concrete types')
|
||||
continue
|
||||
}
|
||||
if parent_info.generic_types.len == info.concrete_types.len {
|
||||
mut fields := parent_info.fields.clone()
|
||||
mut variants := parent_info.variants.clone()
|
||||
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)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
for i in 0 .. variants.len {
|
||||
if t_typ := t.resolve_generic_to_concrete(variants[i], generic_names,
|
||||
info.concrete_types)
|
||||
{
|
||||
variants[i] = t_typ
|
||||
}
|
||||
}
|
||||
typ.info = SumType{
|
||||
...parent_info
|
||||
is_generic: false
|
||||
concrete_types: info.concrete_types.clone()
|
||||
fields: fields
|
||||
variants: variants
|
||||
parent_type: new_type(info.parent_idx).set_flag(.generic)
|
||||
}
|
||||
typ.is_public = true
|
||||
typ.kind = parent.kind
|
||||
} else {
|
||||
util.verror('generic error', 'the number of generic types of sumtype `$parent.name` is inconsistent with the concrete types')
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ pub fn (mut b Builder) middle_stages() ? {
|
|||
util.timing_start('CHECK')
|
||||
|
||||
util.timing_start('Checker.generic_insts_to_concrete')
|
||||
b.checker.generic_insts_to_concrete()
|
||||
b.table.generic_insts_to_concrete()
|
||||
util.timing_measure('Checker.generic_insts_to_concrete')
|
||||
|
||||
b.checker.check_files(b.parsed_files)
|
||||
|
|
|
@ -679,326 +679,6 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) unwrap_generic_type(typ ast.Type, generic_names []string, concrete_types []ast.Type) ast.Type {
|
||||
mut final_concrete_types := []ast.Type{}
|
||||
mut fields := []ast.StructField{}
|
||||
mut nrt := ''
|
||||
mut c_nrt := ''
|
||||
ts := c.table.get_type_symbol(typ)
|
||||
match mut ts.info {
|
||||
ast.Array {
|
||||
mut elem_type := ts.info.elem_type
|
||||
mut elem_sym := c.table.get_type_symbol(elem_type)
|
||||
mut dims := 1
|
||||
for mut elem_sym.info is ast.Array {
|
||||
info := elem_sym.info as ast.Array
|
||||
elem_type = info.elem_type
|
||||
elem_sym = c.table.get_type_symbol(elem_type)
|
||||
dims++
|
||||
}
|
||||
unwrap_typ := c.unwrap_generic_type(elem_type, generic_names, concrete_types)
|
||||
idx := c.table.find_or_register_array_with_dims(unwrap_typ, dims)
|
||||
return ast.new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
ast.ArrayFixed {
|
||||
unwrap_typ := c.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
|
||||
idx := c.table.find_or_register_array_fixed(unwrap_typ, ts.info.size, ast.None{})
|
||||
return ast.new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
ast.Chan {
|
||||
unwrap_typ := c.unwrap_generic_type(ts.info.elem_type, generic_names, concrete_types)
|
||||
idx := c.table.find_or_register_chan(unwrap_typ, unwrap_typ.nr_muls() > 0)
|
||||
return ast.new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
ast.Map {
|
||||
unwrap_key_type := c.unwrap_generic_type(ts.info.key_type, generic_names,
|
||||
concrete_types)
|
||||
unwrap_value_type := c.unwrap_generic_type(ts.info.value_type, generic_names,
|
||||
concrete_types)
|
||||
idx := c.table.find_or_register_map(unwrap_key_type, unwrap_value_type)
|
||||
return ast.new_type(idx).derive_add_muls(typ).clear_flag(.generic)
|
||||
}
|
||||
ast.Struct, ast.Interface, ast.SumType {
|
||||
if !ts.info.is_generic {
|
||||
return typ
|
||||
}
|
||||
nrt = '$ts.name<'
|
||||
c_nrt = '${ts.cname}_T_'
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
if ct := c.table.resolve_generic_to_concrete(ts.info.generic_types[i],
|
||||
generic_names, concrete_types)
|
||||
{
|
||||
gts := c.table.get_type_symbol(ct)
|
||||
nrt += gts.name
|
||||
c_nrt += gts.cname
|
||||
if i != ts.info.generic_types.len - 1 {
|
||||
nrt += ', '
|
||||
c_nrt += '_'
|
||||
}
|
||||
}
|
||||
}
|
||||
nrt += '>'
|
||||
idx := c.table.type_idxs[nrt]
|
||||
if idx != 0 && c.table.type_symbols[idx].kind != .placeholder {
|
||||
return ast.new_type(idx).derive(typ).clear_flag(.generic)
|
||||
} else {
|
||||
// fields type translate to concrete type
|
||||
fields = ts.info.fields.clone()
|
||||
for i in 0 .. fields.len {
|
||||
if fields[i].typ.has_flag(.generic) {
|
||||
sym := c.table.get_type_symbol(fields[i].typ)
|
||||
if sym.kind == .struct_ && fields[i].typ.idx() != typ.idx() {
|
||||
fields[i].typ = c.unwrap_generic_type(fields[i].typ, generic_names,
|
||||
concrete_types)
|
||||
} else {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// update concrete types
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(ts.info.generic_types[i],
|
||||
generic_names, concrete_types)
|
||||
{
|
||||
final_concrete_types << t_typ
|
||||
}
|
||||
}
|
||||
if final_concrete_types.len > 0 {
|
||||
for method in ts.methods {
|
||||
c.table.register_fn_concrete_types(method.name, final_concrete_types)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
match mut ts.info {
|
||||
ast.Struct {
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = final_concrete_types
|
||||
info.parent_type = typ
|
||||
info.fields = fields
|
||||
new_idx := c.table.register_type_symbol(
|
||||
kind: .struct_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: c.mod
|
||||
info: info
|
||||
)
|
||||
return ast.new_type(new_idx).derive(typ).clear_flag(.generic)
|
||||
}
|
||||
ast.Interface {
|
||||
// resolve generic types inside methods
|
||||
mut imethods := ts.info.methods.clone()
|
||||
for mut method in imethods {
|
||||
if t := c.table.resolve_generic_to_concrete(method.return_type, generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
method.return_type = t
|
||||
}
|
||||
for mut param in method.params {
|
||||
if t := c.table.resolve_generic_to_concrete(param.typ, generic_names,
|
||||
concrete_types)
|
||||
{
|
||||
param.typ = t
|
||||
}
|
||||
}
|
||||
}
|
||||
mut all_methods := ts.methods
|
||||
for imethod in imethods {
|
||||
for mut method in all_methods {
|
||||
if imethod.name == method.name {
|
||||
method = imethod
|
||||
}
|
||||
}
|
||||
}
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = final_concrete_types
|
||||
info.parent_type = typ
|
||||
info.fields = fields
|
||||
info.methods = imethods
|
||||
new_idx := c.table.register_type_symbol(
|
||||
kind: .interface_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: c.mod
|
||||
info: info
|
||||
)
|
||||
mut ts_copy := c.table.get_type_symbol(new_idx)
|
||||
for method in all_methods {
|
||||
ts_copy.register_method(method)
|
||||
}
|
||||
return ast.new_type(new_idx).derive(typ).clear_flag(.generic)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// generic struct instantiations to concrete types
|
||||
pub fn (mut c Checker) generic_insts_to_concrete() {
|
||||
for mut typ in c.table.type_symbols {
|
||||
if typ.kind == .generic_inst {
|
||||
info := typ.info as ast.GenericInst
|
||||
parent := c.table.type_symbols[info.parent_idx]
|
||||
if parent.kind == .placeholder {
|
||||
typ.kind = .placeholder
|
||||
continue
|
||||
}
|
||||
match parent.info {
|
||||
ast.Struct {
|
||||
mut parent_info := parent.info as ast.Struct
|
||||
if !parent_info.is_generic {
|
||||
util.verror('generic error', 'struct `$parent.name` is not a generic struct, cannot instantiate to the concrete types')
|
||||
continue
|
||||
}
|
||||
mut fields := parent_info.fields.clone()
|
||||
if parent_info.generic_types.len == info.concrete_types.len {
|
||||
generic_names := parent_info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
for i in 0 .. fields.len {
|
||||
if fields[i].typ.has_flag(.generic) {
|
||||
sym := c.table.get_type_symbol(fields[i].typ)
|
||||
if sym.kind == .struct_ && fields[i].typ.idx() != info.parent_idx {
|
||||
fields[i].typ = c.unwrap_generic_type(fields[i].typ,
|
||||
generic_names, info.concrete_types)
|
||||
} else {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parent_info.is_generic = false
|
||||
parent_info.concrete_types = info.concrete_types.clone()
|
||||
parent_info.fields = fields
|
||||
parent_info.parent_type = ast.new_type(info.parent_idx).set_flag(.generic)
|
||||
typ.info = ast.Struct{
|
||||
...parent_info
|
||||
is_generic: false
|
||||
concrete_types: info.concrete_types.clone()
|
||||
fields: fields
|
||||
parent_type: ast.new_type(info.parent_idx).set_flag(.generic)
|
||||
}
|
||||
typ.is_public = true
|
||||
typ.kind = parent.kind
|
||||
|
||||
parent_sym := c.table.get_type_symbol(parent_info.parent_type)
|
||||
for method in parent_sym.methods {
|
||||
c.table.register_fn_concrete_types(method.name, info.concrete_types)
|
||||
}
|
||||
} else {
|
||||
util.verror('generic error', 'the number of generic types of struct `$parent.name` is inconsistent with the concrete types')
|
||||
}
|
||||
}
|
||||
ast.Interface {
|
||||
mut parent_info := parent.info as ast.Interface
|
||||
if !parent_info.is_generic {
|
||||
util.verror('generic error', 'interface `$parent.name` is not a generic interface, cannot instantiate to the concrete types')
|
||||
continue
|
||||
}
|
||||
if parent_info.generic_types.len == info.concrete_types.len {
|
||||
mut fields := parent_info.fields.clone()
|
||||
generic_names := parent_info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
for i in 0 .. fields.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
mut imethods := parent_info.methods.clone()
|
||||
for mut method in imethods {
|
||||
method.generic_names.clear()
|
||||
if pt := c.table.resolve_generic_to_concrete(method.return_type,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
method.return_type = pt
|
||||
}
|
||||
method.params = method.params.clone()
|
||||
for mut param in method.params {
|
||||
if pt := c.table.resolve_generic_to_concrete(param.typ,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
param.typ = pt
|
||||
}
|
||||
}
|
||||
typ.register_method(method)
|
||||
}
|
||||
mut all_methods := parent.methods
|
||||
for imethod in imethods {
|
||||
for mut method in all_methods {
|
||||
if imethod.name == method.name {
|
||||
method = imethod
|
||||
}
|
||||
}
|
||||
}
|
||||
typ.info = ast.Interface{
|
||||
...parent_info
|
||||
is_generic: false
|
||||
concrete_types: info.concrete_types.clone()
|
||||
fields: fields
|
||||
methods: imethods
|
||||
parent_type: ast.new_type(info.parent_idx).set_flag(.generic)
|
||||
}
|
||||
typ.is_public = true
|
||||
typ.kind = parent.kind
|
||||
typ.methods = all_methods
|
||||
} else {
|
||||
util.verror('generic error', 'the number of generic types of interface `$parent.name` is inconsistent with the concrete types')
|
||||
}
|
||||
}
|
||||
ast.SumType {
|
||||
mut parent_info := parent.info as ast.SumType
|
||||
if !parent_info.is_generic {
|
||||
util.verror('generic error', 'sumtype `$parent.name` is not a generic sumtype, cannot instantiate to the concrete types')
|
||||
continue
|
||||
}
|
||||
if parent_info.generic_types.len == info.concrete_types.len {
|
||||
mut fields := parent_info.fields.clone()
|
||||
mut variants := parent_info.variants.clone()
|
||||
generic_names := parent_info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
for i in 0 .. fields.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
for i in 0 .. variants.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(variants[i],
|
||||
generic_names, info.concrete_types)
|
||||
{
|
||||
variants[i] = t_typ
|
||||
}
|
||||
}
|
||||
typ.info = ast.SumType{
|
||||
...parent_info
|
||||
is_generic: false
|
||||
concrete_types: info.concrete_types.clone()
|
||||
fields: fields
|
||||
variants: variants
|
||||
parent_type: ast.new_type(info.parent_idx).set_flag(.generic)
|
||||
}
|
||||
typ.is_public = true
|
||||
typ.kind = parent.kind
|
||||
} else {
|
||||
util.verror('generic error', 'the number of generic types of sumtype `$parent.name` is inconsistent with the concrete types')
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
||||
if node.typ == ast.void_type {
|
||||
// Short syntax `({foo: bar})`
|
||||
|
@ -1031,7 +711,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||
return ast.void_type
|
||||
}
|
||||
}
|
||||
unwrapped_struct_type := c.unwrap_generic_type(node.typ, c.table.cur_fn.generic_names,
|
||||
unwrapped_struct_type := c.table.unwrap_generic_type(node.typ, c.table.cur_fn.generic_names,
|
||||
c.table.cur_concrete_types)
|
||||
c.ensure_type_exists(unwrapped_struct_type, node.pos) or {}
|
||||
type_sym := c.table.get_type_symbol(node.typ)
|
||||
|
@ -2542,7 +2222,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
|||
}
|
||||
// resolve return generics struct to concrete type
|
||||
if method.generic_names.len > 0 && method.return_type.has_flag(.generic) {
|
||||
node.return_type = c.unwrap_generic_type(method.return_type, method.generic_names,
|
||||
node.return_type = c.table.unwrap_generic_type(method.return_type, method.generic_names,
|
||||
concrete_types)
|
||||
} else {
|
||||
node.return_type = method.return_type
|
||||
|
@ -3201,7 +2881,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
}
|
||||
// resolve return generics struct to concrete type
|
||||
if func.generic_names.len > 0 && func.return_type.has_flag(.generic) {
|
||||
node.return_type = c.unwrap_generic_type(func.return_type, func.generic_names,
|
||||
node.return_type = c.table.unwrap_generic_type(func.return_type, func.generic_names,
|
||||
concrete_types)
|
||||
} else {
|
||||
node.return_type = func.return_type
|
||||
|
@ -3329,7 +3009,7 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty
|
|||
}
|
||||
}
|
||||
inter_sym.info.concrete_types = inferred_types
|
||||
return c.unwrap_generic_type(interface_type, generic_names, inter_sym.info.concrete_types)
|
||||
return c.table.unwrap_generic_type(interface_type, generic_names, inter_sym.info.concrete_types)
|
||||
}
|
||||
}
|
||||
return interface_type
|
||||
|
|
Loading…
Reference in New Issue