mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
stage2: new zir array_init_sent for sentinel-terminated array inits
This uses a new ZIR inst `array_init_sent` (and a ref equivalent) to
represent array init expressions that terminate in a a sentinel value.
The sentienl value is the last value in the `MultiOp` payload. This
makes it a bit more awkward to deal with (lots of "len - 1") but makes
it so that the payload matches the fact that sentinels appear at the end
of arrays. However, this is not a hill I want to die on so if we want to
change it to index 0, I'm happy to do so.
This makes the following work properly:
try expect(@TypeOf([_:0]u8{}) == [0:0]u8);
This commit is contained in:
parent
c9fac41368
commit
85b0a4a8fd
@ -1259,10 +1259,12 @@ fn arrayInitExpr(
|
||||
const types: struct {
|
||||
array: Zir.Inst.Ref,
|
||||
elem: Zir.Inst.Ref,
|
||||
sentinel: Zir.Inst.Ref,
|
||||
} = inst: {
|
||||
if (array_init.ast.type_expr == 0) break :inst .{
|
||||
.array = .none,
|
||||
.elem = .none,
|
||||
.sentinel = .none,
|
||||
};
|
||||
|
||||
infer: {
|
||||
@ -1282,6 +1284,7 @@ fn arrayInitExpr(
|
||||
break :inst .{
|
||||
.array = array_type_inst,
|
||||
.elem = elem_type,
|
||||
.sentinel = .none,
|
||||
};
|
||||
} else {
|
||||
const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);
|
||||
@ -1297,6 +1300,7 @@ fn arrayInitExpr(
|
||||
break :inst .{
|
||||
.array = array_type_inst,
|
||||
.elem = elem_type,
|
||||
.sentinel = sentinel,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1307,6 +1311,7 @@ fn arrayInitExpr(
|
||||
break :inst .{
|
||||
.array = array_type_inst,
|
||||
.elem = elem_type,
|
||||
.sentinel = .none,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1319,25 +1324,25 @@ fn arrayInitExpr(
|
||||
},
|
||||
.ref => {
|
||||
if (types.array != .none) {
|
||||
return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init_ref);
|
||||
return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, true);
|
||||
} else {
|
||||
return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
|
||||
}
|
||||
},
|
||||
.none => {
|
||||
if (types.array != .none) {
|
||||
return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init);
|
||||
return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
|
||||
} else {
|
||||
return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
|
||||
}
|
||||
},
|
||||
.ty, .coerced_ty => |ty_inst| {
|
||||
if (types.array != .none) {
|
||||
const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.array, .array_init);
|
||||
const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
|
||||
return rvalue(gz, rl, result, node);
|
||||
} else {
|
||||
const elem_type = try gz.addUnNode(.elem_type, ty_inst, node);
|
||||
return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.array, .array_init);
|
||||
return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false);
|
||||
}
|
||||
},
|
||||
.ptr => |ptr_inst| {
|
||||
@ -1387,18 +1392,32 @@ fn arrayInitExprRlTy(
|
||||
node: Ast.Node.Index,
|
||||
elements: []const Ast.Node.Index,
|
||||
elem_ty_inst: Zir.Inst.Ref,
|
||||
array_ty: Zir.Inst.Ref,
|
||||
tag: Zir.Inst.Tag,
|
||||
sentinel: Zir.Inst.Ref,
|
||||
ref: bool,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
|
||||
const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
|
||||
.operands_len = @intCast(u32, elements.len + 1),
|
||||
});
|
||||
var extra_index = try reserveExtra(astgen, elements.len + 1);
|
||||
const info: struct {
|
||||
len: usize,
|
||||
tag: Zir.Inst.Tag,
|
||||
} = blk: {
|
||||
if (sentinel != .none) {
|
||||
break :blk .{
|
||||
.len = elements.len + 1,
|
||||
.tag = if (ref) .array_init_sent_ref else .array_init_sent,
|
||||
};
|
||||
} else {
|
||||
break :blk .{
|
||||
.len = elements.len,
|
||||
.tag = if (ref) .array_init_ref else .array_init,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
astgen.extra.items[extra_index] = @enumToInt(array_ty);
|
||||
extra_index += 1;
|
||||
const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
|
||||
.operands_len = @intCast(u32, info.len),
|
||||
});
|
||||
var extra_index = try reserveExtra(astgen, info.len);
|
||||
|
||||
const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };
|
||||
for (elements) |elem_init| {
|
||||
@ -1406,7 +1425,13 @@ fn arrayInitExprRlTy(
|
||||
astgen.extra.items[extra_index] = @enumToInt(elem_ref);
|
||||
extra_index += 1;
|
||||
}
|
||||
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
|
||||
if (sentinel != .none) {
|
||||
astgen.extra.items[extra_index] = @enumToInt(sentinel);
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
return try gz.addPlNodePayloadIndex(info.tag, node, payload_index);
|
||||
}
|
||||
|
||||
fn arrayInitExprRlPtr(
|
||||
@ -2221,8 +2246,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
|
||||
.struct_init_anon_ref,
|
||||
.array_init,
|
||||
.array_init_anon,
|
||||
.array_init_sent,
|
||||
.array_init_ref,
|
||||
.array_init_anon_ref,
|
||||
.array_init_sent_ref,
|
||||
.union_init,
|
||||
.field_type,
|
||||
.field_type_ref,
|
||||
|
||||
40
src/Sema.zig
40
src/Sema.zig
@ -712,8 +712,10 @@ fn analyzeBodyInner(
|
||||
.struct_init_ref => try sema.zirStructInit(block, inst, true),
|
||||
.struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
|
||||
.struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
|
||||
.array_init => try sema.zirArrayInit(block, inst, false),
|
||||
.array_init_ref => try sema.zirArrayInit(block, inst, true),
|
||||
.array_init => try sema.zirArrayInit(block, inst, false, false),
|
||||
.array_init_sent => try sema.zirArrayInit(block, inst, false, true),
|
||||
.array_init_ref => try sema.zirArrayInit(block, inst, true, false),
|
||||
.array_init_sent_ref => try sema.zirArrayInit(block, inst, true, true),
|
||||
.array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
|
||||
.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
|
||||
.union_init => try sema.zirUnionInit(block, inst),
|
||||
@ -11782,6 +11784,7 @@ fn zirArrayInit(
|
||||
block: *Block,
|
||||
inst: Zir.Inst.Index,
|
||||
is_ref: bool,
|
||||
is_sent: bool,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const gpa = sema.gpa;
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
@ -11796,23 +11799,28 @@ fn zirArrayInit(
|
||||
|
||||
for (args) |arg, i| resolved_args[i] = sema.resolveInst(arg);
|
||||
|
||||
const elem_ty = sema.typeOf(resolved_args[1]);
|
||||
const array_ty = switch (resolved_args[0]) {
|
||||
.none => try Type.Tag.array.create(sema.arena, .{
|
||||
.len = resolved_args.len,
|
||||
.elem_type = elem_ty,
|
||||
}),
|
||||
const elem_ty = sema.typeOf(resolved_args[0]);
|
||||
const array_ty = blk: {
|
||||
if (!is_sent) {
|
||||
break :blk try Type.Tag.array.create(sema.arena, .{
|
||||
.len = resolved_args.len,
|
||||
.elem_type = elem_ty,
|
||||
});
|
||||
}
|
||||
|
||||
else => |ref| blk: {
|
||||
assert(sema.typeOf(ref).zigTypeTag() == .Type);
|
||||
var buffer: Value.ToTypeBuffer = undefined;
|
||||
const val = try sema.resolveConstValue(block, src, ref);
|
||||
const ty = val.toType(&buffer);
|
||||
break :blk try ty.copy(sema.arena);
|
||||
},
|
||||
const sentinel_ref = resolved_args[resolved_args.len - 1];
|
||||
const val = try sema.resolveConstValue(block, src, sentinel_ref);
|
||||
break :blk try Type.Tag.array_sentinel.create(sema.arena, .{
|
||||
.len = resolved_args.len - 1,
|
||||
.sentinel = val,
|
||||
.elem_type = elem_ty,
|
||||
});
|
||||
};
|
||||
|
||||
const elems = resolved_args[1..];
|
||||
const elems = if (!is_sent)
|
||||
resolved_args
|
||||
else
|
||||
resolved_args[0 .. resolved_args.len - 1];
|
||||
|
||||
const opt_runtime_src: ?LazySrcLoc = for (elems) |arg| {
|
||||
const arg_src = src; // TODO better source location
|
||||
|
||||
12
src/Zir.zig
12
src/Zir.zig
@ -710,12 +710,20 @@ pub const Inst = struct {
|
||||
/// Array initialization syntax.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init,
|
||||
/// Array initialization with sentinel.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
/// Final op in MultiOp is the sentinel.
|
||||
array_init_sent,
|
||||
/// Anonymous array initialization syntax.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init_anon,
|
||||
/// Array initialization syntax, make the result a pointer.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init_ref,
|
||||
/// Array initialization with sentinel.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
/// Final op in MultiOp is the sentinel.
|
||||
array_init_sent_ref,
|
||||
/// Anonymous array initialization syntax, make the result a pointer.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init_anon_ref,
|
||||
@ -1119,8 +1127,10 @@ pub const Inst = struct {
|
||||
.struct_init_anon,
|
||||
.struct_init_anon_ref,
|
||||
.array_init,
|
||||
.array_init_sent,
|
||||
.array_init_anon,
|
||||
.array_init_ref,
|
||||
.array_init_sent_ref,
|
||||
.array_init_anon_ref,
|
||||
.union_init,
|
||||
.field_type,
|
||||
@ -1377,8 +1387,10 @@ pub const Inst = struct {
|
||||
.struct_init_anon = .pl_node,
|
||||
.struct_init_anon_ref = .pl_node,
|
||||
.array_init = .pl_node,
|
||||
.array_init_sent = .pl_node,
|
||||
.array_init_anon = .pl_node,
|
||||
.array_init_ref = .pl_node,
|
||||
.array_init_sent_ref = .pl_node,
|
||||
.array_init_anon_ref = .pl_node,
|
||||
.union_init = .pl_node,
|
||||
.type_info = .un_node,
|
||||
|
||||
@ -269,6 +269,10 @@ const Writer = struct {
|
||||
.array_init_anon_ref,
|
||||
=> try self.writeArrayInit(stream, inst),
|
||||
|
||||
.array_init_sent,
|
||||
.array_init_sent_ref,
|
||||
=> try self.writeArrayInitSent(stream, inst),
|
||||
|
||||
.slice_start => try self.writeSliceStart(stream, inst),
|
||||
.slice_end => try self.writeSliceEnd(stream, inst),
|
||||
.slice_sentinel => try self.writeSliceSentinel(stream, inst),
|
||||
@ -2022,6 +2026,26 @@ const Writer = struct {
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
|
||||
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
|
||||
const args = self.code.refSlice(extra.end, extra.data.operands_len);
|
||||
const sent = args[args.len - 1];
|
||||
const elems = args[0 .. args.len - 1];
|
||||
|
||||
try self.writeInstRef(stream, sent);
|
||||
try stream.writeAll(", ");
|
||||
|
||||
try stream.writeAll(".{");
|
||||
for (elems) |elem, i| {
|
||||
if (i != 0) try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, elem);
|
||||
}
|
||||
try stream.writeAll("}) ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
|
||||
const safety_str = if (inst_data.safety) "safe" else "unsafe";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user