authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-07 15:57:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-07 15:57:41-04:00
log2234788fa80dfaf1e58df51ff576701f8161b0df
treec544704e7d4981e2cae1c54abb4e6b17bc872268
parent38b47d8aca57efbb10b8000cb726eb24b1f37ccb

add ability to explicitly cast float to integer

closes #414

7 files changed, 58 insertions(+), 12 deletions(-)

src/bigfloat.cpp+4
...@@ -150,3 +150,7 @@ Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) {...@@ -150,3 +150,7 @@ Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) {
150 return CmpEQ;150 return CmpEQ;
151 }151 }
152}152}
153
154bool bigfloat_has_fraction(const BigFloat *bigfloat) {
155 return floorl(bigfloat->value) != bigfloat->value;
156}
src/bigfloat.hpp+1
...@@ -43,5 +43,6 @@ void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count,...@@ -43,5 +43,6 @@ void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count,
4343
44// convenience functions44// convenience functions
45Cmp bigfloat_cmp_zero(const BigFloat *bigfloat);45Cmp bigfloat_cmp_zero(const BigFloat *bigfloat);
46bool bigfloat_has_fraction(const BigFloat *bigfloat);
4647
47#endif48#endif
src/ir.cpp+37-9
...@@ -6206,7 +6206,9 @@ static bool const_val_fits_in_num_lit(ConstExprValue *const_val, TypeTableEntry...@@ -6206,7 +6206,9 @@ static bool const_val_fits_in_num_lit(ConstExprValue *const_val, TypeTableEntry
6206 (const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdNumLitInt)));6206 (const_val->type->id == TypeTableEntryIdInt || const_val->type->id == TypeTableEntryIdNumLitInt)));
6207}6207}
62086208
6209static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) {6209static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type,
6210 bool explicit_cast)
6211{
6210 if (type_is_invalid(other_type)) {6212 if (type_is_invalid(other_type)) {
6211 return false;6213 return false;
6212 }6214 }
...@@ -6243,6 +6245,32 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc...@@ -6243,6 +6245,32 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
6243 return true;6245 return true;
6244 }6246 }
6245 }6247 }
6248 if (explicit_cast && (other_type->id == TypeTableEntryIdInt || other_type->id == TypeTableEntryIdNumLitInt) &&
6249 const_val_is_float)
6250 {
6251 if (bigfloat_has_fraction(&const_val->data.x_bigfloat)) {
6252 Buf *val_buf = buf_alloc();
6253 bigfloat_write_buf(val_buf, &const_val->data.x_bigfloat);
6254
6255 ir_add_error(ira, instruction,
6256 buf_sprintf("fractional component prevents float value %s from being casted to type '%s'",
6257 buf_ptr(val_buf),
6258 buf_ptr(&other_type->name)));
6259 return false;
6260 } else {
6261 BigInt bigint;
6262 bigint_init_bigfloat(&bigint, &const_val->data.x_bigfloat);
6263 if (other_type->id == TypeTableEntryIdNumLitInt) {
6264 return true;
6265 } else {
6266 if (bigint_fits_in_bits(&bigint, other_type->data.integral.bit_count,
6267 other_type->data.integral.is_signed))
6268 {
6269 return true;
6270 }
6271 }
6272 }
6273 }
62466274
6247 const char *num_lit_str;6275 const char *num_lit_str;
6248 Buf *val_buf = buf_alloc();6276 Buf *val_buf = buf_alloc();
...@@ -6425,12 +6453,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6425,12 +6453,12 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6425 if (expected_type->id == TypeTableEntryIdPointer &&6453 if (expected_type->id == TypeTableEntryIdPointer &&
6426 expected_type->data.pointer.is_const)6454 expected_type->data.pointer.is_const)
6427 {6455 {
6428 if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type)) {6456 if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type, false)) {
6429 return ImplicitCastMatchResultYes;6457 return ImplicitCastMatchResultYes;
6430 } else {6458 } else {
6431 return ImplicitCastMatchResultReportedError;6459 return ImplicitCastMatchResultReportedError;
6432 }6460 }
6433 } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) {6461 } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type, false)) {
6434 return ImplicitCastMatchResultYes;6462 return ImplicitCastMatchResultYes;
6435 } else {6463 } else {
6436 return ImplicitCastMatchResultReportedError;6464 return ImplicitCastMatchResultReportedError;
...@@ -6542,7 +6570,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6542,7 +6570,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6542 } else if (prev_type->id == TypeTableEntryIdNumLitInt ||6570 } else if (prev_type->id == TypeTableEntryIdNumLitInt ||
6543 prev_type->id == TypeTableEntryIdNumLitFloat)6571 prev_type->id == TypeTableEntryIdNumLitFloat)
6544 {6572 {
6545 if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type)) {6573 if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) {
6546 prev_inst = cur_inst;6574 prev_inst = cur_inst;
6547 continue;6575 continue;
6548 } else {6576 } else {
...@@ -6551,7 +6579,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6551,7 +6579,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6551 } else if (cur_type->id == TypeTableEntryIdNumLitInt ||6579 } else if (cur_type->id == TypeTableEntryIdNumLitInt ||
6552 cur_type->id == TypeTableEntryIdNumLitFloat)6580 cur_type->id == TypeTableEntryIdNumLitFloat)
6553 {6581 {
6554 if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type)) {6582 if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) {
6555 continue;6583 continue;
6556 } else {6584 } else {
6557 return ira->codegen->builtin_types.entry_invalid;6585 return ira->codegen->builtin_types.entry_invalid;
...@@ -7636,7 +7664,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7636,7 +7664,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7636 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||7664 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
7637 actual_type->id == TypeTableEntryIdNumLitFloat)7665 actual_type->id == TypeTableEntryIdNumLitFloat)
7638 {7666 {
7639 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) {7667 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type, true)) {
7640 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);7668 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
7641 } else {7669 } else {
7642 return ira->codegen->invalid_instruction;7670 return ira->codegen->invalid_instruction;
...@@ -7658,7 +7686,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7658,7 +7686,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7658 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||7686 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
7659 actual_type->id == TypeTableEntryIdNumLitFloat)7687 actual_type->id == TypeTableEntryIdNumLitFloat)
7660 {7688 {
7661 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) {7689 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) {
7662 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);7690 return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
7663 } else {7691 } else {
7664 return ira->codegen->invalid_instruction;7692 return ira->codegen->invalid_instruction;
...@@ -7736,7 +7764,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7736,7 +7764,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7736 return ira->codegen->invalid_instruction;7764 return ira->codegen->invalid_instruction;
77377765
7738 return cast2;7766 return cast2;
7739 } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type)) {7767 } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
7740 CastOp op;7768 CastOp op;
7741 if ((actual_type->id == TypeTableEntryIdNumLitFloat &&7769 if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
7742 wanted_type->id == TypeTableEntryIdFloat) ||7770 wanted_type->id == TypeTableEntryIdFloat) ||
...@@ -8630,7 +8658,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -8630,7 +8658,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
8630 return ira->codegen->builtin_types.entry_invalid;8658 return ira->codegen->builtin_types.entry_invalid;
8631 }8659 }
86328660
8633 ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type);8661 ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type, false);
8634 return resolved_type;8662 return resolved_type;
8635 }8663 }
86368664
std/fmt/errol/index.zig+1-2
...@@ -43,8 +43,7 @@ fn errol3u(val: f64, buffer: []u8) -> FloatDecimal {...@@ -43,8 +43,7 @@ fn errol3u(val: f64, buffer: []u8) -> FloatDecimal {
43 43
44 // normalize the midpoint44 // normalize the midpoint
4545
46 var e: i32 = undefined;46 const e = math.frexp(val).exponent;
47 _ = math.frexp(val, &e);
48 var exp = i16(math.floor(307 + f64(e) * 0.30103));47 var exp = i16(math.floor(307 + f64(e) * 0.30103));
49 if (exp < 20) {48 if (exp < 20) {
50 exp = 20;49 exp = 20;
std/math/index.zig+1-1
...@@ -95,7 +95,7 @@ pub const isSignalNan = @import("isnan.zig").isSignalNan;...@@ -95,7 +95,7 @@ pub const isSignalNan = @import("isnan.zig").isSignalNan;
95pub const fabs = @import("fabs.zig").fabs;95pub const fabs = @import("fabs.zig").fabs;
96pub const ceil = @import("ceil.zig").ceil;96pub const ceil = @import("ceil.zig").ceil;
97pub const floor = @import("floor.zig").floor;97pub const floor = @import("floor.zig").floor;
98pub const trunc = @import("floor.zig").trunc;98pub const trunc = @import("trunc.zig").trunc;
99pub const round = @import("round.zig").round;99pub const round = @import("round.zig").round;
100pub const frexp = @import("frexp.zig").frexp;100pub const frexp = @import("frexp.zig").frexp;
101pub const frexp32_result = @import("frexp.zig").frexp32_result;101pub const frexp32_result = @import("frexp.zig").frexp32_result;
test/cases/cast.zig+7
...@@ -251,3 +251,10 @@ fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {...@@ -251,3 +251,10 @@ fn testPeerErrorAndArray2(x: u8) -> %[]const u8 {
251 else => error.BadValue,251 else => error.BadValue,
252 }252 }
253}253}
254
255test "explicit cast float number literal to integer if no fraction component" {
256 const x = i32(1e4);
257 assert(x == 10000);
258 const y = i32(f32(1e4));
259 assert(y == 10000);
260}
test/compile_errors.zig+7
...@@ -1945,4 +1945,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1945,4 +1945,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1945 \\}1945 \\}
1946 ,1946 ,
1947 ".tmp_source.zig:2:15: error: float literal out of range of any type");1947 ".tmp_source.zig:2:15: error: float literal out of range of any type");
1948
1949 cases.add("explicit cast float literal to integer when there is a fraction component",
1950 \\export fn entry() -> i32 {
1951 \\ i32(12.34)
1952 \\}
1953 ,
1954 ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'");
1948}1955}