mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: simplify generic structs (#10167)
This commit is contained in:
parent
79b97fa361
commit
ae9f8627fc
@ -55,10 +55,9 @@ pub fn panic(s string) {
|
||||
exit(1)
|
||||
}
|
||||
|
||||
struct Option<T> {
|
||||
struct Option {
|
||||
state byte
|
||||
err Error
|
||||
data T
|
||||
}
|
||||
|
||||
pub struct Error {
|
||||
|
@ -561,7 +561,7 @@ pub fn (mut c Checker) infer_fn_generic_types(f ast.Fn, mut call_expr ast.CallEx
|
||||
} else if arg_sym.kind == .struct_ && param.typ.has_flag(.generic) {
|
||||
info := arg_sym.info as ast.Struct
|
||||
generic_names := info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
if gt_name in generic_names {
|
||||
if gt_name in generic_names && info.generic_types.len == info.concrete_types.len {
|
||||
idx := generic_names.index(gt_name)
|
||||
typ = info.concrete_types[idx]
|
||||
}
|
||||
|
@ -611,19 +611,23 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) unwrap_generics_struct_init(struct_type ast.Type) ast.Type {
|
||||
fn (mut c Checker) unwrap_generic_struct(struct_type ast.Type, generic_names []string, concrete_types []ast.Type) ast.Type {
|
||||
ts := c.table.get_type_symbol(struct_type)
|
||||
if ts.info is ast.Struct {
|
||||
if ts.info.is_generic {
|
||||
mut nrt := '$ts.name<'
|
||||
mut c_nrt := '${ts.name}_T_'
|
||||
mut c_nrt := '${ts.cname}_T_'
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
gts := c.table.get_type_symbol(c.unwrap_generic(ts.info.generic_types[i]))
|
||||
nrt += gts.name
|
||||
c_nrt += gts.cname
|
||||
if i != ts.info.generic_types.len - 1 {
|
||||
nrt += ','
|
||||
c_nrt += '_'
|
||||
if ct := c.table.resolve_generic_to_concrete(ts.info.generic_types[i],
|
||||
generic_names, concrete_types, false)
|
||||
{
|
||||
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 += '>'
|
||||
@ -631,30 +635,37 @@ fn (mut c Checker) unwrap_generics_struct_init(struct_type ast.Type) ast.Type {
|
||||
if idx != 0 && c.table.type_symbols[idx].kind != .placeholder {
|
||||
return ast.new_type(idx).derive(struct_type).clear_flag(.generic)
|
||||
} else {
|
||||
// fields type translate to concrete type
|
||||
mut fields := ts.info.fields.clone()
|
||||
if ts.info.generic_types.len == c.cur_concrete_types.len {
|
||||
generic_names := ts.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, c.cur_concrete_types, true)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
for i in 0 .. fields.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ, generic_names,
|
||||
concrete_types, true)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = c.cur_concrete_types.clone()
|
||||
info.parent_type = struct_type
|
||||
info.fields = fields
|
||||
stru_idx := c.table.register_type_symbol(ast.TypeSymbol{
|
||||
kind: .struct_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: c.mod
|
||||
info: info
|
||||
})
|
||||
return ast.new_type(stru_idx).derive(struct_type).clear_flag(.generic)
|
||||
}
|
||||
// update concrete types
|
||||
mut info_concrete_types := []ast.Type{}
|
||||
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, true)
|
||||
{
|
||||
info_concrete_types << t_typ
|
||||
}
|
||||
}
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = info_concrete_types
|
||||
info.parent_type = struct_type
|
||||
info.fields = fields
|
||||
stru_idx := c.table.register_type_symbol(ast.TypeSymbol{
|
||||
kind: .struct_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: c.mod
|
||||
info: info
|
||||
})
|
||||
return ast.new_type(stru_idx).derive(struct_type).clear_flag(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -679,7 +690,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||
struct_init.typ = c.expected_type
|
||||
}
|
||||
}
|
||||
utyp := c.unwrap_generics_struct_init(struct_init.typ)
|
||||
utyp := c.unwrap_generic_struct(struct_init.typ, c.table.cur_fn.generic_names, c.cur_concrete_types)
|
||||
c.ensure_type_exists(utyp, struct_init.pos) or {}
|
||||
type_sym := c.table.get_type_symbol(utyp)
|
||||
if !c.inside_unsafe && type_sym.kind == .sum_type {
|
||||
@ -1682,59 +1693,6 @@ 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_names []string, concrete_types []ast.Type) {
|
||||
rts := c.table.get_type_symbol(return_type)
|
||||
if rts.info is ast.Struct {
|
||||
if rts.info.is_generic {
|
||||
mut nrt := '$rts.name<'
|
||||
mut c_nrt := '${rts.cname}_T_'
|
||||
for i in 0 .. rts.info.generic_types.len {
|
||||
if ct := c.table.resolve_generic_to_concrete(rts.info.generic_types[i],
|
||||
generic_names, concrete_types, false)
|
||||
{
|
||||
gts := c.table.get_type_symbol(ct)
|
||||
nrt += gts.name
|
||||
c_nrt += gts.cname
|
||||
if i != rts.info.generic_types.len - 1 {
|
||||
nrt += ','
|
||||
c_nrt += '_'
|
||||
}
|
||||
}
|
||||
}
|
||||
nrt += '>'
|
||||
idx := c.table.type_idxs[nrt]
|
||||
if idx != 0 {
|
||||
c.ensure_type_exists(idx, call_expr.pos) or {}
|
||||
call_expr.return_type = ast.new_type(idx).derive(return_type).clear_flag(.generic)
|
||||
} else {
|
||||
mut fields := rts.info.fields.clone()
|
||||
if generic_names.len == concrete_types.len {
|
||||
for i in 0 .. fields.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, concrete_types, true)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
mut info := rts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = concrete_types.clone()
|
||||
info.parent_type = return_type
|
||||
info.fields = fields
|
||||
stru_idx := c.table.register_type_symbol(ast.TypeSymbol{
|
||||
kind: .struct_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: c.mod
|
||||
info: info
|
||||
})
|
||||
call_expr.return_type = ast.new_type(stru_idx).derive(return_type).clear_flag(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||
left_type := c.expr(call_expr.left)
|
||||
c.expected_type = left_type
|
||||
@ -2013,7 +1971,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||
}
|
||||
// resolve return generics struct to concrete type
|
||||
if method.generic_names.len > 0 && method.return_type.has_flag(.generic) {
|
||||
c.check_return_generics_struct(method.return_type, mut call_expr, method.generic_names,
|
||||
call_expr.return_type = c.unwrap_generic_struct(method.return_type, method.generic_names,
|
||||
concrete_types)
|
||||
} else {
|
||||
call_expr.return_type = method.return_type
|
||||
@ -2578,7 +2536,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
||||
}
|
||||
// resolve return generics struct to concrete type
|
||||
if func.generic_names.len > 0 && func.return_type.has_flag(.generic) {
|
||||
c.check_return_generics_struct(func.return_type, mut call_expr, func.generic_names,
|
||||
call_expr.return_type = c.unwrap_generic_struct(func.return_type, func.generic_names,
|
||||
concrete_types)
|
||||
} else {
|
||||
call_expr.return_type = func.return_type
|
||||
|
Loading…
Reference in New Issue
Block a user