aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-05-30 17:35:18 -0400
committerGitHub <noreply@github.com>2022-05-30 17:35:18 -0400
commitc84f5a5f91d31b20b2e187d84fc8a80a190a1212 (patch)
treef2c580bac4ad1a649b3decd370ddb6f12316337e /src
parentf846dc420fff629572caa1175bfa64e5fcffaeb5 (diff)
parent0e8307789a3de41759e68c7c04c130889e277991 (diff)
downloadzig-c84f5a5f91d31b20b2e187d84fc8a80a190a1212.tar.gz
zig-c84f5a5f91d31b20b2e187d84fc8a80a190a1212.zip
Merge pull request #11749 from Vexu/stage2
Stage2: improve AstGen for array init expressions
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig94
-rw-r--r--src/Sema.zig101
-rw-r--r--src/Zir.zig26
-rw-r--r--src/print_zir.zig18
4 files changed, 117 insertions, 122 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index ba27165cea..1a79e044fa 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1276,12 +1276,10 @@ 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: {
@@ -1301,7 +1299,6 @@ 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);
@@ -1317,50 +1314,38 @@ fn arrayInitExpr(
break :inst .{
.array = array_type_inst,
.elem = elem_type,
- .sentinel = sentinel,
};
}
}
}
const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr);
_ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node);
- const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr);
break :inst .{
.array = array_type_inst,
- .elem = elem_type,
- .sentinel = .none,
+ .elem = .none,
};
};
switch (rl) {
.discard => {
+ // TODO elements should still be coerced if type is provided
for (array_init.ast.elements) |elem_init| {
_ = try expr(gz, scope, .discard, elem_init);
}
return Zir.Inst.Ref.void_value;
},
.ref => {
- if (types.array != .none) {
- 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);
- }
+ const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref;
+ return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
},
.none => {
- if (types.array != .none) {
- 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);
- }
+ const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon;
+ return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
},
.ty, .coerced_ty => {
- if (types.array != .none) {
- const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
- return rvalue(gz, rl, result, node);
- } else {
- const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
- return rvalue(gz, rl, result, node);
- }
+ const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon;
+ const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
+ return rvalue(gz, rl, result, node);
},
.ptr => |ptr_inst| {
return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array);
@@ -1410,52 +1395,47 @@ fn arrayInitExprRlNone(
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
}
-fn arrayInitExprRlTy(
+fn arrayInitExprInner(
gz: *GenZir,
scope: *Scope,
node: Ast.Node.Index,
elements: []const Ast.Node.Index,
- elem_ty_inst: Zir.Inst.Ref,
- sentinel: Zir.Inst.Ref,
- ref: bool,
+ array_ty_inst: Zir.Inst.Ref,
+ elem_ty: Zir.Inst.Ref,
+ tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
- 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,
- };
- }
- };
-
+ const len = elements.len + @boolToInt(array_ty_inst != .none);
const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
- .operands_len = @intCast(u32, info.len),
+ .operands_len = @intCast(u32, len),
});
- var extra_index = try reserveExtra(astgen, info.len);
-
- const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };
- for (elements) |elem_init| {
- const elem_ref = try expr(gz, scope, elem_rl, elem_init);
- astgen.extra.items[extra_index] = @enumToInt(elem_ref);
+ var extra_index = try reserveExtra(astgen, len);
+ if (array_ty_inst != .none) {
+ astgen.extra.items[extra_index] = @enumToInt(array_ty_inst);
extra_index += 1;
}
- if (sentinel != .none) {
- astgen.extra.items[extra_index] = @enumToInt(sentinel);
+ for (elements) |elem_init, i| {
+ const rl = if (elem_ty != .none)
+ ResultLoc{ .coerced_ty = elem_ty }
+ else if (array_ty_inst != .none and nodeMayNeedMemoryLocation(astgen.tree, elem_init, true)) rl: {
+ const ty_expr = try gz.add(.{
+ .tag = .elem_type_index,
+ .data = .{ .bin = .{
+ .lhs = array_ty_inst,
+ .rhs = @intToEnum(Zir.Inst.Ref, i),
+ } },
+ });
+ break :rl ResultLoc{ .coerced_ty = ty_expr };
+ } else ResultLoc{ .none = {} };
+
+ const elem_ref = try expr(gz, scope, rl, elem_init);
+ astgen.extra.items[extra_index] = @enumToInt(elem_ref);
extra_index += 1;
}
- return try gz.addPlNodePayloadIndex(info.tag, node, payload_index);
+ return try gz.addPlNodePayloadIndex(tag, node, payload_index);
}
fn arrayInitExprRlPtr(
@@ -2243,8 +2223,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.array_mul,
.array_type,
.array_type_sentinel,
+ .elem_type_index,
.vector_type,
- .elem_type,
.indexable_ptr_len,
.anyframe_type,
.as,
@@ -2347,10 +2327,8 @@ 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,
diff --git a/src/Sema.zig b/src/Sema.zig
index e0310e5ad7..fc64e17789 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -726,7 +726,7 @@ fn analyzeBodyInner(
.elem_ptr_imm => try sema.zirElemPtrImm(block, inst),
.elem_val => try sema.zirElemVal(block, inst),
.elem_val_node => try sema.zirElemValNode(block, inst),
- .elem_type => try sema.zirElemType(block, inst),
+ .elem_type_index => try sema.zirElemTypeIndex(block, inst),
.enum_literal => try sema.zirEnumLiteral(block, inst),
.enum_to_int => try sema.zirEnumToInt(block, inst),
.int_to_enum => try sema.zirIntToEnum(block, inst),
@@ -798,10 +798,8 @@ 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, 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 => try sema.zirArrayInit(block, inst, false),
+ .array_init_ref => try sema.zirArrayInit(block, inst, 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),
@@ -3024,7 +3022,10 @@ fn zirArrayBasePtr(
const elem_ty = sema.typeOf(base_ptr).childType();
switch (elem_ty.zigTypeTag()) {
.Array, .Vector => return base_ptr,
- .Struct => if (elem_ty.isTuple()) return base_ptr,
+ .Struct => if (elem_ty.isTuple()) {
+ // TODO validate element count
+ return base_ptr;
+ },
else => {},
}
return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
@@ -3065,7 +3066,10 @@ fn validateArrayInitTy(
switch (ty.zigTypeTag()) {
.Array, .Vector => return,
- .Struct => if (ty.isTuple()) return,
+ .Struct => if (ty.isTuple()) {
+ // TODO validate element count
+ return;
+ },
else => {},
}
return sema.failWithArrayInitNotSupported(block, src, ty);
@@ -5808,12 +5812,17 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
return sema.addType(opt_type);
}
-fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const src = inst_data.src();
- const array_type = try sema.resolveType(block, src, inst_data.operand);
- const elem_type = array_type.elemType();
- return sema.addType(elem_type);
+fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const bin = sema.code.instructions.items(.data)[inst].bin;
+ const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
+ assert(indexable_ty.isIndexable()); // validated by a previous instruction
+ if (indexable_ty.zigTypeTag() == .Struct) {
+ const elem_type = indexable_ty.tupleFields().types[@enumToInt(bin.rhs)];
+ return sema.addType(elem_type);
+ } else {
+ const elem_type = indexable_ty.elemType2();
+ return sema.addType(elem_type);
+ }
}
fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -13280,6 +13289,8 @@ fn zirStructInit(
try sema.requireRuntimeBlock(block, src);
try sema.queueFullTypeResolution(resolved_ty);
return block.addUnionInit(resolved_ty, field_index, init_inst);
+ } else if (resolved_ty.isAnonStruct()) {
+ return sema.fail(block, src, "TODO anon struct init validation", .{});
}
unreachable;
}
@@ -13436,7 +13447,6 @@ 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;
@@ -13444,30 +13454,26 @@ fn zirArrayInit(
const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = sema.code.refSlice(extra.end, extra.data.operands_len);
- assert(args.len != 0);
+ assert(args.len >= 2); // array_ty + at least one element
- const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len);
- defer gpa.free(resolved_args);
-
- for (args) |arg, i| resolved_args[i] = try sema.resolveInst(arg);
+ const array_ty = try sema.resolveType(block, src, args[0]);
+ const sentinel_val = array_ty.sentinel();
- 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,
- });
- }
+ const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null));
+ defer gpa.free(resolved_args);
+ for (args[1..]) |arg, i| {
+ const resolved_arg = try sema.resolveInst(arg);
+ const arg_src = src; // TODO better source location
+ const elem_ty = if (array_ty.zigTypeTag() == .Struct)
+ array_ty.tupleFields().types[i]
+ else
+ array_ty.elemType2();
+ resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src);
+ }
- 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,
- });
- };
+ if (sentinel_val) |some| {
+ resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(), some);
+ }
const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| {
const arg_src = src; // TODO better source location
@@ -13488,7 +13494,7 @@ fn zirArrayInit(
};
try sema.requireRuntimeBlock(block, runtime_src);
- try sema.queueFullTypeResolution(elem_ty);
+ try sema.queueFullTypeResolution(array_ty);
if (is_ref) {
const target = sema.mod.getTarget();
@@ -13498,10 +13504,27 @@ fn zirArrayInit(
});
const alloc = try block.addTy(.alloc, alloc_ty);
+ if (array_ty.isTuple()) {
+ const types = array_ty.tupleFields().types;
+ for (resolved_args) |arg, i| {
+ const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ .mutable = true,
+ .@"addrspace" = target_util.defaultAddressSpace(target, .local),
+ .pointee_type = types[i],
+ });
+ const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
+
+ const index = try sema.addIntUnsigned(Type.usize, i);
+ const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
+ _ = try block.addBinOp(.store, elem_ptr, arg);
+ }
+ return alloc;
+ }
+
const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
.mutable = true,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
- .pointee_type = elem_ty,
+ .pointee_type = array_ty.elemType2(),
});
const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
@@ -13643,6 +13666,10 @@ fn fieldType(
while (true) {
switch (cur_ty.zigTypeTag()) {
.Struct => {
+ if (cur_ty.isAnonStruct()) {
+ const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
+ return sema.addType(cur_ty.tupleFields().types[field_index]);
+ }
const struct_obj = cur_ty.castTag(.@"struct").?.data;
const field = struct_obj.fields.get(field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
diff --git a/src/Zir.zig b/src/Zir.zig
index c722457303..7516a5a873 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -221,9 +221,9 @@ pub const Inst = struct {
/// Uses the `pl_node` union field with `Bin` payload.
/// lhs is length, rhs is element type.
vector_type,
- /// Given an array type, returns the element type.
- /// Uses the `un_node` union field.
- elem_type,
+ /// Given an indexable type, returns the type of the element at given index.
+ /// Uses the `bin` union field. lhs is the indexable type, rhs is the index.
+ elem_type_index,
/// Given a pointer to an indexable object, returns the len property. This is
/// used by for loops. This instruction also emits a for-loop specific compile
/// error if the indexable object is not indexable.
@@ -737,20 +737,12 @@ 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,
@@ -1019,7 +1011,7 @@ pub const Inst = struct {
.array_type,
.array_type_sentinel,
.vector_type,
- .elem_type,
+ .elem_type_index,
.indexable_ptr_len,
.anyframe_type,
.as,
@@ -1153,10 +1145,8 @@ 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,
@@ -1314,7 +1304,7 @@ pub const Inst = struct {
.array_type,
.array_type_sentinel,
.vector_type,
- .elem_type,
+ .elem_type_index,
.indexable_ptr_len,
.anyframe_type,
.as,
@@ -1426,10 +1416,8 @@ 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,
@@ -1554,7 +1542,7 @@ pub const Inst = struct {
.array_type = .bin,
.array_type_sentinel = .pl_node,
.vector_type = .pl_node,
- .elem_type = .un_node,
+ .elem_type_index = .bin,
.indexable_ptr_len = .un_node,
.anyframe_type = .un_node,
.as = .bin,
@@ -1688,10 +1676,8 @@ 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,
diff --git a/src/print_zir.zig b/src/print_zir.zig
index 1f243acc30..6bab2e5628 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -152,6 +152,8 @@ const Writer = struct {
.store_to_inferred_ptr,
=> try self.writeBin(stream, inst),
+ .elem_type_index => try self.writeElemTypeIndex(stream, inst),
+
.alloc,
.alloc_mut,
.alloc_comptime_mut,
@@ -226,7 +228,6 @@ const Writer = struct {
.pop_count,
.byte_swap,
.bit_reverse,
- .elem_type,
.@"resume",
.@"await",
.switch_cond,
@@ -268,10 +269,6 @@ 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),
@@ -543,6 +540,12 @@ const Writer = struct {
try stream.writeByte(')');
}
+ fn writeElemTypeIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
+ const inst_data = self.code.instructions.items(.data)[inst].bin;
+ try self.writeInstRef(stream, inst_data.lhs);
+ try stream.print(", {d})", .{inst_data.rhs});
+ }
+
fn writeUnNode(
self: *Writer,
stream: anytype,
@@ -2085,8 +2088,9 @@ const Writer = struct {
const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = self.code.refSlice(extra.end, extra.data.operands_len);
- try stream.writeAll(".{");
- for (args) |arg, i| {
+ try self.writeInstRef(stream, args[0]);
+ try stream.writeAll("{");
+ for (args[1..]) |arg, i| {
if (i != 0) try stream.writeAll(", ");
try self.writeInstRef(stream, arg);
}