From ab279dace7a1cfe43941209101b6661fd1e02ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Sat, 6 Feb 2021 03:07:05 +0100 Subject: [PATCH] cgen: support `shared` initialization from call returning optional (#8593) --- vlib/v/gen/c/cgen.v | 37 ++++++++++++++------- vlib/v/tests/shared_fn_return_test.v | 48 ++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 vlib/v/tests/shared_fn_return_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 0f108e2059..be17006b9a 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -49,6 +49,7 @@ mut: hotcode_definitions strings.Builder // -live declarations & functions embedded_data strings.Builder // data to embed in the executable/binary shared_types strings.Builder // shared/lock types + shared_functions strings.Builder // shared constructors channel_definitions strings.Builder // channel related code options_typedefs strings.Builder // Option typedefs options strings.Builder // `Option_xxxx` types @@ -78,6 +79,7 @@ mut: inside_map_postfix bool // inside map++/-- postfix expr inside_map_infix bool // inside map< 0 { - b.writeln('\n// V shared types:') - b.write(g.shared_types.str()) + if g.shared_functions.len > 0 { + b.writeln('\n// V shared type functions:') + b.write(g.shared_functions.str()) b.write(c_concurrency_helpers) } if g.channel_definitions.len > 0 { @@ -594,11 +599,11 @@ fn (mut g Gen) find_or_register_shared(t table.Type, base string) string { } mtx_typ := 'sync__RwMutex' g.shared_types.writeln('struct $sh_typ { $base val; $mtx_typ mtx; };') - g.shared_types.writeln('static inline voidptr __dup${sh_typ}(voidptr src, int sz) {') - g.shared_types.writeln('\t$sh_typ* dest = memdup(src, sz);') - g.shared_types.writeln('\tsync__RwMutex_init(&dest->mtx);') - g.shared_types.writeln('\treturn dest;') - g.shared_types.writeln('}') + g.shared_functions.writeln('static inline voidptr __dup${sh_typ}(voidptr src, int sz) {') + g.shared_functions.writeln('\t$sh_typ* dest = memdup(src, sz);') + g.shared_functions.writeln('\tsync__RwMutex_init(&dest->mtx);') + g.shared_functions.writeln('\treturn dest;') + g.shared_functions.writeln('}') g.typedefs2.writeln('typedef struct $sh_typ $sh_typ;') // println('registered shared type $sh_typ') g.shareds << t_idx @@ -2532,10 +2537,15 @@ fn (mut g Gen) expr(node ast.Expr) { // if g.fileis('1.strings') { // println('\ncall_expr()()') // } + ret_type := if node.or_block.kind == .absent { + node.return_type + } else { + node.return_type.clear_flag(.optional) + } mut shared_styp := '' if g.is_shared { - ret_sym := g.table.get_type_symbol(node.return_type) - shared_typ := node.return_type.set_flag(.shared_f) + ret_sym := g.table.get_type_symbol(ret_type) + shared_typ := ret_type.set_flag(.shared_f) shared_styp = g.typ(shared_typ) if ret_sym.kind == .array { g.writeln('($shared_styp*)__dup_shared_array(&($shared_styp){.val = ') @@ -4840,7 +4850,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { if is_amp { g.out.go_back(1) // delete the `&` already generated in `prefix_expr() } - if g.is_shared { + if g.is_shared && !g.inside_opt_data { mut shared_typ := struct_init.typ.set_flag(.shared_f) shared_styp = g.typ(shared_typ) g.writeln('($shared_styp*)__dup${shared_styp}(&($shared_styp){.val = ($styp){') @@ -5012,7 +5022,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { g.write('\n#ifndef __cplusplus\n0\n#endif\n') } g.write('}') - if g.is_shared { + if g.is_shared && !g.inside_opt_data { g.write('}, sizeof($shared_styp))') } else if is_amp { g.write(', sizeof($styp))') @@ -5437,7 +5447,10 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table. expr_stmt := stmt as ast.ExprStmt g.stmt_path_pos << g.out.len g.write('*($mr_styp*) ${cvar_name}.data = ') + old_inside_opt_data := g.inside_opt_data + g.inside_opt_data = true g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_flag(.optional)) + g.inside_opt_data = old_inside_opt_data if g.inside_ternary == 0 && !(expr_stmt.expr is ast.IfExpr) { g.writeln(';') } diff --git a/vlib/v/tests/shared_fn_return_test.v b/vlib/v/tests/shared_fn_return_test.v new file mode 100644 index 0000000000..3c5740abd8 --- /dev/null +++ b/vlib/v/tests/shared_fn_return_test.v @@ -0,0 +1,48 @@ +struct St { +mut: + x f64 +} + +fn f() St { + x := St{ x: 3.25 } + return x +} + +fn g(good bool) ?St { + if !good { + return error('no St created') + } + x := St{ x: 12.75 } + return x +} + +fn test_shared_fn_return() { + shared x := f() + val := rlock x { x.x } + assert val == 3.25 +} + +fn shared_opt_propagate(good bool) ?f64 { + shared x := g(good) ? + ret := rlock x { x.x } + return ret +} + +fn test_shared_opt_propagate() { + x := shared_opt_propagate(true) or { 1.25 } + y := shared_opt_propagate(false) or { 2.125 } + assert x == 12.75 + assert y == 2.125 +} + +fn test_shared_opt_good() { + shared yy := g(true) or { St{ x: 37.5 } } + val := rlock yy { yy.x } + assert val == 12.75 +} + +fn test_shared_opt_bad() { + shared yy := g(false) or { St{ x: 37.5 } } + val := rlock yy { yy.x } + assert val == 37.5 +}