v: simplify handling of function generic parameters (#9673)
parent
78c6e35bde
commit
a2a18ef92c
|
@ -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:
|
||||||
|
|
|
@ -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(', ')
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue