From f4aa139f8dd4294f7e5a27d153e85a02bb3c6b92 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 15 Feb 2025 17:54:17 -0300 Subject: [PATCH] cgen: fix codegen for nested if on return (fix #23723) (#23729) --- vlib/v/gen/c/cgen.v | 5 ++-- vlib/v/gen/c/if.v | 25 ++++++++++++++--- vlib/v/tests/nested_if_return_test.v | 41 ++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 vlib/v/tests/nested_if_return_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index cddf89815..a8a849f1e 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -161,6 +161,7 @@ mut: inside_global_decl bool inside_interface_deref bool last_tmp_call_var []string + last_if_option_type ast.Type // stores the expected if type on nested if expr loop_depth int ternary_names map[string]string ternary_level_names map[string][]string @@ -2068,7 +2069,8 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) bool { styp = 'f64' } } - if stmt.typ.has_flag(.option) { + if stmt.typ.has_flag(.option) + || (g.inside_if_option && stmt.expr is ast.IfExpr) { g.writeln('') g.write('${tmp_var} = ') g.expr(stmt.expr) @@ -2082,7 +2084,6 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) bool { } styp = g.base_type(ret_typ) if stmt.expr is ast.CallExpr && stmt.expr.is_noreturn { - g.expr(stmt.expr) g.writeln(';') } else { g.write('_option_ok(&(${styp}[]) { ') diff --git a/vlib/v/gen/c/if.v b/vlib/v/gen/c/if.v index f9fa855d7..6554d9976 100644 --- a/vlib/v/gen/c/if.v +++ b/vlib/v/gen/c/if.v @@ -185,15 +185,26 @@ fn (mut g Gen) if_expr(node ast.IfExpr) { // easier to use a temp var, than do C tricks with commas, introduce special vars etc // (as it used to be done). // Always use this in -autofree, since ?: can have tmp expressions that have to be freed. - needs_tmp_var := g.need_tmp_var_in_if(node) + needs_tmp_var := g.inside_if_option || g.need_tmp_var_in_if(node) needs_conds_order := g.needs_conds_order(node) - tmp := if node.typ != ast.void_type && needs_tmp_var { g.new_tmp_var() } else { '' } + tmp := if g.inside_if_option || (node.typ != ast.void_type && needs_tmp_var) { + g.new_tmp_var() + } else { + '' + } mut cur_line := '' mut raw_state := false + tmp_if_option_type := g.last_if_option_type if needs_tmp_var { mut styp := g.styp(node.typ) - if node.typ.has_flag(.option) { + if g.inside_if_option || node.typ.has_flag(.option) { raw_state = g.inside_if_option + if node.typ != ast.void_type { + g.last_if_option_type = node.typ + defer { + g.last_if_option_type = tmp_if_option_type + } + } defer { g.inside_if_option = raw_state } @@ -210,7 +221,13 @@ fn (mut g Gen) if_expr(node ast.IfExpr) { cur_line = g.go_before_last_stmt() g.empty_line = true if tmp != '' { - g.writeln('${styp} ${tmp}; /* if prepend */') + if node.typ == ast.void_type && g.last_if_option_type != 0 { + // nested if on return stmt + g.write2(g.styp(g.last_if_option_type), ' ') + } else { + g.write('${styp} ') + } + g.writeln('${tmp}; /* if prepend */') } if g.infix_left_var_name.len > 0 { g.writeln('if (${g.infix_left_var_name}) {') diff --git a/vlib/v/tests/nested_if_return_test.v b/vlib/v/tests/nested_if_return_test.v new file mode 100644 index 000000000..805a3dc6c --- /dev/null +++ b/vlib/v/tests/nested_if_return_test.v @@ -0,0 +1,41 @@ +struct Message { + prio bool +} + +struct Throttler[T] { + max_wait int +mut: + wait_counter int + low_prio_requests []T + high_prio_requests []T +} + +fn new_throttler[T](max_wait int) Throttler[T] { + return Throttler[T]{max_wait, 0, []T{len: 1, init: T{}}, []T{len: 1, init: T{}}} +} + +fn pop[T](mut t Throttler[T]) ?T { + if t.wait_counter <= t.max_wait { + return if t.high_prio_requests.len > 10 { + t.high_prio_requests.pop() + } else { + t.wait_counter = 0 + if t.low_prio_requests.len > 0 { + t.low_prio_requests.pop() + } else { + none + } + } + } else { + return none + } +} + +fn test_main() { + c := chan Message{} + mut throttler := new_throttler[Message](10) + msg := pop(mut throttler) or { return } + assert msg.str() == 'Message{ + prio: false +}' +} -- 2.39.5