Merge pull request #10986 from Vexu/stage2

stage2: actually coerce in coerce_result_ptr at comptime
This commit is contained in:
Andrew Kelley 2022-02-26 14:52:45 -05:00 committed by GitHub
commit 8349a644d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 67 additions and 39 deletions

View File

@ -1593,27 +1593,16 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
}
}
// We would like to rely on the mechanism below even for comptime values.
// However in the case that the pointer points to comptime-mutable value,
// we cannot do it.
if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| {
if (ptr_val.isComptimeMutablePtr()) {
const ptr_ty = try Type.ptr(sema.arena, .{
.pointee_type = pointee_ty,
.@"addrspace" = addr_space,
});
return sema.addConstant(ptr_ty, ptr_val);
}
}
// Make a dummy store through the pointer to test the coercion.
// We will then use the generated instructions to decide what
// kind of transformations to make on the result pointer.
var trash_block = block.makeSubBlock();
trash_block.is_comptime = false;
defer trash_block.instructions.deinit(sema.gpa);
const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
try sema.storePtr(&trash_block, src, ptr, dummy_operand);
try sema.storePtr(&trash_block, src, dummy_ptr, dummy_operand);
{
const air_tags = sema.air_instructions.items(.tag);
@ -1644,6 +1633,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
switch (air_tags[trash_inst]) {
.bitcast => {
if (Air.indexToRef(trash_inst) == dummy_operand) {
if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
return sema.addConstant(ptr_ty, ptr_val);
}
return sema.bitCast(block, ptr_ty, new_ptr, src);
}
const ty_op = air_datas[trash_inst].ty_op;
@ -1652,7 +1644,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
.pointee_type = operand_ty,
.@"addrspace" = addr_space,
});
new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src);
if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);
} else {
new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src);
}
},
.wrap_optional => {
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
}
},
}
} else unreachable; // TODO should not need else unreachable
}
}
pub fn analyzeStructDecl(
@ -16937,7 +16933,6 @@ fn wrapErrorUnionPayload(
const dest_payload_ty = dest_ty.errorUnionPayload();
const coerced = try sema.coerce(block, dest_payload_ty, inst, inst_src);
if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| {
if (val.isUndef()) return sema.addConstUndef(dest_ty);
return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
}
try sema.requireRuntimeBlock(block, inst_src);

View File

@ -3980,7 +3980,7 @@ pub const Type = extern union {
pub fn structFields(ty: Type) Module.Struct.Fields {
switch (ty.tag()) {
.empty_struct => return .{},
.empty_struct, .empty_struct_literal => return .{},
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
assert(struct_obj.haveFieldTypes());
@ -3996,7 +3996,7 @@ pub const Type = extern union {
const struct_obj = ty.castTag(.@"struct").?.data;
return struct_obj.fields.count();
},
.empty_struct => return 0,
.empty_struct, .empty_struct_literal => return 0,
.tuple => return ty.castTag(.tuple).?.data.types.len,
else => unreachable,
}

View File

@ -791,19 +791,24 @@ pub const Value = extern union {
return decl_val.toAllocatedBytes(decl.ty, allocator);
},
.the_only_possible_value => return &[_]u8{},
.slice => return toAllocatedBytes(val.castTag(.slice).?.data.ptr, ty, allocator),
else => {
const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen()));
var elem_value_buf: ElemValueBuffer = undefined;
for (result) |*elem, i| {
const elem_val = val.elemValueBuffer(i, &elem_value_buf);
elem.* = @intCast(u8, elem_val.toUnsignedInt());
}
return result;
.slice => {
const slice = val.castTag(.slice).?.data;
return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(), allocator);
},
else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator),
}
}
fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator) ![]u8 {
const result = try allocator.alloc(u8, @intCast(usize, len));
var elem_value_buf: ElemValueBuffer = undefined;
for (result) |*elem, i| {
const elem_val = val.elemValueBuffer(i, &elem_value_buf);
elem.* = @intCast(u8, elem_val.toUnsignedInt());
}
return result;
}
pub const ToTypeBuffer = Type.Payload.Bits;
/// Asserts that the value is representable as a type.

View File

@ -127,8 +127,11 @@ test {
_ = @import("behavior/bugs/726.zig");
_ = @import("behavior/bugs/1421.zig");
_ = @import("behavior/bugs/1442.zig");
_ = @import("behavior/bugs/1607.zig");
_ = @import("behavior/bugs/2114.zig");
_ = @import("behavior/bugs/3384.zig");
_ = @import("behavior/bugs/3742.zig");
_ = @import("behavior/bugs/5398.zig");
_ = @import("behavior/struct_contains_null_ptr_itself.zig");
_ = @import("behavior/switch_prong_err_enum.zig");
_ = @import("behavior/switch_prong_implicit_cast.zig");
@ -147,11 +150,8 @@ test {
_ = @import("behavior/bugs/828.zig");
_ = @import("behavior/bugs/920.zig");
_ = @import("behavior/bugs/1120.zig");
_ = @import("behavior/bugs/1607.zig");
_ = @import("behavior/bugs/1851.zig");
_ = @import("behavior/bugs/3384.zig");
_ = @import("behavior/bugs/3779.zig");
_ = @import("behavior/bugs/5398.zig");
_ = @import("behavior/bugs/5413.zig");
_ = @import("behavior/bugs/5487.zig");
_ = @import("behavior/bugs/6456.zig");

View File

@ -25,7 +25,7 @@ test "assignment of field with padding" {
.emits_shadows = false,
},
};
try testing.expectEqual(false, renderable.material.transparent);
try testing.expectEqual(false, renderable.material.emits_shadows);
try testing.expectEqual(true, renderable.material.render_color);
try testing.expect(false == renderable.material.transparent);
try testing.expect(false == renderable.material.emits_shadows);
try testing.expect(true == renderable.material.render_color);
}

View File

@ -371,7 +371,9 @@ fn testPeerResolveArrayConstSlice(b: bool) !void {
}
test "implicitly cast from T to anyerror!?T" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try castToOptionalTypeError(1);
comptime try castToOptionalTypeError(1);
@ -387,7 +389,7 @@ fn castToOptionalTypeError(z: i32) !void {
const f = z;
const g: anyerror!?i32 = f;
_ = g catch {};
_ = try g;
const a = A{ .a = z };
const b: anyerror!?A = a;

View File

@ -294,10 +294,11 @@ fn quux_1() !i32 {
}
test "error: Zero sized error set returned with value payload crash" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
_ = foo3(0) catch {};
_ = comptime foo3(0) catch {};
_ = try foo3(0);
_ = comptime try foo3(0);
}
const Error = error{};

View File

@ -1237,3 +1237,28 @@ test "anon init through error union" {
try S.doTheTest();
comptime try S.doTheTest();
}
test "typed init through error unions and optionals" {
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; // TODO
const S = struct {
a: u32,
fn foo() anyerror!?anyerror!@This() {
return @This(){ .a = 1 };
}
fn bar() ?anyerror![2]u8 {
return [2]u8{ 1, 2 };
}
fn doTheTest() !void {
var a = try (try foo()).?;
var b = try bar().?;
try expect(a.a + b[1] == 3);
}
};
try S.doTheTest();
comptime try S.doTheTest();
}