diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 7e00250f8e..f190f09c6f 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -113,6 +113,7 @@ pub enum TypeFlag { generic shared_f atomic_f + option_mut_param_t } /* diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 80b6845a2a..836dcaad48 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -610,10 +610,16 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { if op_overloaded { g.op_arg(left, op_expected_left, var_type) } else { - if !is_decl && left.is_auto_deref_var() { + if !is_decl && left.is_auto_deref_var() && !var_type.has_flag(.option) { g.write('*') } - g.expr(left) + if var_type.has_flag(.option_mut_param_t) { + g.write('memcpy(&') + g.expr(left) + g.write('->data, &') + } else { + g.expr(left) + } if !is_decl && var_type.has_flag(.shared_f) { g.write('->val') // don't reset the mutex, just change the value } @@ -630,7 +636,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { if is_decl { g.writeln(';') } - } else if !g.is_arraymap_set && !str_add && !op_overloaded { + } else if !var_type.has_flag(.option_mut_param_t) && !g.is_arraymap_set && !str_add && !op_overloaded { g.write(' ${op} ') } else if str_add || op_overloaded { g.write(', ') @@ -739,6 +745,9 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { if str_add || op_overloaded { g.write(')') } + if var_type.has_flag(.option_mut_param_t) { + g.write('.data, sizeof(${g.base_type(val_type)}))') + } if g.is_arraymap_set { g.write(' })') g.is_arraymap_set = false diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 9df74aff80..5d3c47adbe 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -112,7 +112,8 @@ fn (mut g Gen) final_gen_str(typ StrType) { } g.str_fn_names << str_fn_name if typ.typ.has_flag(.option) { - g.gen_str_for_option(typ.typ, styp, str_fn_name) + opt_typ := if typ.typ.has_flag(.option_mut_param_t) { styp.replace('*', '') } else { styp } + g.gen_str_for_option(typ.typ, opt_typ, str_fn_name) return } if typ.typ.has_flag(.result) { @@ -185,7 +186,7 @@ fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string) g.auto_str_funcs.writeln('string indent_${str_fn_name}(${styp} it, int indent_count) {') g.auto_str_funcs.writeln('\tstring res;') g.auto_str_funcs.writeln('\tif (it.state == 0) {') - deref := if typ.is_ptr() { '**(${sym.cname}**)&' } else { '*(${sym.cname}*)' } + deref := if typ.is_ptr() && !typ.has_flag(.option_mut_param_t) { '**(${sym.cname}**)&' } else { '*(${sym.cname}*)' } if sym.kind == .string { if typ.nr_muls() > 1 { g.auto_str_funcs.writeln('\t\tres = ptr_str(*(${sym.cname}**)&it.data);') diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index b34886a590..160f27b786 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1076,7 +1076,7 @@ fn (mut g Gen) option_type_name(t ast.Type) (string, string) { } else { styp = '${c.option_name}_${base}' } - if t.is_ptr() { + if t.is_ptr() && !t.has_flag(.option_mut_param_t) { styp = styp.replace('*', '_ptr') } return styp, base @@ -1160,7 +1160,7 @@ fn (mut g Gen) write_options() { done = g.done_options.clone() } for base, styp in g.options { - if base in done { + if base in done || styp.ends_with('*') { continue } done << base @@ -1947,7 +1947,12 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T ret_styp := g.typ(g.unwrap_generic(ret_typ)).replace('*', '_ptr') g.writeln('${ret_styp} ${tmp_var};') } else { - g.writeln('${g.typ(ret_typ)} ${tmp_var};') + if ret_typ.has_flag(.option_mut_param_t) { + styp = styp.replace('*', '') + g.writeln('${g.typ(ret_typ).replace('*', '')} ${tmp_var};') + } else { + g.writeln('${g.typ(ret_typ)} ${tmp_var};') + } } if ret_typ.has_flag(.option) { if expr_typ.has_flag(.option) && expr in [ast.StructInit, ast.ArrayInit, ast.MapInit] { @@ -1969,7 +1974,7 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T } else { g.write('_option_ok(&(${styp}[]) { ') } - if !expr_typ.is_ptr() && ret_typ.is_ptr() { + if !expr_typ.is_ptr() && ret_typ.is_ptr() && !ret_typ.has_flag(.option_mut_param_t) { g.write('&/*ref*/') } } diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index a49a5a5116..ec6cecd310 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -71,6 +71,9 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) { } else { old_inside_opt_or_res := g.inside_opt_or_res g.inside_opt_or_res = true + if expr_type.has_flag(.option_mut_param_t) { + g.write('*') + } g.expr(node.expr) g.inside_opt_or_res = old_inside_opt_or_res } @@ -106,7 +109,11 @@ fn (mut g Gen) dump_expr_definitions() { } else { if typ.has_flag(.option) { str_dumparg_type += '_option_' - ptr_asterisk = ptr_asterisk.replace('*', '_ptr') + if typ.has_flag(.option_mut_param_t) { + ptr_asterisk = ptr_asterisk.replace('*', '') + } else { + ptr_asterisk = ptr_asterisk.replace('*', '_ptr') + } } str_dumparg_type += g.cc_type(dump_type, true) + ptr_asterisk } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 35b07e8149..52064a4e3a 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -2210,6 +2210,9 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as && lang != .c { if arg.expr.is_lvalue() { if expected_type.has_flag(.option) { + if expected_type.has_flag(.option_mut_param_t) { + g.write('&/*opt-mut*/') + } g.expr_with_opt(arg.expr, arg_typ, expected_type) return } else { @@ -2250,6 +2253,9 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as g.write('->val') return } else if expected_type.has_flag(.option) { + if expected_type.has_flag(.option_mut_param_t) { + g.write('&/*opt-mut*/') + } g.expr_with_opt(arg.expr, arg_typ, expected_type) return } else if arg.expr is ast.ArrayInit { diff --git a/vlib/v/gen/c/str.v b/vlib/v/gen/c/str.v index e07b732be5..fd49e56248 100644 --- a/vlib/v/gen/c/str.v +++ b/vlib/v/gen/c/str.v @@ -127,7 +127,11 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) { if str_method_expects_ptr && !is_ptr { g.write('&') } else if is_ptr && typ.has_flag(.option) { - g.write('*(${g.typ(typ)}*)&') + if typ.has_flag(.option_mut_param_t) { + g.write('*') + } else { + g.write('*(${g.typ(typ)}*)&') + } } else if !str_method_expects_ptr && !is_shared && (is_ptr || is_var_mut) { g.write('*'.repeat(typ.nr_muls())) } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index a16034b4d8..04edd00c2f 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -913,6 +913,9 @@ fn (mut p Parser) fn_params() ([]ast.Param, bool, bool) { // p.error('cannot mut') // } // arg_type = arg_type.ref() + if param_type.has_flag(.option) && param_type.nr_muls() == 0 { + param_type = param_type.set_flag(.option_mut_param_t) + } param_type = param_type.set_nr_muls(1) if is_shared { param_type = param_type.set_flag(.shared_f) @@ -1025,6 +1028,9 @@ fn (mut p Parser) fn_params() ([]ast.Param, bool, bool) { pos) return []ast.Param{}, false, false } + if typ.has_flag(.option) && typ.nr_muls() == 0 { + typ = typ.set_flag(.option_mut_param_t) + } typ = typ.set_nr_muls(1) if is_shared { typ = typ.set_flag(.shared_f)