| 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,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 | // Make a dummy store through the pointer to test the coercion. | 1596 | // Make a dummy store through the pointer to test the coercion. |
| 1610 | // We will then use the generated instructions to decide what | 1597 | // We will then use the generated instructions to decide what |
| 1611 | // kind of transformations to make on the result pointer. | 1598 | // kind of transformations to make on the result pointer. |
| 1612 | var trash_block = block.makeSubBlock(); | 1599 | var trash_block = block.makeSubBlock(); |
| 1600 | trash_block.is_comptime = false; | ||
| 1613 | defer trash_block.instructions.deinit(sema.gpa); | 1601 | defer trash_block.instructions.deinit(sema.gpa); |
| 1614 | 1602 | ||
| 1603 | const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); | ||
| 1615 | const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); | 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 | const air_tags = sema.air_instructions.items(.tag); | 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,6 +1633,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1644 | switch (air_tags[trash_inst]) { | 1633 | switch (air_tags[trash_inst]) { |
| 1645 | .bitcast => { | 1634 | .bitcast => { |
| 1646 | if (Air.indexToRef(trash_inst) == dummy_operand) { | 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 | return sema.bitCast(block, ptr_ty, new_ptr, src); | 1639 | return sema.bitCast(block, ptr_ty, new_ptr, src); |
| 1648 | } | 1640 | } |
| 1649 | const ty_op = air_datas[trash_inst].ty_op; | 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,7 +1644,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1652 | .pointee_type = operand_ty, | 1644 | .pointee_type = operand_ty, |
| 1653 | .@"addrspace" = addr_space, | 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 | .wrap_optional => { | 1653 | .wrap_optional => { |
| 1658 | new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true); | 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,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 | pub fn analyzeStructDecl( | 1675 | pub fn analyzeStructDecl( |
| ... | @@ -16937,7 +16933,6 @@ fn wrapErrorUnionPayload( | ... | @@ -16937,7 +16933,6 @@ fn wrapErrorUnionPayload( |
| 16937 | const dest_payload_ty = dest_ty.errorUnionPayload(); | 16933 | const dest_payload_ty = dest_ty.errorUnionPayload(); |
| 16938 | const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src); | 16934 | const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src); |
| 16939 | if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { | 16935 | if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { |
| 16940 | if (val.isUndef()) return sema.addConstUndef(dest_ty); | ||
| 16941 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); | 16936 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); |
| 16942 | } | 16937 | } |
| 16943 | try sema.requireRuntimeBlock(block, inst_src); | 16938 | try sema.requireRuntimeBlock(block, inst_src); |
src/type.zig+2-2| ... | @@ -3980,7 +3980,7 @@ pub const Type = extern union { | ... | @@ -3980,7 +3980,7 @@ pub const Type = extern union { |
| 3980 | 3980 | ||
| 3981 | pub fn structFields(ty: Type) Module.Struct.Fields { | 3981 | pub fn structFields(ty: Type) Module.Struct.Fields { |
| 3982 | switch (ty.tag()) { | 3982 | switch (ty.tag()) { |
| 3983 | .empty_struct => return .{}, | 3983 | .empty_struct, .empty_struct_literal => return .{}, |
| 3984 | .@"struct" => { | 3984 | .@"struct" => { |
| 3985 | const struct_obj = ty.castTag(.@"struct").?.data; | 3985 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3986 | assert(struct_obj.haveFieldTypes()); | 3986 | assert(struct_obj.haveFieldTypes()); |
| ... | @@ -3996,7 +3996,7 @@ pub const Type = extern union { | ... | @@ -3996,7 +3996,7 @@ pub const Type = extern union { |
| 3996 | const struct_obj = ty.castTag(.@"struct").?.data; | 3996 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3997 | return struct_obj.fields.count(); | 3997 | return struct_obj.fields.count(); |
| 3998 | }, | 3998 | }, |
| 3999 | .empty_struct => return 0, | 3999 | .empty_struct, .empty_struct_literal => return 0, |
| 4000 | .tuple => return ty.castTag(.tuple).?.data.types.len, | 4000 | .tuple => return ty.castTag(.tuple).?.data.types.len, |
| 4001 | else => unreachable, | 4001 | else => unreachable, |
| 4002 | } | 4002 | } |
src/value.zig+14-9| ... | @@ -791,19 +791,24 @@ pub const Value = extern union { | ... | @@ -791,19 +791,24 @@ pub const Value = extern union { |
| 791 | return decl_val.toAllocatedBytes(decl.ty, allocator); | 791 | return decl_val.toAllocatedBytes(decl.ty, allocator); |
| 792 | }, | 792 | }, |
| 793 | .the_only_possible_value => return &[_]u8{}, | 793 | .the_only_possible_value => return &[_]u8{}, |
| 794 | .slice => return toAllocatedBytes(val.castTag(.slice).?.data.ptr, ty, allocator), | 794 | .slice => { |
| 795 | else => { | 795 | const slice = val.castTag(.slice).?.data; |
| 796 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen())); | 796 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(), allocator); |
| 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; | ||
| 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 | pub const ToTypeBuffer = Type.Payload.Bits; | 812 | pub const ToTypeBuffer = Type.Payload.Bits; |
| 808 | 813 | ||
| 809 | /// Asserts that the value is representable as a type. | 814 | /// Asserts that the value is representable as a type. |
test/behavior.zig+3-3| ... | @@ -127,8 +127,11 @@ test { | ... | @@ -127,8 +127,11 @@ test { |
| 127 | _ = @import("behavior/bugs/726.zig"); | 127 | _ = @import("behavior/bugs/726.zig"); |
| 128 | _ = @import("behavior/bugs/1421.zig"); | 128 | _ = @import("behavior/bugs/1421.zig"); |
| 129 | _ = @import("behavior/bugs/1442.zig"); | 129 | _ = @import("behavior/bugs/1442.zig"); |
| 130 | _ = @import("behavior/bugs/1607.zig"); | ||
| 130 | _ = @import("behavior/bugs/2114.zig"); | 131 | _ = @import("behavior/bugs/2114.zig"); |
| 132 | _ = @import("behavior/bugs/3384.zig"); | ||
| 131 | _ = @import("behavior/bugs/3742.zig"); | 133 | _ = @import("behavior/bugs/3742.zig"); |
| 134 | _ = @import("behavior/bugs/5398.zig"); | ||
| 132 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); | 135 | _ = @import("behavior/struct_contains_null_ptr_itself.zig"); |
| 133 | _ = @import("behavior/switch_prong_err_enum.zig"); | 136 | _ = @import("behavior/switch_prong_err_enum.zig"); |
| 134 | _ = @import("behavior/switch_prong_implicit_cast.zig"); | 137 | _ = @import("behavior/switch_prong_implicit_cast.zig"); |
| ... | @@ -147,11 +150,8 @@ test { | ... | @@ -147,11 +150,8 @@ test { |
| 147 | _ = @import("behavior/bugs/828.zig"); | 150 | _ = @import("behavior/bugs/828.zig"); |
| 148 | _ = @import("behavior/bugs/920.zig"); | 151 | _ = @import("behavior/bugs/920.zig"); |
| 149 | _ = @import("behavior/bugs/1120.zig"); | 152 | _ = @import("behavior/bugs/1120.zig"); |
| 150 | _ = @import("behavior/bugs/1607.zig"); | ||
| 151 | _ = @import("behavior/bugs/1851.zig"); | 153 | _ = @import("behavior/bugs/1851.zig"); |
| 152 | _ = @import("behavior/bugs/3384.zig"); | ||
| 153 | _ = @import("behavior/bugs/3779.zig"); | 154 | _ = @import("behavior/bugs/3779.zig"); |
| 154 | _ = @import("behavior/bugs/5398.zig"); | ||
| 155 | _ = @import("behavior/bugs/5413.zig"); | 155 | _ = @import("behavior/bugs/5413.zig"); |
| 156 | _ = @import("behavior/bugs/5487.zig"); | 156 | _ = @import("behavior/bugs/5487.zig"); |
| 157 | _ = @import("behavior/bugs/6456.zig"); | 157 | _ = @import("behavior/bugs/6456.zig"); |
test/behavior/bugs/5398.zig+3-3| ... | @@ -25,7 +25,7 @@ test "assignment of field with padding" { | ... | @@ -25,7 +25,7 @@ test "assignment of field with padding" { |
| 25 | .emits_shadows = false, | 25 | .emits_shadows = false, |
| 26 | }, | 26 | }, |
| 27 | }; | 27 | }; |
| 28 | try testing.expectEqual(false, renderable.material.transparent); | 28 | try testing.expect(false == renderable.material.transparent); |
| 29 | try testing.expectEqual(false, renderable.material.emits_shadows); | 29 | try testing.expect(false == renderable.material.emits_shadows); |
| 30 | try testing.expectEqual(true, renderable.material.render_color); | 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,7 +371,9 @@ fn testPeerResolveArrayConstSlice(b: bool) !void { |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | test "implicitly cast from T to anyerror!?T" { | 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 | try castToOptionalTypeError(1); | 378 | try castToOptionalTypeError(1); |
| 377 | comptime try castToOptionalTypeError(1); | 379 | comptime try castToOptionalTypeError(1); |
| ... | @@ -387,7 +389,7 @@ fn castToOptionalTypeError(z: i32) !void { | ... | @@ -387,7 +389,7 @@ fn castToOptionalTypeError(z: i32) !void { |
| 387 | 389 | ||
| 388 | const f = z; | 390 | const f = z; |
| 389 | const g: anyerror!?i32 = f; | 391 | const g: anyerror!?i32 = f; |
| 390 | _ = g catch {}; | 392 | _ = try g; |
| 391 | 393 | ||
| 392 | const a = A{ .a = z }; | 394 | const a = A{ .a = z }; |
| 393 | const b: anyerror!?A = a; | 395 | const b: anyerror!?A = a; |
test/behavior/error.zig+4-3| ... | @@ -294,10 +294,11 @@ fn quux_1() !i32 { | ... | @@ -294,10 +294,11 @@ fn quux_1() !i32 { |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | test "error: Zero sized error set returned with value payload crash" { | 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 | _ = try foo3(0); |
| 300 | _ = comptime foo3(0) catch {}; | 301 | _ = comptime try foo3(0); |
| 301 | } | 302 | } |
| 302 | 303 | ||
| 303 | const Error = error{}; | 304 | const Error = error{}; |
test/behavior/struct.zig+25| ... | @@ -1237,3 +1237,28 @@ test "anon init through error union" { | ... | @@ -1237,3 +1237,28 @@ test "anon init through error union" { |
| 1237 | try S.doTheTest(); | 1237 | try S.doTheTest(); |
| 1238 | comptime try S.doTheTest(); | 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 | } |