Skip to content

Commit e4e5689

Browse files
authored
v: fix mutable option (fix #18818) (fix #24622) (fix #24101) (#19100)
1 parent 18d9364 commit e4e5689

14 files changed

Lines changed: 199 additions & 28 deletions

File tree

‎vlib/v/ast/types.v‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,13 @@ pub mut:
128128

129129
// max of 8
130130
pub enum TypeFlag as u32 {
131-
option = 1 << 24
132-
result = 1 << 25
133-
variadic = 1 << 26
134-
generic = 1 << 27
135-
shared_f = 1 << 28
136-
atomic_f = 1 << 29
131+
option = 1 << 24
132+
result = 1 << 25
133+
variadic = 1 << 26
134+
generic = 1 << 27
135+
shared_f = 1 << 28
136+
atomic_f = 1 << 29
137+
option_mut_param_t = 1 << 30
137138
}
138139

139140
/*

‎vlib/v/gen/c/assign.v‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ fn (mut g Gen) expr_with_opt_or_block(expr ast.Expr, expr_typ ast.Type, var_expr
2525
} else {
2626
'${expr}'
2727
}
28-
g.writeln('if (${c_name(expr_var)}.state != 0) { // assign')
28+
dot_or_ptr := if !expr_typ.has_flag(.option_mut_param_t) { '.' } else { '-> ' }
29+
g.writeln('if (${c_name(expr_var)}${dot_or_ptr}state != 0) { // assign')
2930
if expr is ast.Ident && expr.or_expr.kind == .propagate_option {
3031
g.writeln('\tpanic_option_not_set(_S("none"));')
3132
} else {
@@ -832,10 +833,20 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
832833
if op_overloaded {
833834
g.op_arg(left, op_expected_left, var_type)
834835
} else {
835-
if !is_decl && !is_shared_re_assign && left.is_auto_deref_var() {
836+
if !is_decl && !is_shared_re_assign && left.is_auto_deref_var()
837+
&& !var_type.has_flag(.option) {
836838
g.write('*')
837839
}
838-
g.expr(left)
840+
if node_.op == .assign && var_type.has_flag(.option_mut_param_t) {
841+
g.write('memcpy(&')
842+
g.expr(left)
843+
g.write('->data, *(${g.styp(val_type)}**)&')
844+
} else if var_type.has_flag(.option_mut_param_t) {
845+
g.expr(left)
846+
g.write(' = ')
847+
} else {
848+
g.expr(left)
849+
}
839850
if !is_decl && var_type.has_flag(.shared_f) {
840851
g.write('->val') // don't reset the mutex, just change the value
841852
}
@@ -858,7 +869,8 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
858869
continue
859870
}
860871
}
861-
} else if cur_indexexpr == -1 && !str_add && !op_overloaded {
872+
} else if !var_type.has_flag(.option_mut_param_t) && cur_indexexpr == -1 && !str_add
873+
&& !op_overloaded {
862874
g.write(' ${op} ')
863875
} else if str_add || op_overloaded {
864876
g.write(', ')
@@ -998,6 +1010,9 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
9981010
if str_add || op_overloaded {
9991011
g.write(')')
10001012
}
1013+
if node_.op == .assign && var_type.has_flag(.option_mut_param_t) {
1014+
g.write('.data, sizeof(${g.base_type(val_type)}))')
1015+
}
10011016
if cur_indexexpr != -1 {
10021017
g.cur_indexexpr.delete(cur_indexexpr)
10031018
g.write(' })')

‎vlib/v/gen/c/auto_str_methods.v‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ fn (mut g Gen) final_gen_str(typ StrType) {
129129
g.str_fn_names << str_fn_name
130130
}
131131
if typ.typ.has_flag(.option) {
132-
g.gen_str_for_option(typ.typ, styp, str_fn_name)
132+
opt_typ := if typ.typ.has_flag(.option_mut_param_t) { styp.replace('*', '') } else { styp }
133+
g.gen_str_for_option(typ.typ, opt_typ, str_fn_name)
133134
return
134135
}
135136
if typ.typ.has_flag(.result) {
@@ -202,9 +203,15 @@ fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string)
202203
g.auto_str_funcs.writeln('string indent_${str_fn_name}(${styp} it, int indent_count) {')
203204
g.auto_str_funcs.writeln('\tstring res;')
204205
g.auto_str_funcs.writeln('\tif (it.state == 0) {')
205-
deref := if typ.is_ptr() {
206-
dot := if expects_ptr { '*'.repeat(typ.nr_muls()) } else { '*'.repeat(typ.nr_muls() + 1) }
206+
deref := if typ.is_ptr() && !typ.has_flag(.option_mut_param_t) {
207+
dot := if expects_ptr {
208+
'*'.repeat(typ.nr_muls())
209+
} else {
210+
'*'.repeat(typ.nr_muls() + 1)
211+
}
207212
'${dot}(${sym.cname}**)&'
213+
} else if typ.has_flag(.option_mut_param_t) {
214+
'*(${sym.cname}*)'
208215
} else if expects_ptr {
209216
'(${sym.cname}*)'
210217
} else {

‎vlib/v/gen/c/cgen.v‎

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ fn (g &Gen) result_type_text(styp string, base string) string {
13961396
fn (mut g Gen) register_option(t ast.Type) string {
13971397
styp, base := g.option_type_name(t)
13981398
g.options[base] = styp
1399-
return styp
1399+
return if !t.has_flag(.option_mut_param_t) { styp } else { '${styp}*' }
14001400
}
14011401

14021402
fn (mut g Gen) register_result(t ast.Type) string {
@@ -2294,7 +2294,12 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T
22942294
ret_styp := g.styp(unwrapped_ret_typ).replace('*', '_ptr')
22952295
g.writeln('${ret_styp} ${tmp_var};')
22962296
} else {
2297-
g.writeln('${g.styp(ret_typ)} ${tmp_var};')
2297+
if ret_typ.has_flag(.option_mut_param_t) {
2298+
ret_styp := g.styp(ret_typ).replace('*', '')
2299+
g.writeln('${ret_styp} ${tmp_var};')
2300+
} else {
2301+
g.writeln('${g.styp(ret_typ)} ${tmp_var};')
2302+
}
22982303
}
22992304
mut expr_is_fixed_array_var := false
23002305
mut fn_option_clone := false
@@ -2336,8 +2341,21 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T
23362341
}
23372342
}
23382343
if !expr.is_literal() && expr_typ != ast.nil_type
2339-
&& ret_typ.nr_muls() > expr_typ.nr_muls() {
2344+
&& ret_typ.nr_muls() > expr_typ.nr_muls()
2345+
&& !ret_typ.has_flag(.option_mut_param_t) {
23402346
g.write('&'.repeat(ret_typ.nr_muls() - expr_typ.nr_muls()))
2347+
} else if ret_typ.has_flag(.option_mut_param_t) {
2348+
if expr_typ.is_ptr() {
2349+
if ret_typ.nr_muls() < expr_typ.nr_muls() {
2350+
g.write('*')
2351+
}
2352+
} else {
2353+
if expr_typ.has_flag(.option) {
2354+
fn_option_clone = true
2355+
g.write('(${styp})')
2356+
}
2357+
g.write('&')
2358+
}
23412359
}
23422360
}
23432361
} else {
@@ -3789,15 +3807,21 @@ fn (mut g Gen) expr(node_ ast.Expr) {
37893807
cur_line := g.go_before_last_stmt().trim_space()
37903808
mut expr_str := ''
37913809
mut is_unwrapped := true
3810+
mut dot_or_ptr := '.'
37923811
if mut node.expr is ast.ComptimeSelector && node.expr.left is ast.Ident {
37933812
// val.$(field.name)?
37943813
expr_str = g.gen_comptime_selector(node.expr)
37953814
} else if mut node.expr is ast.Ident && node.expr.ct_expr {
37963815
// val?
37973816
expr_str = node.expr.name
37983817
is_unwrapped = !g.inside_assign
3818+
dot_or_ptr = if !(node.expr.obj is ast.Var && node.expr.obj.is_auto_deref) {
3819+
'.'
3820+
} else {
3821+
'->'
3822+
}
37993823
}
3800-
g.writeln('if (${expr_str}.state != 0) {')
3824+
g.writeln('if (${expr_str}${dot_or_ptr}state != 0) {')
38013825
g.writeln2('\tpanic_option_not_set(_S("none"));', '}')
38023826
g.write(cur_line)
38033827
if is_unwrapped {
@@ -5199,8 +5223,14 @@ fn (mut g Gen) ident(node ast.Ident) {
51995223
if !g.is_assign_lhs && is_auto_heap {
52005224
g.write('(*${name})')
52015225
} else {
5202-
if node.obj is ast.Var && node.obj.is_inherited {
5203-
g.write(closure_ctx + '->')
5226+
if node.obj is ast.Var {
5227+
// mutable option var
5228+
if (g.is_assign_lhs || g.inside_struct_init) && node.obj.is_auto_deref {
5229+
g.write('*')
5230+
}
5231+
if node.obj.is_inherited {
5232+
g.write(closure_ctx + '->')
5233+
}
52045234
}
52055235
g.write(name)
52065236
}
@@ -5352,8 +5382,9 @@ fn (mut g Gen) ident(node ast.Ident) {
53525382
}
53535383
}
53545384
if i == 0 && node.obj.ct_type_var != .smartcast && node.obj.is_unwrapped {
5355-
dot := if !node.obj.ct_type_unwrapped && !node.obj.orig_type.is_ptr()
5356-
&& obj_sym.is_heap() {
5385+
dot := if (!node.obj.ct_type_unwrapped && !node.obj.orig_type.is_ptr()
5386+
&& obj_sym.is_heap())
5387+
|| node.obj.orig_type.has_flag(.option_mut_param_t) {
53575388
'->'
53585389
} else {
53595390
'.'
@@ -7044,7 +7075,11 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
70447075
// Returns the type of the last stmt
70457076
fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Type) {
70467077
cvar_name := c_name(var_name)
7047-
tmp_op := if var_name in g.tmp_var_ptr { '->' } else { '.' }
7078+
tmp_op := if var_name in g.tmp_var_ptr || return_type.has_flag(.option_mut_param_t) {
7079+
'->'
7080+
} else {
7081+
'.'
7082+
}
70487083
if or_block.kind == .block && or_block.stmts.len == 0 {
70497084
// generate nothing, block is empty
70507085
g.write(';\n${util.tabs(g.indent)}(void)${cvar_name};')

‎vlib/v/gen/c/dumpexpr.v‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) {
8282
} else {
8383
old_inside_opt_or_res := g.inside_opt_or_res
8484
g.inside_opt_or_res = true
85+
if expr_type.has_flag(.option_mut_param_t) {
86+
g.write('*')
87+
}
8588
g.expr(node.expr)
8689
g.inside_opt_or_res = old_inside_opt_or_res
8790
}

‎vlib/v/gen/c/fn.v‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2631,7 +2631,11 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as
26312631
if (arg.expr is ast.Ident && arg.expr.kind in [.global, .variable])
26322632
|| arg.expr is ast.SelectorExpr {
26332633
g.write('&')
2634-
g.expr(arg.expr)
2634+
if expected_type.has_flag(.option_mut_param_t) {
2635+
g.expr_with_opt(arg.expr, arg_typ, expected_type)
2636+
} else {
2637+
g.expr(arg.expr)
2638+
}
26352639
} else {
26362640
// Special case for mutable arrays. We can't `&` function
26372641
// results, have to use `(array[]){ expr }[0]` hack.
@@ -2667,6 +2671,9 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as
26672671
&& lang != .c {
26682672
if arg.expr.is_lvalue() {
26692673
if expected_type.has_flag(.option) {
2674+
if expected_type.has_flag(.option_mut_param_t) {
2675+
g.write('(${g.styp(expected_type)})&')
2676+
}
26702677
g.expr_with_opt(arg.expr, arg_typ, expected_type)
26712678
return
26722679
} else if arg.expr is ast.Ident && arg.expr.language == .c {
@@ -2729,6 +2736,11 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as
27292736
g.write('->val')
27302737
return
27312738
} else if expected_type.has_flag(.option) {
2739+
if expected_type.has_flag(.option_mut_param_t)
2740+
&& arg_typ.nr_muls() <= expected_type.nr_muls() && !(arg.expr is ast.Ident
2741+
&& (arg.expr.obj is ast.Var && arg.expr.obj.is_inherited)) {
2742+
g.write('&')
2743+
}
27322744
if (arg_sym.info is ast.Alias || exp_sym.info is ast.Alias) && expected_type != arg_typ {
27332745
g.expr_opt_with_alias(arg.expr, arg_typ, expected_type)
27342746
} else {

‎vlib/v/gen/c/if.v‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,12 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
330330
g.write('if (${var_name} = ')
331331
g.expr(branch.cond.expr)
332332
if branch.cond.expr_type.has_flag(.option) {
333-
g.writeln(', ${var_name}.state == 0) {')
333+
dot_or_ptr := if !branch.cond.expr_type.has_flag(.option_mut_param_t) {
334+
'.'
335+
} else {
336+
'-> '
337+
}
338+
g.writeln(', ${var_name}${dot_or_ptr}state == 0) {')
334339
} else if branch.cond.expr_type.has_flag(.result) {
335340
g.writeln(', !${var_name}.is_error) {')
336341
}
@@ -366,7 +371,12 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
366371
if is_auto_heap {
367372
g.writeln('\t${base_type}* ${left_var_name} = HEAP(${base_type}, *(${base_type}*)${var_name}.data);')
368373
} else {
369-
g.writeln('\t${base_type} ${left_var_name} = *(${base_type}*)${var_name}.data;')
374+
dot_or_ptr := if !branch.cond.expr_type.has_flag(.option_mut_param_t) {
375+
'.'
376+
} else {
377+
'-> '
378+
}
379+
g.writeln('\t${base_type} ${left_var_name} = *(${base_type}*)${var_name}${dot_or_ptr}data;')
370380
}
371381
} else if branch.cond.vars.len > 1 {
372382
sym := g.table.sym(branch.cond.expr_type)

‎vlib/v/gen/c/infix.v‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,14 +1174,16 @@ fn (mut g Gen) gen_is_none_check(node ast.InfixExpr) {
11741174
g.expr(node.left)
11751175
g.write(')')
11761176
g.inside_opt_or_res = old_inside_opt_or_res
1177-
g.write('.state')
1177+
dot_or_ptr := if !node.left_type.has_flag(.option_mut_param_t) { '.' } else { '->' }
1178+
g.write('${dot_or_ptr}state')
11781179
} else {
11791180
stmt_str := g.go_before_last_stmt().trim_space()
11801181
g.empty_line = true
11811182
left_var := g.expr_with_opt(node.left, node.left_type, node.left_type)
11821183
g.writeln(';')
11831184
g.write2(stmt_str, ' ')
1184-
g.write('${left_var}.state')
1185+
dot_or_ptr := if !node.left_type.has_flag(.option_mut_param_t) { '.' } else { '->' }
1186+
g.write('${left_var}${dot_or_ptr}state')
11851187
}
11861188
g.write(' ${node.op.str()} 2') // none state
11871189
}

‎vlib/v/gen/c/str.v‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,11 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
167167
g.write('&')
168168
}
169169
} else if is_ptr && typ.has_flag(.option) {
170-
g.write('*(${g.styp(typ)}*)&')
170+
if typ.has_flag(.option_mut_param_t) {
171+
g.write('*')
172+
} else {
173+
g.write('*(${g.styp(typ)}*)&')
174+
}
171175
} else if !str_method_expects_ptr && !is_shared && (is_ptr || is_var_mut) {
172176
if sym.is_c_struct() {
173177
g.write(c_struct_ptr(sym, typ, str_method_expects_ptr))

‎vlib/v/gen/c/utils.v‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ fn (mut g Gen) unwrap_option_type(typ ast.Type, name string, is_auto_heap bool)
162162
if parent_typ.has_flag(.option) {
163163
g.write('.data)')
164164
}
165+
} else if typ.has_flag(.option_mut_param_t) {
166+
g.write('(*(${styp}*)${name}->data)')
165167
} else {
166168
g.write('(*(${styp}*)${name}.data)')
167169
}

0 commit comments

Comments
 (0)