From 81b44dc2c96d20bdc7ebe69438d68b1cb84503fd Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 29 May 2020 04:30:00 +0200 Subject: [PATCH] generics: generic call inside generic call; checker: check mut args at call --- examples/vweb/vweb_example.v | 2 +- vlib/sync/pool.v | 2 +- vlib/v/checker/checker.v | 14 +++++++++++++ vlib/v/gen/cgen.v | 38 +++++++++++++++--------------------- vlib/v/gen/fn.v | 7 +++++++ vlib/v/parser/fn.v | 10 ++++++++-- vlib/v/table/table.v | 2 +- vlib/v/tests/generics_test.v | 2 +- vlib/vweb/vweb.v | 2 +- 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/examples/vweb/vweb_example.v b/examples/vweb/vweb_example.v index 9bbdd0ee15..6fea04f88b 100644 --- a/examples/vweb/vweb_example.v +++ b/examples/vweb/vweb_example.v @@ -17,7 +17,7 @@ fn main() { vweb.run(port) } -pub fn (mut app App) init() { +pub fn (app App) init() { app.vweb.handle_static('.') } diff --git a/vlib/sync/pool.v b/vlib/sync/pool.v index 8cbaf79b13..52ed9b08e9 100644 --- a/vlib/sync/pool.v +++ b/vlib/sync/pool.v @@ -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() } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 0d3a2077de..8caa823346 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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()) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index ca6a4b31b5..fcf8f36c17 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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 { diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 47512ccca4..4c43023ff2 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -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) +} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index c576ab129b..3fe6476efd 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -30,9 +30,15 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp // `foo(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()` + // 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() diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index b0a876c5d8..417247e3f0 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -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 } diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index c03b9f0662..523b396039 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -210,6 +210,6 @@ fn test_generic_fn_with_variadics(){ p(s) p(i) p(abc) - p('Good','morning','world') + p('Good', 'morning', 'world') } */ diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index e753a77f06..9772108f16 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -142,7 +142,7 @@ pub fn run(port int) { //app.reset() for { conn := l.accept() or { panic('accept() failed') } - handle_conn(conn, mut app) + handle_conn(conn, mut app) //foobar() // TODO move this to handle_conn(conn, app) //message := readall(conn)