From ae9f8627fc8b13878717c6300610d0d33d99ae4c Mon Sep 17 00:00:00 2001 From: yuyi Date: Sun, 23 May 2021 10:54:58 +0800 Subject: [PATCH] checker: simplify generic structs (#10167) --- vlib/builtin/js/builtin.v | 3 +- vlib/v/checker/check_types.v | 2 +- vlib/v/checker/checker.v | 128 ++++++++++++----------------------- 3 files changed, 45 insertions(+), 88 deletions(-) diff --git a/vlib/builtin/js/builtin.v b/vlib/builtin/js/builtin.v index 09a6d5c1b5..9fe53ce564 100644 --- a/vlib/builtin/js/builtin.v +++ b/vlib/builtin/js/builtin.v @@ -55,10 +55,9 @@ pub fn panic(s string) { exit(1) } -struct Option { +struct Option { state byte err Error - data T } pub struct Error { diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index b1a7e62ad4..43c565aea1 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -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] } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 5a86f2ba63..47772a326b 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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