generics: generic call inside generic call; checker: check mut args at call
							parent
							
								
									f0a9b88ac4
								
							
						
					
					
						commit
						81b44dc2c9
					
				|  | @ -17,7 +17,7 @@ fn main() { | |||
| 	vweb.run<App>(port) | ||||
| } | ||||
| 
 | ||||
| pub fn (mut app App) init() { | ||||
| pub fn (app App) init() { | ||||
| 	app.vweb.handle_static('.') | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ pub fn (mut pool PoolProcessor) work_on_pointers(items []voidptr) { | |||
| 	pool.thread_contexts << [voidptr(0)].repeat(pool.items.len) | ||||
| 	pool.waitgroup.add(njobs) | ||||
| 	for i := 0; i < njobs; i++ { | ||||
| 		go process_in_thread(pool,i) | ||||
| 		go process_in_thread(mut pool,i) | ||||
| 	} | ||||
| 	pool.waitgroup.wait() | ||||
| } | ||||
|  |  | |||
|  | @ -860,6 +860,16 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { | |||
| 		// TODO: impl typeof properly (probably not going to be a fn call)
 | ||||
| 		return table.string_type | ||||
| 	} | ||||
| 	if call_expr.generic_type == table.t_type { | ||||
| 		if c.mod != '' && c.mod != 'main' { | ||||
| 			// Need to prepend the module when adding a generic type to a function
 | ||||
| 			// `fn_gen_types['mymod.myfn'] == ['string', 'int']`
 | ||||
| 			c.table.register_fn_gen_type(c.mod + '.' + fn_name, c.cur_generic_type) | ||||
| 		} else { | ||||
| 			c.table.register_fn_gen_type(fn_name, c.cur_generic_type) | ||||
| 		} | ||||
| 		// call_expr.generic_type = c.unwrap_generic(call_expr.generic_type)
 | ||||
| 	} | ||||
| 	// if c.fileis('json_test.v') {
 | ||||
| 	// println(fn_name)
 | ||||
| 	// }
 | ||||
|  | @ -984,6 +994,10 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { | |||
| 		if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i { | ||||
| 			c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) | ||||
| 		} | ||||
| 		if arg.is_mut && !call_arg.is_mut { | ||||
| 			c.error('`$arg.name` is a mutable argument, you need to provide `mut`: `${call_expr.name}(mut ...)`', | ||||
| 				call_arg.expr.position()) | ||||
| 		} | ||||
| 		// Handle expected interface
 | ||||
| 		if arg_typ_sym.kind == .interface_ { | ||||
| 			c.type_implements(typ, arg.typ, call_arg.expr.position()) | ||||
|  |  | |||
|  | @ -384,8 +384,10 @@ typedef struct { | |||
| 			.alias { | ||||
| 				parent := &g.table.types[typ.parent_idx] | ||||
| 				styp := typ.name.replace('.', '__') | ||||
| 				is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.` | ||||
| 				parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.', '__') } | ||||
| 				is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == | ||||
| 					`.` | ||||
| 				parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.', | ||||
| 						'__') } | ||||
| 				g.definitions.writeln('typedef $parent_styp $styp;') | ||||
| 			} | ||||
| 			.array { | ||||
|  | @ -842,7 +844,9 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type) | |||
| 	got_is_ptr := got_type.is_ptr() | ||||
| 	expected_is_ptr := expected_type.is_ptr() | ||||
| 	neither_void := table.voidptr_type !in [got_type, expected_type] | ||||
| 	if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, .placeholder] { | ||||
| 	if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, | ||||
| 		.placeholder | ||||
| 	] { | ||||
| 		got_deref_type := got_type.deref() | ||||
| 		deref_sym := g.table.get_type_symbol(got_deref_type) | ||||
| 		deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx] | ||||
|  | @ -901,7 +905,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { | |||
| 	if return_type != table.void_type && return_type != 0 { | ||||
| 		sym := g.table.get_type_symbol(return_type) | ||||
| 		// the left vs. right is ugly and should be removed
 | ||||
| 		if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len > 1 { | ||||
| 		if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len > | ||||
| 			1 { | ||||
| 			// multi return
 | ||||
| 			// TODO Handle in if_expr
 | ||||
| 			is_optional := return_type.flag_is(.optional) | ||||
|  | @ -1317,6 +1322,9 @@ fn (mut g Gen) expr(node ast.Expr) { | |||
| 		ast.CharLiteral { | ||||
| 			g.write("'$it.val'") | ||||
| 		} | ||||
| 		ast.ComptimeCall { | ||||
| 			g.write('/*c*/') | ||||
| 		} | ||||
| 		ast.ConcatExpr { | ||||
| 			g.concat_expr(it) | ||||
| 		} | ||||
|  | @ -1836,7 +1844,8 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) { | |||
| 		g.writeln('// match 0') | ||||
| 		return | ||||
| 	} | ||||
| 	is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary > 0 | ||||
| 	is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary > | ||||
| 		0 | ||||
| 	if is_expr { | ||||
| 		g.inside_ternary++ | ||||
| 		// g.write('/* EM ret type=${g.typ(node.return_type)}		expected_type=${g.typ(node.expected_type)}  */')
 | ||||
|  | @ -2202,14 +2211,9 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { | |||
| [inline] | ||||
| fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool { | ||||
| 	match expr { | ||||
| 		ast.CallExpr { | ||||
| 			return g.table.get_type_symbol(it.return_type).kind == .multi_return | ||||
| 		} | ||||
| 		else { | ||||
| 			return false | ||||
| 		} | ||||
| 		ast.CallExpr { return g.table.get_type_symbol(it.return_type).kind == .multi_return } | ||||
| 		else { return false } | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| fn (mut g Gen) return_statement(node ast.Return) { | ||||
|  | @ -2247,20 +2251,15 @@ fn (mut g Gen) return_statement(node ast.Return) { | |||
| 		} else { | ||||
| 			styp = g.typ(g.fn_decl.return_type) | ||||
| 		} | ||||
| 
 | ||||
| 		// Use this to keep the tmp assignments in order
 | ||||
| 		mut multi_unpack := '' | ||||
| 
 | ||||
| 
 | ||||
| 		g.write('($styp){') | ||||
| 
 | ||||
| 		mut arg_idx := 0 | ||||
| 		for i, expr in node.exprs { | ||||
| 			// Check if we are dealing with a multi return and handle it seperately
 | ||||
| 			if g.expr_is_multi_return_call(expr) { | ||||
| 				c := expr as ast.CallExpr | ||||
| 				expr_sym := g.table.get_type_symbol(c.return_type) | ||||
| 
 | ||||
| 				// Create a tmp for this call
 | ||||
| 				tmp := g.new_tmp_var() | ||||
| 				s := g.go_before_stmt(0) | ||||
|  | @ -2270,7 +2269,6 @@ fn (mut g Gen) return_statement(node ast.Return) { | |||
| 				g.writeln(';') | ||||
| 				multi_unpack += g.go_before_stmt(0) | ||||
| 				g.write(s) | ||||
| 
 | ||||
| 				expr_types := expr_sym.mr_info().types | ||||
| 				for j, _ in expr_types { | ||||
| 					g.write('.arg$arg_idx=${tmp}.arg$j') | ||||
|  | @ -2279,10 +2277,8 @@ fn (mut g Gen) return_statement(node ast.Return) { | |||
| 					} | ||||
| 					arg_idx++ | ||||
| 				} | ||||
| 
 | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			g.write('.arg$arg_idx=') | ||||
| 			g.expr(expr) | ||||
| 			arg_idx++ | ||||
|  | @ -2291,11 +2287,9 @@ fn (mut g Gen) return_statement(node ast.Return) { | |||
| 			} | ||||
| 		} | ||||
| 		g.write('}') | ||||
| 
 | ||||
| 		if fn_return_is_optional { | ||||
| 			g.write(' }, sizeof($styp))') | ||||
| 		} | ||||
| 
 | ||||
| 		// Make sure to add our unpacks
 | ||||
| 		g.insert_before_stmt(multi_unpack) | ||||
| 	} else if node.exprs.len >= 1 { | ||||
|  |  | |||
|  | @ -12,6 +12,9 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) { | |||
| 		// || it.no_body {
 | ||||
| 		return | ||||
| 	} | ||||
| 	//if g.fileis('vweb.v') {
 | ||||
| 		//println('\ngen_fn_decl() $it.name $it.is_generic $g.cur_generic_type')
 | ||||
| 	//}
 | ||||
| 	former_cur_fn := g.cur_fn | ||||
| 	g.cur_fn = &it | ||||
| 	defer { | ||||
|  | @ -760,3 +763,7 @@ fn (mut g Gen) is_gui_app() bool { | |||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| fn (g &Gen) fileis(s string) bool { | ||||
| 	return g.file.path.contains(s) | ||||
| } | ||||
|  |  | |||
|  | @ -30,9 +30,15 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp | |||
| 		// `foo<int>(10)`
 | ||||
| 		p.next() // `<`
 | ||||
| 		p.expr_mod = '' | ||||
| 		generic_type = p.parse_type() | ||||
| 		mut generic_type = p.parse_type() | ||||
| 		if generic_type == table.t_type { | ||||
| 			// Handle `foo<T>()`
 | ||||
| 			// generic_type = p.cur_gen_type
 | ||||
| 		} | ||||
| 		p.check(.gt) // `>`
 | ||||
| 		p.table.register_fn_gen_type(fn_name, generic_type) | ||||
| 		if generic_type != table.t_type { | ||||
| 			p.table.register_fn_gen_type(fn_name, generic_type) | ||||
| 		} | ||||
| 	} | ||||
| 	p.check(.lpar) | ||||
| 	args := p.call_args() | ||||
|  |  | |||
|  | @ -482,6 +482,6 @@ pub fn (table &Table) register_fn_gen_type(fn_name string, typ Type) { | |||
| 	} | ||||
| 	a << typ | ||||
| 	// sym := table.get_type_symbol(typ)
 | ||||
| 	// println('registering fn gen type $sym.name')
 | ||||
| 	// println('registering fn ($fn_name) gen type $sym.name')
 | ||||
| 	table.fn_gen_types[fn_name] = a | ||||
| } | ||||
|  |  | |||
|  | @ -210,6 +210,6 @@ fn test_generic_fn_with_variadics(){ | |||
| 	p(s) | ||||
| 	p(i) | ||||
| 	p(abc) | ||||
| 	p('Good','morning','world') | ||||
| 	p('Good', 'morning', 'world') | ||||
| } | ||||
| */ | ||||
|  |  | |||
|  | @ -142,7 +142,7 @@ pub fn run<T>(port int) { | |||
| 	//app.reset()
 | ||||
| 	for { | ||||
| 		conn := l.accept() or { panic('accept() failed') } | ||||
| 		handle_conn(conn, mut app) | ||||
| 		handle_conn<T>(conn, mut app) | ||||
| 		//foobar<T>()
 | ||||
| 		// TODO move this to handle_conn<T>(conn, app)
 | ||||
| 		//message := readall(conn)
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue