From cb0b94c0648dd7f44c035d2e66e6f45095da1ea2 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 6 Dec 2025 00:46:42 +0100 Subject: [PATCH] - Optional does not play well with bit ops #2618. --- releasenotes.md | 1 + src/compiler/sema_expr.c | 14 ++++++----- .../expressions/not_in_wrong_position.c3 | 4 ---- .../expressions/optional_and_bitops.c3t | 23 +++++++++++++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) delete mode 100644 test/test_suite/expressions/not_in_wrong_position.c3 create mode 100644 test/test_suite/expressions/optional_and_bitops.c3t diff --git a/releasenotes.md b/releasenotes.md index 2be845fc8..41898e94d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -8,6 +8,7 @@ ### Fixes - Regression with npot vector in struct triggering an assert #2219. - Casting bitstruct to wider base type should be single step #2616. +- Optional does not play well with bit ops #2618. ### Stdlib changes diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8986e0dcd..fac18bc7c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1485,11 +1485,12 @@ static inline bool sema_binary_analyse_arithmetic_subexpr(SemaContext *context, Type *left_type = type_no_optional(left->type)->canonical; Type *right_type = type_no_optional(right->type)->canonical; + Type *flat_left = type_flatten(left_type); if (bool_and_bitstruct_is_allowed) { - if (left_type->type_kind == TYPE_BITSTRUCT && left_type == right_type) return true; - if (left_type == type_bool && right_type == type_bool) return true; + if (flat_left->type_kind == TYPE_BITSTRUCT && left_type == right_type) return true; + if (flat_left == type_bool && left_type == right_type) return true; } // 2. Perform promotion to a common type. return sema_binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, error, @@ -7623,7 +7624,8 @@ static bool sema_binary_arithmetic_promotion(SemaContext *context, Expr *left, E } Type *max = cast_numeric_arithmetic_promotion(type_find_max_type(left_type, right_type, left, right)); - if (!max || (!type_underlying_is_numeric(max) && !(allow_bool_vec && type_flat_is_bool_vector(max)))) + Type *flat_max = max ? type_flatten(max) : NULL; + if (!max || (!type_is_numeric(flat_max) && !(allow_bool_vec && (flat_max == type_bool || type_flat_is_bool_vector(flat_max))))) { CHECK_ON_DEFINED(failed_ref); if (!error_message) @@ -7632,7 +7634,6 @@ static bool sema_binary_arithmetic_promotion(SemaContext *context, Expr *left, E } RETURN_SEMA_ERROR(parent, error_message, type_quoted_error_string(left->type), type_quoted_error_string(right->type)); } - Type *flat_max = type_flatten(max); if (type_is_signed(flat_max)) { if (!sema_check_untyped_promotion(context, left, true, flat_max, max)) return false; @@ -8146,8 +8147,9 @@ static bool sema_expr_analyse_bit(SemaContext *context, Expr *expr, Expr *left, if (!overload) return true; // 2. Check that both are integers or bools. - bool is_bool = left->type->canonical == type_bool; - bool is_bitstruct = left->type->canonical->type_kind == TYPE_BITSTRUCT; + Type *flat_left = type_flatten(left->type); + bool is_bool = flat_left == type_bool; + bool is_bitstruct = flat_left->type_kind == TYPE_BITSTRUCT; if (!is_bool && !is_bitstruct && !expr_both_any_integer_or_integer_bool_vector(left, right)) { diff --git a/test/test_suite/expressions/not_in_wrong_position.c3 b/test/test_suite/expressions/not_in_wrong_position.c3 deleted file mode 100644 index a0e68c976..000000000 --- a/test/test_suite/expressions/not_in_wrong_position.c3 +++ /dev/null @@ -1,4 +0,0 @@ -fn void main() -{ - x = (a ~ a); // #error: can't appear -} diff --git a/test/test_suite/expressions/optional_and_bitops.c3t b/test/test_suite/expressions/optional_and_bitops.c3t new file mode 100644 index 000000000..573c5ed20 --- /dev/null +++ b/test/test_suite/expressions/optional_and_bitops.c3t @@ -0,0 +1,23 @@ +module test; +bitstruct Foo : int +{ + bool a; +} + +typedef Bool = bool; +typedef Foo2 = Foo; +fn void main() +{ + Foo? a, b; + + Foo? c = a | b; + (a | b)!!; + Foo? d = a & b; + Foo? e = a ^ b; + Bool? x; + bool zz; + x = x | x; + Bool? w = x | (Bool)zz; + Foo2? y, z; + y = y | z; +} \ No newline at end of file