| author | |
| committer | |
| log | 8349a644d0b9d4b2d58d736a14cdcc567a9e9b89 |
| tree | 419fe3dc7cab67d43f0cc5b85040340476ab42a1 |
| parent | b3aa1ab693ac160a07c44f07c7b90577039860a1 |
| parent | bf5c055562b88f1a686815c85d2a29c0889a97ee |
| signature |
stage2: actually coerce in coerce_result_ptr at comptime8 files changed, 67 insertions(+), 39 deletions(-)
src/Sema.zig+12-17| ... | ... | @@ -1593,27 +1593,16 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1593 | 1593 | } |
| 1594 | 1594 | } |
| 1595 | 1595 | |
| 1596 | // We would like to rely on the mechanism below even for comptime values. | |
| 1597 | // However in the case that the pointer points to comptime-mutable value, | |
| 1598 | // we cannot do it. | |
| 1599 | if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| { | |
| 1600 | if (ptr_val.isComptimeMutablePtr()) { | |
| 1601 | const ptr_ty = try Type.ptr(sema.arena, .{ | |
| 1602 | .pointee_type = pointee_ty, | |
| 1603 | .@"addrspace" = addr_space, | |
| 1604 | }); | |
| 1605 | return sema.addConstant(ptr_ty, ptr_val); | |
| 1606 | } | |
| 1607 | } | |
| 1608 | ||
| 1609 | 1596 | // Make a dummy store through the pointer to test the coercion. |
| 1610 | 1597 | // We will then use the generated instructions to decide what |
| 1611 | 1598 | // kind of transformations to make on the result pointer. |
| 1612 | 1599 | var trash_block = block.makeSubBlock(); |
| 1600 | trash_block.is_comptime = false; | |
| 1613 | 1601 | defer trash_block.instructions.deinit(sema.gpa); |
| 1614 | 1602 | |
| 1603 | const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); | |
| 1615 | 1604 | const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); |
| 1616 | try sema.storePtr(&trash_block, src, ptr, dummy_operand); | |
| 1605 | try sema.storePtr(&trash_block, src, dummy_ptr, dummy_operand); | |
| 1617 | 1606 | |
| 1618 | 1607 | { |
| 1619 | 1608 | const air_tags = sema.air_instructions.items(.tag); |
| ... | ... | @@ -1644,6 +1633,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1644 | 1633 | switch (air_tags[trash_inst]) { |
| 1645 | 1634 | .bitcast => { |
| 1646 | 1635 | if (Air.indexToRef(trash_inst) == dummy_operand) { |
| 1636 | if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { | |
| 1637 | return sema.addConstant(ptr_ty, ptr_val); | |
| 1638 | } | |
| 1647 | 1639 | return sema.bitCast(block, ptr_ty, new_ptr, src); |
| 1648 | 1640 | } |
| 1649 | 1641 | const ty_op = air_datas[trash_inst].ty_op; |
| ... | ... | @@ -1652,7 +1644,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1652 | 1644 | .pointee_type = operand_ty, |
| 1653 | 1645 | .@"addrspace" = addr_space, |
| 1654 | 1646 | }); |
| 1655 | new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src); | |
| 1647 | if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { | |
| 1648 | new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val); | |
| 1649 | } else { | |
| 1650 | new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src); | |
| 1651 | } | |
| 1656 | 1652 | }, |
| 1657 | 1653 | .wrap_optional => { |
| 1658 | 1654 | new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true); |
| ... | ... | @@ -1673,7 +1669,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1673 | 1669 | } |
| 1674 | 1670 | }, |
| 1675 | 1671 | } |
| 1676 | } else unreachable; // TODO should not need else unreachable | |
| 1672 | } | |
| 1677 | 1673 | } |
| 1678 | 1674 | |
| 1679 | 1675 | pub fn analyzeStructDecl( |
| ... | ... | @@ -16937,7 +16933,6 @@ fn wrapErrorUnionPayload( |
| 16937 | 16933 | const dest_payload_ty = dest_ty.errorUnionPayload(); |
| 16938 | 16934 | const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src); |
| 16939 | 16935 | if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { |
| 16940 | if (val.isUndef()) return sema.addConstUndef(dest_ty); | |
| 16941 | 16936 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); |
| 16942 | 16937 | } |
| 16943 | 16938 | try sema.requireRuntimeBlock(block, inst_src); |
src/type.zig+2-2| ... | ... | @@ -3980,7 +3980,7 @@ pub const Type = extern union { |
| 3980 | 3980 | |
| 3981 | 3981 | pub fn structFields(ty: Type) Module.Struct.Fields { |
| 3982 | 3982 | switch (ty.tag()) { |
| 3983 | .empty_struct => return .{}, | |
| 3983 | .empty_struct, .empty_struct_literal => return .{}, | |
| 3984 | 3984 | .@"struct" => { |
| 3985 | 3985 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3986 | 3986 | assert(struct_obj.haveFieldTypes()); |
| ... | ... | @@ -3996,7 +3996,7 @@ pub const Type = extern union { |
| 3996 | 3996 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3997 | 3997 | return struct_obj.fields.count(); |
| 3998 | 3998 | }, |
| 3999 | .empty_struct => return 0, | |
| 3999 | .empty_struct, .empty_struct_literal => return 0, | |
| 4000 | 4000 | .tuple => return ty.castTag(.tuple).?.data.types.len, |
| 4001 | 4001 | else => unreachable, |
| 4002 | 4002 | } |
src/value.zig+14-9| ... | ... | @@ -791,19 +791,24 @@ pub const Value = extern union { |
| 791 | 791 | return decl_val.toAllocatedBytes(decl.ty, allocator); |
| 792 | 792 | }, |
| 793 | 793 | .the_only_possible_value => return &[_]u8{}, |
| 794 | .slice => return toAllocatedBytes(val.castTag(.slice).?.data.ptr, ty, allocator), | |
| 795 | else => { | |
| 796 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen())); | |
| 797 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 798 | for (result) |*elem, i| { | |
| 799 | const elem_val = val.elemValueBuffer(i, &elem_value_buf); | |
| 800 | elem.* = @intCast(u8, elem_val.toUnsignedInt()); | |
| 801 | } | |
| 802 | return result; | |
| 794 | .slice => { | |
| 795 | const slice = val.castTag(.slice).?.data; | |
| 796 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(), allocator); | |
| 803 | 797 | }, |
| 798 | else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator), | |
| 804 | 799 | } |
| 805 | 800 | } |
| 806 | 801 | |
| 802 | fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator) ![]u8 { | |
| 803 | const result = try allocator.alloc(u8, @intCast(usize, len)); | |
| 804 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 805 | for (result) |*elem, i| { | |
| 806 | const elem_val = val.elemValueBuffer(i, &elem_value_buf); | |
| 807 | elem.* = @intCast(u8, elem_val.toUnsignedInt()); | |
| 808 | } | |
| 809 | return result; | |
| 810 | } | |
| 811 | ||
| 807 | 812 | pub const ToTypeBuffer = Type.Payload.Bits; |
| 808 | 813 | |
| 809 | 814 | /// Asserts that the value is representable as a type. |
test/behavior.zig+3-3| ... | ... | @@ -127,8 +127,11 @@ test { |
| 127 | 127 | _ = @import("behavior/bugs/726.zig"); |
| 128 | 128 | _ = @import("behavior/bugs/1421.zig"); |
| 129 | 129 | _ = @import("behavior/bugs/1442.zig"); |
| 130 | _ = @import("behavior/bugs/1607.zig"); | |
| 130 | 131 | _ = @import("behavior/bugs/2114.zig"); |
| 132 | _ = @import("behavior/bugs/3384.zig"); | |
| 131 | 133 | _ = @import("behavior/bugs/3742.zig"); |
| 134 | _ = @import("behavior/bugs/5398.zig"); | |
| 132 | 135 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
| 133 | 136 | _ = @import("behavior/switch_prong_err_enum.zig"); |
| 134 | 137 | _ = @import("behavior/switch_prong_implicit_cast.zig"); |
| ... | ... | @@ -147,11 +150,8 @@ test { |
| 147 | 150 | _ = @import("behavior/bugs/828.zig"); |
| 148 | 151 | _ = @import("behavior/bugs/920.zig"); |
| 149 | 152 | _ = @import("behavior/bugs/1120.zig"); |
| 150 | _ = @import("behavior/bugs/1607.zig"); | |
| 151 | 153 | _ = @import("behavior/bugs/1851.zig"); |
| 152 | _ = @import("behavior/bugs/3384.zig"); | |
| 153 | 154 | _ = @import("behavior/bugs/3779.zig"); |
| 154 | _ = @import("behavior/bugs/5398.zig"); | |
| 155 | 155 | _ = @import("behavior/bugs/5413.zig"); |
| 156 | 156 | _ = @import("behavior/bugs/5487.zig"); |
| 157 | 157 | _ = @import("behavior/bugs/6456.zig"); |
test/behavior/bugs/5398.zig+3-3| ... | ... | @@ -25,7 +25,7 @@ test "assignment of field with padding" { |
| 25 | 25 | .emits_shadows = false, |
| 26 | 26 | }, |
| 27 | 27 | }; |
| 28 | try testing.expectEqual(false, renderable.material.transparent); | |
| 29 | try testing.expectEqual(false, renderable.material.emits_shadows); | |
| 30 | try testing.expectEqual(true, renderable.material.render_color); | |
| 28 | try testing.expect(false == renderable.material.transparent); | |
| 29 | try testing.expect(false == renderable.material.emits_shadows); | |
| 30 | try testing.expect(true == renderable.material.render_color); | |
| 31 | 31 | } |
test/behavior/cast.zig+4-2| ... | ... | @@ -371,7 +371,9 @@ fn testPeerResolveArrayConstSlice(b: bool) !void { |
| 371 | 371 | } |
| 372 | 372 | |
| 373 | 373 | test "implicitly cast from T to anyerror!?T" { |
| 374 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 375 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 376 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 375 | 377 | |
| 376 | 378 | try castToOptionalTypeError(1); |
| 377 | 379 | comptime try castToOptionalTypeError(1); |
| ... | ... | @@ -387,7 +389,7 @@ fn castToOptionalTypeError(z: i32) !void { |
| 387 | 389 | |
| 388 | 390 | const f = z; |
| 389 | 391 | const g: anyerror!?i32 = f; |
| 390 | _ = g catch {}; | |
| 392 | _ = try g; | |
| 391 | 393 | |
| 392 | 394 | const a = A{ .a = z }; |
| 393 | 395 | const b: anyerror!?A = a; |
test/behavior/error.zig+4-3| ... | ... | @@ -294,10 +294,11 @@ fn quux_1() !i32 { |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | 296 | test "error: Zero sized error set returned with value payload crash" { |
| 297 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 297 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 298 | 299 | |
| 299 | _ = foo3(0) catch {}; | |
| 300 | _ = comptime foo3(0) catch {}; | |
| 300 | _ = try foo3(0); | |
| 301 | _ = comptime try foo3(0); | |
| 301 | 302 | } |
| 302 | 303 | |
| 303 | 304 | const Error = error{}; |
test/behavior/struct.zig+25| ... | ... | @@ -1237,3 +1237,28 @@ test "anon init through error union" { |
| 1237 | 1237 | try S.doTheTest(); |
| 1238 | 1238 | comptime try S.doTheTest(); |
| 1239 | 1239 | } |
| 1240 | ||
| 1241 | test "typed init through error unions and optionals" { | |
| 1242 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 1243 | if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO | |
| 1244 | ||
| 1245 | const S = struct { | |
| 1246 | a: u32, | |
| 1247 | ||
| 1248 | fn foo() anyerror!?anyerror!@This() { | |
| 1249 | return @This(){ .a = 1 }; | |
| 1250 | } | |
| 1251 | fn bar() ?anyerror![2]u8 { | |
| 1252 | return [2]u8{ 1, 2 }; | |
| 1253 | } | |
| 1254 | ||
| 1255 | fn doTheTest() !void { | |
| 1256 | var a = try (try foo()).?; | |
| 1257 | var b = try bar().?; | |
| 1258 | try expect(a.a + b[1] == 3); | |
| 1259 | } | |
| 1260 | }; | |
| 1261 | ||
| 1262 | try S.doTheTest(); | |
| 1263 | comptime try S.doTheTest(); | |
| 1264 | } |