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

View File

@ -62,11 +62,11 @@ pub fn (node &FnDecl) stringify(t &Table, cur_mod string, m2a map[string]string)
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] { if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
f.write_string(' ') f.write_string(' ')
} }
if node.generic_params.len > 0 { if node.generic_names.len > 0 {
f.write_string('<') f.write_string('<')
for i, param in node.generic_params { for i, gname in node.generic_names {
is_last := i == node.generic_params.len - 1 is_last := i == node.generic_names.len - 1
f.write_string(param.name) f.write_string(gname)
if !is_last { if !is_last {
f.write_string(', ') 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) 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) { if ftyp.has_flag(.optional) {
return `s` return `s`
} else if typ.is_float() { } 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) mut param_elem_sym := c.table.get_type_symbol(param_elem_info.elem_type)
for { for {
if arg_elem_sym.kind == .array && param_elem_sym.kind == .array 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_info = arg_elem_sym.info as ast.Array
arg_elem_sym = c.table.get_type_symbol(arg_elem_info.elem_type) arg_elem_sym = c.table.get_type_symbol(arg_elem_info.elem_type)
param_elem_info = param_elem_sym.info as ast.Array 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) 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) c.error('unknown struct `$type_sym.name`', struct_init.pos)
return 0 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 { match mut selector_expr.expr {
ast.Ident { ast.Ident {
name := selector_expr.expr.name name := selector_expr.expr.name
valid_generic := util.is_generic_type_name(name) valid_generic := util.is_generic_type_name(name) && name in c.cur_fn.generic_names
&& c.cur_fn.generic_params.filter(it.name == name).len != 0
if valid_generic { if valid_generic {
name_type = ast.Type(c.table.find_type_idx(name)).set_flag(.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 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) { if typ.has_flag(.generic) {
sym := c.table.get_type_symbol(typ) if t_typ := c.table.resolve_generic_by_names(typ, c.cur_fn.generic_names, c.cur_generic_types) {
for i, generic_param in c.cur_fn.generic_params { return t_typ
if generic_param.name == sym.name {
return c.cur_generic_types[i].derive(typ).clear_flag(.generic)
}
} }
} }
return 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) { fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.returns = false 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. // Just remember the generic function for now.
// It will be processed later in c.post_process_generic_fns, // It will be processed later in c.post_process_generic_fns,
// after all other normal functions are processed. // 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) // 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)) sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut styp := sym.cname mut styp := sym.cname
// TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker) // 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 // We are using prebuilt modules, we do not need to generate
// their functions in main.c. // their functions in main.c.
if node.mod != 'main' && node.mod != 'help' && !should_bundle_module && !g.pref.is_test 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 skip = true
} }
} }
@ -127,7 +127,7 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
// if g.fileis('vweb.v') { // if g.fileis('vweb.v') {
// println('\ngen_fn_decl() $node.name $node.is_generic $g.cur_generic_type') // 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 // loop thru each generic type and generate a function
for gen_types in g.table.fn_gen_types[node.name] { for gen_types in g.table.fn_gen_types[node.name] {
if g.pref.is_verbose { 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) { if typ.has_flag(.generic) {
sym := g.table.get_type_symbol(typ) if t_typ := g.table.resolve_generic_by_names(typ, g.cur_fn.generic_names, g.cur_generic_types) {
for i, generic_param in g.cur_fn.generic_params { return t_typ
if generic_param.name == sym.name {
return g.cur_generic_types[i].derive(typ).clear_flag(.generic)
}
} }
} }
return typ return typ

View File

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