From b3283356520766db8a41e1a8aa4b990646c12287 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:19 +0300 Subject: [PATCH] checker: support flag_var bitwise_operator= .enum_flag (fixes #20940) --- vlib/v/checker/assign.v | 15 ++++++++-- .../enums/enum_flag_compound_assign_test.v | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/enums/enum_flag_compound_assign_test.v diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index ef1f14f13..de3aba4d9 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -789,8 +789,19 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', right.pos()) } } - .and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, - .right_shift_assign { + .and_assign, .or_assign, .xor_assign { + left_final_sym := c.table.final_sym(left_type_unwrapped) + if left_final_sym.info is ast.Enum && left_final_sym.info.is_flag { + // `@[flag]` tagged enums support compound bitwise assignment. + } else if !left_sym.is_int() && !left_final_sym.is_int() { + c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`', + left.pos()) + } else if !right_sym.is_int() && !c.table.final_sym(right_type_unwrapped).is_int() { + c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`', + right.pos()) + } + } + .mod_assign, .left_shift_assign, .right_shift_assign { if !left_sym.is_int() && !c.table.final_sym(left_type_unwrapped).is_int() { c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`', left.pos()) diff --git a/vlib/v/tests/enums/enum_flag_compound_assign_test.v b/vlib/v/tests/enums/enum_flag_compound_assign_test.v new file mode 100644 index 000000000..5574daa21 --- /dev/null +++ b/vlib/v/tests/enums/enum_flag_compound_assign_test.v @@ -0,0 +1,28 @@ +@[flag] +enum FlagEnumCompoundAssign { + a + b + c +} + +type FlagEnumCompoundAssignAlias = FlagEnumCompoundAssign + +fn test_flag_enum_compound_assign_with_short_enum_values() { + mut flag := FlagEnumCompoundAssign.a + flag |= .b + assert flag == .a | .b + flag ^= .a + assert flag == .b + flag &= .b + assert flag == .b +} + +fn test_flag_enum_alias_compound_assign_with_short_enum_values() { + mut flag := FlagEnumCompoundAssignAlias(FlagEnumCompoundAssign.a) + flag |= .c + assert flag == .a | .c + flag ^= .a + assert flag == .c + flag &= .c + assert flag == .c +} -- 2.39.5