diff --git a/src/bigfloat.cpp b/src/bigfloat.cpp index 3986efc19d..22ff9c29a3 100644 --- a/src/bigfloat.cpp +++ b/src/bigfloat.cpp @@ -150,3 +150,7 @@ Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { return CmpEQ; } } + +bool bigfloat_has_fraction(const BigFloat *bigfloat) { + return floorl(bigfloat->value) != bigfloat->value; +} diff --git a/src/bigfloat.hpp b/src/bigfloat.hpp index 2f32f37110..30aa754ce6 100644 --- a/src/bigfloat.hpp +++ b/src/bigfloat.hpp @@ -43,5 +43,6 @@ void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, // convenience functions Cmp bigfloat_cmp_zero(const BigFloat *bigfloat); +bool bigfloat_has_fraction(const BigFloat *bigfloat); #endif diff --git a/src/ir.cpp b/src/ir.cpp index 686c247117..5c21f06f40 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6206,7 +6206,9 @@ static bool const_val_fits_in_num_lit(ConstExprValue *const_val, TypeTableEntry (const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdNumLitInt))); } -static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) { +static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type, + bool explicit_cast) +{ if (type_is_invalid(other_type)) { return false; } @@ -6243,6 +6245,32 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc return true; } } + if (explicit_cast && (other_type->id == TypeTableEntryIdInt || other_type->id == TypeTableEntryIdNumLitInt) && + const_val_is_float) + { + if (bigfloat_has_fraction(&const_val->data.x_bigfloat)) { + Buf *val_buf = buf_alloc(); + bigfloat_write_buf(val_buf, &const_val->data.x_bigfloat); + + ir_add_error(ira, instruction, + buf_sprintf("fractional component prevents float value %s from being casted to type '%s'", + buf_ptr(val_buf), + buf_ptr(&other_type->name))); + return false; + } else { + BigInt bigint; + bigint_init_bigfloat(&bigint, &const_val->data.x_bigfloat); + if (other_type->id == TypeTableEntryIdNumLitInt) { + return true; + } else { + if (bigint_fits_in_bits(&bigint, other_type->data.integral.bit_count, + other_type->data.integral.is_signed)) + { + return true; + } + } + } + } const char *num_lit_str; Buf *val_buf = buf_alloc(); @@ -6425,12 +6453,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, if (expected_type->id == TypeTableEntryIdPointer && expected_type->data.pointer.is_const) { - if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type)) { + if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type, false)) { return ImplicitCastMatchResultYes; } else { return ImplicitCastMatchResultReportedError; } - } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) { + } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type, false)) { return ImplicitCastMatchResultYes; } else { return ImplicitCastMatchResultReportedError; @@ -6542,7 +6570,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod } else if (prev_type->id == TypeTableEntryIdNumLitInt || prev_type->id == TypeTableEntryIdNumLitFloat) { - if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type)) { + if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) { prev_inst = cur_inst; continue; } else { @@ -6551,7 +6579,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod } else if (cur_type->id == TypeTableEntryIdNumLitInt || cur_type->id == TypeTableEntryIdNumLitFloat) { - if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type)) { + if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) { continue; } else { return ira->codegen->builtin_types.entry_invalid; @@ -7636,7 +7664,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) { + if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type, true)) { return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; @@ -7658,7 +7686,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) { + if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) { return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; @@ -7736,7 +7764,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ira->codegen->invalid_instruction; return cast2; - } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type)) { + } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { CastOp op; if ((actual_type->id == TypeTableEntryIdNumLitFloat && wanted_type->id == TypeTableEntryIdFloat) || @@ -8630,7 +8658,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp return ira->codegen->builtin_types.entry_invalid; } - ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type); + ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type, false); return resolved_type; } diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig index 8bf5cf9bac..f824f492fb 100644 --- a/std/fmt/errol/index.zig +++ b/std/fmt/errol/index.zig @@ -43,8 +43,7 @@ fn errol3u(val: f64, buffer: []u8) -> FloatDecimal { // normalize the midpoint - var e: i32 = undefined; - _ = math.frexp(val, &e); + const e = math.frexp(val).exponent; var exp = i16(math.floor(307 + f64(e) * 0.30103)); if (exp < 20) { exp = 20; diff --git a/std/math/index.zig b/std/math/index.zig index c27c2d8ab2..e564faee4d 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -95,7 +95,7 @@ pub const isSignalNan = @import("isnan.zig").isSignalNan; pub const fabs = @import("fabs.zig").fabs; pub const ceil = @import("ceil.zig").ceil; pub const floor = @import("floor.zig").floor; -pub const trunc = @import("floor.zig").trunc; +pub const trunc = @import("trunc.zig").trunc; pub const round = @import("round.zig").round; pub const frexp = @import("frexp.zig").frexp; pub const frexp32_result = @import("frexp.zig").frexp32_result; diff --git a/test/cases/cast.zig b/test/cases/cast.zig index b53df1a6eb..75fa5c99b9 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -251,3 +251,10 @@ fn testPeerErrorAndArray2(x: u8) -> %[]const u8 { else => error.BadValue, } } + +test "explicit cast float number literal to integer if no fraction component" { + const x = i32(1e4); + assert(x == 10000); + const y = i32(f32(1e4)); + assert(y == 10000); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index c78d17a916..58df6ce123 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1945,4 +1945,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} , ".tmp_source.zig:2:15: error: float literal out of range of any type"); + + cases.add("explicit cast float literal to integer when there is a fraction component", + \\export fn entry() -> i32 { + \\ i32(12.34) + \\} + , + ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); }