| author | |
| committer | |
| log | 07f64a2e13ab80acffba7f7bdd5d7c58df7893c0 |
| tree | e35bf8eea3846afca0a3d42f1436b1759f39c60a |
| parent | 070282a96ec23fb41041843d5753608ec5090f8b |
The following, from the documentation as of the time of writing, illustrates
the problem:
```zig
// Compile time coercion of float to int
test "implicit cast to comptime_int" {
var f: f32 = 54.0 / 5;
_ = f;
}
```
It is not clear how to unify the types of 54.0 and 5 to perform the
division. We can either
- cast 54.0 to comptime_int resulting in @as(comptime_int, 10), which is
casted to @as(f32, 10), or
- cast 5 to comptime_float resulting in @as(comptime_float, 10.8), which
is casted to @as(f32, 10.8)
Since the two resulting values are different, a compiler error is appropriate.
If we know that casting to either type will result in the same value we
don't need to error. For instance, 10.0 / 2 is okay, as is 10 / 2.0.
Fixes: #123642 files changed, 20 insertions(+), 4 deletions(-)
src/Sema.zig+16| ... | @@ -11202,6 +11202,22 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -11202,6 +11202,22 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 11202 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); | 11202 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs); |
| 11203 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); | 11203 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs); |
| 11204 | 11204 | ||
| 11205 | if ((lhs_ty.tag() == .comptime_float and rhs_ty.tag() == .comptime_int) or | ||
| 11206 | (lhs_ty.tag() == .comptime_int and rhs_ty.tag() == .comptime_float)) | ||
| 11207 | { | ||
| 11208 | // If it makes a difference whether we coerce to ints or floats before doing the division, error. | ||
| 11209 | // If lhs % rhs is 0, it doesn't matter. | ||
| 11210 | var lhs_val = maybe_lhs_val orelse unreachable; | ||
| 11211 | var rhs_val = maybe_rhs_val orelse unreachable; | ||
| 11212 | var rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable; | ||
| 11213 | var float_rem = rem.toFloat(f32); | ||
| 11214 | if (float_rem != 0.0) { | ||
| 11215 | return sema.fail(block, src, "ambiguous coercion of division operands: '{s}' and '{s}': division has non-zero reminder: {d}", .{ | ||
| 11216 | @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), float_rem, | ||
| 11217 | }); | ||
| 11218 | } | ||
| 11219 | } | ||
| 11220 | |||
| 11205 | // TODO: emit compile error when .div is used on integers and there would be an | 11221 | // TODO: emit compile error when .div is used on integers and there would be an |
| 11206 | // ambiguous result between div_floor and div_trunc. | 11222 | // ambiguous result between div_floor and div_trunc. |
| 11207 | 11223 |
test/behavior/floatop.zig+4-4| ... | @@ -194,8 +194,8 @@ fn testSin() !void { | ... | @@ -194,8 +194,8 @@ fn testSin() !void { |
| 194 | const eps = epsForType(ty); | 194 | const eps = epsForType(ty); |
| 195 | try expect(@sin(@as(ty, 0)) == 0); | 195 | try expect(@sin(@as(ty, 0)) == 0); |
| 196 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps)); | 196 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps)); |
| 197 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps)); | 197 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2.0)), 1, eps)); |
| 198 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps)); | 198 | try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps)); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | { | 201 | { |
| ... | @@ -228,8 +228,8 @@ fn testCos() !void { | ... | @@ -228,8 +228,8 @@ fn testCos() !void { |
| 228 | const eps = epsForType(ty); | 228 | const eps = epsForType(ty); |
| 229 | try expect(@cos(@as(ty, 0)) == 1); | 229 | try expect(@cos(@as(ty, 0)) == 1); |
| 230 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps)); | 230 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps)); |
| 231 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps)); | 231 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2.0)), 0, eps)); |
| 232 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps)); | 232 | try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps)); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | { | 235 | { |