mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Merge pull request 'Sema: Support peer type resolution for floats and small integers' (#30921) from jayschwa/zig:ptr-small-int-and-floats into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30921 Reviewed-by: Andrew Kelley <andrew@ziglang.org>
This commit is contained in:
@@ -10,6 +10,17 @@ test "peer resolve int widening" {
|
||||
try expectEqual(i16, @TypeOf(c));
|
||||
}
|
||||
|
||||
test "peer resolve small int and float" {
|
||||
// This only works for integer types that can coerce to the float type.
|
||||
// Larger integer types will cause a compiler error; no float widening occurs.
|
||||
var i: u8 = 12;
|
||||
var f: f32 = 34;
|
||||
_ = .{ &i, &f };
|
||||
const x = i + f;
|
||||
try expectEqual(x, 46.0);
|
||||
try expectEqual(@TypeOf(x), f32);
|
||||
}
|
||||
|
||||
test "peer resolve arrays of different size to const slice" {
|
||||
try expectEqualStrings("true", boolToStr(true));
|
||||
try expectEqualStrings("false", boolToStr(false));
|
||||
|
||||
+25
-18
@@ -27799,15 +27799,7 @@ fn coerceExtra(
|
||||
}
|
||||
const int_info = inst_ty.intInfo(zcu);
|
||||
const int_precision = int_info.bits - @intFromBool(int_info.signedness == .signed);
|
||||
const float_precision: u8 = switch (dest_ty.toIntern()) {
|
||||
.f16_type => 11,
|
||||
.f32_type => 24,
|
||||
.f64_type => 53,
|
||||
.f80_type => 64,
|
||||
.f128_type => 113,
|
||||
else => unreachable,
|
||||
};
|
||||
if (int_precision <= float_precision) {
|
||||
if (int_precision <= dest_ty.floatSignificandBits(target)) {
|
||||
try sema.requireRuntimeBlock(block, inst_src, null);
|
||||
return block.addTyOp(.float_from_int, dest_ty, inst);
|
||||
}
|
||||
@@ -32762,16 +32754,10 @@ fn resolvePeerTypesInner(
|
||||
.fixed_float => {
|
||||
var opt_cur_ty: ?Type = null;
|
||||
|
||||
for (peer_tys, peer_vals, 0..) |opt_ty, opt_val, i| {
|
||||
for (peer_tys, 0..) |opt_ty, i| {
|
||||
const ty = opt_ty orelse continue;
|
||||
switch (ty.zigTypeTag(zcu)) {
|
||||
.comptime_float, .comptime_int => {},
|
||||
.int => {
|
||||
if (opt_val == null) return .{ .conflict = .{
|
||||
.peer_idx_a = strat_reason,
|
||||
.peer_idx_b = i,
|
||||
} };
|
||||
},
|
||||
.comptime_float, .comptime_int, .int => {},
|
||||
.float => {
|
||||
if (opt_cur_ty) |cur_ty| {
|
||||
if (cur_ty.eql(ty, zcu)) continue;
|
||||
@@ -32798,7 +32784,28 @@ fn resolvePeerTypesInner(
|
||||
|
||||
// Note that fixed_float is only chosen if there is at least one fixed-width float peer,
|
||||
// so opt_cur_ty must be non-null.
|
||||
return .{ .success = opt_cur_ty.? };
|
||||
const cur_ty = opt_cur_ty.?;
|
||||
|
||||
// Ensure that any integer peers can coerce safely to the resulting float.
|
||||
for (peer_tys, peer_vals, 0..) |opt_ty, opt_val, i| {
|
||||
const ty = opt_ty orelse continue;
|
||||
switch (ty.zigTypeTag(zcu)) {
|
||||
.comptime_float, .comptime_int, .float => {},
|
||||
.int => {
|
||||
if (opt_val != null) continue;
|
||||
const int_info = ty.intInfo(zcu);
|
||||
const int_precision = int_info.bits - @intFromBool(int_info.signedness == .signed);
|
||||
if (int_precision > cur_ty.floatSignificandBits(target))
|
||||
return .{ .conflict = .{
|
||||
.peer_idx_a = strat_reason,
|
||||
.peer_idx_b = i,
|
||||
} };
|
||||
},
|
||||
else => unreachable, // Previous pass returned on this branch.
|
||||
}
|
||||
}
|
||||
|
||||
return .{ .success = cur_ty };
|
||||
},
|
||||
|
||||
.tuple => {
|
||||
|
||||
@@ -1935,6 +1935,18 @@ pub fn floatBits(ty: Type, target: *const Target) u16 {
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type is a fixed-size float or comptime_float.
|
||||
pub fn floatSignificandBits(ty: Type, target: *const Target) u16 {
|
||||
return switch (ty.floatBits(target)) {
|
||||
16 => 11,
|
||||
32 => 24,
|
||||
64 => 53,
|
||||
80 => 64,
|
||||
128 => 113,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type is a function or a function pointer.
|
||||
pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type {
|
||||
return Type.fromInterned(zcu.intern_pool.funcTypeReturnType(ty.toIntern()));
|
||||
|
||||
@@ -175,6 +175,7 @@ test "type coercion from int to float" {
|
||||
var int: Int = std.math.minInt(Int);
|
||||
while (int < std.math.maxInt(Int)) : (int += 1)
|
||||
try value(Float, int);
|
||||
try value(Float, int); // max
|
||||
}
|
||||
|
||||
// Check that the min and max values of the integer type can safely be
|
||||
@@ -202,6 +203,8 @@ test "type coercion from int to float" {
|
||||
try check.edgeValues(f128, u113);
|
||||
try check.edgeValues(f128, i114);
|
||||
|
||||
try check.value(c_longdouble, @as(u1, 0)); // Smoke test - size varies by target.
|
||||
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
|
||||
@@ -1924,6 +1927,47 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
|
||||
try expectEqual(@as(T, 1.234), r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: float and runtime-known fixed-width integer" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn testPeerType(Float: type, Int: type) !void {
|
||||
var i: Int = 100;
|
||||
_ = &i;
|
||||
var f: Float = 1.234;
|
||||
_ = &f;
|
||||
comptime assert(@TypeOf(i, f) == Float);
|
||||
comptime assert(@TypeOf(f, i) == Float);
|
||||
|
||||
var t = true;
|
||||
_ = &t;
|
||||
const r1 = if (t) i else f;
|
||||
const r2 = if (t) f else i;
|
||||
|
||||
try expectEqual(@as(Float, 100.0), r1);
|
||||
try expectEqual(@as(Float, 1.234), r2);
|
||||
}
|
||||
};
|
||||
|
||||
try S.testPeerType(f16, u11);
|
||||
try S.testPeerType(f16, i12);
|
||||
|
||||
try S.testPeerType(f32, u24);
|
||||
try S.testPeerType(f32, i25);
|
||||
|
||||
try S.testPeerType(f64, u53);
|
||||
try S.testPeerType(f64, i54);
|
||||
|
||||
try S.testPeerType(f80, u64);
|
||||
try S.testPeerType(f80, i65);
|
||||
|
||||
try S.testPeerType(f128, u113);
|
||||
try S.testPeerType(f128, i114);
|
||||
|
||||
try S.testPeerType(c_longdouble, u8); // Smoke test - size varies by target.
|
||||
}
|
||||
|
||||
test "peer type resolution: same array type with sentinel" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// Test that peer type resolution fails for integer types that cannot safely coerce to a float.
|
||||
|
||||
fn testAdd(Float: type, Int: type) void {
|
||||
var i: Int = 0;
|
||||
_ = &i;
|
||||
var f: Float = 0;
|
||||
_ = &f;
|
||||
_ = i + f;
|
||||
_ = f + i;
|
||||
}
|
||||
|
||||
export fn entry() void {
|
||||
testAdd(f16, u11); // Okay
|
||||
testAdd(f16, u12); // Too big
|
||||
|
||||
testAdd(f16, i12);
|
||||
testAdd(f16, i13);
|
||||
|
||||
testAdd(f32, u24);
|
||||
testAdd(f32, u25);
|
||||
|
||||
testAdd(f32, i25);
|
||||
testAdd(f32, i26);
|
||||
|
||||
testAdd(f64, u53);
|
||||
testAdd(f64, u54);
|
||||
|
||||
testAdd(f64, i54);
|
||||
testAdd(f64, i55);
|
||||
|
||||
testAdd(f80, u64);
|
||||
testAdd(f80, u65);
|
||||
|
||||
testAdd(f80, i65);
|
||||
testAdd(f80, i66);
|
||||
|
||||
testAdd(f128, u113);
|
||||
testAdd(f128, u114);
|
||||
|
||||
testAdd(f128, i114);
|
||||
testAdd(f128, i115);
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :8:11: error: incompatible types: 'i115' and 'f128'
|
||||
// :8:9: note: type 'i115' here
|
||||
// :8:13: note: type 'f128' here
|
||||
// :8:11: error: incompatible types: 'i13' and 'f16'
|
||||
// :8:9: note: type 'i13' here
|
||||
// :8:13: note: type 'f16' here
|
||||
// :8:11: error: incompatible types: 'i26' and 'f32'
|
||||
// :8:9: note: type 'i26' here
|
||||
// :8:13: note: type 'f32' here
|
||||
// :8:11: error: incompatible types: 'i55' and 'f64'
|
||||
// :8:9: note: type 'i55' here
|
||||
// :8:13: note: type 'f64' here
|
||||
// :8:11: error: incompatible types: 'i66' and 'f80'
|
||||
// :8:9: note: type 'i66' here
|
||||
// :8:13: note: type 'f80' here
|
||||
// :8:11: error: incompatible types: 'u114' and 'f128'
|
||||
// :8:9: note: type 'u114' here
|
||||
// :8:13: note: type 'f128' here
|
||||
// :8:11: error: incompatible types: 'u12' and 'f16'
|
||||
// :8:9: note: type 'u12' here
|
||||
// :8:13: note: type 'f16' here
|
||||
// :8:11: error: incompatible types: 'u25' and 'f32'
|
||||
// :8:9: note: type 'u25' here
|
||||
// :8:13: note: type 'f32' here
|
||||
// :8:11: error: incompatible types: 'u54' and 'f64'
|
||||
// :8:9: note: type 'u54' here
|
||||
// :8:13: note: type 'f64' here
|
||||
// :8:11: error: incompatible types: 'u65' and 'f80'
|
||||
// :8:9: note: type 'u65' here
|
||||
// :8:13: note: type 'f80' here
|
||||
Reference in New Issue
Block a user