From 0c9a3ca94a63ca82e76e67d58c1089a7ba1ad587 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:24 +0300 Subject: [PATCH] checker: fix clang build error with if expr in or block (fixes #15214) --- vlib/v/checker/if.v | 27 ++++++++++++- vlib/v/tests/if_expr_in_or_block_test.v | 52 +++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index b414dfd5e..c90519308 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -49,6 +49,18 @@ fn (mut c Checker) is_always_true_self_comparison(cond ast.Expr) bool { return false } +fn (c &Checker) is_interface_smartcast_sumtype_variant(expr ast.Expr, expected_type ast.Type, got_type ast.Type) bool { + sum_type := expected_type.clear_option_and_result() + if c.table.type_kind(sum_type) != .sum_type || !got_type.is_ptr() { + return false + } + if expr is ast.Ident && expr.obj is ast.Var { + return c.table.is_interface_var(expr.obj) + && c.table.is_sumtype_or_in_variant(sum_type, got_type.deref()) + } + return false +} + // gen_branch_context_string generate current branches context string. // context include generic types, `$for`. fn (mut c Checker) gen_branch_context_string() string { @@ -476,6 +488,15 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } } } + if c.is_interface_smartcast_sumtype_variant(stmt.expr, former_expected_type, + stmt.typ) + { + node.is_expr = true + node.typ = former_expected_type.clear_option_and_result() + unsafe { + goto end_if + } + } if node.is_expr && c.table.sym(former_expected_type).kind == .sum_type { node.typ = former_expected_type unsafe { @@ -518,7 +539,8 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } else { if !node.typ.has_option_or_result() && !node.typ.has_flag(.shared_f) && stmt.typ != ast.voidptr_type - && stmt.typ.nr_muls() != node.typ.nr_muls() { + && stmt.typ.nr_muls() != node.typ.nr_muls() + && !c.is_interface_smartcast_sumtype_variant(stmt.expr, node.typ, stmt.typ) { c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(stmt.typ)}`', node.pos) } @@ -527,7 +549,8 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { node.is_expr = true } if c.inside_assign && node.is_expr && !node.typ.has_flag(.shared_f) - && stmt.typ != ast.voidptr_type { + && stmt.typ != ast.voidptr_type + && !c.is_interface_smartcast_sumtype_variant(stmt.expr, node.typ, stmt.typ) { if stmt.typ.is_ptr() != node.typ.is_ptr() { c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(stmt.typ)}`', node.pos) diff --git a/vlib/v/tests/if_expr_in_or_block_test.v b/vlib/v/tests/if_expr_in_or_block_test.v index 77f91a11d..33b12452a 100644 --- a/vlib/v/tests/if_expr_in_or_block_test.v +++ b/vlib/v/tests/if_expr_in_or_block_test.v @@ -103,3 +103,55 @@ fn test_if_expr_with_multiple_branches_in_or_block() { } assert val == 1 } + +struct IfExprEmptyReply { + value int +} + +struct IfExprRedisError { + msg_ string +} + +fn (e IfExprRedisError) msg() string { + return e.msg_ +} + +fn (e IfExprRedisError) code() int { + return 0 +} + +const if_expr_nil_reply = IfExprRedisError{'nil'} + +type IfExprReply = IfExprEmptyReply | IfExprRedisError + +fn if_expr_read_reply(msg string) !IfExprReply { + return IError(IfExprRedisError{msg}) +} + +fn if_expr_decode_reply(msg string) IfExprReply { + return if_expr_read_reply(msg) or { + if err is IfExprRedisError { + if err == if_expr_nil_reply { + IfExprEmptyReply{0} + } else { + err + } + } else { + panic(err) + } + } +} + +fn test_if_expr_in_or_block_with_smartcasted_interface_sumtype_value() { + reply1 := if_expr_decode_reply('nil') + assert reply1 is IfExprEmptyReply + if reply1 is IfExprEmptyReply { + assert reply1.value == 0 + } + + reply2 := if_expr_decode_reply('x') + assert reply2 is IfExprRedisError + if reply2 is IfExprRedisError { + assert reply2.msg_ == 'x' + } +} -- 2.39.5