mirror of
https://github.com/ziglang/zig.git
synced 2025-12-27 08:33:15 +00:00
AstGen: improve generated Zir for array init exprs
This commit is contained in:
parent
ee651c3cd3
commit
c7b778992e
114
src/AstGen.zig
114
src/AstGen.zig
@ -1273,16 +1273,8 @@ fn arrayInitExpr(
|
||||
|
||||
assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init.
|
||||
|
||||
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,
|
||||
};
|
||||
const array_ty: Zir.Inst.Ref = inst: {
|
||||
if (array_init.ast.type_expr == 0) break :inst .none;
|
||||
|
||||
infer: {
|
||||
const array_type: Ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) {
|
||||
@ -1297,15 +1289,10 @@ fn arrayInitExpr(
|
||||
const len_inst = try gz.addInt(array_init.ast.elements.len);
|
||||
const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
|
||||
if (array_type.ast.sentinel == 0) {
|
||||
const array_type_inst = try gz.addBin(.array_type, len_inst, elem_type);
|
||||
break :inst .{
|
||||
.array = array_type_inst,
|
||||
.elem = elem_type,
|
||||
.sentinel = .none,
|
||||
};
|
||||
break :inst try gz.addBin(.array_type, len_inst, elem_type);
|
||||
} else {
|
||||
const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel);
|
||||
const array_type_inst = try gz.addPlNode(
|
||||
break :inst try gz.addPlNode(
|
||||
.array_type_sentinel,
|
||||
array_init.ast.type_expr,
|
||||
Zir.Inst.ArrayTypeSentinel{
|
||||
@ -1314,76 +1301,57 @@ fn arrayInitExpr(
|
||||
.sentinel = sentinel,
|
||||
},
|
||||
);
|
||||
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,
|
||||
};
|
||||
break :inst array_type_inst;
|
||||
};
|
||||
|
||||
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 (array_ty != .none) .array_init_ref else .array_init_anon_ref;
|
||||
return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, 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 (array_ty != .none) .array_init else .array_init_anon;
|
||||
return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, 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 (array_ty != .none) .array_init else .array_init_anon;
|
||||
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, tag);
|
||||
return rvalue(gz, rl, result, node);
|
||||
},
|
||||
.ptr => |ptr_inst| {
|
||||
return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array);
|
||||
return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, array_ty);
|
||||
},
|
||||
.inferred_ptr => |ptr_inst| {
|
||||
if (types.array == .none) {
|
||||
if (array_ty == .none) {
|
||||
// We treat this case differently so that we don't get a crash when
|
||||
// analyzing array_base_ptr against an alloc_inferred_mut.
|
||||
// See corresponding logic in structInitExpr.
|
||||
const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
|
||||
return rvalue(gz, rl, result, node);
|
||||
} else {
|
||||
return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, types.array);
|
||||
return arrayInitExprRlPtr(gz, scope, rl, node, ptr_inst, array_init.ast.elements, array_ty);
|
||||
}
|
||||
},
|
||||
.block_ptr => |block_gz| {
|
||||
// This condition is here for the same reason as the above condition in `inferred_ptr`.
|
||||
// See corresponding logic in structInitExpr.
|
||||
if (types.array == .none and astgen.isInferred(block_gz.rl_ptr)) {
|
||||
if (array_ty == .none and astgen.isInferred(block_gz.rl_ptr)) {
|
||||
const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
|
||||
return rvalue(gz, rl, result, node);
|
||||
}
|
||||
return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, types.array);
|
||||
return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, array_ty);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1410,52 +1378,33 @@ 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,
|
||||
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);
|
||||
var extra_index = try reserveExtra(astgen, len);
|
||||
if (array_ty_inst != .none) {
|
||||
astgen.extra.items[extra_index] = @enumToInt(array_ty_inst);
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
const elem_rl: ResultLoc = .{ .ty = elem_ty_inst };
|
||||
for (elements) |elem_init| {
|
||||
const elem_ref = try expr(gz, scope, elem_rl, elem_init);
|
||||
const elem_ref = try expr(gz, scope, .none, elem_init);
|
||||
astgen.extra.items[extra_index] = @enumToInt(elem_ref);
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
if (sentinel != .none) {
|
||||
astgen.extra.items[extra_index] = @enumToInt(sentinel);
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
return try gz.addPlNodePayloadIndex(info.tag, node, payload_index);
|
||||
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
}
|
||||
|
||||
fn arrayInitExprRlPtr(
|
||||
@ -2244,7 +2193,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.vector_type,
|
||||
.elem_type,
|
||||
.indexable_ptr_len,
|
||||
.anyframe_type,
|
||||
.as,
|
||||
@ -2347,10 +2295,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,
|
||||
|
||||
45
src/Sema.zig
45
src/Sema.zig
@ -726,7 +726,6 @@ 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),
|
||||
.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 +797,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),
|
||||
@ -13436,7 +13433,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 +13440,23 @@ 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);
|
||||
const array_ty = try sema.resolveType(block, src, args[0]);
|
||||
const sentinel_val = array_ty.sentinel();
|
||||
|
||||
const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null));
|
||||
defer gpa.free(resolved_args);
|
||||
const elem_ty = array_ty.elemType2();
|
||||
for (args[1..]) |arg, i| {
|
||||
const resolved_arg = try sema.resolveInst(arg);
|
||||
const arg_src = src; // TODO better source location
|
||||
resolved_args[i] = try sema.coerce(block, elem_ty, resolved_arg, arg_src);
|
||||
}
|
||||
|
||||
for (args) |arg, i| resolved_args[i] = try sema.resolveInst(arg);
|
||||
|
||||
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 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(elem_ty, some);
|
||||
}
|
||||
|
||||
const opt_runtime_src: ?LazySrcLoc = for (resolved_args) |arg| {
|
||||
const arg_src = src; // TODO better source location
|
||||
@ -13488,7 +13477,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();
|
||||
|
||||
20
src/Zir.zig
20
src/Zir.zig
@ -221,9 +221,6 @@ 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 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 +734,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 +1008,6 @@ pub const Inst = struct {
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.vector_type,
|
||||
.elem_type,
|
||||
.indexable_ptr_len,
|
||||
.anyframe_type,
|
||||
.as,
|
||||
@ -1153,10 +1141,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 +1300,6 @@ pub const Inst = struct {
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.vector_type,
|
||||
.elem_type,
|
||||
.indexable_ptr_len,
|
||||
.anyframe_type,
|
||||
.as,
|
||||
@ -1426,10 +1411,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 +1537,6 @@ pub const Inst = struct {
|
||||
.array_type = .bin,
|
||||
.array_type_sentinel = .pl_node,
|
||||
.vector_type = .pl_node,
|
||||
.elem_type = .un_node,
|
||||
.indexable_ptr_len = .un_node,
|
||||
.anyframe_type = .un_node,
|
||||
.as = .bin,
|
||||
@ -1688,10 +1670,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,
|
||||
|
||||
@ -226,7 +226,6 @@ const Writer = struct {
|
||||
.pop_count,
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
.elem_type,
|
||||
.@"resume",
|
||||
.@"await",
|
||||
.switch_cond,
|
||||
@ -268,10 +267,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),
|
||||
@ -2085,8 +2080,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);
|
||||
}
|
||||
|
||||
@ -942,3 +942,10 @@ test "comptime int in switch in catch is casted to correct inferred type" {
|
||||
};
|
||||
_ = b;
|
||||
}
|
||||
|
||||
test "vector initialized with array init syntax has proper type" {
|
||||
comptime {
|
||||
const actual = -@Vector(4, i32){ 1, 2, 3, 4 };
|
||||
try std.testing.expectEqual(@Vector(4, i32){ -1, -2, -3, -4 }, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,8 +194,6 @@ test "tuple as the result from a labeled block" {
|
||||
}
|
||||
|
||||
test "initializing tuple with explicit type" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
|
||||
const T = @TypeOf(.{ @as(i32, 0), @as(u32, 0) });
|
||||
var a = T{ 0, 0 };
|
||||
_ = a;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user