From 5c21c748c98606628a2539e5c3d558a598605781 Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 30 Mar 2021 20:23:17 +0800 Subject: [PATCH] builder,checker,table: simpify generics unwrap and struct processing (#9531) --- vlib/v/builder/c.v | 6 +- vlib/v/builder/generics.v | 44 --------- vlib/v/checker/check_types.v | 144 ---------------------------- vlib/v/checker/checker.v | 10 +- vlib/v/table/table.v | 177 +++++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 196 deletions(-) delete mode 100644 vlib/v/builder/generics.v diff --git a/vlib/v/builder/c.v b/vlib/v/builder/c.v index 9a5434eb4f..51a51ec862 100644 --- a/vlib/v/builder/c.v +++ b/vlib/v/builder/c.v @@ -17,12 +17,12 @@ pub fn (mut b Builder) gen_c(v_files []string) string { if b.pref.only_check_syntax { return '' } - // + util.timing_start('CHECK') - b.generic_struct_insts_to_concrete() + b.table.generic_struct_insts_to_concrete() b.checker.check_files(b.parsed_files) util.timing_measure('CHECK') - // + if b.pref.skip_unused { markused.mark_used(mut b.table, b.pref, b.parsed_files) } diff --git a/vlib/v/builder/generics.v b/vlib/v/builder/generics.v deleted file mode 100644 index 199e52bba7..0000000000 --- a/vlib/v/builder/generics.v +++ /dev/null @@ -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 - } - } -} diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 13bf6828d4..f8cd2a40fe 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -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) } - -// 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 -} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index cd1ae0583c..5a67b16f74 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) } 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.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() if rts.info.generic_types.len == generic_types.len { for i, _ in fields { - if t_typ := c.resolve_generic_by_types(fields[i].typ, rts.info.generic_types, - generic_types) + if t_typ := c.table.resolve_generic_by_types(fields[i].typ, + rts.info.generic_types, generic_types) { 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 param.typ.has_flag(.generic) && 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) { 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) } 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 return typ } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 4e4861a873..4143502fbe 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -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 + } + } +}