checker: simplify generic structs (#10167)

pull/10179/head
yuyi 2021-05-23 10:54:58 +08:00 committed by GitHub
parent 79b97fa361
commit ae9f8627fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 88 deletions

View File

@ -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 {

View File

@ -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]
}

View File

@ -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