diff --git a/src/check_type.cpp b/src/check_type.cpp index 5e5959e24..9414b794e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2846,9 +2846,14 @@ gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) { } Type *type = core_type(o->type); if (is_type_untyped(type) || is_type_integer(type)) { - if (o->value.kind == ExactValue_Integer) { - BigInt count = o->value.value_integer; - if (big_int_is_neg(&o->value.value_integer)) { + ExactValue value = o->value; + if (value.kind == ExactValue_Float) { + // NOTE: an integral float is a valid count, but it must be range checked as an integer + value = exact_value_to_integer(value); + } + if (value.kind == ExactValue_Integer) { + BigInt count = value.value_integer; + if (big_int_is_neg(&count)) { gbAllocator a = heap_allocator(); String str = big_int_to_string(a, &count); error(e, "Invalid negative array count, %.*s", LIT(str)); @@ -2864,12 +2869,6 @@ gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) { error(e, "Array count too large, %.*s", LIT(str)); gb_free(a, str.text); return 0; - } else if (o->value.kind == ExactValue_Float) { - u64 u = cast(u64)o->value.value_float; - f64 f = cast(f64)u; - if (f == o->value.value_float) { - return u; - } } } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 545b415a6..2f82a52cf 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -419,6 +419,12 @@ gb_internal ExactValue exact_value_to_integer(ExactValue v) { case ExactValue_Integer: return v; case ExactValue_Float: { + f64 const min = cast(f64)I64_MIN; // -2^63 + f64 const max = -min; // 2^63, one past I64_MAX + // NOTE: the conversion below is undefined outside of this range, NaN included + if (!(v.value_float >= min && v.value_float < max)) { + break; + } i64 i = cast(i64)v.value_float; f64 f = cast(f64)i; if (f == v.value_float) { diff --git a/tests/internal/test_array_count.odin b/tests/internal/test_array_count.odin new file mode 100644 index 000000000..597462c4c --- /dev/null +++ b/tests/internal/test_array_count.odin @@ -0,0 +1,25 @@ +package test_internal + +import "core:testing" + +@(test) +array_count_from_integral_float :: proc(t: ^testing.T) { + testing.expect_value(t, len([3.0]u8{}), 3) + testing.expect_value(t, len([0.0]u8{}), 0) + testing.expect_value(t, size_of([3.0]u32), 12) + + // folded constant expressions + Halved :: 6.0 / 2.0 + Summed :: 1.5 + 1.5 + testing.expect_value(t, len([Halved]u8{}), 3) + testing.expect_value(t, len([Summed]u8{}), 3) + + // NOTE: keep below one BigInt limb: 2^28 on windows, 2^60 on linux + testing.expect_value(t, len([65536.0]struct{}{}), 1 << 16) + + testing.expect_value(t, size_of(matrix[2.0, 3.0]f32), 24) + testing.expect_value(t, size_of(#simd[4.0]u8), 4) + + Sparse :: [2.0]u8 + testing.expect_value(t, len(Sparse{1, 2}), 2) +}