mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 13:30:45 +00:00
Sema: implement calling a fn ptr via a union field
Also, ignore `packed` on unions because that will be removed from the language.
This commit is contained in:
parent
2dd7255713
commit
91619cdf57
@ -1104,9 +1104,6 @@ pub const Union = struct {
|
||||
|
||||
pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout {
|
||||
assert(u.status == .have_layout);
|
||||
const is_packed = u.layout == .Packed;
|
||||
if (is_packed) @panic("TODO packed unions");
|
||||
|
||||
var most_aligned_field: usize = undefined;
|
||||
var most_aligned_field_size: u64 = undefined;
|
||||
var biggest_field: usize = undefined;
|
||||
|
||||
58
src/Sema.zig
58
src/Sema.zig
@ -12152,34 +12152,16 @@ fn fieldCallBind(
|
||||
const field_index = @intCast(u32, field_index_usize);
|
||||
const field = struct_obj.fields.values()[field_index];
|
||||
|
||||
const ptr_field_ty = try Type.ptr(arena, .{
|
||||
.pointee_type = field.ty,
|
||||
.mutable = ptr_ty.ptrIsMutable(),
|
||||
.@"addrspace" = ptr_ty.ptrAddressSpace(),
|
||||
});
|
||||
|
||||
if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
|
||||
const pointer = try sema.addConstant(
|
||||
ptr_field_ty,
|
||||
try Value.Tag.field_ptr.create(arena, .{
|
||||
.container_ptr = struct_ptr_val,
|
||||
.field_index = field_index,
|
||||
}),
|
||||
);
|
||||
return sema.analyzeLoad(block, src, pointer, src);
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
|
||||
return sema.analyzeLoad(block, src, ptr_inst, src);
|
||||
return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
|
||||
},
|
||||
.Union => {
|
||||
const union_ty = try sema.resolveTypeFields(block, src, concrete_ty);
|
||||
const fields = union_ty.unionFields();
|
||||
const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
|
||||
const field_index = @intCast(u32, field_index_usize);
|
||||
const field = fields.values()[field_index];
|
||||
|
||||
_ = field_index_usize;
|
||||
return sema.fail(block, src, "TODO implement field calls on unions", .{});
|
||||
return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
|
||||
},
|
||||
.Type => {
|
||||
const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
|
||||
@ -12236,6 +12218,38 @@ fn fieldCallBind(
|
||||
return sema.fail(block, src, "type '{}' has no field or member function named '{s}'", .{ concrete_ty, field_name });
|
||||
}
|
||||
|
||||
fn finishFieldCallBind(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
ptr_ty: Type,
|
||||
field_ty: Type,
|
||||
field_index: u32,
|
||||
object_ptr: Air.Inst.Ref,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const arena = sema.arena;
|
||||
const ptr_field_ty = try Type.ptr(arena, .{
|
||||
.pointee_type = field_ty,
|
||||
.mutable = ptr_ty.ptrIsMutable(),
|
||||
.@"addrspace" = ptr_ty.ptrAddressSpace(),
|
||||
});
|
||||
|
||||
if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
|
||||
const pointer = try sema.addConstant(
|
||||
ptr_field_ty,
|
||||
try Value.Tag.field_ptr.create(arena, .{
|
||||
.container_ptr = struct_ptr_val,
|
||||
.field_index = field_index,
|
||||
}),
|
||||
);
|
||||
return sema.analyzeLoad(block, src, pointer, src);
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
|
||||
return sema.analyzeLoad(block, src, ptr_inst, src);
|
||||
}
|
||||
|
||||
fn namespaceLookup(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
|
||||
@ -165,6 +165,18 @@ test "union with specified enum tag" {
|
||||
comptime try doTest();
|
||||
}
|
||||
|
||||
test "packed union generates correctly aligned LLVM type" {
|
||||
const U = packed union {
|
||||
f1: fn () error{TestUnexpectedResult}!void,
|
||||
f2: u32,
|
||||
};
|
||||
var foo = [_]U{
|
||||
U{ .f1 = doTest },
|
||||
U{ .f2 = 0 },
|
||||
};
|
||||
try foo[0].f1();
|
||||
}
|
||||
|
||||
fn doTest() error{TestUnexpectedResult}!void {
|
||||
try expect((try bar(Payload{ .A = 1234 })) == -10);
|
||||
}
|
||||
|
||||
@ -3,38 +3,6 @@ const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const Tag = std.meta.Tag;
|
||||
|
||||
const Letter = enum { A, B, C };
|
||||
const Payload = union(Letter) {
|
||||
A: i32,
|
||||
B: f64,
|
||||
C: bool,
|
||||
};
|
||||
|
||||
fn doTest() error{TestUnexpectedResult}!void {
|
||||
try expect((try bar(Payload{ .A = 1234 })) == -10);
|
||||
}
|
||||
|
||||
fn bar(value: Payload) error{TestUnexpectedResult}!i32 {
|
||||
try expect(@as(Letter, value) == Letter.A);
|
||||
return switch (value) {
|
||||
Payload.A => |x| return x - 1244,
|
||||
Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21,
|
||||
Payload.C => |x| if (x) @as(i32, 30) else 31,
|
||||
};
|
||||
}
|
||||
|
||||
test "packed union generates correctly aligned LLVM type" {
|
||||
const U = packed union {
|
||||
f1: fn () error{TestUnexpectedResult}!void,
|
||||
f2: u32,
|
||||
};
|
||||
var foo = [_]U{
|
||||
U{ .f1 = doTest },
|
||||
U{ .f2 = 0 },
|
||||
};
|
||||
try foo[0].f1();
|
||||
}
|
||||
|
||||
const MultipleChoice = union(enum(u32)) {
|
||||
A = 20,
|
||||
B = 40,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user