diff --git a/releasenotes.md b/releasenotes.md index 8093dcfd1..9278bb257 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -21,6 +21,7 @@ - Fix lexer allowing a trailing underscore (_) with hex and binary literals. - Fix `--list-operators` CLI command printing underscore (_) and hash (#). - Fix bug in temp allocator when temp memory is exhausted and allocation needs overaligned mem. #1715 +- Incorrectly handles distinct enums and pointers with '+=' and '-=' #1717. ### Stdlib changes - Increase BitWriter.write_bits limit up to 32 bits. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 467ccda1f..13fc8e858 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -5717,13 +5717,13 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr * if (int_only && !type_flat_is_intlike(flat)) { if (allow_bitstruct && flat->type_kind == TYPE_BITSTRUCT) goto BITSTRUCT_OK; - RETURN_SEMA_ERROR(left, "Expected an integer here."); + RETURN_SEMA_ERROR(left, "Expected an integer here, not a value of type %s.", type_quoted_error_string(left->type)); } // 4. In any case, these ops are only defined on numbers. if (!type_underlying_is_numeric(flat) && !(is_add_sub && type_underlying_may_add_sub(left->type))) { - RETURN_SEMA_ERROR(left, "Expected a numeric type here."); + RETURN_SEMA_ERROR(left, "Expected a numeric type here, not a value of type %s.", type_quoted_error_string(left->type)); } BITSTRUCT_OK: @@ -5731,7 +5731,6 @@ BITSTRUCT_OK: // 5. Analyse RHS if (!sema_analyse_expr(context, right)) return false; - // 3. Copy type & set properties. if (IS_OPTIONAL(right) && !IS_OPTIONAL(left)) { @@ -5742,8 +5741,30 @@ BITSTRUCT_OK: bool optional = IS_OPTIONAL(left) || IS_OPTIONAL(right); // 5. In the pointer case we have to treat this differently. - if (left_type_canonical->type_kind == TYPE_POINTER) + if (flat->type_kind == TYPE_ENUM) { + if (type_flat_distinct_inline(no_fail)->type_kind != TYPE_ENUM) + { + RETURN_SEMA_ERROR(expr, "A value of type %s cannot be added to or subtracted from.", type_quoted_error_string(left->type)); + } + // 7. Finally, check that the right side is indeed an integer. + if (!type_is_integer(right->type->canonical)) + { + RETURN_SEMA_ERROR(right, + "The right side was '%s' but only integers are valid on the right side of %s when the left side is an enum.", + type_to_error_string(right->type), + token_type_to_string(binaryop_to_token(expr->binary_expr.operator))); + } + if (!cast_implicit(context, right, flat->decl->enums.type_info->type, false)) return false; + goto END; + } + if (type_is_pointer_like(flat)) + { + // Not inline pointer-like + if (!type_is_pointer_like(no_fail)) + { + RETURN_SEMA_ERROR(expr, "A value of type %s cannot be added to or subtracted from.", type_quoted_error_string(left->type)); + } // 7. Finally, check that the right side is indeed an integer. if (!type_is_integer(right->type->canonical)) { diff --git a/test/test_suite/distinct/disntinct_add_fail.c3 b/test/test_suite/distinct/disntinct_add_fail.c3 new file mode 100644 index 000000000..d90e42d62 --- /dev/null +++ b/test/test_suite/distinct/disntinct_add_fail.c3 @@ -0,0 +1,12 @@ +// #target: macos-x64 +module test; +import std; + +fn void main() +{ + DString y; + + y ^= 1; // #error: Expected an integer here + y += 1.0; // #error: A value of type 'DString' + y += 1; // #error: A value of type 'DString' +} diff --git a/test/test_suite/enumerations/enum_add_sub.c3t b/test/test_suite/enumerations/enum_add_sub.c3t index ed5c71c45..20772f44a 100644 --- a/test/test_suite/enumerations/enum_add_sub.c3t +++ b/test/test_suite/enumerations/enum_add_sub.c3t @@ -4,7 +4,7 @@ enum Foo { ABC } -distinct Abc = Foo; +distinct Abc = inline Foo; distinct BarInt = int; enum Bar : BarInt { diff --git a/test/test_suite/enumerations/inc_assign.c3t b/test/test_suite/enumerations/inc_assign.c3t new file mode 100644 index 000000000..88c71105a --- /dev/null +++ b/test/test_suite/enumerations/inc_assign.c3t @@ -0,0 +1,35 @@ +// #target: macos-x64 +module test; +import std; + +enum Abc +{ + ABCD, + OKFEOFKE, + OFKEOFK +} + +distinct Bob = inline Abc; +fn void main() +{ + Abc y; + y += 1; + Bob gh; + gh += 1; +} + +/* #expect: test.ll + +entry: + %y = alloca i32, align 4 + %gh = alloca i32, align 4 + store i32 0, ptr %y, align 4 + %0 = load i32, ptr %y, align 4 + %add = add i32 %0, 1 + store i32 %add, ptr %y, align 4 + store i32 0, ptr %gh, align 4 + %1 = load i32, ptr %gh, align 4 + %add1 = add i32 %1, 1 + store i32 %add1, ptr %gh, align 4 + ret void +} \ No newline at end of file diff --git a/test/test_suite/enumerations/inc_assign_fail.c3 b/test/test_suite/enumerations/inc_assign_fail.c3 new file mode 100644 index 000000000..25ce04994 --- /dev/null +++ b/test/test_suite/enumerations/inc_assign_fail.c3 @@ -0,0 +1,24 @@ +// #target: macos-x64 +module test; +import std; + +enum Abc +{ + ABCD, + OKFEOFKE, + OFKEOFK +} + +distinct Bob = Abc; +fn void main() +{ + Abc y; + y ^= 1; // #error: Expected an integer here, not a value of type + y += 1.0; // #error: The right side was 'double' + Bob gh; + gh += 1; // #error: A value of type 'Bob' +} + +/* #expect: test.ll + +feofke \ No newline at end of file