diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1f9f272eb..c34026a58 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4572,61 +4572,56 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } + for_array(i, operands) { + Operand *a = &operands[i]; + for_array(j, operands) { + if (i == j) { + continue; + } + Operand *b = &operands[j]; + + convert_to_typed(c, a, b->type); + if (a->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, b, a->type); + if (b->mode == Addressing_Invalid) { + return false; + } + } + } + + for (isize i = 0; i < operands.count-1; i++) { + Operand *a = &operands[i]; + Operand *b = &operands[i+1]; + + if (!are_types_identical(a->type, b->type)) { + gbString type_a = type_to_string(a->type); + gbString type_b = type_to_string(b->type); + error(a->expr, + "Mismatched types to 'min', '%s' vs '%s'", + type_a, type_b); + gb_string_free(type_b); + gb_string_free(type_a); + return false; + } + } + if (all_constant) { ExactValue value = operands[0].value; - Type *type = operands[0].type; for (isize i = 1; i < operands.count; i++) { Operand y = operands[i]; if (compare_exact_values(Token_Lt, value, y.value)) { // okay } else { value = y.value; - type = y.type; } } operand->value = value; - operand->type = type; } else { operand->mode = Addressing_Value; - operand->type = original_type; - - for_array(i, operands) { - Operand *a = &operands[i]; - for_array(j, operands) { - if (i == j) { - continue; - } - Operand *b = &operands[j]; - - convert_to_typed(c, a, b->type); - if (a->mode == Addressing_Invalid) { - return false; - } - convert_to_typed(c, b, a->type); - if (b->mode == Addressing_Invalid) { - return false; - } - } - } - - for (isize i = 0; i < operands.count-1; i++) { - Operand *a = &operands[i]; - Operand *b = &operands[i+1]; - - if (!are_types_identical(a->type, b->type)) { - gbString type_a = type_to_string(a->type); - gbString type_b = type_to_string(b->type); - error(a->expr, - "Mismatched types to 'min', '%s' vs '%s'", - type_a, type_b); - gb_string_free(type_b); - gb_string_free(type_a); - return false; - } - } - - operand->type = operands[0].type; } + operand->type = operands[0].type; break; } @@ -4769,61 +4764,56 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } + for_array(i, operands) { + Operand *a = &operands[i]; + for_array(j, operands) { + if (i == j) { + continue; + } + Operand *b = &operands[j]; + + convert_to_typed(c, a, b->type); + if (a->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, b, a->type); + if (b->mode == Addressing_Invalid) { + return false; + } + } + } + + for (isize i = 0; i < operands.count-1; i++) { + Operand *a = &operands[i]; + Operand *b = &operands[i+1]; + + if (!are_types_identical(a->type, b->type)) { + gbString type_a = type_to_string(a->type); + gbString type_b = type_to_string(b->type); + error(a->expr, + "Mismatched types to 'max', '%s' vs '%s'", + type_a, type_b); + gb_string_free(type_b); + gb_string_free(type_a); + return false; + } + } + if (all_constant) { ExactValue value = operands[0].value; - Type *type = operands[0].type; for (isize i = 1; i < operands.count; i++) { Operand y = operands[i]; if (compare_exact_values(Token_Gt, value, y.value)) { // okay } else { - type = y.type; value = y.value; } } operand->value = value; - operand->type = type; } else { operand->mode = Addressing_Value; - operand->type = original_type; - - for_array(i, operands) { - Operand *a = &operands[i]; - for_array(j, operands) { - if (i == j) { - continue; - } - Operand *b = &operands[j]; - - convert_to_typed(c, a, b->type); - if (a->mode == Addressing_Invalid) { - return false; - } - convert_to_typed(c, b, a->type); - if (b->mode == Addressing_Invalid) { - return false; - } - } - } - - for (isize i = 0; i < operands.count-1; i++) { - Operand *a = &operands[i]; - Operand *b = &operands[i+1]; - - if (!are_types_identical(a->type, b->type)) { - gbString type_a = type_to_string(a->type); - gbString type_b = type_to_string(b->type); - error(a->expr, - "Mismatched types to 'max', '%s' vs '%s'", - type_a, type_b); - gb_string_free(type_b); - gb_string_free(type_a); - return false; - } - } - - operand->type = operands[0].type; } + operand->type = operands[0].type; break; } @@ -4932,7 +4922,32 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } - Type *type = x.type; + for (isize i = 0; i < 3; i++) { + Operand *a = ops[i]; + for (isize j = 0; j < 3; j++) { + if (i == j) { + continue; + } + Operand *b = ops[j]; + convert_to_typed(c, a, b->type); + if (a->mode == Addressing_Invalid) { + return false; + } + } + } + + if (!are_types_identical(x.type, y.type) || !are_types_identical(x.type, z.type)) { + gbString type_x = type_to_string(x.type); + gbString type_y = type_to_string(y.type); + gbString type_z = type_to_string(z.type); + error(call, + "Mismatched types to 'clamp', '%s', '%s', '%s'", + type_x, type_y, type_z); + gb_string_free(type_z); + gb_string_free(type_y); + gb_string_free(type_x); + return false; + } if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && @@ -4944,47 +4959,15 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Constant; if (compare_exact_values(Token_Lt, a, b)) { operand->value = b; - operand->type = y.type; } else if (compare_exact_values(Token_Gt, a, c)) { operand->value = c; - operand->type = z.type; } else { operand->value = a; - operand->type = x.type; } } else { operand->mode = Addressing_Value; - operand->type = type; - - for (isize i = 0; i < 3; i++) { - Operand *a = ops[i]; - for (isize j = 0; j < 3; j++) { - if (i == j) { - continue; - } - Operand *b = ops[j]; - convert_to_typed(c, a, b->type); - if (a->mode == Addressing_Invalid) { - return false; - } - } - } - - if (!are_types_identical(x.type, y.type) || !are_types_identical(x.type, z.type)) { - gbString type_x = type_to_string(x.type); - gbString type_y = type_to_string(y.type); - gbString type_z = type_to_string(z.type); - error(call, - "Mismatched types to 'clamp', '%s', '%s', '%s'", - type_x, type_y, type_z); - gb_string_free(type_z); - gb_string_free(type_y); - gb_string_free(type_x); - return false; - } - - operand->type = ops[0]->type; } + operand->type = x.type; break; } diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 3d39655e4..791e9e973 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -45,6 +45,7 @@ set ODIN=..\..\..\odin %ODIN% check "..\test_issue_7429" %COMMON% || exit /b %ODIN% check "..\test_issue_7708_mismatch" %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b %ODIN% check "..\test_issue_7938" -no-entry-point %COMMON% 2>&1 | find /c "Error: Missing return statement" | findstr /x "3" || exit /b +%ODIN% check "..\test_issue_7975_7976_mismatch" %COMMON% 2>&1 | find /c "Error:" | findstr /x "8" || exit /b %ODIN% check "..\test_issue_ambiguous_union_literal" %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b %ODIN% check "..\test_issue_global_when_cycle" -no-entry-point %COMMON% 2>&1 | find /c "Contradictory global" | findstr /x "4" || exit /b %ODIN% check "..\test_issue_global_when_cycle_ambiguous" -no-entry-point %COMMON% 2>&1 | find /c "Ambiguous global" | findstr /x "1" || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index ad815b457..8ce15311d 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -144,6 +144,13 @@ else exit 1 fi +if [[ $($ODIN check ../test_issue_7975_7976_mismatch $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 8 ]]; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi + if [[ $($ODIN check ../test_issue_poly_proc_value $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 4 ]]; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_7975_7976/test_issue_7975_7976.odin b/tests/issues/test_issue_7975_7976/test_issue_7975_7976.odin new file mode 100644 index 000000000..b3d7bf78c --- /dev/null +++ b/tests/issues/test_issue_7975_7976/test_issue_7975_7976.odin @@ -0,0 +1,21 @@ +// Tests issues #7975 https://github.com/odin-lang/Odin/issues/7975 and #7976 https://github.com/odin-lang/Odin/issues/7976 +// Constant arguments to `min`, `max` and `clamp` are unified into a single type, as non-constant ones are +package test_issue_7975_7976 + +import "core:testing" + +@(test) +test_constant_min_max_clamp :: proc(t: ^testing.T) { + a := min(1, 2.5) + b := max(3, 1.5) + c := clamp(3, 0.5, 2) + d := min("b", "string_literal") + + testing.expect_value(t, typeid_of(type_of(a)), f64) + testing.expect_value(t, typeid_of(type_of(b)), f64) + testing.expect_value(t, typeid_of(type_of(c)), f64) + testing.expect_value(t, a, 1.0) + testing.expect_value(t, b, 3.0) + testing.expect_value(t, c, 2.0) + testing.expect_value(t, d, "b") +} diff --git a/tests/issues/test_issue_7975_7976_mismatch/test_issue_7975_7976_mismatch.odin b/tests/issues/test_issue_7975_7976_mismatch/test_issue_7975_7976_mismatch.odin new file mode 100644 index 000000000..6f9363989 --- /dev/null +++ b/tests/issues/test_issue_7975_7976_mismatch/test_issue_7975_7976_mismatch.odin @@ -0,0 +1,14 @@ +// Tests issues #7975 https://github.com/odin-lang/Odin/issues/7975 and #7976 https://github.com/odin-lang/Odin/issues/7976 +// Constant arguments to `min`, `max` and `clamp` which cannot be unified into a single type must be rejected +package test_issue_7975_7976_mismatch + +main :: proc() { + _ = min(3.14, "string_literal") + _ = max(42, "string_literal") + _ = min('a', "b") + _ = clamp(1.5, "string_test", 5.5) + _ = clamp(1.5, 42, "string_test") + _ = min(i32(1), u8(2)) + _ = max(3.5, i32(2)) + _ = clamp(i32(1), 2, u8(3)) +} diff --git a/tests/issues/test_simple.odin b/tests/issues/test_simple.odin index 42d06d31d..19030f255 100644 --- a/tests/issues/test_simple.odin +++ b/tests/issues/test_simple.odin @@ -52,6 +52,7 @@ package tests_issues @(require) import "test_issue_7853" @(require) import "test_issue_7875_7471" @(require) import "test_issue_7889" +@(require) import "test_issue_7975_7976" @(require) import "test_issue_fast_isel_lowering" @(require) import "test_issue_omitted_field_union" @(require) import "test_issue_equal_proc_dependencies"