v: simplify handling of function generic parameters (#9673)

pull/9672/head
yuyi 2021-04-11 14:02:57 +08:00 committed by GitHub
parent 78c6e35bde
commit a2a18ef92c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 26 additions and 38 deletions

View File

@ -373,7 +373,7 @@ pub:
is_builtin bool // this function is defined in builtin/strconv
body_pos token.Position // function bodys position
file string
generic_params []GenericParam
generic_names []string
is_direct_arr bool // direct array access
attrs []Attr
skip_gen bool // this function doesn't need to be generated (for example [if foo])
@ -391,11 +391,6 @@ pub mut:
pos token.Position // function declaration position
}
pub struct GenericParam {
pub:
name string
}
// break, continue
pub struct BranchStmt {
pub:

View File

@ -62,11 +62,11 @@ pub fn (node &FnDecl) stringify(t &Table, cur_mod string, m2a map[string]string)
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
f.write_string(' ')
}
if node.generic_params.len > 0 {
if node.generic_names.len > 0 {
f.write_string('<')
for i, param in node.generic_params {
is_last := i == node.generic_params.len - 1
f.write_string(param.name)
for i, gname in node.generic_names {
is_last := i == node.generic_names.len - 1
f.write_string(gname)
if !is_last {
f.write_string(', ')
}

View File

@ -360,7 +360,7 @@ pub fn (mut c Checker) symmetric_check(left ast.Type, right ast.Type) bool {
return c.check_basic(left, right)
}
pub fn (c &Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) byte {
pub fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) byte {
if ftyp.has_flag(.optional) {
return `s`
} else if typ.is_float() {
@ -521,7 +521,7 @@ pub fn (mut c Checker) infer_fn_types(f ast.Fn, mut call_expr ast.CallExpr) {
mut param_elem_sym := c.table.get_type_symbol(param_elem_info.elem_type)
for {
if arg_elem_sym.kind == .array && param_elem_sym.kind == .array
&& c.cur_fn.generic_params.filter(it.name == param_elem_sym.name).len == 0 {
&& param_elem_sym.name !in c.cur_fn.generic_names {
arg_elem_info = arg_elem_sym.info as ast.Array
arg_elem_sym = c.table.get_type_symbol(arg_elem_info.elem_type)
param_elem_info = param_elem_sym.info as ast.Array

View File

@ -514,7 +514,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
struct_init.pos)
}
}
if type_sym.name.len == 1 && c.cur_fn.generic_params.len == 0 {
if type_sym.name.len == 1 && c.cur_fn.generic_names.len == 0 {
c.error('unknown struct `$type_sym.name`', struct_init.pos)
return 0
}
@ -2495,8 +2495,7 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) ast.Typ
match mut selector_expr.expr {
ast.Ident {
name := selector_expr.expr.name
valid_generic := util.is_generic_type_name(name)
&& c.cur_fn.generic_params.filter(it.name == name).len != 0
valid_generic := util.is_generic_type_name(name) && name in c.cur_fn.generic_names
if valid_generic {
name_type = ast.Type(c.table.find_type_idx(name)).set_flag(.generic)
}
@ -4051,13 +4050,10 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
c.expected_type = ast.void_type
}
pub fn (c &Checker) unwrap_generic(typ ast.Type) ast.Type {
pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
if typ.has_flag(.generic) {
sym := c.table.get_type_symbol(typ)
for i, generic_param in c.cur_fn.generic_params {
if generic_param.name == sym.name {
return c.cur_generic_types[i].derive(typ).clear_flag(.generic)
}
if t_typ := c.table.resolve_generic_by_names(typ, c.cur_fn.generic_names, c.cur_generic_types) {
return t_typ
}
}
return typ
@ -6332,7 +6328,7 @@ fn (mut c Checker) post_process_generic_fns() {
fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.returns = false
if node.generic_params.len > 0 && c.cur_generic_types.len == 0 {
if node.generic_names.len > 0 && c.cur_generic_types.len == 0 {
// Just remember the generic function for now.
// It will be processed later in c.post_process_generic_fns,
// after all other normal functions are processed.

View File

@ -687,7 +687,7 @@ static inline Option_void __Option_${styp}_pushval($styp ch, $el_type e) {
}
// cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo)
fn (g &Gen) cc_type(typ ast.Type, is_prefix_struct bool) string {
fn (mut g Gen) cc_type(typ ast.Type, is_prefix_struct bool) string {
sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut styp := sym.cname
// TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker)

View File

@ -64,7 +64,7 @@ fn (mut g Gen) process_fn_decl(node ast.FnDecl) {
// We are using prebuilt modules, we do not need to generate
// their functions in main.c.
if node.mod != 'main' && node.mod != 'help' && !should_bundle_module && !g.pref.is_test
&& node.generic_params.len == 0 {
&& node.generic_names.len == 0 {
skip = true
}
}
@ -127,7 +127,7 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
// if g.fileis('vweb.v') {
// println('\ngen_fn_decl() $node.name $node.is_generic $g.cur_generic_type')
// }
if node.generic_params.len > 0 && g.cur_generic_types.len == 0 { // need the cur_generic_type check to avoid inf. recursion
if node.generic_names.len > 0 && g.cur_generic_types.len == 0 { // need the cur_generic_type check to avoid inf. recursion
// loop thru each generic type and generate a function
for gen_types in g.table.fn_gen_types[node.name] {
if g.pref.is_verbose {
@ -475,13 +475,10 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
}
}
pub fn (g &Gen) unwrap_generic(typ ast.Type) ast.Type {
pub fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
if typ.has_flag(.generic) {
sym := g.table.get_type_symbol(typ)
for i, generic_param in g.cur_fn.generic_params {
if generic_param.name == sym.name {
return g.cur_generic_types[i].derive(typ).clear_flag(.generic)
}
if t_typ := g.table.resolve_generic_by_names(typ, g.cur_fn.generic_names, g.cur_generic_types) {
return t_typ
}
}
return typ

View File

@ -274,7 +274,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
}
}
// <T>
generic_params := p.parse_generic_params()
generic_names := p.parse_generic_names()
// Args
args2, are_args_type_only, is_variadic := p.fn_args()
params << args2
@ -338,7 +338,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
params: params
return_type: return_type
is_variadic: is_variadic
generic_names: generic_params.map(it.name)
generic_names: generic_names
is_pub: is_pub
is_deprecated: is_deprecated
is_unsafe: is_unsafe
@ -367,7 +367,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
params: params
return_type: return_type
is_variadic: is_variadic
generic_names: generic_params.map(it.name)
generic_names: generic_names
is_pub: is_pub
is_deprecated: is_deprecated
is_unsafe: is_unsafe
@ -422,7 +422,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
name: rec.name
typ: rec.typ
}
generic_params: generic_params
generic_names: generic_names
receiver_pos: rec.pos
is_method: is_method
method_type_pos: rec.type_pos
@ -517,10 +517,10 @@ fn (mut p Parser) fn_receiver(mut params []ast.Param, mut rec ReceiverParsingInf
return
}
fn (mut p Parser) parse_generic_params() []ast.GenericParam {
fn (mut p Parser) parse_generic_names() []string {
mut param_names := []string{}
if p.tok.kind != .lt {
return []ast.GenericParam{}
return param_names
}
p.check(.lt)
mut first_done := false
@ -551,7 +551,7 @@ fn (mut p Parser) parse_generic_params() []ast.GenericParam {
count++
}
p.check(.gt)
return param_names.map(ast.GenericParam{it})
return param_names
}
// is_generic_name returns true if the current token is a generic name.