authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-08-27 17:14:31-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-30 16:50:30-04:00
loge2ff486de5f3aceb21730e1feabbaf9b03432660
tree2ee27be7108be3486d785554cc63ebd89645eec1
parent49075d20557994da4eb341e7431de38a6df2088b

Sema: cleanup `coerceExtra`

* remove unreachable code * remove already handled cases * avoid `InternPool.getCoerced` * add some undef checks * error when converting undef int to float Closes #16987

5 files changed, 102 insertions(+), 99 deletions(-)

src/Module.zig+1-1
......@@ -6360,7 +6360,7 @@ pub fn errorSetFromUnsortedNames(
63606360
63616361/// Supports only pointers, not pointer-like optionals.
63626362pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
6363 assert(ty.zigTypeTag(mod) == .Pointer);
6363 assert(ty.zigTypeTag(mod) == .Pointer and !ty.isSlice(mod));
63646364 const i = try intern(mod, .{ .ptr = .{
63656365 .ty = ty.toIntern(),
63666366 .addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },
src/Sema.zig+86-97
......@@ -17282,12 +17282,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1728217282 for (enum_field_vals, 0..) |*field_val, i| {
1728317283 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
1728417284 const value_val = if (enum_type.values.len > 0)
17285 try mod.intern_pool.getCoerced(gpa, enum_type.values.get(ip)[i], .comptime_int_type)
17285 try mod.intern_pool.getCoercedInts(
17286 mod.gpa,
17287 mod.intern_pool.indexToKey(enum_type.values.get(ip)[i]).int,
17288 .comptime_int_type,
17289 )
1728617290 else
17287 try mod.intern(.{ .int = .{
17288 .ty = .comptime_int_type,
17289 .storage = .{ .u64 = @intCast(i) },
17290 } });
17291 (try mod.intValue(Type.comptime_int, i)).toIntern();
1729117292 // TODO: write something like getCoercedInts to avoid needing to dupe
1729217293 const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));
1729317294 const name_val = v: {
......@@ -21259,7 +21260,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2125921260 try sema.checkFloatType(block, operand_src, operand_scalar_ty);
2126021261
2126121262 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
21262 const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty);
21263 const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty, .truncate);
2126321264 return Air.internedToRef(result_val.toIntern());
2126421265 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
2126521266 return sema.failWithNeededComptime(block, operand_src, .{
......@@ -27575,21 +27576,21 @@ fn coerceExtra(
2757527576 return block.addBitCast(dest_ty, inst);
2757627577 }
2757727578
27578 const is_undef = inst_ty.zigTypeTag(mod) == .Undefined;
27579
2758027579 switch (dest_ty.zigTypeTag(mod)) {
2758127580 .Optional => optional: {
27582 // undefined sets the optional bit also to undefined.
27583 if (is_undef) {
27584 return mod.undefRef(dest_ty);
27585 }
27581 if (maybe_inst_val) |val| {
27582 // undefined sets the optional bit also to undefined.
27583 if (val.toIntern() == .undef) {
27584 return mod.undefRef(dest_ty);
27585 }
2758627586
27587 // null to ?T
27588 if (inst_ty.zigTypeTag(mod) == .Null) {
27589 return Air.internedToRef((try mod.intern(.{ .opt = .{
27590 .ty = dest_ty.toIntern(),
27591 .val = .none,
27592 } })));
27587 // null to ?T
27588 if (val.toIntern() == .null_value) {
27589 return Air.internedToRef((try mod.intern(.{ .opt = .{
27590 .ty = dest_ty.toIntern(),
27591 .val = .none,
27592 } })));
27593 }
2759327594 }
2759427595
2759527596 // cast from ?*T and ?[*]T to ?*anyopaque
......@@ -27681,7 +27682,9 @@ fn coerceExtra(
2768127682
2768227683 if (dest_info.sentinel != .none) {
2768327684 if (array_ty.sentinel(mod)) |inst_sent| {
27684 if (dest_info.sentinel != (try mod.getCoerced(inst_sent, dst_elem_type)).toIntern()) {
27685 if (Air.internedToRef(dest_info.sentinel) !=
27686 try sema.coerceInMemory(inst_sent, dst_elem_type))
27687 {
2768527688 in_memory_result = .{ .ptr_sentinel = .{
2768627689 .actual = inst_sent,
2768727690 .wanted = dest_info.sentinel.toValue(),
......@@ -27758,9 +27761,10 @@ fn coerceExtra(
2775827761 switch (dest_info.flags.size) {
2775927762 // coercion to C pointer
2776027763 .C => switch (inst_ty.zigTypeTag(mod)) {
27761 .Null => {
27762 return Air.internedToRef((try mod.getCoerced(Value.null, dest_ty)).toIntern());
27763 },
27764 .Null => return Air.internedToRef(try mod.intern(.{ .ptr = .{
27765 .ty = dest_ty.toIntern(),
27766 .addr = .{ .int = .zero_usize },
27767 } })),
2776427768 .ComptimeInt => {
2776527769 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
2776627770 error.NotCoercible => break :pointer,
......@@ -27865,10 +27869,19 @@ fn coerceExtra(
2786527869 // we use a dummy pointer value with the required alignment.
2786627870 return Air.internedToRef((try mod.intern(.{ .ptr = .{
2786727871 .ty = dest_ty.toIntern(),
27868 .addr = .{ .int = (if (dest_info.flags.alignment != .none)
27869 try mod.intValue(Type.usize, dest_info.flags.alignment.toByteUnitsOptional().?)
27872 .addr = .{ .int = if (dest_info.flags.alignment != .none)
27873 (try mod.intValue(
27874 Type.usize,
27875 dest_info.flags.alignment.toByteUnitsOptional().?,
27876 )).toIntern()
2787027877 else
27871 try mod.getCoerced(try dest_info.child.toType().lazyAbiAlignment(mod), Type.usize)).toIntern() },
27878 try mod.intern_pool.getCoercedInts(
27879 mod.gpa,
27880 mod.intern_pool.indexToKey(
27881 (try dest_info.child.toType().lazyAbiAlignment(mod)).toIntern(),
27882 ).int,
27883 .usize_type,
27884 ) },
2787227885 .len = (try mod.intValue(Type.usize, 0)).toIntern(),
2787327886 } })));
2787427887 }
......@@ -27904,8 +27917,8 @@ fn coerceExtra(
2790427917 }
2790527918
2790627919 if (dest_info.sentinel == .none or inst_info.sentinel == .none or
27907 dest_info.sentinel !=
27908 try mod.intern_pool.getCoerced(sema.gpa, inst_info.sentinel, dest_info.child))
27920 Air.internedToRef(dest_info.sentinel) !=
27921 try sema.coerceInMemory(inst_info.sentinel.toValue(), dest_info.child.toType()))
2790927922 break :p;
2791027923
2791127924 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
......@@ -27915,10 +27928,7 @@ fn coerceExtra(
2791527928 },
2791627929 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
2791727930 .Float, .ComptimeFloat => float: {
27918 if (is_undef) {
27919 return mod.undefRef(dest_ty);
27920 }
27921 const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
27931 const val = maybe_inst_val orelse {
2792227932 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
2792327933 if (!opts.report_err) return error.NotCoercible;
2792427934 return sema.failWithNeededComptime(block, inst_src, .{
......@@ -27927,29 +27937,23 @@ fn coerceExtra(
2792727937 }
2792827938 break :float;
2792927939 };
27930
27931 if (val.floatHasFraction(mod)) {
27932 return sema.fail(
27933 block,
27934 inst_src,
27935 "fractional component prevents float value '{}' from coercion to type '{}'",
27936 .{ val.fmtValue(inst_ty, mod), dest_ty.fmt(mod) },
27937 );
27938 }
27939 const result_val = try sema.intFromFloat(block, inst_src, val, inst_ty, dest_ty);
27940 const result_val = try sema.intFromFloat(block, inst_src, val, inst_ty, dest_ty, .exact);
2794027941 return Air.internedToRef(result_val.toIntern());
2794127942 },
2794227943 .Int, .ComptimeInt => {
27943 if (is_undef) {
27944 return mod.undefRef(dest_ty);
27945 }
27946 if (try sema.resolveMaybeUndefVal(inst)) |val| {
27944 if (maybe_inst_val) |val| {
2794727945 // comptime-known integer to other number
2794827946 if (!(try sema.intFitsInType(val, dest_ty, null))) {
2794927947 if (!opts.report_err) return error.NotCoercible;
2795027948 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });
2795127949 }
27952 return Air.internedToRef((try mod.getCoerced(val, dest_ty)).toIntern());
27950 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
27951 .undef => try mod.undefRef(dest_ty),
27952 .int => |int| Air.internedToRef(
27953 try mod.intern_pool.getCoercedInts(mod.gpa, int, dest_ty.toIntern()),
27954 ),
27955 else => unreachable,
27956 };
2795327957 }
2795427958 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
2795527959 if (!opts.report_err) return error.NotCoercible;
......@@ -27970,9 +27974,6 @@ fn coerceExtra(
2797027974 return block.addTyOp(.intcast, dest_ty, inst);
2797127975 }
2797227976 },
27973 .Undefined => {
27974 return mod.undefRef(dest_ty);
27975 },
2797627977 else => {},
2797727978 },
2797827979 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
......@@ -27982,10 +27983,7 @@ fn coerceExtra(
2798227983 return Air.internedToRef(result_val.toIntern());
2798327984 },
2798427985 .Float => {
27985 if (is_undef) {
27986 return mod.undefRef(dest_ty);
27987 }
27988 if (try sema.resolveMaybeUndefVal(inst)) |val| {
27986 if (maybe_inst_val) |val| {
2798927987 const result_val = try val.floatCast(dest_ty, mod);
2799027988 if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
2799127989 return sema.fail(
......@@ -28012,10 +28010,7 @@ fn coerceExtra(
2801228010 }
2801328011 },
2801428012 .Int, .ComptimeInt => int: {
28015 if (is_undef) {
28016 return mod.undefRef(dest_ty);
28017 }
28018 const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
28013 const val = maybe_inst_val orelse {
2801928014 if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
2802028015 if (!opts.report_err) return error.NotCoercible;
2802128016 return sema.failWithNeededComptime(block, inst_src, .{
......@@ -28037,9 +28032,6 @@ fn coerceExtra(
2803728032 //}
2803828033 return Air.internedToRef(result_val.toIntern());
2803928034 },
28040 .Undefined => {
28041 return mod.undefRef(dest_ty);
28042 },
2804328035 else => {},
2804428036 },
2804528037 .Enum => switch (inst_ty.zigTypeTag(mod)) {
......@@ -28070,9 +28062,6 @@ fn coerceExtra(
2807028062 return sema.unionToTag(block, dest_ty, inst, inst_src);
2807128063 }
2807228064 },
28073 .Undefined => {
28074 return mod.undefRef(dest_ty);
28075 },
2807628065 else => {},
2807728066 },
2807828067 .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
......@@ -28107,9 +28096,6 @@ fn coerceExtra(
2810728096 // E to E!T
2810828097 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
2810928098 },
28110 .Undefined => {
28111 return mod.undefRef(dest_ty);
28112 },
2811328099 else => eu: {
2811428100 // T to E!T
2811528101 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
......@@ -28125,9 +28111,6 @@ fn coerceExtra(
2812528111 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
2812628112 }
2812728113 },
28128 .Undefined => {
28129 return mod.undefRef(dest_ty);
28130 },
2813128114 else => {},
2813228115 },
2813328116 .Array => switch (inst_ty.zigTypeTag(mod)) {
......@@ -28140,9 +28123,6 @@ fn coerceExtra(
2814028123 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
2814128124 }
2814228125 },
28143 .Undefined => {
28144 return mod.undefRef(dest_ty);
28145 },
2814628126 else => {},
2814728127 },
2814828128 .Vector => switch (inst_ty.zigTypeTag(mod)) {
......@@ -28152,9 +28132,6 @@ fn coerceExtra(
2815228132 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
2815328133 }
2815428134 },
28155 .Undefined => {
28156 return mod.undefRef(dest_ty);
28157 },
2815828135 else => {},
2815928136 },
2816028137 .Struct => blk: {
......@@ -28174,9 +28151,7 @@ fn coerceExtra(
2817428151 // undefined to anything. We do this after the big switch above so that
2817528152 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
2817628153 // should initialize the length field of the slice.
28177 if (is_undef) {
28178 return mod.undefRef(dest_ty);
28179 }
28154 if (maybe_inst_val) |val| if (val.toIntern() == .undef) return mod.undefRef(dest_ty);
2818028155
2818128156 if (!opts.report_err) return error.NotCoercible;
2818228157
......@@ -34043,10 +34018,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3404334018 switch (mod.intern_pool.indexToKey(val.toIntern())) {
3404434019 .int => |int| switch (int.storage) {
3404534020 .u64, .i64, .big_int => return val,
34046 .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{
34047 .ty = int.ty,
34048 .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? },
34049 } })).toValue(),
34021 .lazy_align, .lazy_size => return mod.intValue(
34022 int.ty.toType(),
34023 (try val.getUnsignedIntAdvanced(mod, sema)).?,
34024 ),
3405034025 },
3405134026 .ptr => |ptr| {
3405234027 const resolved_len = switch (ptr.len) {
......@@ -36217,20 +36192,21 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3621736192 .auto, .explicit => {
3621836193 if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
3621936194
36220 switch (enum_type.names.len) {
36221 0 => {
36222 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
36223 return only.toValue();
36224 },
36225 1 => return try mod.getCoerced((if (enum_type.values.len == 0)
36226 try mod.intern(.{ .int = .{
36227 .ty = enum_type.tag_ty,
36228 .storage = .{ .u64 = 0 },
36229 } })
36230 else
36231 enum_type.values.get(ip)[0]).toValue(), ty),
36195 return switch (enum_type.names.len) {
36196 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
36197 1 => try mod.intern(.{ .enum_tag = .{
36198 .ty = ty.toIntern(),
36199 .int = if (enum_type.values.len == 0)
36200 (try mod.intValue(enum_type.tag_ty.toType(), 0)).toIntern()
36201 else
36202 try mod.intern_pool.getCoercedInts(
36203 mod.gpa,
36204 mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
36205 enum_type.tag_ty,
36206 ),
36207 } }),
3623236208 else => return null,
36233 }
36209 }.toValue();
3623436210 },
3623536211 },
3623636212
......@@ -37069,6 +37045,8 @@ fn intSubWithOverflowScalar(
3706937045 };
3707037046}
3707137047
37048const IntFromFloatMode = enum { exact, truncate };
37049
3707237050fn intFromFloat(
3707337051 sema: *Sema,
3707437052 block: *Block,
......@@ -37076,6 +37054,7 @@ fn intFromFloat(
3707637054 val: Value,
3707737055 float_ty: Type,
3707837056 int_ty: Type,
37057 mode: IntFromFloatMode,
3707937058) CompileError!Value {
3708037059 const mod = sema.mod;
3708137060 if (float_ty.zigTypeTag(mod) == .Vector) {
......@@ -37084,14 +37063,14 @@ fn intFromFloat(
3708437063 const scalar_ty = int_ty.scalarType(mod);
3708537064 for (result_data, 0..) |*scalar, i| {
3708637065 const elem_val = try val.elemValue(sema.mod, i);
37087 scalar.* = try (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod);
37066 scalar.* = try (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod), mode)).intern(scalar_ty, mod);
3708837067 }
3708937068 return (try mod.intern(.{ .aggregate = .{
3709037069 .ty = int_ty.toIntern(),
3709137070 .storage = .{ .elems = result_data },
3709237071 } })).toValue();
3709337072 }
37094 return sema.intFromFloatScalar(block, src, val, float_ty, int_ty);
37073 return sema.intFromFloatScalar(block, src, val, float_ty, int_ty, mode);
3709537074}
3709637075
3709737076// float is expected to be finite and non-NaN
......@@ -37126,9 +37105,19 @@ fn intFromFloatScalar(
3712637105 val: Value,
3712737106 float_ty: Type,
3712837107 int_ty: Type,
37108 mode: IntFromFloatMode,
3712937109) CompileError!Value {
3713037110 const mod = sema.mod;
3713137111
37112 if (val.isUndef(mod)) return sema.failWithUseOfUndef(block, src);
37113
37114 if (mode == .exact and val.floatHasFraction(mod)) return sema.fail(
37115 block,
37116 src,
37117 "fractional component prevents float value '{}' from coercion to type '{}'",
37118 .{ val.fmtValue(float_ty, mod), int_ty.fmt(mod) },
37119 );
37120
3713237121 const float = val.toFloat(f128, mod);
3713337122 if (std.math.isNan(float)) {
3713437123 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
src/value.zig+1-1
......@@ -1866,7 +1866,7 @@ pub const Value = struct {
18661866
18671867 pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
18681868 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1869 .undef => (try mod.intern(.{ .undef = float_ty.toIntern() })).toValue(),
1869 .undef => try mod.undefValue(float_ty),
18701870 .int => |int| switch (int.storage) {
18711871 .big_int => |big_int| {
18721872 const float = bigIntToFloat(big_int.limbs, big_int.positive);
test/behavior/cast.zig+13
......@@ -1155,6 +1155,8 @@ fn foobar(func: PFN_void) !void {
11551155}
11561156
11571157test "cast function with an opaque parameter" {
1158 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1159
11581160 const Container = struct {
11591161 const Ctx = opaque {};
11601162 ctx: *Ctx,
......@@ -2494,3 +2496,14 @@ test "@intFromBool on vector" {
24942496 try S.doTheTest();
24952497 try comptime S.doTheTest();
24962498}
2499
2500test "numeric coercions with undefined" {
2501 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
2502 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2503
2504 const from: i32 = undefined;
2505 var to: f32 = from;
2506 to = @floatFromInt(from);
2507 to = 42.0;
2508 try expectEqual(@as(f32, 42.0), to);
2509}
test/behavior/undefined.zig+1
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
45const mem = std.mem;
56
67fn initStaticArray() [10]i32 {