From 23477fc77fc43af4f110eb030dc5338d1fc99949 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 21 Sep 2025 02:34:05 -0300 Subject: [PATCH] comptime: fix $compile_error on $match when used on return stmt (fix #25348) (#25358) --- vlib/v/ast/ast.v | 9 ++- vlib/v/checker/match.v | 16 +++- vlib/v/gen/c/comptime.v | 81 ++++++++++--------- .../tests/comptime/comptime_match_ret_test.v | 12 +++ 4 files changed, 73 insertions(+), 45 deletions(-) create mode 100644 vlib/v/tests/comptime/comptime_match_ret_test.v diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 6456a1397..ca22b999c 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1297,10 +1297,11 @@ pub: post_comments []Comment // comments below ´... }´ branch_pos token.Pos // for checker errors about invalid branches pub mut: - stmts []Stmt // right side - exprs []Expr // left side - scope &Scope = unsafe { nil } - id int + stmts []Stmt // right side + exprs []Expr // left side + scope &Scope = unsafe { nil } + id int + is_comptime_err bool // $compile_warn(), $compile_error() } pub struct SelectExpr { diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index a07157d2d..2c7da8b29 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -266,11 +266,17 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } else { node.expected_type } - expr_type := c.unwrap_generic(if stmt.expr is ast.CallExpr { - stmt.typ + branch.is_comptime_err = stmt.expr is ast.ComptimeCall + && stmt.expr.kind in [.compile_error, .compile_warn] + expr_type := if branch.is_comptime_err { + c.expected_type } else { - c.expr(mut stmt.expr) - }) + c.unwrap_generic(if stmt.expr is ast.CallExpr { + stmt.typ + } else { + c.expr(mut stmt.expr) + }) + } unwrapped_expected_type := c.unwrap_generic(node.expected_type) must_be_option = must_be_option || expr_type == ast.none_type stmt.typ = expr_type @@ -434,6 +440,8 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { c.error('`match` expression requires an expression as the last statement of every branch', stmt.pos) } + } else if c.inside_return && mut stmt is ast.Return && ret_type == ast.void_type { + ret_type = if stmt.types.len > 0 { stmt.types[0] } else { c.expected_type } } } first_iteration = false diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index f5a6dc810..b98e2f344 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -1004,49 +1004,56 @@ fn (mut g Gen) comptime_match(node ast.MatchExpr) { } else { g.writeln('#else') } - - if node.is_expr { + if node.is_expr && !branch.is_comptime_err { len := branch.stmts.len if len > 0 { - last := branch.stmts.last() as ast.ExprStmt - if len > 1 { - g.indent++ - g.writeln('{') - g.stmts(branch.stmts[..len - 1]) - g.set_current_pos_as_last_stmt_pos() - prev_skip_stmt_pos := g.skip_stmt_pos - g.skip_stmt_pos = true - if is_opt_or_result { - tmp_var2 := g.new_tmp_var() - g.write('{ ${g.base_type(node.return_type)} ${tmp_var2} = ') - g.stmt(last) - g.writeln('builtin___result_ok(&(${g.base_type(node.return_type)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.return_type)}));') - g.writeln('}') + last := branch.stmts.last() + if last is ast.ExprStmt { + if len > 1 { + g.indent++ + g.writeln('{') + g.stmts(branch.stmts[..len - 1]) + g.set_current_pos_as_last_stmt_pos() + prev_skip_stmt_pos := g.skip_stmt_pos + g.skip_stmt_pos = true + if is_opt_or_result { + tmp_var2 := g.new_tmp_var() + g.write('{ ${g.base_type(node.return_type)} ${tmp_var2} = ') + g.stmt(last) + g.writeln('builtin___result_ok(&(${g.base_type(node.return_type)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.return_type)}));') + g.writeln('}') + } else { + g.write('\t${tmp_var} = ') + g.stmt(last) + } + g.skip_stmt_pos = prev_skip_stmt_pos + g.writeln2(';', '}') + g.indent-- } else { - g.write('\t${tmp_var} = ') - g.stmt(last) + g.indent++ + g.set_current_pos_as_last_stmt_pos() + prev_skip_stmt_pos := g.skip_stmt_pos + g.skip_stmt_pos = true + if is_opt_or_result { + tmp_var2 := g.new_tmp_var() + g.write('{ ${g.base_type(node.return_type)} ${tmp_var2} = ') + g.stmt(last) + g.writeln('builtin___result_ok(&(${g.base_type(node.return_type)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.return_type)}));') + g.writeln('}') + } else { + g.write('${tmp_var} = ') + g.stmt(last) + } + g.skip_stmt_pos = prev_skip_stmt_pos + g.writeln(';') + g.indent-- } - g.skip_stmt_pos = prev_skip_stmt_pos - g.writeln2(';', '}') - g.indent-- - } else { - g.indent++ - g.set_current_pos_as_last_stmt_pos() - prev_skip_stmt_pos := g.skip_stmt_pos - g.skip_stmt_pos = true - if is_opt_or_result { - tmp_var2 := g.new_tmp_var() - g.write('{ ${g.base_type(node.return_type)} ${tmp_var2} = ') - g.stmt(last) - g.writeln('builtin___result_ok(&(${g.base_type(node.return_type)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.return_type)}));') - g.writeln('}') - } else { + } else if last is ast.Return { + if last.exprs.len > 0 { g.write('${tmp_var} = ') - g.stmt(last) + g.expr(last.exprs[0]) + g.writeln(';') } - g.skip_stmt_pos = prev_skip_stmt_pos - g.writeln(';') - g.indent-- } } } else { diff --git a/vlib/v/tests/comptime/comptime_match_ret_test.v b/vlib/v/tests/comptime/comptime_match_ret_test.v new file mode 100644 index 000000000..2d4587998 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_match_ret_test.v @@ -0,0 +1,12 @@ +fn test[T]() bool { + return $match T { + i8 { true } + i16 { true } + $else { $compile_error('unsupported type') } + } +} + +fn test_main() { + assert test[i8]() == true + assert test[i16]() == true +} -- 2.39.5