builder,checker,table: simpify generics unwrap and struct processing (#9531)
parent
15d9f50be9
commit
5c21c748c9
|
@ -17,12 +17,12 @@ pub fn (mut b Builder) gen_c(v_files []string) string {
|
||||||
if b.pref.only_check_syntax {
|
if b.pref.only_check_syntax {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
//
|
|
||||||
util.timing_start('CHECK')
|
util.timing_start('CHECK')
|
||||||
b.generic_struct_insts_to_concrete()
|
b.table.generic_struct_insts_to_concrete()
|
||||||
b.checker.check_files(b.parsed_files)
|
b.checker.check_files(b.parsed_files)
|
||||||
util.timing_measure('CHECK')
|
util.timing_measure('CHECK')
|
||||||
//
|
|
||||||
if b.pref.skip_unused {
|
if b.pref.skip_unused {
|
||||||
markused.mark_used(mut b.table, b.pref, b.parsed_files)
|
markused.mark_used(mut b.table, b.pref, b.parsed_files)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
module builder
|
|
||||||
|
|
||||||
import v.table
|
|
||||||
|
|
||||||
// NOTE: Think about generic struct implementation
|
|
||||||
// this might not be the best strategy. - joe-c
|
|
||||||
//
|
|
||||||
// generic struct instantiations to concrete types
|
|
||||||
pub fn (b &Builder) generic_struct_insts_to_concrete() {
|
|
||||||
for idx, _ in b.table.type_symbols {
|
|
||||||
mut typ := unsafe { &b.table.type_symbols[idx] }
|
|
||||||
if typ.kind == .generic_struct_inst {
|
|
||||||
info := typ.info as table.GenericStructInst
|
|
||||||
parent := b.table.type_symbols[info.parent_idx]
|
|
||||||
if parent.kind == .placeholder {
|
|
||||||
typ.kind = .placeholder
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mut parent_info := parent.info as table.Struct
|
|
||||||
mut fields := parent_info.fields.clone()
|
|
||||||
for i, _ in fields {
|
|
||||||
mut field := fields[i]
|
|
||||||
if field.typ.has_flag(.generic) {
|
|
||||||
if parent_info.generic_types.len != info.generic_types.len {
|
|
||||||
// TODO: proper error
|
|
||||||
panic('generic template mismatch')
|
|
||||||
}
|
|
||||||
for j, gp in parent_info.generic_types {
|
|
||||||
if gp == field.typ {
|
|
||||||
field.typ = info.generic_types[j].derive(field.typ).clear_flag(.generic)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fields[i] = field
|
|
||||||
}
|
|
||||||
parent_info.generic_types = []
|
|
||||||
parent_info.fields = fields
|
|
||||||
typ.is_public = true
|
|
||||||
typ.kind = .struct_
|
|
||||||
typ.info = parent_info
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -488,147 +488,3 @@ pub fn (mut c Checker) infer_fn_types(f table.Fn, mut call_expr ast.CallExpr) {
|
||||||
}
|
}
|
||||||
c.table.register_fn_gen_type(f.name, inferred_types)
|
c.table.register_fn_gen_type(f.name, inferred_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve_generic_by_names 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.
|
|
||||||
fn (mut c Checker) resolve_generic_by_names(generic_type table.Type, generic_names []string, generic_types []table.Type) ?table.Type {
|
|
||||||
mut sym := c.table.get_type_symbol(generic_type)
|
|
||||||
if sym.name in generic_names {
|
|
||||||
index := generic_names.index(sym.name)
|
|
||||||
mut typ := generic_types[index]
|
|
||||||
typ = typ.set_nr_muls(generic_type.nr_muls())
|
|
||||||
if generic_type.has_flag(.optional) {
|
|
||||||
typ = typ.set_flag(.optional)
|
|
||||||
}
|
|
||||||
return typ
|
|
||||||
} else if sym.kind == .array {
|
|
||||||
info := sym.info as table.Array
|
|
||||||
mut elem_type := info.elem_type
|
|
||||||
mut elem_sym := c.table.get_type_symbol(elem_type)
|
|
||||||
mut dims := 1
|
|
||||||
for mut elem_sym.info is table.Array {
|
|
||||||
elem_type = elem_sym.info.elem_type
|
|
||||||
elem_sym = c.table.get_type_symbol(elem_type)
|
|
||||||
dims++
|
|
||||||
}
|
|
||||||
if typ := c.resolve_generic_by_names(elem_type, generic_names, generic_types) {
|
|
||||||
idx := c.table.find_or_register_array_with_dims(typ, dims)
|
|
||||||
array_typ := table.new_type(idx)
|
|
||||||
return array_typ
|
|
||||||
}
|
|
||||||
} else if sym.kind == .chan {
|
|
||||||
info := sym.info as table.Chan
|
|
||||||
if typ := c.resolve_generic_by_names(info.elem_type, generic_names, generic_types) {
|
|
||||||
idx := c.table.find_or_register_chan(typ, typ.nr_muls() > 0)
|
|
||||||
chan_typ := table.new_type(idx)
|
|
||||||
return chan_typ
|
|
||||||
}
|
|
||||||
} else if mut sym.info is table.MultiReturn {
|
|
||||||
mut types := []table.Type{}
|
|
||||||
mut type_changed := false
|
|
||||||
for ret_type in sym.info.types {
|
|
||||||
if typ := c.resolve_generic_by_names(ret_type, generic_names, generic_types) {
|
|
||||||
types << typ
|
|
||||||
type_changed = true
|
|
||||||
} else {
|
|
||||||
types << ret_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if type_changed {
|
|
||||||
idx := c.table.find_or_register_multi_return(types)
|
|
||||||
typ := table.new_type(idx)
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
} else if mut sym.info is table.Map {
|
|
||||||
mut type_changed := false
|
|
||||||
mut unwrapped_key_type := sym.info.key_type
|
|
||||||
mut unwrapped_value_type := sym.info.value_type
|
|
||||||
if typ := c.resolve_generic_by_names(sym.info.key_type, generic_names, generic_types) {
|
|
||||||
unwrapped_key_type = typ
|
|
||||||
type_changed = true
|
|
||||||
}
|
|
||||||
if typ := c.resolve_generic_by_names(sym.info.value_type, generic_names, generic_types) {
|
|
||||||
unwrapped_value_type = typ
|
|
||||||
type_changed = true
|
|
||||||
}
|
|
||||||
if type_changed {
|
|
||||||
idx := c.table.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
|
||||||
typ := table.new_type(idx)
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return none
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolve_generic_by_types 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.
|
|
||||||
fn (mut c Checker) resolve_generic_by_types(generic_type table.Type, from_types []table.Type, to_types []table.Type) ?table.Type {
|
|
||||||
mut sym := c.table.get_type_symbol(generic_type)
|
|
||||||
if generic_type in from_types {
|
|
||||||
index := from_types.index(generic_type)
|
|
||||||
mut typ := to_types[index]
|
|
||||||
typ = typ.set_nr_muls(generic_type.nr_muls())
|
|
||||||
if generic_type.has_flag(.optional) {
|
|
||||||
typ = typ.set_flag(.optional)
|
|
||||||
}
|
|
||||||
return typ
|
|
||||||
} else if sym.kind == .array {
|
|
||||||
info := sym.info as table.Array
|
|
||||||
mut elem_type := info.elem_type
|
|
||||||
mut elem_sym := c.table.get_type_symbol(elem_type)
|
|
||||||
mut dims := 1
|
|
||||||
for mut elem_sym.info is table.Array {
|
|
||||||
elem_type = elem_sym.info.elem_type
|
|
||||||
elem_sym = c.table.get_type_symbol(elem_type)
|
|
||||||
dims++
|
|
||||||
}
|
|
||||||
if typ := c.resolve_generic_by_types(elem_type, from_types, to_types) {
|
|
||||||
idx := c.table.find_or_register_array_with_dims(typ, dims)
|
|
||||||
array_typ := table.new_type(idx)
|
|
||||||
return array_typ
|
|
||||||
}
|
|
||||||
} else if sym.kind == .chan {
|
|
||||||
info := sym.info as table.Chan
|
|
||||||
if typ := c.resolve_generic_by_types(info.elem_type, from_types, to_types) {
|
|
||||||
idx := c.table.find_or_register_chan(typ, typ.nr_muls() > 0)
|
|
||||||
chan_typ := table.new_type(idx)
|
|
||||||
return chan_typ
|
|
||||||
}
|
|
||||||
} else if mut sym.info is table.MultiReturn {
|
|
||||||
mut types := []table.Type{}
|
|
||||||
mut type_changed := false
|
|
||||||
for ret_type in sym.info.types {
|
|
||||||
if typ := c.resolve_generic_by_types(ret_type, from_types, to_types) {
|
|
||||||
types << typ
|
|
||||||
type_changed = true
|
|
||||||
} else {
|
|
||||||
types << ret_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if type_changed {
|
|
||||||
idx := c.table.find_or_register_multi_return(types)
|
|
||||||
typ := table.new_type(idx)
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
} else if mut sym.info is table.Map {
|
|
||||||
mut type_changed := false
|
|
||||||
mut unwrapped_key_type := sym.info.key_type
|
|
||||||
mut unwrapped_value_type := sym.info.value_type
|
|
||||||
if typ := c.resolve_generic_by_types(sym.info.key_type, from_types, to_types) {
|
|
||||||
unwrapped_key_type = typ
|
|
||||||
type_changed = true
|
|
||||||
}
|
|
||||||
if typ := c.resolve_generic_by_types(sym.info.value_type, from_types, to_types) {
|
|
||||||
unwrapped_value_type = typ
|
|
||||||
type_changed = true
|
|
||||||
}
|
|
||||||
if type_changed {
|
|
||||||
idx := c.table.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
|
||||||
typ := table.new_type(idx)
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return none
|
|
||||||
}
|
|
||||||
|
|
|
@ -1638,7 +1638,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
c.infer_fn_types(method, mut call_expr)
|
c.infer_fn_types(method, mut call_expr)
|
||||||
}
|
}
|
||||||
if call_expr.generic_types.len > 0 && method.return_type != 0 {
|
if call_expr.generic_types.len > 0 && method.return_type != 0 {
|
||||||
if typ := c.resolve_generic_by_names(method.return_type, method.generic_names,
|
if typ := c.table.resolve_generic_by_names(method.return_type, method.generic_names,
|
||||||
call_expr.generic_types)
|
call_expr.generic_types)
|
||||||
{
|
{
|
||||||
call_expr.return_type = typ
|
call_expr.return_type = typ
|
||||||
|
@ -1995,8 +1995,8 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
mut fields := rts.info.fields.clone()
|
mut fields := rts.info.fields.clone()
|
||||||
if rts.info.generic_types.len == generic_types.len {
|
if rts.info.generic_types.len == generic_types.len {
|
||||||
for i, _ in fields {
|
for i, _ in fields {
|
||||||
if t_typ := c.resolve_generic_by_types(fields[i].typ, rts.info.generic_types,
|
if t_typ := c.table.resolve_generic_by_types(fields[i].typ,
|
||||||
generic_types)
|
rts.info.generic_types, generic_types)
|
||||||
{
|
{
|
||||||
fields[i].typ = t_typ
|
fields[i].typ = t_typ
|
||||||
}
|
}
|
||||||
|
@ -2143,7 +2143,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
if f.generic_names.len > 0 {
|
if f.generic_names.len > 0 {
|
||||||
if param.typ.has_flag(.generic)
|
if param.typ.has_flag(.generic)
|
||||||
&& f.generic_names.len == call_expr.generic_types.len {
|
&& f.generic_names.len == call_expr.generic_types.len {
|
||||||
if unwrap_typ := c.resolve_generic_by_names(param.typ, f.generic_names,
|
if unwrap_typ := c.table.resolve_generic_by_names(param.typ, f.generic_names,
|
||||||
call_expr.generic_types)
|
call_expr.generic_types)
|
||||||
{
|
{
|
||||||
if (unwrap_typ.idx() == typ.idx())
|
if (unwrap_typ.idx() == typ.idx())
|
||||||
|
@ -2178,7 +2178,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
c.infer_fn_types(f, mut call_expr)
|
c.infer_fn_types(f, mut call_expr)
|
||||||
}
|
}
|
||||||
if call_expr.generic_types.len > 0 && f.return_type != 0 {
|
if call_expr.generic_types.len > 0 && f.return_type != 0 {
|
||||||
if typ := c.resolve_generic_by_names(f.return_type, f.generic_names, call_expr.generic_types) {
|
if typ := c.table.resolve_generic_by_names(f.return_type, f.generic_names, call_expr.generic_types) {
|
||||||
call_expr.return_type = typ
|
call_expr.return_type = typ
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
|
@ -938,3 +938,180 @@ pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolve_generic_by_names 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_by_names(generic_type Type, generic_names []string, generic_types []Type) ?Type {
|
||||||
|
mut sym := t.get_type_symbol(generic_type)
|
||||||
|
if sym.name in generic_names {
|
||||||
|
index := generic_names.index(sym.name)
|
||||||
|
mut typ := generic_types[index]
|
||||||
|
typ = typ.set_nr_muls(generic_type.nr_muls())
|
||||||
|
if generic_type.has_flag(.optional) {
|
||||||
|
typ = typ.set_flag(.optional)
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
} else if sym.kind == .array {
|
||||||
|
info := sym.info as Array
|
||||||
|
mut elem_type := info.elem_type
|
||||||
|
mut elem_sym := t.get_type_symbol(elem_type)
|
||||||
|
mut dims := 1
|
||||||
|
for mut elem_sym.info is Array {
|
||||||
|
elem_type = elem_sym.info.elem_type
|
||||||
|
elem_sym = t.get_type_symbol(elem_type)
|
||||||
|
dims++
|
||||||
|
}
|
||||||
|
if typ := t.resolve_generic_by_names(elem_type, generic_names, generic_types) {
|
||||||
|
idx := t.find_or_register_array_with_dims(typ, dims)
|
||||||
|
array_typ := new_type(idx)
|
||||||
|
return array_typ
|
||||||
|
}
|
||||||
|
} else if sym.kind == .chan {
|
||||||
|
info := sym.info as Chan
|
||||||
|
if typ := t.resolve_generic_by_names(info.elem_type, generic_names, generic_types) {
|
||||||
|
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
|
||||||
|
chan_typ := new_type(idx)
|
||||||
|
return chan_typ
|
||||||
|
}
|
||||||
|
} else if mut sym.info is MultiReturn {
|
||||||
|
mut types := []Type{}
|
||||||
|
mut type_changed := false
|
||||||
|
for ret_type in sym.info.types {
|
||||||
|
if typ := t.resolve_generic_by_names(ret_type, generic_names, generic_types) {
|
||||||
|
types << typ
|
||||||
|
type_changed = true
|
||||||
|
} else {
|
||||||
|
types << ret_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if type_changed {
|
||||||
|
idx := t.find_or_register_multi_return(types)
|
||||||
|
typ := new_type(idx)
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
} else if mut sym.info is Map {
|
||||||
|
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_by_names(sym.info.key_type, generic_names, generic_types) {
|
||||||
|
unwrapped_key_type = typ
|
||||||
|
type_changed = true
|
||||||
|
}
|
||||||
|
if typ := t.resolve_generic_by_names(sym.info.value_type, generic_names, generic_types) {
|
||||||
|
unwrapped_value_type = typ
|
||||||
|
type_changed = true
|
||||||
|
}
|
||||||
|
if type_changed {
|
||||||
|
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
||||||
|
return new_type(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve_generic_by_types 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_by_types(generic_type Type, from_types []Type, to_types []Type) ?Type {
|
||||||
|
mut sym := t.get_type_symbol(generic_type)
|
||||||
|
if generic_type in from_types {
|
||||||
|
index := from_types.index(generic_type)
|
||||||
|
mut typ := to_types[index]
|
||||||
|
typ = typ.set_nr_muls(generic_type.nr_muls())
|
||||||
|
if generic_type.has_flag(.optional) {
|
||||||
|
typ = typ.set_flag(.optional)
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
} else if sym.kind == .array {
|
||||||
|
info := sym.info as Array
|
||||||
|
mut elem_type := info.elem_type
|
||||||
|
mut elem_sym := t.get_type_symbol(elem_type)
|
||||||
|
mut dims := 1
|
||||||
|
for mut elem_sym.info is Array {
|
||||||
|
elem_type = elem_sym.info.elem_type
|
||||||
|
elem_sym = t.get_type_symbol(elem_type)
|
||||||
|
dims++
|
||||||
|
}
|
||||||
|
if typ := t.resolve_generic_by_types(elem_type, from_types, to_types) {
|
||||||
|
idx := t.find_or_register_array_with_dims(typ, dims)
|
||||||
|
return new_type(idx)
|
||||||
|
}
|
||||||
|
} else if sym.kind == .chan {
|
||||||
|
info := sym.info as Chan
|
||||||
|
if typ := t.resolve_generic_by_types(info.elem_type, from_types, to_types) {
|
||||||
|
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
|
||||||
|
return new_type(idx)
|
||||||
|
}
|
||||||
|
} else if mut sym.info is MultiReturn {
|
||||||
|
mut types := []Type{}
|
||||||
|
mut type_changed := false
|
||||||
|
for ret_type in sym.info.types {
|
||||||
|
if typ := t.resolve_generic_by_types(ret_type, from_types, to_types) {
|
||||||
|
types << typ
|
||||||
|
type_changed = true
|
||||||
|
} else {
|
||||||
|
types << ret_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if type_changed {
|
||||||
|
idx := t.find_or_register_multi_return(types)
|
||||||
|
return new_type(idx)
|
||||||
|
}
|
||||||
|
} else if mut sym.info is Map {
|
||||||
|
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_by_types(sym.info.key_type, from_types, to_types) {
|
||||||
|
unwrapped_key_type = typ
|
||||||
|
type_changed = true
|
||||||
|
}
|
||||||
|
if typ := t.resolve_generic_by_types(sym.info.value_type, from_types, to_types) {
|
||||||
|
unwrapped_value_type = typ
|
||||||
|
type_changed = true
|
||||||
|
}
|
||||||
|
if type_changed {
|
||||||
|
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
||||||
|
return new_type(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
// generic struct instantiations to concrete types
|
||||||
|
pub fn (mut t Table) generic_struct_insts_to_concrete() {
|
||||||
|
for idx, _ in t.type_symbols {
|
||||||
|
mut typ := unsafe { &t.type_symbols[idx] }
|
||||||
|
if typ.kind == .generic_struct_inst {
|
||||||
|
info := typ.info as GenericStructInst
|
||||||
|
parent := t.type_symbols[info.parent_idx]
|
||||||
|
if parent.kind == .placeholder {
|
||||||
|
typ.kind = .placeholder
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mut parent_info := parent.info as Struct
|
||||||
|
mut fields := parent_info.fields.clone()
|
||||||
|
for i, _ in fields {
|
||||||
|
mut field := fields[i]
|
||||||
|
if field.typ.has_flag(.generic) {
|
||||||
|
if parent_info.generic_types.len != info.generic_types.len {
|
||||||
|
// TODO: proper error
|
||||||
|
panic('generic template mismatch')
|
||||||
|
}
|
||||||
|
for j, gp in parent_info.generic_types {
|
||||||
|
if gp == field.typ {
|
||||||
|
field.typ = info.generic_types[j].derive(field.typ).clear_flag(.generic)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fields[i] = field
|
||||||
|
}
|
||||||
|
parent_info.generic_types = []
|
||||||
|
parent_info.fields = fields
|
||||||
|
typ.is_public = true
|
||||||
|
typ.kind = .struct_
|
||||||
|
typ.info = parent_info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue