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
 | ||||
| 	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: | ||||
|  |  | |||
|  | @ -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(', ') | ||||
| 			} | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  |  | |||
|  | @ -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)
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue