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(...@@ -6360,7 +6360,7 @@ pub fn errorSetFromUnsortedNames(
63606360
6361/// Supports only pointers, not pointer-like optionals.6361/// Supports only pointers, not pointer-like optionals.
6362pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {6362pub 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));
6364 const i = try intern(mod, .{ .ptr = .{6364 const i = try intern(mod, .{ .ptr = .{
6365 .ty = ty.toIntern(),6365 .ty = ty.toIntern(),
6366 .addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },6366 .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...@@ -17282,12 +17282,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17282 for (enum_field_vals, 0..) |*field_val, i| {17282 for (enum_field_vals, 0..) |*field_val, i| {
17283 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;17283 const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
17284 const value_val = if (enum_type.values.len > 0)17284 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 )
17286 else17290 else
17287 try mod.intern(.{ .int = .{17291 (try mod.intValue(Type.comptime_int, i)).toIntern();
17288 .ty = .comptime_int_type,
17289 .storage = .{ .u64 = @intCast(i) },
17290 } });
17291 // TODO: write something like getCoercedInts to avoid needing to dupe17292 // TODO: write something like getCoercedInts to avoid needing to dupe
17292 const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));17293 const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));
17293 const name_val = v: {17294 const name_val = v: {
...@@ -21259,7 +21260,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -21259,7 +21260,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
21259 try sema.checkFloatType(block, operand_src, operand_scalar_ty);21260 try sema.checkFloatType(block, operand_src, operand_scalar_ty);
2126021261
21261 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {21262 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);
21263 return Air.internedToRef(result_val.toIntern());21264 return Air.internedToRef(result_val.toIntern());
21264 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {21265 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
21265 return sema.failWithNeededComptime(block, operand_src, .{21266 return sema.failWithNeededComptime(block, operand_src, .{
...@@ -27575,21 +27576,21 @@ fn coerceExtra(...@@ -27575,21 +27576,21 @@ fn coerceExtra(
27575 return block.addBitCast(dest_ty, inst);27576 return block.addBitCast(dest_ty, inst);
27576 }27577 }
2757727578
27578 const is_undef = inst_ty.zigTypeTag(mod) == .Undefined;
27579
27580 switch (dest_ty.zigTypeTag(mod)) {27579 switch (dest_ty.zigTypeTag(mod)) {
27581 .Optional => optional: {27580 .Optional => optional: {
27582 // undefined sets the optional bit also to undefined.27581 if (maybe_inst_val) |val| {
27583 if (is_undef) {27582 // undefined sets the optional bit also to undefined.
27584 return mod.undefRef(dest_ty);27583 if (val.toIntern() == .undef) {
27585 }27584 return mod.undefRef(dest_ty);
27585 }
2758627586
27587 // null to ?T27587 // null to ?T
27588 if (inst_ty.zigTypeTag(mod) == .Null) {27588 if (val.toIntern() == .null_value) {
27589 return Air.internedToRef((try mod.intern(.{ .opt = .{27589 return Air.internedToRef((try mod.intern(.{ .opt = .{
27590 .ty = dest_ty.toIntern(),27590 .ty = dest_ty.toIntern(),
27591 .val = .none,27591 .val = .none,
27592 } })));27592 } })));
27593 }
27593 }27594 }
2759427595
27595 // cast from ?*T and ?[*]T to ?*anyopaque27596 // cast from ?*T and ?[*]T to ?*anyopaque
...@@ -27681,7 +27682,9 @@ fn coerceExtra(...@@ -27681,7 +27682,9 @@ fn coerceExtra(
2768127682
27682 if (dest_info.sentinel != .none) {27683 if (dest_info.sentinel != .none) {
27683 if (array_ty.sentinel(mod)) |inst_sent| {27684 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 {
27685 in_memory_result = .{ .ptr_sentinel = .{27688 in_memory_result = .{ .ptr_sentinel = .{
27686 .actual = inst_sent,27689 .actual = inst_sent,
27687 .wanted = dest_info.sentinel.toValue(),27690 .wanted = dest_info.sentinel.toValue(),
...@@ -27758,9 +27761,10 @@ fn coerceExtra(...@@ -27758,9 +27761,10 @@ fn coerceExtra(
27758 switch (dest_info.flags.size) {27761 switch (dest_info.flags.size) {
27759 // coercion to C pointer27762 // coercion to C pointer
27760 .C => switch (inst_ty.zigTypeTag(mod)) {27763 .C => switch (inst_ty.zigTypeTag(mod)) {
27761 .Null => {27764 .Null => return Air.internedToRef(try mod.intern(.{ .ptr = .{
27762 return Air.internedToRef((try mod.getCoerced(Value.null, dest_ty)).toIntern());27765 .ty = dest_ty.toIntern(),
27763 },27766 .addr = .{ .int = .zero_usize },
27767 } })),
27764 .ComptimeInt => {27768 .ComptimeInt => {
27765 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {27769 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
27766 error.NotCoercible => break :pointer,27770 error.NotCoercible => break :pointer,
...@@ -27865,10 +27869,19 @@ fn coerceExtra(...@@ -27865,10 +27869,19 @@ fn coerceExtra(
27865 // we use a dummy pointer value with the required alignment.27869 // we use a dummy pointer value with the required alignment.
27866 return Air.internedToRef((try mod.intern(.{ .ptr = .{27870 return Air.internedToRef((try mod.intern(.{ .ptr = .{
27867 .ty = dest_ty.toIntern(),27871 .ty = dest_ty.toIntern(),
27868 .addr = .{ .int = (if (dest_info.flags.alignment != .none)27872 .addr = .{ .int = if (dest_info.flags.alignment != .none)
27869 try mod.intValue(Type.usize, dest_info.flags.alignment.toByteUnitsOptional().?)27873 (try mod.intValue(
27874 Type.usize,
27875 dest_info.flags.alignment.toByteUnitsOptional().?,
27876 )).toIntern()
27870 else27877 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 ) },
27872 .len = (try mod.intValue(Type.usize, 0)).toIntern(),27885 .len = (try mod.intValue(Type.usize, 0)).toIntern(),
27873 } })));27886 } })));
27874 }27887 }
...@@ -27904,8 +27917,8 @@ fn coerceExtra(...@@ -27904,8 +27917,8 @@ fn coerceExtra(
27904 }27917 }
2790527918
27906 if (dest_info.sentinel == .none or inst_info.sentinel == .none or27919 if (dest_info.sentinel == .none or inst_info.sentinel == .none or
27907 dest_info.sentinel !=27920 Air.internedToRef(dest_info.sentinel) !=
27908 try mod.intern_pool.getCoerced(sema.gpa, inst_info.sentinel, dest_info.child))27921 try sema.coerceInMemory(inst_info.sentinel.toValue(), dest_info.child.toType()))
27909 break :p;27922 break :p;
2791027923
27911 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);27924 const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
...@@ -27915,10 +27928,7 @@ fn coerceExtra(...@@ -27915,10 +27928,7 @@ fn coerceExtra(
27915 },27928 },
27916 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {27929 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
27917 .Float, .ComptimeFloat => float: {27930 .Float, .ComptimeFloat => float: {
27918 if (is_undef) {27931 const val = maybe_inst_val orelse {
27919 return mod.undefRef(dest_ty);
27920 }
27921 const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
27922 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {27932 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
27923 if (!opts.report_err) return error.NotCoercible;27933 if (!opts.report_err) return error.NotCoercible;
27924 return sema.failWithNeededComptime(block, inst_src, .{27934 return sema.failWithNeededComptime(block, inst_src, .{
...@@ -27927,29 +27937,23 @@ fn coerceExtra(...@@ -27927,29 +27937,23 @@ fn coerceExtra(
27927 }27937 }
27928 break :float;27938 break :float;
27929 };27939 };
2793027940 const result_val = try sema.intFromFloat(block, inst_src, val, inst_ty, dest_ty, .exact);
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 return Air.internedToRef(result_val.toIntern());27941 return Air.internedToRef(result_val.toIntern());
27941 },27942 },
27942 .Int, .ComptimeInt => {27943 .Int, .ComptimeInt => {
27943 if (is_undef) {27944 if (maybe_inst_val) |val| {
27944 return mod.undefRef(dest_ty);
27945 }
27946 if (try sema.resolveMaybeUndefVal(inst)) |val| {
27947 // comptime-known integer to other number27945 // comptime-known integer to other number
27948 if (!(try sema.intFitsInType(val, dest_ty, null))) {27946 if (!(try sema.intFitsInType(val, dest_ty, null))) {
27949 if (!opts.report_err) return error.NotCoercible;27947 if (!opts.report_err) return error.NotCoercible;
27950 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });27948 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });
27951 }27949 }
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 };
27953 }27957 }
27954 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {27958 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
27955 if (!opts.report_err) return error.NotCoercible;27959 if (!opts.report_err) return error.NotCoercible;
...@@ -27970,9 +27974,6 @@ fn coerceExtra(...@@ -27970,9 +27974,6 @@ fn coerceExtra(
27970 return block.addTyOp(.intcast, dest_ty, inst);27974 return block.addTyOp(.intcast, dest_ty, inst);
27971 }27975 }
27972 },27976 },
27973 .Undefined => {
27974 return mod.undefRef(dest_ty);
27975 },
27976 else => {},27977 else => {},
27977 },27978 },
27978 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {27979 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
...@@ -27982,10 +27983,7 @@ fn coerceExtra(...@@ -27982,10 +27983,7 @@ fn coerceExtra(
27982 return Air.internedToRef(result_val.toIntern());27983 return Air.internedToRef(result_val.toIntern());
27983 },27984 },
27984 .Float => {27985 .Float => {
27985 if (is_undef) {27986 if (maybe_inst_val) |val| {
27986 return mod.undefRef(dest_ty);
27987 }
27988 if (try sema.resolveMaybeUndefVal(inst)) |val| {
27989 const result_val = try val.floatCast(dest_ty, mod);27987 const result_val = try val.floatCast(dest_ty, mod);
27990 if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {27988 if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
27991 return sema.fail(27989 return sema.fail(
...@@ -28012,10 +28010,7 @@ fn coerceExtra(...@@ -28012,10 +28010,7 @@ fn coerceExtra(
28012 }28010 }
28013 },28011 },
28014 .Int, .ComptimeInt => int: {28012 .Int, .ComptimeInt => int: {
28015 if (is_undef) {28013 const val = maybe_inst_val orelse {
28016 return mod.undefRef(dest_ty);
28017 }
28018 const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
28019 if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {28014 if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
28020 if (!opts.report_err) return error.NotCoercible;28015 if (!opts.report_err) return error.NotCoercible;
28021 return sema.failWithNeededComptime(block, inst_src, .{28016 return sema.failWithNeededComptime(block, inst_src, .{
...@@ -28037,9 +28032,6 @@ fn coerceExtra(...@@ -28037,9 +28032,6 @@ fn coerceExtra(
28037 //}28032 //}
28038 return Air.internedToRef(result_val.toIntern());28033 return Air.internedToRef(result_val.toIntern());
28039 },28034 },
28040 .Undefined => {
28041 return mod.undefRef(dest_ty);
28042 },
28043 else => {},28035 else => {},
28044 },28036 },
28045 .Enum => switch (inst_ty.zigTypeTag(mod)) {28037 .Enum => switch (inst_ty.zigTypeTag(mod)) {
...@@ -28070,9 +28062,6 @@ fn coerceExtra(...@@ -28070,9 +28062,6 @@ fn coerceExtra(
28070 return sema.unionToTag(block, dest_ty, inst, inst_src);28062 return sema.unionToTag(block, dest_ty, inst, inst_src);
28071 }28063 }
28072 },28064 },
28073 .Undefined => {
28074 return mod.undefRef(dest_ty);
28075 },
28076 else => {},28065 else => {},
28077 },28066 },
28078 .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {28067 .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
...@@ -28107,9 +28096,6 @@ fn coerceExtra(...@@ -28107,9 +28096,6 @@ fn coerceExtra(
28107 // E to E!T28096 // E to E!T
28108 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);28097 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
28109 },28098 },
28110 .Undefined => {
28111 return mod.undefRef(dest_ty);
28112 },
28113 else => eu: {28099 else => eu: {
28114 // T to E!T28100 // T to E!T
28115 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {28101 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
...@@ -28125,9 +28111,6 @@ fn coerceExtra(...@@ -28125,9 +28111,6 @@ fn coerceExtra(
28125 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);28111 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
28126 }28112 }
28127 },28113 },
28128 .Undefined => {
28129 return mod.undefRef(dest_ty);
28130 },
28131 else => {},28114 else => {},
28132 },28115 },
28133 .Array => switch (inst_ty.zigTypeTag(mod)) {28116 .Array => switch (inst_ty.zigTypeTag(mod)) {
...@@ -28140,9 +28123,6 @@ fn coerceExtra(...@@ -28140,9 +28123,6 @@ fn coerceExtra(
28140 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);28123 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
28141 }28124 }
28142 },28125 },
28143 .Undefined => {
28144 return mod.undefRef(dest_ty);
28145 },
28146 else => {},28126 else => {},
28147 },28127 },
28148 .Vector => switch (inst_ty.zigTypeTag(mod)) {28128 .Vector => switch (inst_ty.zigTypeTag(mod)) {
...@@ -28152,9 +28132,6 @@ fn coerceExtra(...@@ -28152,9 +28132,6 @@ fn coerceExtra(
28152 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);28132 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
28153 }28133 }
28154 },28134 },
28155 .Undefined => {
28156 return mod.undefRef(dest_ty);
28157 },
28158 else => {},28135 else => {},
28159 },28136 },
28160 .Struct => blk: {28137 .Struct => blk: {
...@@ -28174,9 +28151,7 @@ fn coerceExtra(...@@ -28174,9 +28151,7 @@ fn coerceExtra(
28174 // undefined to anything. We do this after the big switch above so that28151 // undefined to anything. We do this after the big switch above so that
28175 // special logic has a chance to run first, such as `*[N]T` to `[]T` which28152 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
28176 // should initialize the length field of the slice.28153 // should initialize the length field of the slice.
28177 if (is_undef) {28154 if (maybe_inst_val) |val| if (val.toIntern() == .undef) return mod.undefRef(dest_ty);
28178 return mod.undefRef(dest_ty);
28179 }
2818028155
28181 if (!opts.report_err) return error.NotCoercible;28156 if (!opts.report_err) return error.NotCoercible;
2818228157
...@@ -34043,10 +34018,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -34043,10 +34018,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
34043 switch (mod.intern_pool.indexToKey(val.toIntern())) {34018 switch (mod.intern_pool.indexToKey(val.toIntern())) {
34044 .int => |int| switch (int.storage) {34019 .int => |int| switch (int.storage) {
34045 .u64, .i64, .big_int => return val,34020 .u64, .i64, .big_int => return val,
34046 .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{34021 .lazy_align, .lazy_size => return mod.intValue(
34047 .ty = int.ty,34022 int.ty.toType(),
34048 .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? },34023 (try val.getUnsignedIntAdvanced(mod, sema)).?,
34049 } })).toValue(),34024 ),
34050 },34025 },
34051 .ptr => |ptr| {34026 .ptr => |ptr| {
34052 const resolved_len = switch (ptr.len) {34027 const resolved_len = switch (ptr.len) {
...@@ -36217,20 +36192,21 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -36217,20 +36192,21 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
36217 .auto, .explicit => {36192 .auto, .explicit => {
36218 if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;36193 if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
3621936194
36220 switch (enum_type.names.len) {36195 return switch (enum_type.names.len) {
36221 0 => {36196 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
36222 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });36197 1 => try mod.intern(.{ .enum_tag = .{
36223 return only.toValue();36198 .ty = ty.toIntern(),
36224 },36199 .int = if (enum_type.values.len == 0)
36225 1 => return try mod.getCoerced((if (enum_type.values.len == 0)36200 (try mod.intValue(enum_type.tag_ty.toType(), 0)).toIntern()
36226 try mod.intern(.{ .int = .{36201 else
36227 .ty = enum_type.tag_ty,36202 try mod.intern_pool.getCoercedInts(
36228 .storage = .{ .u64 = 0 },36203 mod.gpa,
36229 } })36204 mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
36230 else36205 enum_type.tag_ty,
36231 enum_type.values.get(ip)[0]).toValue(), ty),36206 ),
36207 } }),
36232 else => return null,36208 else => return null,
36233 }36209 }.toValue();
36234 },36210 },
36235 },36211 },
3623636212
...@@ -37069,6 +37045,8 @@ fn intSubWithOverflowScalar(...@@ -37069,6 +37045,8 @@ fn intSubWithOverflowScalar(
37069 };37045 };
37070}37046}
3707137047
37048const IntFromFloatMode = enum { exact, truncate };
37049
37072fn intFromFloat(37050fn intFromFloat(
37073 sema: *Sema,37051 sema: *Sema,
37074 block: *Block,37052 block: *Block,
...@@ -37076,6 +37054,7 @@ fn intFromFloat(...@@ -37076,6 +37054,7 @@ fn intFromFloat(
37076 val: Value,37054 val: Value,
37077 float_ty: Type,37055 float_ty: Type,
37078 int_ty: Type,37056 int_ty: Type,
37057 mode: IntFromFloatMode,
37079) CompileError!Value {37058) CompileError!Value {
37080 const mod = sema.mod;37059 const mod = sema.mod;
37081 if (float_ty.zigTypeTag(mod) == .Vector) {37060 if (float_ty.zigTypeTag(mod) == .Vector) {
...@@ -37084,14 +37063,14 @@ fn intFromFloat(...@@ -37084,14 +37063,14 @@ fn intFromFloat(
37084 const scalar_ty = int_ty.scalarType(mod);37063 const scalar_ty = int_ty.scalarType(mod);
37085 for (result_data, 0..) |*scalar, i| {37064 for (result_data, 0..) |*scalar, i| {
37086 const elem_val = try val.elemValue(sema.mod, i);37065 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);
37088 }37067 }
37089 return (try mod.intern(.{ .aggregate = .{37068 return (try mod.intern(.{ .aggregate = .{
37090 .ty = int_ty.toIntern(),37069 .ty = int_ty.toIntern(),
37091 .storage = .{ .elems = result_data },37070 .storage = .{ .elems = result_data },
37092 } })).toValue();37071 } })).toValue();
37093 }37072 }
37094 return sema.intFromFloatScalar(block, src, val, float_ty, int_ty);37073 return sema.intFromFloatScalar(block, src, val, float_ty, int_ty, mode);
37095}37074}
3709637075
37097// float is expected to be finite and non-NaN37076// float is expected to be finite and non-NaN
...@@ -37126,9 +37105,19 @@ fn intFromFloatScalar(...@@ -37126,9 +37105,19 @@ fn intFromFloatScalar(
37126 val: Value,37105 val: Value,
37127 float_ty: Type,37106 float_ty: Type,
37128 int_ty: Type,37107 int_ty: Type,
37108 mode: IntFromFloatMode,
37129) CompileError!Value {37109) CompileError!Value {
37130 const mod = sema.mod;37110 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
37132 const float = val.toFloat(f128, mod);37121 const float = val.toFloat(f128, mod);
37133 if (std.math.isNan(float)) {37122 if (std.math.isNan(float)) {
37134 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{37123 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 {...@@ -1866,7 +1866,7 @@ pub const Value = struct {
18661866
1867 pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {1867 pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
1868 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1868 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),
1870 .int => |int| switch (int.storage) {1870 .int => |int| switch (int.storage) {
1871 .big_int => |big_int| {1871 .big_int => |big_int| {
1872 const float = bigIntToFloat(big_int.limbs, big_int.positive);1872 const float = bigIntToFloat(big_int.limbs, big_int.positive);
test/behavior/cast.zig+13
...@@ -1155,6 +1155,8 @@ fn foobar(func: PFN_void) !void {...@@ -1155,6 +1155,8 @@ fn foobar(func: PFN_void) !void {
1155}1155}
11561156
1157test "cast function with an opaque parameter" {1157test "cast function with an opaque parameter" {
1158 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1159
1158 const Container = struct {1160 const Container = struct {
1159 const Ctx = opaque {};1161 const Ctx = opaque {};
1160 ctx: *Ctx,1162 ctx: *Ctx,
...@@ -2494,3 +2496,14 @@ test "@intFromBool on vector" {...@@ -2494,3 +2496,14 @@ test "@intFromBool on vector" {
2494 try S.doTheTest();2496 try S.doTheTest();
2495 try comptime S.doTheTest();2497 try comptime S.doTheTest();
2496}2498}
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 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
4const mem = std.mem;5const mem = std.mem;
56
6fn initStaticArray() [10]i32 {7fn initStaticArray() [10]i32 {