From 74ae8870e8bfe0e62b00596838419003e9e88f6f Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Sun, 17 Aug 2025 06:48:09 +0800 Subject: [PATCH] cgen: fix mutable sumtype (fix #25108) (#25111) --- vlib/v/gen/c/cgen.v | 31 ++++++++-------- vlib/v/gen/c/json.v | 36 +++++++++---------- .../tests/sumtypes/sumtype_arg_mutable_test.v | 18 +++++----- vlib/v/tests/sumtypes/sumtype_mutable_test.v | 12 +++---- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 50bf954ec..66be4430f 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2805,9 +2805,10 @@ fn (mut g Gen) write_sumtype_casting_fn(fun SumtypeCastingFn) { } else { // g.definitions.writeln('${g.static_modifier} inline ${exp_cname} ${fun.fn_name}(${got_cname}* x);') // sb.writeln('${g.static_modifier} inline ${exp_cname} ${fun.fn_name}(${got_cname}* x) {') - g.definitions.writeln('${exp_cname} ${fun.fn_name}(${got_cname}* x);') - sb.writeln('${exp_cname} ${fun.fn_name}(${got_cname}* x) {') - sb.writeln('\t${got_cname}* ptr = memdup(x, sizeof(${got_cname}));') + g.definitions.writeln('${exp_cname} ${fun.fn_name}(${got_cname}* x, bool is_mut);') + sb.writeln('${exp_cname} ${fun.fn_name}(${got_cname}* x, bool is_mut) {') + sb.writeln('\t${got_cname}* ptr = x;') + sb.writeln('\tif (!is_mut) { ptr = memdup(x, sizeof(${got_cname})); }') } for embed_hierarchy in g.table.get_embeds(got_sym) { // last embed in the hierarchy @@ -2853,19 +2854,14 @@ fn (mut g Gen) write_sumtype_casting_fn(fun SumtypeCastingFn) { fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Type, got ast.Type, exp_styp string, got_is_ptr bool, got_is_fn bool, got_styp string) { mut rparen_n := 1 - mut mutable_idx := 0 + mut mutable_is_mut_arg_pos := 0 is_not_ptr_and_fn := !got_is_ptr && !got_is_fn is_sumtype_cast := !got_is_fn && fname.contains('_to_sumtype_') is_comptime_variant := is_not_ptr_and_fn && expr is ast.Ident && g.comptime.is_comptime_variant_var(expr) if exp.is_ptr() { - if $d('mutable_sumtype', false) && is_sumtype_cast && g.expected_arg_mut - && expr is ast.Ident { - g.write('&(${exp_styp.trim_right('*')}){._${got_styp.trim_right('*')}=') - rparen_n = 0 - mutable_idx = got.idx() - } else if (expr is ast.UnsafeExpr && expr.expr is ast.Nil) || got == ast.nil_type { + if (expr is ast.UnsafeExpr && expr.expr is ast.Nil) || got == ast.nil_type { g.write('(void*)0') return } else { @@ -2875,6 +2871,7 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty } else { g.write('${fname}(') } + mutable_is_mut_arg_pos = rparen_n if is_not_ptr_and_fn { is_cast_fixed_array_init := expr is ast.CastExpr && (expr.expr is ast.ArrayInit && expr.expr.is_fixed) @@ -2915,10 +2912,14 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty g.expr(expr) g.left_is_opt = old_left_is_opt } - if mutable_idx != 0 { - g.write(', ._typ=${mutable_idx}}') + if is_sumtype_cast { + // the `_to_sumtype_` family of functions last `is_mut` param + g.write(')'.repeat(rparen_n - mutable_is_mut_arg_pos)) + g.write(', ${exp.is_ptr()}') + g.write(')'.repeat(mutable_is_mut_arg_pos)) + } else { + g.write(')'.repeat(rparen_n)) } - g.write(')'.repeat(rparen_n)) } // use instead of expr() when you need a var to use as reference @@ -3100,7 +3101,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ g.expr(expr) g.writeln(';') g.write2(stmt_str, ' ') - g.write('${fname}(&${tmp_var})') + g.write('${fname}(&${tmp_var}, ${unwrapped_expected_type.is_ptr()})') return } else { g.call_cfn_for_casting_expr(fname, expr, expected_type, got_type, @@ -3505,7 +3506,7 @@ fn (mut g Gen) gen_clone_assignment(var_type ast.Type, val ast.Expr, typ ast.Typ g.write('}, sizeof(${shared_styp}))') } if is_sumtype { - g.write('))') + g.write('), false)') } } else if right_sym.kind == .string { // `str1 = str2` => `str1 = str2.clone()` diff --git a/vlib/v/gen/c/json.v b/vlib/v/gen/c/json.v index cf40af089..db30ad49b 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -381,8 +381,8 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st if fv_sym.kind == .struct && !is_option && field_op != '->' { dec.writeln('\tif (root->type == cJSON_NULL) { ') dec.writeln('\t\tstruct ${first_variant_name} empty = {0};') - dec.writeln('res = ${variant_typ}_to_sumtype_${ret_styp}(&empty); } \n else ') - // dec.writeln('res = ${variant_typ}_to_sumtype_${sym.cname}(&empty); } \n else ') + dec.writeln('res = ${variant_typ}_to_sumtype_${ret_styp}(&empty, false); } \n else ') + // dec.writeln('res = ${variant_typ}_to_sumtype_${sym.cname}(&empty, false); } \n else ') } // dec.writeln('if (cJSON_IsObject(root) || (cJSON_IsArray(root) && cJSON_IsObject(root->child))) {') @@ -409,7 +409,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st // Helpers for decoding g.get_sumtype_casting_fn(variant, typ) - g.definitions.writeln('static inline ${sym.cname} ${variant_typ}_to_sumtype_${sym.cname}(${variant_typ}* x);') + g.definitions.writeln('static inline ${sym.cname} ${variant_typ}_to_sumtype_${sym.cname}(${variant_typ}* x, bool is_mut);') // ENCODING enc.writeln('\tif (${var_data}${field_op}_typ == ${int(variant.idx())}) {') @@ -485,9 +485,9 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st dec.writeln('\t\t${variant_typ} value = *(${variant_typ}*)(${tmp}.data);') } if is_option { - dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}(&value) }, (${option_name}*)&res, sizeof(${sym.cname}));') + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}(&value, false) }, (${option_name}*)&res, sizeof(${sym.cname}));') } else { - dec.writeln('\t\tres = ${variant_typ}_to_sumtype_${ret_styp}(&value);') + dec.writeln('\t\tres = ${variant_typ}_to_sumtype_${ret_styp}(&value, false);') } dec.writeln('\t}') } $else { @@ -498,10 +498,10 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st if utyp.has_flag(.option) { dec.writeln('\t\t\t\t${prefix}res.state = 0;') tmp_time_var := g.new_tmp_var() - dec.writeln('\t\t\t\t${g.base_type(utyp)} ${tmp_time_var} = ${variant_typ}_to_sumtype_${sym.cname}(&${tmp});') + dec.writeln('\t\t\t\t${g.base_type(utyp)} ${tmp_time_var} = ${variant_typ}_to_sumtype_${sym.cname}(&${tmp}, false);') dec.writeln('\t\t\t\tvmemcpy(&${prefix}res.data, ${tmp_time_var}._time__Time, sizeof(${variant_typ}));') } else { - dec.writeln('\t\t\t\t${prefix}res = ${variant_typ}_to_sumtype_${sym.cname}(&${tmp});') + dec.writeln('\t\t\t\t${prefix}res = ${variant_typ}_to_sumtype_${sym.cname}(&${tmp}, false);') } dec.writeln('\t\t\t}') } else if !is_js_prim(variant_typ) && variant_sym.kind != .enum { @@ -512,9 +512,9 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st dec.writeln('\t\t\t\t\treturn (${result_name}_${ret_styp}){ .is_error = true, .err = ${tmp}.err, .data = {0} };') dec.writeln('\t\t\t\t}') if is_option { - dec.writeln('\t\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}((${variant_typ}*)${tmp}.data) }, (${option_name}*)&res, sizeof(${sym.cname}));') + dec.writeln('\t\t\t\t_option_ok(&(${sym.cname}[]){ ${variant_typ}_to_sumtype_${sym.cname}((${variant_typ}*)${tmp}.data, false) }, (${option_name}*)&res, sizeof(${sym.cname}));') } else { - dec.writeln('\t\t\t\t${prefix}res = ${variant_typ}_to_sumtype_${sym.cname}((${variant_typ}*)${tmp}.data);') + dec.writeln('\t\t\t\t${prefix}res = ${variant_typ}_to_sumtype_${sym.cname}((${variant_typ}*)${tmp}.data, false);') } dec.writeln('\t\t\t}') } @@ -536,7 +536,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st var_t := 'bool' dec.writeln('\t\tif (cJSON_IsBool(root)) {') dec.writeln('\t\t\t${var_t} value = ${js_dec_name(var_t)}(root);') - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value, false);') dec.writeln('\t\t}') } @@ -552,9 +552,9 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st dec.writeln('\t\tif (cJSON_IsNumber(root)) {') dec.writeln('\t\t\t${var_t} value = ${js_dec_name('u64')}(root);') if utyp.has_flag(.option) { - dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value, false) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') } else { - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value, false);') } dec.writeln('\t\t}') } @@ -568,9 +568,9 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st dec.writeln('\t\tif (cJSON_IsString(root)) {') dec.writeln('\t\t\t${var_t} value = ${js_dec_name(var_t)}(root);') if utyp.has_flag(.option) { - dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value, false) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') } else { - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value, false);') } dec.writeln('\t\t}') } @@ -592,9 +592,9 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st dec.writeln('\t\t\t\treturn (${result_name}_${ret_styp}){ .is_error = true, .err = ${tmp}.err, .data = {0} };') dec.writeln('\t\t\t}') if utyp.has_flag(.option) { - dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}((${var_t}*)${tmp}.data) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}((${var_t}*)${tmp}.data, false) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') } else { - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}((${var_t}*)${tmp}.data);') + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}((${var_t}*)${tmp}.data, false);') } dec.writeln('\t\t}') } @@ -611,9 +611,9 @@ fn (mut g Gen) gen_sumtype_enc_dec(utyp ast.Type, sym ast.TypeSymbol, mut enc st dec.writeln('\t\tif (cJSON_IsNumber(root)) {') dec.writeln('\t\t\t${var_t} value = ${js_dec_name(var_t)}(root);') if utyp.has_flag(.option) { - dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') + dec.writeln('\t\t\t_option_ok(&(${sym.cname}[]){ ${var_t}_to_sumtype_${sym.cname}(&value, false) }, (${option_name}*)&${prefix}res, sizeof(${sym.cname}));') } else { - dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value);') + dec.writeln('\t\t\t${prefix}res = ${var_t}_to_sumtype_${sym.cname}(&value, false);') } dec.writeln('\t\t}') } diff --git a/vlib/v/tests/sumtypes/sumtype_arg_mutable_test.v b/vlib/v/tests/sumtypes/sumtype_arg_mutable_test.v index 413658a0a..29995372f 100644 --- a/vlib/v/tests/sumtypes/sumtype_arg_mutable_test.v +++ b/vlib/v/tests/sumtypes/sumtype_arg_mutable_test.v @@ -28,14 +28,12 @@ fn test_main() { mut s := String{ s: 'string' } - if $d('mutable_sumtype', false) { - assert i.i == 333 - assert s.s == 'string' - init(mut i) - init(mut s) - assert i.i == 0 - assert s.s == '' - init_int(mut i) - assert i.i == 0 - } + assert i.i == 333 + assert s.s == 'string' + init(mut i) + init(mut s) + assert i.i == 0 + assert s.s == '' + init_int(mut i) + assert i.i == 0 } diff --git a/vlib/v/tests/sumtypes/sumtype_mutable_test.v b/vlib/v/tests/sumtypes/sumtype_mutable_test.v index 89b8560c4..f509c5150 100644 --- a/vlib/v/tests/sumtypes/sumtype_mutable_test.v +++ b/vlib/v/tests/sumtypes/sumtype_mutable_test.v @@ -14,13 +14,11 @@ fn test_main() { mut my_struct := &MyStructA{ test: false } - if $d('mutable_sumtype', false) { - assert my_struct.test == false - my_struct.test = true - assert my_struct.test == true - but_why(mut my_struct) - assert my_struct.test == false - } + assert my_struct.test == false + my_struct.test = true + assert my_struct.test == true + but_why(mut my_struct) + assert my_struct.test == false } fn but_why(mut passed MySumType) { -- 2.39.5