mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
compiler: preserve result type information through address-of operator
This commit introduces the new `ref_coerced_ty` result type into AstGen.
This represents a expression which we want to treat as an lvalue, and
the pointer will be coerced to a given type.
This change gives known result types to many expressions, in particular
struct and array initializations. This allows certain casts to work
which previously required explicitly specifying types via `@as`. It also
eliminates our dependence on anonymous struct types for expressions of
the form `&.{ ... }` - this paves the way for #16865, and also results
in less Sema magic happening for such initializations, also leading to
potentially better runtime code.
As part of these changes, this commit also implements #17194 by
disallowing RLS on explicitly-typed struct and array initializations.
Apologies for linking these changes - it seemed rather pointless to try
and separate them, since they both make big changes to struct and array
initializations in AstGen. The rationale for this change can be found in
the proposal - in essence, performing RLS whilst maintaining the
semantics of the intermediary type is a very difficult problem to solve.
This allowed the problematic `coerce_result_ptr` ZIR instruction to be
completely eliminated, which in turn also simplified the logic for
inferred allocations in Sema - thanks to this, we almost break even on
line count!
In doing this, the ZIR instructions surrounding these initializations
have been restructured - some have been added and removed, and others
renamed for clarity (and their semantics changed slightly). In order to
optimize ZIR tag count, the `struct_init_anon_ref` and
`array_init_anon_ref` instructions have been removed in favour of using
`ref` on a standard anonymous value initialization, since these
instructions are now virtually never used.
Lastly, it's worth noting that this commit introduces a slightly strange
source of generic poison types: in the expression `@as(*anyopaque, &x)`,
the sub-expression `x` has a generic poison result type, despite no
generic code being involved. This turns out to be a logical choice,
because we don't know the result type for `x`, and the generic poison
type represents precisely this case, providing the semantics we need.
Resolves: #16512
Resolves: #17194
This commit is contained in:
parent
01906a3ad8
commit
09a57583a4
35 changed files with 1261 additions and 1035 deletions
|
|
@ -514,7 +514,12 @@ pub const StackIterator = struct {
|
|||
|
||||
return StackIterator{
|
||||
.first_address = first_address,
|
||||
.fp = fp orelse @frameAddress(),
|
||||
// TODO: this is a workaround for #16876
|
||||
//.fp = fp orelse @frameAddress(),
|
||||
.fp = fp orelse blk: {
|
||||
const fa = @frameAddress();
|
||||
break :blk fa;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
561
src/AstGen.zig
561
src/AstGen.zig
|
|
@ -265,14 +265,17 @@ const ResultInfo = struct {
|
|||
discard,
|
||||
/// The expression has an inferred type, and it will be evaluated as an rvalue.
|
||||
none,
|
||||
/// The expression must generate a pointer rather than a value. For example, the left hand side
|
||||
/// of an assignment uses this kind of result location.
|
||||
ref,
|
||||
/// The expression will be coerced into this type, but it will be evaluated as an rvalue.
|
||||
ty: Zir.Inst.Ref,
|
||||
/// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
|
||||
/// so no `as` instruction needs to be emitted.
|
||||
coerced_ty: Zir.Inst.Ref,
|
||||
/// The expression must generate a pointer rather than a value. For example, the left hand side
|
||||
/// of an assignment uses this kind of result location.
|
||||
ref,
|
||||
/// The expression must generate a pointer rather than a value, and the pointer will be coerced
|
||||
/// by other code to this type, which is guaranteed by earlier instructions to be a pointer type.
|
||||
ref_coerced_ty: Zir.Inst.Ref,
|
||||
/// The expression must store its result into this typed pointer. The result instruction
|
||||
/// from the expression must be ignored.
|
||||
ptr: PtrResultLoc,
|
||||
|
|
@ -303,26 +306,30 @@ const ResultInfo = struct {
|
|||
/// Find the result type for a cast builtin given the result location.
|
||||
/// If the location does not have a known result type, emits an error on
|
||||
/// the given node.
|
||||
fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
switch (rl) {
|
||||
.discard, .none, .ref, .inferred_ptr => {},
|
||||
.ty, .coerced_ty => |ty_ref| return ty_ref,
|
||||
fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.Ref {
|
||||
return switch (rl) {
|
||||
.discard, .none, .ref, .inferred_ptr, .destructure => null,
|
||||
.ty, .coerced_ty => |ty_ref| ty_ref,
|
||||
.ref_coerced_ty => |ptr_ty| try gz.addUnNode(.elem_type, ptr_ty, node),
|
||||
.ptr => |ptr| {
|
||||
const ptr_ty = try gz.addUnNode(.typeof, ptr.inst, node);
|
||||
return gz.addUnNode(.elem_type, ptr_ty, node);
|
||||
},
|
||||
.destructure => |destructure| {
|
||||
return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
|
||||
try astgen.errNoteNode(destructure.src_node, "destructure expressions do not provide a single result type", .{}),
|
||||
try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
|
||||
});
|
||||
return try gz.addUnNode(.elem_type, ptr_ty, node);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
|
||||
fn resultTypeForCast(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
if (try rl.resultType(gz, node)) |ty| return ty;
|
||||
switch (rl) {
|
||||
.destructure => |destructure| return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
|
||||
try astgen.errNoteNode(destructure.src_node, "destructure expressions do not provide a single result type", .{}),
|
||||
try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
|
||||
});
|
||||
}),
|
||||
else => return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
|
||||
try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
|
||||
}),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -933,7 +940,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
|||
const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);
|
||||
_ = try gz.addUnNode(.validate_deref, lhs, node);
|
||||
switch (ri.rl) {
|
||||
.ref => return lhs,
|
||||
.ref, .ref_coerced_ty => return lhs,
|
||||
else => {
|
||||
const result = try gz.addUnNode(.load, lhs, node);
|
||||
return rvalue(gz, ri, result, node);
|
||||
|
|
@ -941,7 +948,11 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
|||
}
|
||||
},
|
||||
.address_of => {
|
||||
const result = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
|
||||
const operand_rl: ResultInfo.Loc = if (try ri.rl.resultType(gz, node)) |res_ty_inst| rl: {
|
||||
_ = try gz.addUnTok(.validate_ref_ty, res_ty_inst, tree.firstToken(node));
|
||||
break :rl .{ .ref_coerced_ty = res_ty_inst };
|
||||
} else .ref;
|
||||
const result = try expr(gz, scope, .{ .rl = operand_rl }, node_datas[node].lhs);
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.optional_type => {
|
||||
|
|
@ -950,7 +961,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
|||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.unwrap_optional => switch (ri.rl) {
|
||||
.ref => {
|
||||
.ref, .ref_coerced_ty => {
|
||||
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
|
||||
|
||||
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
|
||||
|
|
@ -1001,7 +1012,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
|||
else
|
||||
null;
|
||||
switch (ri.rl) {
|
||||
.ref => return orelseCatchExpr(
|
||||
.ref, .ref_coerced_ty => return orelseCatchExpr(
|
||||
gz,
|
||||
scope,
|
||||
ri,
|
||||
|
|
@ -1028,7 +1039,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
|||
}
|
||||
},
|
||||
.@"orelse" => switch (ri.rl) {
|
||||
.ref => return orelseCatchExpr(
|
||||
.ref, .ref_coerced_ty => return orelseCatchExpr(
|
||||
gz,
|
||||
scope,
|
||||
ri,
|
||||
|
|
@ -1432,6 +1443,8 @@ fn arrayInitExpr(
|
|||
break :inst .{ array_type_inst, .none };
|
||||
};
|
||||
|
||||
if (array_ty != .none) {
|
||||
// Typed inits do not use RLS for language simplicity.
|
||||
switch (ri.rl) {
|
||||
.discard => {
|
||||
if (elem_ty != .none) {
|
||||
|
|
@ -1439,10 +1452,10 @@ fn arrayInitExpr(
|
|||
for (array_init.ast.elements) |elem_init| {
|
||||
_ = try expr(gz, scope, elem_ri, elem_init);
|
||||
}
|
||||
} else if (array_ty != .none) {
|
||||
} else {
|
||||
for (array_init.ast.elements, 0..) |elem_init, i| {
|
||||
const this_elem_ty = try gz.add(.{
|
||||
.tag = .elem_type_index,
|
||||
.tag = .array_init_elem_type,
|
||||
.data = .{ .bin = .{
|
||||
.lhs = array_ty,
|
||||
.rhs = @enumFromInt(i),
|
||||
|
|
@ -1450,55 +1463,55 @@ fn arrayInitExpr(
|
|||
});
|
||||
_ = try expr(gz, scope, .{ .rl = .{ .ty = this_elem_ty } }, elem_init);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
return .void_value;
|
||||
},
|
||||
.ref => return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, true),
|
||||
else => {
|
||||
const array_inst = try arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, false);
|
||||
return rvalue(gz, ri, array_inst, node);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
switch (ri.rl) {
|
||||
.none => return arrayInitExprAnon(gz, scope, node, array_init.ast.elements),
|
||||
.discard => {
|
||||
for (array_init.ast.elements) |elem_init| {
|
||||
_ = try expr(gz, scope, .{ .rl = .discard }, elem_init);
|
||||
}
|
||||
}
|
||||
return Zir.Inst.Ref.void_value;
|
||||
},
|
||||
.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, elem_ty, tag);
|
||||
const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
|
||||
return gz.addUnTok(.ref, result, tree.firstToken(node));
|
||||
},
|
||||
.none => {
|
||||
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, elem_ty, tag);
|
||||
.ref_coerced_ty => |ptr_ty_inst| {
|
||||
const dest_arr_ty_inst = try gz.addPlNode(.validate_array_init_ref_ty, node, Zir.Inst.ArrayInitRefTy{
|
||||
.ptr_ty = ptr_ty_inst,
|
||||
.elem_count = @intCast(array_init.ast.elements.len),
|
||||
});
|
||||
return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, dest_arr_ty_inst, .none, true);
|
||||
},
|
||||
.ty, .coerced_ty => |ty_inst| {
|
||||
const arr_ty = if (array_ty != .none) array_ty else blk: {
|
||||
const arr_ty = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
|
||||
_ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{
|
||||
.ty = arr_ty,
|
||||
.ty, .coerced_ty => |result_ty_inst| {
|
||||
_ = try gz.addPlNode(.validate_array_init_result_ty, node, Zir.Inst.ArrayInit{
|
||||
.ty = result_ty_inst,
|
||||
.init_count = @intCast(array_init.ast.elements.len),
|
||||
});
|
||||
break :blk arr_ty;
|
||||
};
|
||||
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, arr_ty, elem_ty, .array_init);
|
||||
return rvalue(gz, ri, result, node);
|
||||
return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, result_ty_inst, .none, false);
|
||||
},
|
||||
.ptr => |ptr_res| {
|
||||
return arrayInitExprRlPtr(gz, scope, node, ptr_res.inst, array_init.ast.elements, array_ty);
|
||||
.ptr => |ptr| {
|
||||
try arrayInitExprPtr(gz, scope, node, array_init.ast.elements, ptr.inst);
|
||||
return .void_value;
|
||||
},
|
||||
.inferred_ptr => |ptr_inst| {
|
||||
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.
|
||||
.inferred_ptr => {
|
||||
// We can't get elem pointers of an untyped inferred alloc, so must perform a
|
||||
// standard anonymous initialization followed by an rvalue store.
|
||||
// See corresponding logic in structInitExpr.
|
||||
const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
|
||||
const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
|
||||
return rvalue(gz, ri, result, node);
|
||||
} else {
|
||||
return arrayInitExprRlPtr(gz, scope, node, ptr_inst, array_init.ast.elements, array_ty);
|
||||
}
|
||||
},
|
||||
.destructure => |destructure| {
|
||||
if (array_ty != .none) {
|
||||
// We have a specific type, so there may be things like default
|
||||
// field values messing with us. Do this as a standard typed
|
||||
// init followed by an rvalue destructure.
|
||||
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, .array_init);
|
||||
return rvalue(gz, ri, result, node);
|
||||
}
|
||||
// Untyped init - destructure directly into result pointers
|
||||
if (array_init.ast.elements.len != destructure.components.len) {
|
||||
return astgen.failNodeNotes(node, "expected {} elements for destructure, found {}", .{
|
||||
|
|
@ -1521,12 +1534,12 @@ fn arrayInitExpr(
|
|||
}
|
||||
}
|
||||
|
||||
fn arrayInitExprRlNone(
|
||||
/// An array initialization expression using an `array_init_anon` instruction.
|
||||
fn arrayInitExprAnon(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
elements: []const Ast.Node.Index,
|
||||
tag: Zir.Inst.Tag,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
|
||||
|
|
@ -1540,95 +1553,84 @@ fn arrayInitExprRlNone(
|
|||
astgen.extra.items[extra_index] = @intFromEnum(elem_ref);
|
||||
extra_index += 1;
|
||||
}
|
||||
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
return try gz.addPlNodePayloadIndex(.array_init_anon, node, payload_index);
|
||||
}
|
||||
|
||||
fn arrayInitExprInner(
|
||||
/// An array initialization expression using an `array_init` or `array_init_ref` instruction.
|
||||
fn arrayInitExprTyped(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
elements: []const Ast.Node.Index,
|
||||
array_ty_inst: Zir.Inst.Ref,
|
||||
elem_ty: Zir.Inst.Ref,
|
||||
tag: Zir.Inst.Tag,
|
||||
ty_inst: Zir.Inst.Ref,
|
||||
maybe_elem_ty_inst: Zir.Inst.Ref,
|
||||
is_ref: bool,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
|
||||
const len = elements.len + @intFromBool(array_ty_inst != .none);
|
||||
const len = elements.len + 1; // +1 for type
|
||||
const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
|
||||
.operands_len = @intCast(len),
|
||||
});
|
||||
var extra_index = try reserveExtra(astgen, len);
|
||||
if (array_ty_inst != .none) {
|
||||
astgen.extra.items[extra_index] = @intFromEnum(array_ty_inst);
|
||||
astgen.extra.items[extra_index] = @intFromEnum(ty_inst);
|
||||
extra_index += 1;
|
||||
|
||||
if (maybe_elem_ty_inst != .none) {
|
||||
const elem_ri: ResultInfo = .{ .rl = .{ .coerced_ty = maybe_elem_ty_inst } };
|
||||
for (elements) |elem_init| {
|
||||
const elem_inst = try expr(gz, scope, elem_ri, elem_init);
|
||||
astgen.extra.items[extra_index] = @intFromEnum(elem_inst);
|
||||
extra_index += 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
for (elements, 0..) |elem_init, i| {
|
||||
const ri = if (elem_ty != .none)
|
||||
ResultInfo{ .rl = .{ .coerced_ty = elem_ty } }
|
||||
else if (array_ty_inst != .none) ri: {
|
||||
const ty_expr = try gz.add(.{
|
||||
.tag = .elem_type_index,
|
||||
const ri: ResultInfo = .{ .rl = .{ .coerced_ty = try gz.add(.{
|
||||
.tag = .array_init_elem_type,
|
||||
.data = .{ .bin = .{
|
||||
.lhs = array_ty_inst,
|
||||
.lhs = ty_inst,
|
||||
.rhs = @enumFromInt(i),
|
||||
} },
|
||||
});
|
||||
break :ri ResultInfo{ .rl = .{ .coerced_ty = ty_expr } };
|
||||
} else ResultInfo{ .rl = .{ .none = {} } };
|
||||
}) } };
|
||||
|
||||
const elem_ref = try expr(gz, scope, ri, elem_init);
|
||||
astgen.extra.items[extra_index] = @intFromEnum(elem_ref);
|
||||
const elem_inst = try expr(gz, scope, ri, elem_init);
|
||||
astgen.extra.items[extra_index] = @intFromEnum(elem_inst);
|
||||
extra_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
const tag: Zir.Inst.Tag = if (is_ref) .array_init_ref else .array_init;
|
||||
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
}
|
||||
|
||||
fn arrayInitExprRlPtr(
|
||||
/// An array initialization expression using element pointers.
|
||||
fn arrayInitExprPtr(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
result_ptr: Zir.Inst.Ref,
|
||||
elements: []const Ast.Node.Index,
|
||||
array_ty: Zir.Inst.Ref,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
if (array_ty == .none) {
|
||||
const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node);
|
||||
return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements);
|
||||
}
|
||||
|
||||
const casted_ptr = try gz.addPlNode(.coerce_result_ptr, node, Zir.Inst.Bin{ .lhs = array_ty, .rhs = result_ptr });
|
||||
return arrayInitExprRlPtrInner(gz, scope, node, casted_ptr, elements);
|
||||
}
|
||||
|
||||
fn arrayInitExprRlPtrInner(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
result_ptr: Zir.Inst.Ref,
|
||||
elements: []const Ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
ptr_inst: Zir.Inst.Ref,
|
||||
) InnerError!void {
|
||||
const astgen = gz.astgen;
|
||||
|
||||
const array_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node);
|
||||
|
||||
const payload_index = try addExtra(astgen, Zir.Inst.Block{
|
||||
.body_len = @intCast(elements.len),
|
||||
});
|
||||
var extra_index = try reserveExtra(astgen, elements.len);
|
||||
|
||||
for (elements, 0..) |elem_init, i| {
|
||||
const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{
|
||||
.ptr = result_ptr,
|
||||
const elem_ptr_inst = try gz.addPlNode(.array_init_elem_ptr, elem_init, Zir.Inst.ElemPtrImm{
|
||||
.ptr = array_ptr_inst,
|
||||
.index = @intCast(i),
|
||||
});
|
||||
astgen.extra.items[extra_index] = refToIndex(elem_ptr).?;
|
||||
astgen.extra.items[extra_index] = refToIndex(elem_ptr_inst).?;
|
||||
extra_index += 1;
|
||||
_ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr } } }, elem_init);
|
||||
_ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr_inst } } }, elem_init);
|
||||
}
|
||||
|
||||
_ = try gz.addPlNodePayloadIndex(.validate_array_init, node, payload_index);
|
||||
return .void_value;
|
||||
_ = try gz.addPlNodePayloadIndex(.validate_ptr_array_init, node, payload_index);
|
||||
}
|
||||
|
||||
fn structInitExpr(
|
||||
|
|
@ -1643,7 +1645,26 @@ fn structInitExpr(
|
|||
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
if (struct_init.ast.fields.len == 0) {
|
||||
// Anonymous init with no fields.
|
||||
switch (ri.rl) {
|
||||
.discard => return .void_value,
|
||||
.ref_coerced_ty => |ptr_ty_inst| return gz.addUnNode(.struct_init_empty_ref_result, ptr_ty_inst, node),
|
||||
.ty, .coerced_ty => |ty_inst| return gz.addUnNode(.struct_init_empty_result, ty_inst, node),
|
||||
.ptr => {
|
||||
// TODO: should we modify this to use RLS for the field stores here?
|
||||
const ty_inst = (try ri.rl.resultType(gz, node)).?;
|
||||
const val = try gz.addUnNode(.struct_init_empty_result, ty_inst, node);
|
||||
return rvalue(gz, ri, val, node);
|
||||
},
|
||||
.none, .ref, .inferred_ptr => {
|
||||
return rvalue(gz, ri, .empty_struct, node);
|
||||
},
|
||||
.destructure => |destructure| {
|
||||
return astgen.failNodeNotes(node, "empty initializer cannot be destructured", .{}, &.{
|
||||
try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
} else array: {
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
|
|
@ -1694,86 +1715,67 @@ fn structInitExpr(
|
|||
}
|
||||
}
|
||||
|
||||
switch (ri.rl) {
|
||||
.discard => {
|
||||
if (struct_init.ast.type_expr != 0) {
|
||||
// Typed inits do not use RLS for language simplicity.
|
||||
const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
|
||||
_ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
|
||||
} else {
|
||||
_ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
|
||||
switch (ri.rl) {
|
||||
.ref => return structInitExprTyped(gz, scope, node, struct_init, ty_inst, true),
|
||||
else => {
|
||||
const struct_inst = try structInitExprTyped(gz, scope, node, struct_init, ty_inst, false);
|
||||
return rvalue(gz, ri, struct_inst, node);
|
||||
},
|
||||
}
|
||||
return Zir.Inst.Ref.void_value;
|
||||
}
|
||||
|
||||
switch (ri.rl) {
|
||||
.none => return structInitExprAnon(gz, scope, node, struct_init),
|
||||
.discard => {
|
||||
// Even if discarding we must perform an anonymous init to check for duplicate field names.
|
||||
// TODO: should duplicate field names be caught in AstGen?
|
||||
_ = try structInitExprAnon(gz, scope, node, struct_init);
|
||||
return .void_value;
|
||||
},
|
||||
.ref => {
|
||||
if (struct_init.ast.type_expr != 0) {
|
||||
const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
|
||||
return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
|
||||
} else {
|
||||
return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref);
|
||||
}
|
||||
const result = try structInitExprAnon(gz, scope, node, struct_init);
|
||||
return gz.addUnTok(.ref, result, tree.firstToken(node));
|
||||
},
|
||||
.none => {
|
||||
if (struct_init.ast.type_expr != 0) {
|
||||
const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
|
||||
return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
|
||||
} else {
|
||||
return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
|
||||
}
|
||||
.ref_coerced_ty => |ptr_ty_inst| {
|
||||
const result_ty_inst = try gz.addUnNode(.elem_type, ptr_ty_inst, node);
|
||||
_ = try gz.addUnNode(.validate_struct_init_result_ty, result_ty_inst, node);
|
||||
return structInitExprTyped(gz, scope, node, struct_init, result_ty_inst, true);
|
||||
},
|
||||
.ty, .coerced_ty => |ty_inst| {
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
const struct_ty_inst = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, struct_ty_inst, node);
|
||||
const result = try structInitExprRlTy(gz, scope, node, struct_init, struct_ty_inst, .struct_init);
|
||||
return rvalue(gz, ri, result, node);
|
||||
}
|
||||
const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node);
|
||||
const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
|
||||
return rvalue(gz, ri, result, node);
|
||||
.ty, .coerced_ty => |result_ty_inst| {
|
||||
_ = try gz.addUnNode(.validate_struct_init_result_ty, result_ty_inst, node);
|
||||
return structInitExprTyped(gz, scope, node, struct_init, result_ty_inst, false);
|
||||
},
|
||||
.ptr => |ptr_res| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_res.inst),
|
||||
.inferred_ptr => |ptr_inst| {
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
// We treat this case differently so that we don't get a crash when
|
||||
// analyzing field_base_ptr against an alloc_inferred_mut.
|
||||
.ptr => |ptr| {
|
||||
try structInitExprPtr(gz, scope, node, struct_init, ptr.inst);
|
||||
return .void_value;
|
||||
},
|
||||
.inferred_ptr => {
|
||||
// We can't get field pointers of an untyped inferred alloc, so must perform a
|
||||
// standard anonymous initialization followed by an rvalue store.
|
||||
// See corresponding logic in arrayInitExpr.
|
||||
const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
|
||||
return rvalue(gz, ri, result, node);
|
||||
} else {
|
||||
return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst);
|
||||
}
|
||||
const struct_inst = try structInitExprAnon(gz, scope, node, struct_init);
|
||||
return rvalue(gz, ri, struct_inst, node);
|
||||
},
|
||||
.destructure => |destructure| {
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
// This is an untyped init, so is an actual struct, which does
|
||||
// not support destructuring.
|
||||
return astgen.failNodeNotes(node, "struct value cannot be destructured", .{}, &.{
|
||||
try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
|
||||
});
|
||||
}
|
||||
// You can init tuples using struct init syntax and numeric field
|
||||
// names, but as with array inits, we could be bitten by default
|
||||
// fields. Therefore, we do a normal typed init then an rvalue
|
||||
// destructure.
|
||||
const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
|
||||
const result = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn structInitExprRlNone(
|
||||
/// A struct initialization expression using a `struct_init_anon` instruction.
|
||||
fn structInitExprAnon(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
struct_init: Ast.full.StructInit,
|
||||
ty_inst: Zir.Inst.Ref,
|
||||
tag: Zir.Inst.Tag,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
|
|
@ -1787,79 +1789,24 @@ fn structInitExprRlNone(
|
|||
for (struct_init.ast.fields) |field_init| {
|
||||
const name_token = tree.firstToken(field_init) - 2;
|
||||
const str_index = try astgen.identAsString(name_token);
|
||||
const sub_ri: ResultInfo = if (ty_inst != .none)
|
||||
ResultInfo{ .rl = .{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
|
||||
.container_type = ty_inst,
|
||||
.name_start = str_index,
|
||||
}) } }
|
||||
else
|
||||
.{ .rl = .none };
|
||||
setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
|
||||
.field_name = str_index,
|
||||
.init = try expr(gz, scope, sub_ri, field_init),
|
||||
.init = try expr(gz, scope, .{ .rl = .none }, field_init),
|
||||
});
|
||||
extra_index += field_size;
|
||||
}
|
||||
|
||||
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
return gz.addPlNodePayloadIndex(.struct_init_anon, node, payload_index);
|
||||
}
|
||||
|
||||
fn structInitExprRlPtr(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
struct_init: Ast.full.StructInit,
|
||||
result_ptr: Zir.Inst.Ref,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node);
|
||||
return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr);
|
||||
}
|
||||
const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
|
||||
_ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
|
||||
|
||||
const casted_ptr = try gz.addPlNode(.coerce_result_ptr, node, Zir.Inst.Bin{ .lhs = ty_inst, .rhs = result_ptr });
|
||||
return structInitExprRlPtrInner(gz, scope, node, struct_init, casted_ptr);
|
||||
}
|
||||
|
||||
fn structInitExprRlPtrInner(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
struct_init: Ast.full.StructInit,
|
||||
result_ptr: Zir.Inst.Ref,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
|
||||
const payload_index = try addExtra(astgen, Zir.Inst.Block{
|
||||
.body_len = @intCast(struct_init.ast.fields.len),
|
||||
});
|
||||
var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len);
|
||||
|
||||
for (struct_init.ast.fields) |field_init| {
|
||||
const name_token = tree.firstToken(field_init) - 2;
|
||||
const str_index = try astgen.identAsString(name_token);
|
||||
const field_ptr = try gz.addPlNode(.field_ptr_init, field_init, Zir.Inst.Field{
|
||||
.lhs = result_ptr,
|
||||
.field_name_start = str_index,
|
||||
});
|
||||
astgen.extra.items[extra_index] = refToIndex(field_ptr).?;
|
||||
extra_index += 1;
|
||||
_ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init);
|
||||
}
|
||||
|
||||
_ = try gz.addPlNodePayloadIndex(.validate_struct_init, node, payload_index);
|
||||
return Zir.Inst.Ref.void_value;
|
||||
}
|
||||
|
||||
fn structInitExprRlTy(
|
||||
/// A struct initialization expression using a `struct_init` or `struct_init_ref` instruction.
|
||||
fn structInitExprTyped(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
struct_init: Ast.full.StructInit,
|
||||
ty_inst: Zir.Inst.Ref,
|
||||
tag: Zir.Inst.Tag,
|
||||
is_ref: bool,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
|
|
@ -1873,18 +1820,52 @@ fn structInitExprRlTy(
|
|||
for (struct_init.ast.fields) |field_init| {
|
||||
const name_token = tree.firstToken(field_init) - 2;
|
||||
const str_index = try astgen.identAsString(name_token);
|
||||
const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
|
||||
const field_ty_inst = try gz.addPlNode(.struct_init_field_type, field_init, Zir.Inst.FieldType{
|
||||
.container_type = ty_inst,
|
||||
.name_start = str_index,
|
||||
});
|
||||
setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{
|
||||
.field_type = refToIndex(field_ty_inst).?,
|
||||
.init = try expr(gz, scope, .{ .rl = .{ .ty = field_ty_inst } }, field_init),
|
||||
.init = try expr(gz, scope, .{ .rl = .{ .coerced_ty = field_ty_inst } }, field_init),
|
||||
});
|
||||
extra_index += field_size;
|
||||
}
|
||||
|
||||
return try gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
const tag: Zir.Inst.Tag = if (is_ref) .struct_init_ref else .struct_init;
|
||||
return gz.addPlNodePayloadIndex(tag, node, payload_index);
|
||||
}
|
||||
|
||||
/// A struct initialization expression using field pointers.
|
||||
fn structInitExprPtr(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
struct_init: Ast.full.StructInit,
|
||||
ptr_inst: Zir.Inst.Ref,
|
||||
) InnerError!void {
|
||||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
|
||||
const struct_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node);
|
||||
|
||||
const payload_index = try addExtra(astgen, Zir.Inst.Block{
|
||||
.body_len = @intCast(struct_init.ast.fields.len),
|
||||
});
|
||||
var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len);
|
||||
|
||||
for (struct_init.ast.fields) |field_init| {
|
||||
const name_token = tree.firstToken(field_init) - 2;
|
||||
const str_index = try astgen.identAsString(name_token);
|
||||
const field_ptr = try gz.addPlNode(.struct_init_field_ptr, field_init, Zir.Inst.Field{
|
||||
.lhs = struct_ptr_inst,
|
||||
.field_name_start = str_index,
|
||||
});
|
||||
astgen.extra.items[extra_index] = refToIndex(field_ptr).?;
|
||||
extra_index += 1;
|
||||
_ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init);
|
||||
}
|
||||
|
||||
_ = try gz.addPlNodePayloadIndex(.validate_ptr_struct_init, node, payload_index);
|
||||
}
|
||||
|
||||
/// This explicitly calls expr in a comptime scope by wrapping it in a `block_comptime` if
|
||||
|
|
@ -2314,7 +2295,7 @@ fn labeledBlockExpr(
|
|||
const need_rl = astgen.nodes_need_rl.contains(block_node);
|
||||
const block_ri: ResultInfo = if (need_rl) ri else .{
|
||||
.rl = switch (ri.rl) {
|
||||
.ptr => .{ .ty = try ri.rl.resultType(gz, block_node, undefined) },
|
||||
.ptr => .{ .ty = (try ri.rl.resultType(gz, block_node)).? },
|
||||
.inferred_ptr => .none,
|
||||
else => ri.rl,
|
||||
},
|
||||
|
|
@ -2504,7 +2485,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.array_mul,
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.elem_type_index,
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
.vector_elem_type,
|
||||
|
|
@ -2531,7 +2511,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.cmp_gte,
|
||||
.cmp_gt,
|
||||
.cmp_neq,
|
||||
.coerce_result_ptr,
|
||||
.decl_ref,
|
||||
.decl_val,
|
||||
.load,
|
||||
|
|
@ -2539,11 +2518,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.elem_ptr,
|
||||
.elem_val,
|
||||
.elem_ptr_node,
|
||||
.elem_ptr_imm,
|
||||
.elem_val_node,
|
||||
.elem_val_imm,
|
||||
.field_ptr,
|
||||
.field_ptr_init,
|
||||
.field_val,
|
||||
.field_ptr_named,
|
||||
.field_val_named,
|
||||
|
|
@ -2599,17 +2576,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.import,
|
||||
.switch_block,
|
||||
.switch_block_ref,
|
||||
.struct_init_empty,
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
.struct_init_anon,
|
||||
.struct_init_anon_ref,
|
||||
.array_init,
|
||||
.array_init_anon,
|
||||
.array_init_ref,
|
||||
.array_init_anon_ref,
|
||||
.union_init,
|
||||
.field_type,
|
||||
.field_type_ref,
|
||||
.error_set_decl,
|
||||
.error_set_decl_anon,
|
||||
|
|
@ -2680,14 +2647,27 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.@"await",
|
||||
.ret_err_value_code,
|
||||
.closure_get,
|
||||
.array_base_ptr,
|
||||
.field_base_ptr,
|
||||
.ret_ptr,
|
||||
.ret_type,
|
||||
.for_len,
|
||||
.@"try",
|
||||
.try_ptr,
|
||||
.opt_eu_base_ty,
|
||||
.opt_eu_base_ptr_init,
|
||||
.coerce_ptr_elem_ty,
|
||||
.struct_init_empty,
|
||||
.struct_init_empty_result,
|
||||
.struct_init_empty_ref_result,
|
||||
.struct_init_anon,
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
.struct_init_field_type,
|
||||
.struct_init_field_ptr,
|
||||
.array_init_anon,
|
||||
.array_init,
|
||||
.array_init_ref,
|
||||
.validate_array_init_ref_ty,
|
||||
.array_init_elem_type,
|
||||
.array_init_elem_ptr,
|
||||
=> break :b false,
|
||||
|
||||
.extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
|
||||
|
|
@ -2738,18 +2718,21 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||
.store_node,
|
||||
.store_to_inferred_ptr,
|
||||
.resolve_inferred_alloc,
|
||||
.validate_struct_init,
|
||||
.validate_array_init,
|
||||
.set_runtime_safety,
|
||||
.closure_capture,
|
||||
.memcpy,
|
||||
.memset,
|
||||
.validate_array_init_ty,
|
||||
.validate_struct_init_ty,
|
||||
.validate_deref,
|
||||
.validate_destructure,
|
||||
.save_err_ret_index,
|
||||
.restore_err_ret_index,
|
||||
.validate_struct_init_ty,
|
||||
.validate_struct_init_result_ty,
|
||||
.validate_ptr_struct_init,
|
||||
.validate_array_init_ty,
|
||||
.validate_array_init_result_ty,
|
||||
.validate_ptr_array_init,
|
||||
.validate_ref_ty,
|
||||
=> break :b true,
|
||||
|
||||
.@"defer" => unreachable,
|
||||
|
|
@ -5635,7 +5618,7 @@ fn tryExpr(
|
|||
const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
|
||||
|
||||
const operand_ri: ResultInfo = switch (ri.rl) {
|
||||
.ref => .{ .rl = .ref, .ctx = .error_handling_expr },
|
||||
.ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = .error_handling_expr },
|
||||
else => .{ .rl = .none, .ctx = .error_handling_expr },
|
||||
};
|
||||
// This could be a pointer or value depending on the `ri` parameter.
|
||||
|
|
@ -5648,7 +5631,7 @@ fn tryExpr(
|
|||
defer else_scope.unstack();
|
||||
|
||||
const err_tag = switch (ri.rl) {
|
||||
.ref => Zir.Inst.Tag.err_union_code_ptr,
|
||||
.ref, .ref_coerced_ty => Zir.Inst.Tag.err_union_code_ptr,
|
||||
else => Zir.Inst.Tag.err_union_code,
|
||||
};
|
||||
const err_code = try else_scope.addUnNode(err_tag, operand, node);
|
||||
|
|
@ -5659,7 +5642,7 @@ fn tryExpr(
|
|||
try else_scope.setTryBody(try_inst, operand);
|
||||
const result = indexToRef(try_inst);
|
||||
switch (ri.rl) {
|
||||
.ref => return result,
|
||||
.ref, .ref_coerced_ty => return result,
|
||||
else => return rvalue(parent_gz, ri, result, node),
|
||||
}
|
||||
}
|
||||
|
|
@ -5682,7 +5665,7 @@ fn orelseCatchExpr(
|
|||
const need_rl = astgen.nodes_need_rl.contains(node);
|
||||
const block_ri: ResultInfo = if (need_rl) ri else .{
|
||||
.rl = switch (ri.rl) {
|
||||
.ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },
|
||||
.ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
|
||||
.inferred_ptr => .none,
|
||||
else => ri.rl,
|
||||
},
|
||||
|
|
@ -5700,7 +5683,7 @@ fn orelseCatchExpr(
|
|||
defer block_scope.unstack();
|
||||
|
||||
const operand_ri: ResultInfo = switch (block_scope.break_result_info.rl) {
|
||||
.ref => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none },
|
||||
.ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none },
|
||||
else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none },
|
||||
};
|
||||
// This could be a pointer or value depending on the `operand_ri` parameter.
|
||||
|
|
@ -5722,7 +5705,7 @@ fn orelseCatchExpr(
|
|||
// This could be a pointer or value depending on `unwrap_op`.
|
||||
const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
|
||||
const then_result = switch (ri.rl) {
|
||||
.ref => unwrapped_payload,
|
||||
.ref, .ref_coerced_ty => unwrapped_payload,
|
||||
else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node),
|
||||
};
|
||||
_ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, node);
|
||||
|
|
@ -5793,7 +5776,7 @@ fn fieldAccess(
|
|||
node: Ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
switch (ri.rl) {
|
||||
.ref => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node),
|
||||
.ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node),
|
||||
else => {
|
||||
const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node);
|
||||
return rvalue(gz, ri, access, node);
|
||||
|
|
@ -5837,7 +5820,7 @@ fn arrayAccess(
|
|||
const tree = gz.astgen.tree;
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
switch (ri.rl) {
|
||||
.ref => {
|
||||
.ref, .ref_coerced_ty => {
|
||||
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
|
||||
|
||||
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
|
||||
|
|
@ -5951,7 +5934,7 @@ fn ifExpr(
|
|||
const need_rl = astgen.nodes_need_rl.contains(node);
|
||||
const block_ri: ResultInfo = if (need_rl) ri else .{
|
||||
.rl = switch (ri.rl) {
|
||||
.ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },
|
||||
.ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
|
||||
.inferred_ptr => .none,
|
||||
else => ri.rl,
|
||||
},
|
||||
|
|
@ -6181,7 +6164,7 @@ fn whileExpr(
|
|||
const need_rl = astgen.nodes_need_rl.contains(node);
|
||||
const block_ri: ResultInfo = if (need_rl) ri else .{
|
||||
.rl = switch (ri.rl) {
|
||||
.ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },
|
||||
.ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
|
||||
.inferred_ptr => .none,
|
||||
else => ri.rl,
|
||||
},
|
||||
|
|
@ -6455,7 +6438,7 @@ fn forExpr(
|
|||
const need_rl = astgen.nodes_need_rl.contains(node);
|
||||
const block_ri: ResultInfo = if (need_rl) ri else .{
|
||||
.rl = switch (ri.rl) {
|
||||
.ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },
|
||||
.ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
|
||||
.inferred_ptr => .none,
|
||||
else => ri.rl,
|
||||
},
|
||||
|
|
@ -6773,7 +6756,7 @@ fn switchExpr(
|
|||
const need_rl = astgen.nodes_need_rl.contains(switch_node);
|
||||
const block_ri: ResultInfo = if (need_rl) ri else .{
|
||||
.rl = switch (ri.rl) {
|
||||
.ptr => .{ .ty = try ri.rl.resultType(parent_gz, switch_node, undefined) },
|
||||
.ptr => .{ .ty = (try ri.rl.resultType(parent_gz, switch_node)).? },
|
||||
.inferred_ptr => .none,
|
||||
else => ri.rl,
|
||||
},
|
||||
|
|
@ -7465,7 +7448,7 @@ fn localVarRef(
|
|||
gpa,
|
||||
);
|
||||
|
||||
return rvalue(gz, ri, value_inst, ident);
|
||||
return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
|
||||
}
|
||||
s = local_val.parent;
|
||||
},
|
||||
|
|
@ -7498,10 +7481,10 @@ fn localVarRef(
|
|||
);
|
||||
|
||||
switch (ri.rl) {
|
||||
.ref => return ptr_inst,
|
||||
.ref, .ref_coerced_ty => return ptr_inst,
|
||||
else => {
|
||||
const loaded = try gz.addUnNode(.load, ptr_inst, ident);
|
||||
return rvalue(gz, ri, loaded, ident);
|
||||
return rvalueNoCoercePreRef(gz, ri, loaded, ident);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -7535,10 +7518,10 @@ fn localVarRef(
|
|||
// Decl references happen by name rather than ZIR index so that when unrelated
|
||||
// decls are modified, ZIR code containing references to them can be unmodified.
|
||||
switch (ri.rl) {
|
||||
.ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
|
||||
.ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
|
||||
else => {
|
||||
const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
|
||||
return rvalue(gz, ri, result, ident);
|
||||
return rvalueNoCoercePreRef(gz, ri, result, ident);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -7924,7 +7907,7 @@ fn bitCast(
|
|||
node: Ast.Node.Index,
|
||||
operand_node: Ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const dest_type = try ri.rl.resultType(gz, node, "@bitCast");
|
||||
const dest_type = try ri.rl.resultTypeForCast(gz, node, "@bitCast");
|
||||
const operand = try reachableExpr(gz, scope, .{ .rl = .none }, operand_node, node);
|
||||
const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
|
||||
.lhs = dest_type,
|
||||
|
|
@ -8024,7 +8007,7 @@ fn ptrCast(
|
|||
// Full cast including result type
|
||||
|
||||
const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);
|
||||
const result_type = try ri.rl.resultType(gz, root_node, flags.needResultTypeBuiltinName());
|
||||
const result_type = try ri.rl.resultTypeForCast(gz, root_node, flags.needResultTypeBuiltinName());
|
||||
const operand = try expr(gz, scope, .{ .rl = .none }, node);
|
||||
try emitDbgStmt(gz, cursor);
|
||||
const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{
|
||||
|
|
@ -8208,7 +8191,7 @@ fn builtinCall(
|
|||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.field => {
|
||||
if (ri.rl == .ref) {
|
||||
if (ri.rl == .ref or ri.rl == .ref_coerced_ty) {
|
||||
return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
|
||||
.lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
|
||||
.field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]),
|
||||
|
|
@ -8475,7 +8458,7 @@ fn builtinCall(
|
|||
try emitDbgNode(gz, node);
|
||||
|
||||
const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{
|
||||
.lhs = try ri.rl.resultType(gz, node, "@errSetCast"),
|
||||
.lhs = try ri.rl.resultTypeForCast(gz, node, "@errSetCast"),
|
||||
.rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
|
||||
.node = gz.nodeIndexToRelative(node),
|
||||
});
|
||||
|
|
@ -8548,7 +8531,7 @@ fn builtinCall(
|
|||
},
|
||||
|
||||
.splat => {
|
||||
const result_type = try ri.rl.resultType(gz, node, "@splat");
|
||||
const result_type = try ri.rl.resultTypeForCast(gz, node, "@splat");
|
||||
const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
|
||||
const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
|
||||
const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
|
||||
|
|
@ -8810,7 +8793,7 @@ fn typeCast(
|
|||
builtin_name: []const u8,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
|
||||
const result_type = try ri.rl.resultType(gz, node, builtin_name);
|
||||
const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
|
||||
const operand = try expr(gz, scope, .{ .rl = .none }, operand_node);
|
||||
|
||||
try emitDbgStmt(gz, cursor);
|
||||
|
|
@ -10069,6 +10052,29 @@ fn rvalue(
|
|||
ri: ResultInfo,
|
||||
raw_result: Zir.Inst.Ref,
|
||||
src_node: Ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
return rvalueInner(gz, ri, raw_result, src_node, true);
|
||||
}
|
||||
|
||||
/// Like `rvalue`, but refuses to perform coercions before taking references for
|
||||
/// the `ref_coerced_ty` result type. This is used for local variables which do
|
||||
/// not have `alloc`s, because we want variables to have consistent addresses,
|
||||
/// i.e. we want them to act like lvalues.
|
||||
fn rvalueNoCoercePreRef(
|
||||
gz: *GenZir,
|
||||
ri: ResultInfo,
|
||||
raw_result: Zir.Inst.Ref,
|
||||
src_node: Ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
return rvalueInner(gz, ri, raw_result, src_node, false);
|
||||
}
|
||||
|
||||
fn rvalueInner(
|
||||
gz: *GenZir,
|
||||
ri: ResultInfo,
|
||||
raw_result: Zir.Inst.Ref,
|
||||
src_node: Ast.Node.Index,
|
||||
allow_coerce_pre_ref: bool,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const result = r: {
|
||||
if (refToIndex(raw_result)) |result_index| {
|
||||
|
|
@ -10088,7 +10094,14 @@ fn rvalue(
|
|||
_ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
|
||||
return .void_value;
|
||||
},
|
||||
.ref => {
|
||||
.ref, .ref_coerced_ty => {
|
||||
const coerced_result = if (allow_coerce_pre_ref and ri.rl == .ref_coerced_ty) res: {
|
||||
const ptr_ty = ri.rl.ref_coerced_ty;
|
||||
break :res try gz.addPlNode(.coerce_ptr_elem_ty, src_node, Zir.Inst.Bin{
|
||||
.lhs = ptr_ty,
|
||||
.rhs = result,
|
||||
});
|
||||
} else result;
|
||||
// We need a pointer but we have a value.
|
||||
// Unfortunately it's not quite as simple as directly emitting a ref
|
||||
// instruction here because we need subsequent address-of operator on
|
||||
|
|
@ -10096,14 +10109,14 @@ fn rvalue(
|
|||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
const src_token = tree.firstToken(src_node);
|
||||
const result_index = refToIndex(result) orelse
|
||||
return gz.addUnTok(.ref, result, src_token);
|
||||
const result_index = refToIndex(coerced_result) orelse
|
||||
return gz.addUnTok(.ref, coerced_result, src_token);
|
||||
const zir_tags = gz.astgen.instructions.items(.tag);
|
||||
if (zir_tags[result_index].isParam() or astgen.isInferred(result))
|
||||
return gz.addUnTok(.ref, result, src_token);
|
||||
if (zir_tags[result_index].isParam() or astgen.isInferred(coerced_result))
|
||||
return gz.addUnTok(.ref, coerced_result, src_token);
|
||||
const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token);
|
||||
gop.value_ptr.* = try gz.makeUnTok(.ref, coerced_result, src_token);
|
||||
}
|
||||
return indexToRef(gop.value_ptr.*);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -669,17 +669,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
|
|||
=> {
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const full = tree.fullArrayInit(&buf, node).?;
|
||||
const have_type = if (full.ast.type_expr != 0) have_type: {
|
||||
|
||||
if (full.ast.type_expr != 0) {
|
||||
// Explicitly typed init does not participate in RLS
|
||||
_ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none);
|
||||
break :have_type true;
|
||||
} else ri.have_type;
|
||||
if (have_type) {
|
||||
const elem_ri: ResultInfo = .{
|
||||
.have_type = true,
|
||||
.have_ptr = ri.have_ptr,
|
||||
};
|
||||
for (full.ast.elements) |elem_init| {
|
||||
_ = try astrl.expr(elem_init, block, elem_ri);
|
||||
_ = try astrl.expr(elem_init, block, ResultInfo.type_only);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ri.have_type) {
|
||||
// Always forward type information
|
||||
// If we have a result pointer, we use and forward it
|
||||
for (full.ast.elements) |elem_init| {
|
||||
_ = try astrl.expr(elem_init, block, ri);
|
||||
}
|
||||
return ri.have_ptr;
|
||||
} else {
|
||||
|
|
@ -702,17 +706,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
|
|||
=> {
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const full = tree.fullStructInit(&buf, node).?;
|
||||
const have_type = if (full.ast.type_expr != 0) have_type: {
|
||||
|
||||
if (full.ast.type_expr != 0) {
|
||||
// Explicitly typed init does not participate in RLS
|
||||
_ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none);
|
||||
break :have_type true;
|
||||
} else ri.have_type;
|
||||
if (have_type) {
|
||||
const elem_ri: ResultInfo = .{
|
||||
.have_type = true,
|
||||
.have_ptr = ri.have_ptr,
|
||||
};
|
||||
for (full.ast.fields) |field_init| {
|
||||
_ = try astrl.expr(field_init, block, elem_ri);
|
||||
_ = try astrl.expr(field_init, block, ResultInfo.type_only);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ri.have_type) {
|
||||
// Always forward type information
|
||||
// If we have a result pointer, we use and forward it
|
||||
for (full.ast.fields) |field_init| {
|
||||
_ = try astrl.expr(field_init, block, ri);
|
||||
}
|
||||
return ri.have_ptr;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2391,34 +2391,6 @@ fn walkInstruction(
|
|||
.expr = .{ .@"&" = expr_index },
|
||||
};
|
||||
},
|
||||
.array_init_anon_ref => {
|
||||
const pl_node = data[inst_index].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
|
||||
const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
|
||||
const array_data = try self.arena.alloc(usize, operands.len);
|
||||
|
||||
for (operands, 0..) |op, idx| {
|
||||
const wr = try self.walkRef(
|
||||
file,
|
||||
parent_scope,
|
||||
parent_src,
|
||||
op,
|
||||
false,
|
||||
call_ctx,
|
||||
);
|
||||
const expr_index = self.exprs.items.len;
|
||||
try self.exprs.append(self.arena, wr.expr);
|
||||
array_data[idx] = expr_index;
|
||||
}
|
||||
|
||||
const expr_index = self.exprs.items.len;
|
||||
try self.exprs.append(self.arena, .{ .array = array_data });
|
||||
|
||||
return DocData.WalkResult{
|
||||
.typeRef = null,
|
||||
.expr = .{ .@"&" = expr_index },
|
||||
};
|
||||
},
|
||||
.float => {
|
||||
const float = data[inst_index].float;
|
||||
return DocData.WalkResult{
|
||||
|
|
@ -2709,9 +2681,7 @@ fn walkInstruction(
|
|||
.expr = .{ .declRef = decl_status },
|
||||
};
|
||||
},
|
||||
.field_val, .field_ptr, .field_type => {
|
||||
// TODO: field type uses Zir.Inst.FieldType, it just happens to have the
|
||||
// same layout as Zir.Inst.Field :^)
|
||||
.field_val, .field_ptr => {
|
||||
const pl_node = data[inst_index].pl_node;
|
||||
const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
|
||||
|
||||
|
|
@ -2730,8 +2700,7 @@ fn walkInstruction(
|
|||
};
|
||||
|
||||
if (tags[lhs] != .field_val and
|
||||
tags[lhs] != .field_ptr and
|
||||
tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
|
||||
tags[lhs] != .field_ptr) break :blk lhs_extra.data.lhs;
|
||||
|
||||
lhs_extra = file.zir.extraData(
|
||||
Zir.Inst.Field,
|
||||
|
|
@ -2870,7 +2839,7 @@ fn walkInstruction(
|
|||
|
||||
const field_name = blk: {
|
||||
const field_inst_index = init_extra.data.field_type;
|
||||
if (tags[field_inst_index] != .field_type) unreachable;
|
||||
if (tags[field_inst_index] != .struct_init_field_type) unreachable;
|
||||
const field_pl_node = data[field_inst_index].pl_node;
|
||||
const field_extra = file.zir.extraData(
|
||||
Zir.Inst.FieldType,
|
||||
|
|
|
|||
929
src/Sema.zig
929
src/Sema.zig
File diff suppressed because it is too large
Load diff
331
src/Zir.zig
331
src/Zir.zig
|
|
@ -242,10 +242,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 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 type, returns its element type.
|
||||
/// Given a pointer type, returns its element type. Reaches through any optional or error
|
||||
/// union types wrapping the pointer. Asserts that the underlying type is a pointer type.
|
||||
/// Returns generic poison if the element type is `anyopaque`.
|
||||
/// Uses the `un_node` field.
|
||||
elem_type,
|
||||
/// Given an indexable pointer (slice, many-ptr, single-ptr-to-array), returns its
|
||||
|
|
@ -353,11 +352,6 @@ pub const Inst = struct {
|
|||
/// `!=`
|
||||
/// Uses the `pl_node` union field. Payload is `Bin`.
|
||||
cmp_neq,
|
||||
/// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
|
||||
/// as type coercion from the new element type to the old element type.
|
||||
/// Uses the `pl_node` union field. Payload is `Bin`.
|
||||
/// LHS is destination element type, RHS is result pointer.
|
||||
coerce_result_ptr,
|
||||
/// Conditional branch. Splits control flow based on a boolean condition value.
|
||||
/// Uses the `pl_node` union field. AST node is an if, while, for, etc.
|
||||
/// Payload is `CondBr`.
|
||||
|
|
@ -419,13 +413,6 @@ pub const Inst = struct {
|
|||
/// Payload is `Bin`.
|
||||
/// No OOB safety check is emitted.
|
||||
elem_ptr,
|
||||
/// Same as `elem_ptr_node` except the index is stored immediately rather than
|
||||
/// as a reference to another ZIR instruction.
|
||||
/// Uses the `pl_node` union field. AST node is an element inside array initialization
|
||||
/// syntax. Payload is `ElemPtrImm`.
|
||||
/// This instruction has a way to set the result type to be a
|
||||
/// single-pointer or a many-pointer.
|
||||
elem_ptr_imm,
|
||||
/// Given an array, slice, or pointer, returns the element at the provided index.
|
||||
/// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
|
||||
elem_val_node,
|
||||
|
|
@ -463,8 +450,6 @@ pub const Inst = struct {
|
|||
/// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
|
||||
/// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
|
||||
field_ptr,
|
||||
/// Same as `field_ptr` but used for struct init.
|
||||
field_ptr_init,
|
||||
/// Given a struct or object that contains virtual fields, returns the named field.
|
||||
/// The field name is stored in string_bytes. Used by a.b syntax.
|
||||
/// This instruction also accepts a pointer.
|
||||
|
|
@ -688,84 +673,123 @@ pub const Inst = struct {
|
|||
/// A switch expression. Uses the `pl_node` union field.
|
||||
/// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
|
||||
switch_block_ref,
|
||||
/// Given a
|
||||
/// *A returns *A
|
||||
/// *E!A returns *A
|
||||
/// *?A returns *A
|
||||
/// Uses the `un_node` field.
|
||||
array_base_ptr,
|
||||
/// Given a
|
||||
/// *S returns *S
|
||||
/// *E!S returns *S
|
||||
/// *?S returns *S
|
||||
/// Uses the `un_node` field.
|
||||
field_base_ptr,
|
||||
/// Given a type, strips all optional and error union types wrapping it.
|
||||
/// e.g. `E!?u32` becomes `u32`, `[]u8` becomes `[]u8`.
|
||||
/// Uses the `un_node` field.
|
||||
opt_eu_base_ty,
|
||||
/// Checks that the type supports array init syntax.
|
||||
/// Returns the underlying indexable type (since the given type may be e.g. an optional).
|
||||
/// Uses the `un_node` field.
|
||||
validate_array_init_ty,
|
||||
/// Checks that the type supports struct init syntax.
|
||||
/// Returns the underlying struct type (since the given type may be e.g. an optional).
|
||||
/// Uses the `un_node` field.
|
||||
validate_struct_init_ty,
|
||||
/// Given a set of `field_ptr` instructions, assumes they are all part of a struct
|
||||
/// initialization expression, and emits compile errors for duplicate fields
|
||||
/// as well as missing fields, if applicable.
|
||||
/// This instruction asserts that there is at least one field_ptr instruction,
|
||||
/// because it must use one of them to find out the struct type.
|
||||
/// Uses the `pl_node` field. Payload is `Block`.
|
||||
validate_struct_init,
|
||||
/// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an
|
||||
/// array initialization expression, and emits a compile error if the number of
|
||||
/// elements does not match the array type.
|
||||
/// This instruction asserts that there is at least one `elem_ptr_imm` instruction,
|
||||
/// because it must use one of them to find out the array type.
|
||||
/// Uses the `pl_node` field. Payload is `Block`.
|
||||
validate_array_init,
|
||||
/// Check that operand type supports the dereference operand (.*).
|
||||
/// Uses the `un_node` field.
|
||||
validate_deref,
|
||||
/// Check that the operand's type is an array or tuple with the given number of elements.
|
||||
/// Uses the `pl_node` field. Payload is `ValidateDestructure`.
|
||||
validate_destructure,
|
||||
/// A struct literal with a specified type, with no fields.
|
||||
/// Uses the `un_node` field.
|
||||
struct_init_empty,
|
||||
/// Given a struct or union, and a field name as a string index,
|
||||
/// returns the field type. Uses the `pl_node` field. Payload is `FieldType`.
|
||||
field_type,
|
||||
/// Given a struct or union, and a field name as a Ref,
|
||||
/// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.
|
||||
field_type_ref,
|
||||
/// Finalizes a typed struct or union initialization, performs validation, and returns the
|
||||
/// struct or union value.
|
||||
/// Uses the `pl_node` field. Payload is `StructInit`.
|
||||
struct_init,
|
||||
/// Struct initialization syntax, make the result a pointer.
|
||||
/// Uses the `pl_node` field. Payload is `StructInit`.
|
||||
struct_init_ref,
|
||||
/// Struct initialization without a type.
|
||||
/// Given a pointer, initializes all error unions and optionals in the pointee to payloads,
|
||||
/// returning the base payload pointer. For instance, converts *E!?T into a valid *T
|
||||
/// (clobbering any existing error or null value).
|
||||
/// Uses the `un_node` field.
|
||||
opt_eu_base_ptr_init,
|
||||
/// Coerce a given value such that when a reference is taken, the resulting pointer will be
|
||||
/// coercible to the given type. For instance, given a value of type 'u32' and the pointer
|
||||
/// type '*u64', coerces the value to a 'u64'. Asserts that the type is a pointer type.
|
||||
/// Uses the `pl_node` field. Payload is `Bin`.
|
||||
/// LHS is the pointer type, RHS is the value.
|
||||
coerce_ptr_elem_ty,
|
||||
/// Given a type, validate that it is a pointer type suitable for return from the address-of
|
||||
/// operator. Emit a compile error if not.
|
||||
/// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type.
|
||||
validate_ref_ty,
|
||||
|
||||
// The following tags all relate to struct initialization expressions.
|
||||
|
||||
/// A struct literal with a specified explicit type, with no fields.
|
||||
/// Uses the `un_node` field.
|
||||
struct_init_empty,
|
||||
/// An anonymous struct literal with a known result type, with no fields.
|
||||
/// Uses the `un_node` field.
|
||||
struct_init_empty_result,
|
||||
/// An anonymous struct literal with no fields, returned by reference, with a known result
|
||||
/// type for the pointer. Asserts that the type is a pointer.
|
||||
/// Uses the `un_node` field.
|
||||
struct_init_empty_ref_result,
|
||||
/// Struct initialization without a type. Creates a value of an anonymous struct type.
|
||||
/// Uses the `pl_node` field. Payload is `StructInitAnon`.
|
||||
struct_init_anon,
|
||||
/// Anonymous struct initialization syntax, make the result a pointer.
|
||||
/// Uses the `pl_node` field. Payload is `StructInitAnon`.
|
||||
struct_init_anon_ref,
|
||||
/// Array initialization syntax.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init,
|
||||
/// Anonymous array initialization syntax.
|
||||
/// Finalizes a typed struct or union initialization, performs validation, and returns the
|
||||
/// struct or union value. The given type must be validated prior to this instruction, using
|
||||
/// `validate_struct_init_ty` or `validate_struct_init_result_ty`. If the given type is
|
||||
/// generic poison, this is downgraded to an anonymous initialization.
|
||||
/// Uses the `pl_node` field. Payload is `StructInit`.
|
||||
struct_init,
|
||||
/// Struct initialization syntax, make the result a pointer. Equivalent to `struct_init`
|
||||
/// followed by `ref` - this ZIR tag exists as an optimization for a common pattern.
|
||||
/// Uses the `pl_node` field. Payload is `StructInit`.
|
||||
struct_init_ref,
|
||||
/// Checks that the type supports struct init syntax. Always returns void.
|
||||
/// Uses the `un_node` field.
|
||||
validate_struct_init_ty,
|
||||
/// Like `validate_struct_init_ty`, but additionally accepts types which structs coerce to.
|
||||
/// Used on the known result type of a struct init expression. Always returns void.
|
||||
/// Uses the `un_node` field.
|
||||
validate_struct_init_result_ty,
|
||||
/// Given a set of `struct_init_field_ptr` instructions, assumes they are all part of a
|
||||
/// struct initialization expression, and emits compile errors for duplicate fields as well
|
||||
/// as missing fields, if applicable.
|
||||
/// This instruction asserts that there is at least one struct_init_field_ptr instruction,
|
||||
/// because it must use one of them to find out the struct type.
|
||||
/// Uses the `pl_node` field. Payload is `Block`.
|
||||
validate_ptr_struct_init,
|
||||
/// Given a type being used for a struct initialization expression, returns the type of the
|
||||
/// field with the given name.
|
||||
/// Uses the `pl_node` field. Payload is `FieldType`.
|
||||
struct_init_field_type,
|
||||
/// Given a pointer being used as the result pointer of a struct initialization expression,
|
||||
/// return a pointer to the field of the given name.
|
||||
/// Uses the `pl_node` field. The AST node is the field initializer. Payload is Field.
|
||||
struct_init_field_ptr,
|
||||
|
||||
// The following tags all relate to array initialization expressions.
|
||||
|
||||
/// Array initialization without a type. Creates a value of a tuple type.
|
||||
/// 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 initialization syntax with a known type. The given type must be validated prior to
|
||||
/// this instruction, using some `validate_array_init_*_ty` instruction.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`, where the first operand is the type.
|
||||
array_init,
|
||||
/// Array initialization syntax, make the result a pointer. Equivalent to `array_init`
|
||||
/// followed by `ref`- this ZIR tag exists as an optimization for a common pattern.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`, where the first operand is the type.
|
||||
array_init_ref,
|
||||
/// Anonymous array initialization syntax, make the result a pointer.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init_anon_ref,
|
||||
/// Checks that the type supports array init syntax. Always returns void.
|
||||
/// Uses the `pl_node` field. Payload is `ArrayInit`.
|
||||
validate_array_init_ty,
|
||||
/// Like `validate_array_init_ty`, but additionally accepts types which arrays coerce to.
|
||||
/// Used on the known result type of an array init expression. Always returns void.
|
||||
/// Uses the `pl_node` field. Payload is `ArrayInit`.
|
||||
validate_array_init_result_ty,
|
||||
/// Given a pointer or slice type and an element count, return the expected type of an array
|
||||
/// initializer such that a pointer to the initializer has the given pointer type, checking
|
||||
/// that this type supports array init syntax and emitting a compile error if not. Preserves
|
||||
/// error union and optional wrappers on the array type, if any.
|
||||
/// Asserts that the given type is a pointer or slice type.
|
||||
/// Uses the `pl_node` field. Payload is `ArrayInitRefTy`.
|
||||
validate_array_init_ref_ty,
|
||||
/// Given a set of `array_init_elem_ptr` instructions, assumes they are all part of an array
|
||||
/// initialization expression, and emits a compile error if the number of elements does not
|
||||
/// match the array type.
|
||||
/// This instruction asserts that there is at least one `array_init_elem_ptr` instruction,
|
||||
/// because it must use one of them to find out the array type.
|
||||
/// Uses the `pl_node` field. Payload is `Block`.
|
||||
validate_ptr_array_init,
|
||||
/// Given a type being used for an array initialization expression, returns the type of the
|
||||
/// element at the given index.
|
||||
/// Uses the `bin` union field. lhs is the indexable type, rhs is the index.
|
||||
array_init_elem_type,
|
||||
/// Given a pointer being used as the result pointer of an array initialization expression,
|
||||
/// return a pointer to the element at the given index.
|
||||
/// Uses the `pl_node` union field. AST node is an element inside array initialization
|
||||
/// syntax. Payload is `ElemPtrImm`.
|
||||
array_init_elem_ptr,
|
||||
|
||||
/// Implements the `@unionInit` builtin.
|
||||
/// Uses the `pl_node` field. Payload is `UnionInit`.
|
||||
union_init,
|
||||
|
|
@ -1038,7 +1062,6 @@ pub const Inst = struct {
|
|||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.vector_type,
|
||||
.elem_type_index,
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
.vector_elem_type,
|
||||
|
|
@ -1066,7 +1089,6 @@ pub const Inst = struct {
|
|||
.cmp_gte,
|
||||
.cmp_gt,
|
||||
.cmp_neq,
|
||||
.coerce_result_ptr,
|
||||
.error_set_decl,
|
||||
.error_set_decl_anon,
|
||||
.error_set_decl_func,
|
||||
|
|
@ -1082,7 +1104,6 @@ pub const Inst = struct {
|
|||
.elem_ptr,
|
||||
.elem_val,
|
||||
.elem_ptr_node,
|
||||
.elem_ptr_imm,
|
||||
.elem_val_node,
|
||||
.elem_val_imm,
|
||||
.ensure_result_used,
|
||||
|
|
@ -1091,7 +1112,6 @@ pub const Inst = struct {
|
|||
.@"export",
|
||||
.export_value,
|
||||
.field_ptr,
|
||||
.field_ptr_init,
|
||||
.field_val,
|
||||
.field_ptr_named,
|
||||
.field_val_named,
|
||||
|
|
@ -1154,25 +1174,9 @@ pub const Inst = struct {
|
|||
.set_eval_branch_quota,
|
||||
.switch_block,
|
||||
.switch_block_ref,
|
||||
.array_base_ptr,
|
||||
.field_base_ptr,
|
||||
.validate_array_init_ty,
|
||||
.validate_struct_init_ty,
|
||||
.validate_struct_init,
|
||||
.validate_array_init,
|
||||
.validate_deref,
|
||||
.validate_destructure,
|
||||
.struct_init_empty,
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
.struct_init_anon,
|
||||
.struct_init_anon_ref,
|
||||
.array_init,
|
||||
.array_init_anon,
|
||||
.array_init_ref,
|
||||
.array_init_anon_ref,
|
||||
.union_init,
|
||||
.field_type,
|
||||
.field_type_ref,
|
||||
.enum_from_int,
|
||||
.int_from_enum,
|
||||
|
|
@ -1254,7 +1258,29 @@ pub const Inst = struct {
|
|||
.save_err_ret_index,
|
||||
.restore_err_ret_index,
|
||||
.for_len,
|
||||
.opt_eu_base_ty,
|
||||
.opt_eu_base_ptr_init,
|
||||
.coerce_ptr_elem_ty,
|
||||
.struct_init_empty,
|
||||
.struct_init_empty_result,
|
||||
.struct_init_empty_ref_result,
|
||||
.struct_init_anon,
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
.validate_struct_init_ty,
|
||||
.validate_struct_init_result_ty,
|
||||
.validate_ptr_struct_init,
|
||||
.struct_init_field_type,
|
||||
.struct_init_field_ptr,
|
||||
.array_init_anon,
|
||||
.array_init,
|
||||
.array_init_ref,
|
||||
.validate_array_init_ty,
|
||||
.validate_array_init_result_ty,
|
||||
.validate_array_init_ref_ty,
|
||||
.validate_ptr_array_init,
|
||||
.array_init_elem_type,
|
||||
.array_init_elem_ptr,
|
||||
.validate_ref_ty,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
|
|
@ -1307,10 +1333,6 @@ pub const Inst = struct {
|
|||
.store_node,
|
||||
.store_to_inferred_ptr,
|
||||
.resolve_inferred_alloc,
|
||||
.validate_array_init_ty,
|
||||
.validate_struct_init_ty,
|
||||
.validate_struct_init,
|
||||
.validate_array_init,
|
||||
.validate_deref,
|
||||
.validate_destructure,
|
||||
.@"export",
|
||||
|
|
@ -1323,6 +1345,13 @@ pub const Inst = struct {
|
|||
.defer_err_code,
|
||||
.restore_err_ret_index,
|
||||
.save_err_ret_index,
|
||||
.validate_struct_init_ty,
|
||||
.validate_struct_init_result_ty,
|
||||
.validate_ptr_struct_init,
|
||||
.validate_array_init_ty,
|
||||
.validate_array_init_result_ty,
|
||||
.validate_ptr_array_init,
|
||||
.validate_ref_ty,
|
||||
=> true,
|
||||
|
||||
.param,
|
||||
|
|
@ -1346,7 +1375,6 @@ pub const Inst = struct {
|
|||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.vector_type,
|
||||
.elem_type_index,
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
.vector_elem_type,
|
||||
|
|
@ -1374,7 +1402,6 @@ pub const Inst = struct {
|
|||
.cmp_gte,
|
||||
.cmp_gt,
|
||||
.cmp_neq,
|
||||
.coerce_result_ptr,
|
||||
.error_set_decl,
|
||||
.error_set_decl_anon,
|
||||
.error_set_decl_func,
|
||||
|
|
@ -1385,11 +1412,9 @@ pub const Inst = struct {
|
|||
.elem_ptr,
|
||||
.elem_val,
|
||||
.elem_ptr_node,
|
||||
.elem_ptr_imm,
|
||||
.elem_val_node,
|
||||
.elem_val_imm,
|
||||
.field_ptr,
|
||||
.field_ptr_init,
|
||||
.field_val,
|
||||
.field_ptr_named,
|
||||
.field_val_named,
|
||||
|
|
@ -1447,19 +1472,7 @@ pub const Inst = struct {
|
|||
.typeof_log2_int_type,
|
||||
.switch_block,
|
||||
.switch_block_ref,
|
||||
.array_base_ptr,
|
||||
.field_base_ptr,
|
||||
.struct_init_empty,
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
.struct_init_anon,
|
||||
.struct_init_anon_ref,
|
||||
.array_init,
|
||||
.array_init_anon,
|
||||
.array_init_ref,
|
||||
.array_init_anon_ref,
|
||||
.union_init,
|
||||
.field_type,
|
||||
.field_type_ref,
|
||||
.enum_from_int,
|
||||
.int_from_enum,
|
||||
|
|
@ -1546,7 +1559,22 @@ pub const Inst = struct {
|
|||
.for_len,
|
||||
.@"try",
|
||||
.try_ptr,
|
||||
.opt_eu_base_ty,
|
||||
.opt_eu_base_ptr_init,
|
||||
.coerce_ptr_elem_ty,
|
||||
.struct_init_empty,
|
||||
.struct_init_empty_result,
|
||||
.struct_init_empty_ref_result,
|
||||
.struct_init_anon,
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
.struct_init_field_type,
|
||||
.struct_init_field_ptr,
|
||||
.array_init_anon,
|
||||
.array_init,
|
||||
.array_init_ref,
|
||||
.validate_array_init_ref_ty,
|
||||
.array_init_elem_type,
|
||||
.array_init_elem_ptr,
|
||||
=> false,
|
||||
|
||||
.extended => switch (data.extended.opcode) {
|
||||
|
|
@ -1580,7 +1608,6 @@ pub const Inst = struct {
|
|||
.array_type = .pl_node,
|
||||
.array_type_sentinel = .pl_node,
|
||||
.vector_type = .pl_node,
|
||||
.elem_type_index = .bin,
|
||||
.elem_type = .un_node,
|
||||
.indexable_ptr_elem_type = .un_node,
|
||||
.vector_elem_type = .un_node,
|
||||
|
|
@ -1612,7 +1639,6 @@ pub const Inst = struct {
|
|||
.cmp_gte = .pl_node,
|
||||
.cmp_gt = .pl_node,
|
||||
.cmp_neq = .pl_node,
|
||||
.coerce_result_ptr = .pl_node,
|
||||
.condbr = .pl_node,
|
||||
.condbr_inline = .pl_node,
|
||||
.@"try" = .pl_node,
|
||||
|
|
@ -1631,7 +1657,6 @@ pub const Inst = struct {
|
|||
.div = .pl_node,
|
||||
.elem_ptr = .pl_node,
|
||||
.elem_ptr_node = .pl_node,
|
||||
.elem_ptr_imm = .pl_node,
|
||||
.elem_val = .pl_node,
|
||||
.elem_val_node = .pl_node,
|
||||
.elem_val_imm = .elem_val_imm,
|
||||
|
|
@ -1643,7 +1668,6 @@ pub const Inst = struct {
|
|||
.@"export" = .pl_node,
|
||||
.export_value = .pl_node,
|
||||
.field_ptr = .pl_node,
|
||||
.field_ptr_init = .pl_node,
|
||||
.field_val = .pl_node,
|
||||
.field_ptr_named = .pl_node,
|
||||
.field_val_named = .pl_node,
|
||||
|
|
@ -1701,30 +1725,16 @@ pub const Inst = struct {
|
|||
.enum_literal = .str_tok,
|
||||
.switch_block = .pl_node,
|
||||
.switch_block_ref = .pl_node,
|
||||
.array_base_ptr = .un_node,
|
||||
.field_base_ptr = .un_node,
|
||||
.opt_eu_base_ty = .un_node,
|
||||
.validate_array_init_ty = .pl_node,
|
||||
.validate_struct_init_ty = .un_node,
|
||||
.validate_struct_init = .pl_node,
|
||||
.validate_array_init = .pl_node,
|
||||
.validate_deref = .un_node,
|
||||
.validate_destructure = .pl_node,
|
||||
.struct_init_empty = .un_node,
|
||||
.field_type = .pl_node,
|
||||
.field_type_ref = .pl_node,
|
||||
.struct_init = .pl_node,
|
||||
.struct_init_ref = .pl_node,
|
||||
.struct_init_anon = .pl_node,
|
||||
.struct_init_anon_ref = .pl_node,
|
||||
.array_init = .pl_node,
|
||||
.array_init_anon = .pl_node,
|
||||
.array_init_ref = .pl_node,
|
||||
.array_init_anon_ref = .pl_node,
|
||||
.union_init = .pl_node,
|
||||
.type_info = .un_node,
|
||||
.size_of = .un_node,
|
||||
.bit_size_of = .un_node,
|
||||
.opt_eu_base_ptr_init = .un_node,
|
||||
.coerce_ptr_elem_ty = .pl_node,
|
||||
.validate_ref_ty = .un_tok,
|
||||
|
||||
.int_from_ptr = .un_node,
|
||||
.compile_error = .un_node,
|
||||
|
|
@ -1826,6 +1836,27 @@ pub const Inst = struct {
|
|||
.save_err_ret_index = .save_err_ret_index,
|
||||
.restore_err_ret_index = .restore_err_ret_index,
|
||||
|
||||
.struct_init_empty = .un_node,
|
||||
.struct_init_empty_result = .un_node,
|
||||
.struct_init_empty_ref_result = .un_node,
|
||||
.struct_init_anon = .pl_node,
|
||||
.struct_init = .pl_node,
|
||||
.struct_init_ref = .pl_node,
|
||||
.validate_struct_init_ty = .un_node,
|
||||
.validate_struct_init_result_ty = .un_node,
|
||||
.validate_ptr_struct_init = .pl_node,
|
||||
.struct_init_field_type = .pl_node,
|
||||
.struct_init_field_ptr = .pl_node,
|
||||
.array_init_anon = .pl_node,
|
||||
.array_init = .pl_node,
|
||||
.array_init_ref = .pl_node,
|
||||
.validate_array_init_ty = .pl_node,
|
||||
.validate_array_init_result_ty = .pl_node,
|
||||
.validate_array_init_ref_ty = .pl_node,
|
||||
.validate_ptr_array_init = .pl_node,
|
||||
.array_init_elem_type = .bin,
|
||||
.array_init_elem_ptr = .pl_node,
|
||||
|
||||
.extended = .extended,
|
||||
});
|
||||
};
|
||||
|
|
@ -2771,6 +2802,11 @@ pub const Inst = struct {
|
|||
};
|
||||
};
|
||||
|
||||
pub const ArrayInitRefTy = struct {
|
||||
ptr_ty: Ref,
|
||||
elem_count: u32,
|
||||
};
|
||||
|
||||
pub const Field = struct {
|
||||
lhs: Ref,
|
||||
/// Offset into `string_bytes`.
|
||||
|
|
@ -3064,9 +3100,10 @@ pub const Inst = struct {
|
|||
fields_len: u32,
|
||||
|
||||
pub const Item = struct {
|
||||
/// The `field_type` ZIR instruction for this field init.
|
||||
/// The `struct_init_field_type` ZIR instruction for this field init.
|
||||
field_type: Index,
|
||||
/// The field init expression to be used as the field value.
|
||||
/// The field init expression to be used as the field value. This value will be coerced
|
||||
/// to the field type if not already.
|
||||
init: Ref,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -205,8 +205,6 @@ 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,
|
||||
|
|
@ -241,7 +239,6 @@ const Writer = struct {
|
|||
.is_non_err_ptr,
|
||||
.ret_is_non_err,
|
||||
.typeof,
|
||||
.struct_init_empty,
|
||||
.type_info,
|
||||
.size_of,
|
||||
.bit_size_of,
|
||||
|
|
@ -281,18 +278,16 @@ const Writer = struct {
|
|||
.bit_reverse,
|
||||
.@"resume",
|
||||
.@"await",
|
||||
.array_base_ptr,
|
||||
.field_base_ptr,
|
||||
.validate_struct_init_ty,
|
||||
.make_ptr_const,
|
||||
.validate_deref,
|
||||
.check_comptime_control_flow,
|
||||
.opt_eu_base_ty,
|
||||
.opt_eu_base_ptr_init,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
.ret_implicit,
|
||||
.closure_capture,
|
||||
.validate_ref_ty,
|
||||
=> try self.writeUnTok(stream, inst),
|
||||
|
||||
.bool_br_and,
|
||||
|
|
@ -300,7 +295,6 @@ const Writer = struct {
|
|||
=> try self.writeBoolBr(stream, inst),
|
||||
|
||||
.validate_destructure => try self.writeValidateDestructure(stream, inst),
|
||||
.validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
|
||||
.array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
|
||||
.ptr_type => try self.writePtrType(stream, inst),
|
||||
.int => try self.writeInt(stream, inst),
|
||||
|
|
@ -316,12 +310,6 @@ const Writer = struct {
|
|||
.@"break",
|
||||
.break_inline,
|
||||
=> try self.writeBreak(stream, inst),
|
||||
.array_init,
|
||||
.array_init_ref,
|
||||
=> try self.writeArrayInit(stream, inst),
|
||||
.array_init_anon,
|
||||
.array_init_anon_ref,
|
||||
=> try self.writeArrayInitAnon(stream, inst),
|
||||
|
||||
.slice_start => try self.writeSliceStart(stream, inst),
|
||||
.slice_end => try self.writeSliceEnd(stream, inst),
|
||||
|
|
@ -330,10 +318,44 @@ const Writer = struct {
|
|||
|
||||
.union_init => try self.writeUnionInit(stream, inst),
|
||||
|
||||
// Struct inits
|
||||
|
||||
.struct_init_empty,
|
||||
.struct_init_empty_result,
|
||||
.struct_init_empty_ref_result,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.struct_init_anon => try self.writeStructInitAnon(stream, inst),
|
||||
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
=> try self.writeStructInit(stream, inst),
|
||||
|
||||
.validate_struct_init_ty,
|
||||
.validate_struct_init_result_ty,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.validate_ptr_struct_init => try self.writeBlock(stream, inst),
|
||||
.struct_init_field_type => try self.writeStructInitFieldType(stream, inst),
|
||||
.struct_init_field_ptr => try self.writePlNodeField(stream, inst),
|
||||
|
||||
// Array inits
|
||||
|
||||
.array_init_anon => try self.writeArrayInitAnon(stream, inst),
|
||||
|
||||
.array_init,
|
||||
.array_init_ref,
|
||||
=> try self.writeArrayInit(stream, inst),
|
||||
|
||||
.validate_array_init_ty,
|
||||
.validate_array_init_result_ty,
|
||||
=> try self.writeValidateArrayInitTy(stream, inst),
|
||||
|
||||
.validate_array_init_ref_ty => try self.writeValidateArrayInitRefTy(stream, inst),
|
||||
.validate_ptr_array_init => try self.writeBlock(stream, inst),
|
||||
.array_init_elem_type => try self.writeArrayInitElemType(stream, inst),
|
||||
.array_init_elem_ptr => try self.writeArrayInitElemPtr(stream, inst),
|
||||
|
||||
.atomic_load => try self.writeAtomicLoad(stream, inst),
|
||||
.atomic_store => try self.writeAtomicStore(stream, inst),
|
||||
.atomic_rmw => try self.writeAtomicRmw(stream, inst),
|
||||
|
|
@ -342,11 +364,6 @@ const Writer = struct {
|
|||
.field_parent_ptr => try self.writeFieldParentPtr(stream, inst),
|
||||
.builtin_call => try self.writeBuiltinCall(stream, inst),
|
||||
|
||||
.struct_init_anon,
|
||||
.struct_init_anon_ref,
|
||||
=> try self.writeStructInitAnon(stream, inst),
|
||||
|
||||
.field_type => try self.writeFieldType(stream, inst),
|
||||
.field_type_ref => try self.writeFieldTypeRef(stream, inst),
|
||||
|
||||
.add,
|
||||
|
|
@ -409,16 +426,14 @@ const Writer = struct {
|
|||
.elem_val_node,
|
||||
.elem_ptr,
|
||||
.elem_val,
|
||||
.coerce_result_ptr,
|
||||
.array_type,
|
||||
.coerce_ptr_elem_ty,
|
||||
=> try self.writePlNodeBin(stream, inst),
|
||||
|
||||
.for_len => try self.writePlNodeMultiOp(stream, inst),
|
||||
|
||||
.elem_val_imm => try self.writeElemValImm(stream, inst),
|
||||
|
||||
.elem_ptr_imm => try self.writeElemPtrImm(stream, inst),
|
||||
|
||||
.@"export" => try self.writePlNodeExport(stream, inst),
|
||||
.export_value => try self.writePlNodeExportValue(stream, inst),
|
||||
|
||||
|
|
@ -430,8 +445,6 @@ const Writer = struct {
|
|||
.block_inline,
|
||||
.suspend_block,
|
||||
.loop,
|
||||
.validate_struct_init,
|
||||
.validate_array_init,
|
||||
.c_import,
|
||||
.typeof_builtin,
|
||||
=> try self.writeBlock(stream, inst),
|
||||
|
|
@ -452,9 +465,8 @@ const Writer = struct {
|
|||
.switch_block_ref,
|
||||
=> try self.writeSwitchBlock(stream, inst),
|
||||
|
||||
.field_ptr,
|
||||
.field_ptr_init,
|
||||
.field_val,
|
||||
.field_ptr,
|
||||
=> try self.writePlNodeField(stream, inst),
|
||||
|
||||
.field_ptr_named,
|
||||
|
|
@ -617,7 +629,7 @@ const Writer = struct {
|
|||
try stream.writeByte(')');
|
||||
}
|
||||
|
||||
fn writeElemTypeIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
fn writeArrayInitElemType(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})", .{@intFromEnum(inst_data.rhs)});
|
||||
|
|
@ -972,7 +984,7 @@ const Writer = struct {
|
|||
try stream.print(", {d})", .{inst_data.idx});
|
||||
}
|
||||
|
||||
fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
fn writeArrayInitElemPtr(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.ElemPtrImm, inst_data.payload_index).data;
|
||||
|
||||
|
|
@ -1004,6 +1016,16 @@ const Writer = struct {
|
|||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeValidateArrayInitRefTy(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.ArrayInitRefTy, inst_data.payload_index).data;
|
||||
|
||||
try self.writeInstRef(stream, extra.ptr_ty);
|
||||
try stream.writeAll(", ");
|
||||
try stream.print(", {}) ", .{extra.elem_count});
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeStructInit(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.StructInit, inst_data.payload_index);
|
||||
|
|
@ -1134,7 +1156,7 @@ const Writer = struct {
|
|||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
fn writeStructInitFieldType(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.FieldType, inst_data.payload_index).data;
|
||||
try self.writeInstRef(stream, extra.container_type);
|
||||
|
|
|
|||
11
src/type.zig
11
src/type.zig
|
|
@ -3182,6 +3182,17 @@ pub const Type = struct {
|
|||
};
|
||||
}
|
||||
|
||||
/// Traverses optional child types and error union payloads until the type
|
||||
/// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
|
||||
pub fn optEuBaseType(ty: Type, mod: *Module) Type {
|
||||
var cur = ty;
|
||||
while (true) switch (cur.zigTypeTag(mod)) {
|
||||
.Optional => cur = cur.optionalChild(mod),
|
||||
.ErrorUnion => cur = cur.errorUnionPayload(mod),
|
||||
else => return cur,
|
||||
};
|
||||
}
|
||||
|
||||
pub const @"u1": Type = .{ .ip_index = .u1_type };
|
||||
pub const @"u8": Type = .{ .ip_index = .u8_type };
|
||||
pub const @"u16": Type = .{ .ip_index = .u16_type };
|
||||
|
|
|
|||
|
|
@ -780,3 +780,37 @@ test "runtime side-effects in comptime-known array init" {
|
|||
try expectEqual([4]u4{ 1, 2, 4, 8 }, init);
|
||||
try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);
|
||||
}
|
||||
|
||||
test "slice initialized through reference to anonymous array init provides result types" {
|
||||
var my_u32: u32 = 123;
|
||||
var my_u64: u64 = 456;
|
||||
const foo: []const u16 = &.{
|
||||
@intCast(my_u32),
|
||||
@intCast(my_u64),
|
||||
@truncate(my_u32),
|
||||
@truncate(my_u64),
|
||||
};
|
||||
try std.testing.expectEqualSlices(u16, &.{ 123, 456, 123, 456 }, foo);
|
||||
}
|
||||
|
||||
test "pointer to array initialized through reference to anonymous array init provides result types" {
|
||||
var my_u32: u32 = 123;
|
||||
var my_u64: u64 = 456;
|
||||
const foo: *const [4]u16 = &.{
|
||||
@intCast(my_u32),
|
||||
@intCast(my_u64),
|
||||
@truncate(my_u32),
|
||||
@truncate(my_u64),
|
||||
};
|
||||
try std.testing.expectEqualSlices(u16, &.{ 123, 456, 123, 456 }, foo);
|
||||
}
|
||||
|
||||
test "tuple initialized through reference to anonymous array init provides result types" {
|
||||
const Tuple = struct { u64, *const u32 };
|
||||
const foo: *const Tuple = &.{
|
||||
@intCast(12345),
|
||||
@ptrFromInt(0x1000),
|
||||
};
|
||||
try expect(foo[0] == 12345);
|
||||
try expect(@intFromPtr(foo[1]) == 0x1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2493,3 +2493,29 @@ test "@as does not corrupt values with incompatible representations" {
|
|||
});
|
||||
try std.testing.expectApproxEqAbs(@as(f32, 1.23), x, 0.001);
|
||||
}
|
||||
|
||||
test "result information is preserved through many nested structures" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
const E = error{Foo};
|
||||
const T = *const ?E!struct { x: ?*const E!?u8 };
|
||||
|
||||
var val: T = &.{ .x = &@truncate(0x1234) };
|
||||
|
||||
const struct_val = val.*.? catch unreachable;
|
||||
const int_val = (struct_val.x.?.* catch unreachable).?;
|
||||
|
||||
try expect(int_val == 0x34);
|
||||
}
|
||||
};
|
||||
|
||||
try S.doTheTest();
|
||||
try comptime S.doTheTest();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -548,3 +548,21 @@ test "pointer to array has explicit alignment" {
|
|||
const casted = S.func(&bases);
|
||||
try expect(casted[0].a == 2);
|
||||
}
|
||||
|
||||
test "result type preserved through multiple references" {
|
||||
const S = struct { x: u32 };
|
||||
var my_u64: u64 = 12345;
|
||||
const foo: *const *const *const S = &&&.{
|
||||
.x = @intCast(my_u64),
|
||||
};
|
||||
try expect(foo.*.*.*.x == 12345);
|
||||
}
|
||||
|
||||
test "result type found through optional pointer" {
|
||||
const ptr1: ?*const u32 = &@intCast(123);
|
||||
const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) };
|
||||
try expect(ptr1.?.* == 123);
|
||||
try expect(ptr2.?.len == 2);
|
||||
try expect(ptr2.?[0] == 123);
|
||||
try expect(ptr2.?[1] == 0xCD);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1760,3 +1760,18 @@ test "runtime side-effects in comptime-known struct init" {
|
|||
try expectEqual(S{ .a = 1, .b = 2, .c = 4, .d = 8 }, init);
|
||||
try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);
|
||||
}
|
||||
|
||||
test "pointer to struct initialized through reference to anonymous initializer provides result types" {
|
||||
const S = struct { a: u8, b: u16, c: *const anyopaque };
|
||||
var my_u16: u16 = 0xABCD;
|
||||
const s: *const S = &.{
|
||||
// intentionally out of order
|
||||
.c = @ptrCast("hello"),
|
||||
.b = my_u16,
|
||||
.a = @truncate(my_u16),
|
||||
};
|
||||
try expect(s.a == 0xCD);
|
||||
try expect(s.b == 0xABCD);
|
||||
const str: *const [5]u8 = @ptrCast(s.c);
|
||||
try std.testing.expectEqualSlices(u8, "hello", str);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,5 @@ pub export fn entry() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :7:14: error: runtime-known argument passed to parameter of comptime-only type
|
||||
// :9:12: note: declared here
|
||||
// :4:16: note: struct requires comptime because of this field
|
||||
// :4:16: note: types are not available at runtime
|
||||
// :7:25: error: unable to resolve comptime value
|
||||
// :7:25: note: initializer of comptime only struct must be comptime-known
|
||||
|
|
|
|||
|
|
@ -18,6 +18,6 @@ export fn entry() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :11:27: error: expected type 'u8', found '?u8'
|
||||
// :11:27: note: cannot convert optional to payload type
|
||||
// :11:27: note: consider using '.?', 'orelse', or 'if'
|
||||
// :11:20: error: expected type 'u8', found '?u8'
|
||||
// :11:20: note: cannot convert optional to payload type
|
||||
// :11:20: note: consider using '.?', 'orelse', or 'if'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
export fn foo() void {
|
||||
const x: *const anyopaque = &@intCast(123);
|
||||
_ = x;
|
||||
}
|
||||
export fn bar() void {
|
||||
const x: *const anyopaque = &.{
|
||||
.x = @intCast(123),
|
||||
};
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:34: error: @intCast must have a known result type
|
||||
// :2:34: note: result type is unknown due to opaque pointer type
|
||||
// :2:34: note: use @as to provide explicit result type
|
||||
// :7:14: error: @intCast must have a known result type
|
||||
// :6:35: note: result type is unknown due to opaque pointer type
|
||||
// :7:14: note: use @as to provide explicit result type
|
||||
|
|
@ -10,6 +10,11 @@ export fn c() void {
|
|||
export fn d() void {
|
||||
bar(@floatFromInt(123));
|
||||
}
|
||||
export fn f() void {
|
||||
bar(.{
|
||||
.x = @intCast(123),
|
||||
});
|
||||
}
|
||||
|
||||
fn bar(_: anytype) void {}
|
||||
|
||||
|
|
@ -18,14 +23,17 @@ fn bar(_: anytype) void {}
|
|||
// target=native
|
||||
//
|
||||
// :2:9: error: @ptrFromInt must have a known result type
|
||||
// :2:9: note: result type is unknown due to anytype parameter
|
||||
// :2:8: note: result type is unknown due to anytype parameter
|
||||
// :2:9: note: use @as to provide explicit result type
|
||||
// :5:9: error: @ptrCast must have a known result type
|
||||
// :5:9: note: result type is unknown due to anytype parameter
|
||||
// :5:8: note: result type is unknown due to anytype parameter
|
||||
// :5:9: note: use @as to provide explicit result type
|
||||
// :8:9: error: @intCast must have a known result type
|
||||
// :8:9: note: result type is unknown due to anytype parameter
|
||||
// :8:8: note: result type is unknown due to anytype parameter
|
||||
// :8:9: note: use @as to provide explicit result type
|
||||
// :11:9: error: @floatFromInt must have a known result type
|
||||
// :11:9: note: result type is unknown due to anytype parameter
|
||||
// :11:8: note: result type is unknown due to anytype parameter
|
||||
// :11:9: note: use @as to provide explicit result type
|
||||
// :15:14: error: @intCast must have a known result type
|
||||
// :14:8: note: result type is unknown due to anytype parameter
|
||||
// :15:14: note: use @as to provide explicit result type
|
||||
|
|
|
|||
|
|
@ -31,5 +31,6 @@ export fn e() void {
|
|||
// :2:13: error: expected type 'usize', found '*const [5:0]u8'
|
||||
// :7:10: error: type 'usize' cannot represent integer value '-1'
|
||||
// :12:10: error: expected type 'usize', found '*const [5:0]u8'
|
||||
// :17:13: error: expected type 'usize', found '*const struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}'
|
||||
// :17:13: error: expected type 'usize', found pointer
|
||||
// :17:13: note: address-of operator always returns a pointer
|
||||
// :22:20: error: overflow of integer type 'usize' with value '-1'
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ pub export fn entry8() void {
|
|||
// target=native
|
||||
// backend=stage2
|
||||
//
|
||||
// :6:19: error: value stored in comptime field does not match the default value of the field
|
||||
// :14:19: error: value stored in comptime field does not match the default value of the field
|
||||
// :6:9: error: value stored in comptime field does not match the default value of the field
|
||||
// :14:9: error: value stored in comptime field does not match the default value of the field
|
||||
// :19:38: error: value stored in comptime field does not match the default value of the field
|
||||
// :31:19: error: value stored in comptime field does not match the default value of the field
|
||||
// :25:29: note: default value set here
|
||||
|
|
@ -80,5 +80,6 @@ pub export fn entry8() void {
|
|||
// :35:29: note: default value set here
|
||||
// :45:12: error: value stored in comptime field does not match the default value of the field
|
||||
// :53:25: error: value stored in comptime field does not match the default value of the field
|
||||
// :66:43: error: value stored in comptime field does not match the default value of the field
|
||||
// :59:35: error: value stored in comptime field does not match the default value of the field
|
||||
// :66:36: error: value stored in comptime field does not match the default value of the field
|
||||
// :59:30: error: value stored in comptime field does not match the default value of the field
|
||||
// :57:29: note: default value set here
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@ export fn entry() void {
|
|||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// :4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
|
||||
// :4:26: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
|
||||
|
|
|
|||
|
|
@ -39,4 +39,6 @@ export fn entry() void {
|
|||
// :8:25: note: type 'i32' here
|
||||
// :16:16: error: expected type 'tmp.h.T', found 'void'
|
||||
// :15:15: note: struct declared here
|
||||
// :22:9: error: incompatible types: 'void' and 'tmp.k.T'
|
||||
// :22:13: error: incompatible types: 'void' and 'tmp.k.T'
|
||||
// :22:25: note: type 'void' here
|
||||
// :24:13: note: type 'tmp.k.T' here
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ comptime {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:29: error: expected type '[][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'
|
||||
// :2:29: error: expected type '[][]const u8', found '*const [2][]const u8'
|
||||
// :2:29: note: cast discards const qualifier
|
||||
// :6:31: error: expected type '*[2][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'
|
||||
// :6:31: error: expected type '*[2][]const u8', found '*const [2][]const u8'
|
||||
// :6:31: note: cast discards const qualifier
|
||||
// :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}'
|
||||
// :11:19: error: expected type '*tmp.S', found '*const tmp.S'
|
||||
// :11:19: note: cast discards const qualifier
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ export fn entry() void {
|
|||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// :2:15: error: cannot assign to constant
|
||||
// :2:5: error: cannot assign to constant
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@ export fn entry() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :5:10: error: cannot assign to constant
|
||||
// :5:5: error: cannot assign to constant
|
||||
|
|
|
|||
|
|
@ -18,6 +18,6 @@ export fn entry() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
|
||||
// :12:25: note: cannot convert error union to payload type
|
||||
// :12:25: note: consider using 'try', 'catch', or 'if'
|
||||
// :12:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
|
||||
// :12:15: note: cannot convert error union to payload type
|
||||
// :12:15: note: consider using 'try', 'catch', or 'if'
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ pub const Container = struct {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:36: error: expected type 'i32', found '?i32'
|
||||
// :3:36: note: cannot convert optional to payload type
|
||||
// :3:36: note: consider using '.?', 'orelse', or 'if'
|
||||
// :3:23: error: expected type 'i32', found '?i32'
|
||||
// :3:23: note: cannot convert optional to payload type
|
||||
// :3:23: note: consider using '.?', 'orelse', or 'if'
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ pub const Container = struct {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:36: error: expected type 'i32', found '?i32'
|
||||
// :3:36: note: cannot convert optional to payload type
|
||||
// :3:36: note: consider using '.?', 'orelse', or 'if'
|
||||
// :3:23: error: expected type 'i32', found '?i32'
|
||||
// :3:23: note: cannot convert optional to payload type
|
||||
// :3:23: note: consider using '.?', 'orelse', or 'if'
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ export fn entry() void {
|
|||
// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'
|
||||
// :5:12: note: struct declared here
|
||||
// :2:12: note: struct declared here
|
||||
// :7:11: note: function return type declared here
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ export fn f() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :7:29: error: unable to resolve comptime value
|
||||
// :7:29: note: initializer of comptime only struct must be comptime-known
|
||||
// :7:23: error: unable to resolve comptime value
|
||||
// :7:23: note: initializer of comptime only struct must be comptime-known
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ export fn f() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :7:29: error: unable to resolve comptime value
|
||||
// :7:29: note: initializer of comptime only union must be comptime-known
|
||||
// :7:23: error: unable to resolve comptime value
|
||||
// :7:23: note: initializer of comptime only union must be comptime-known
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ export fn entry() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:20: error: expected type 'comptime_int', found '*const u8'
|
||||
// :2:20: error: expected type 'comptime_int', found pointer
|
||||
// :2:20: note: address-of operator always returns a pointer
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
export fn entry() void {
|
||||
export fn entry1() void {
|
||||
const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
|
||||
_ = y;
|
||||
}
|
||||
export fn entry2() void {
|
||||
const x: [:2]const u8 = &.{ 1, 2 };
|
||||
const y: [:1]const u8 = x;
|
||||
_ = y;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:29: error: expected type '[:1]const u8', found '*const [2:2]u8'
|
||||
// :2:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'
|
||||
// :2:37: error: expected type '[2:1]u8', found '[2:2]u8'
|
||||
// :2:37: note: array sentinel '2' cannot cast into array sentinel '1'
|
||||
// :7:29: error: expected type '[:1]const u8', found '[:2]const u8'
|
||||
// :7:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ export fn u2m() void {
|
|||
// target=native
|
||||
//
|
||||
// :10:20: error: union initializer must initialize one field
|
||||
// :1:12: note: union declared here
|
||||
// :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field
|
||||
// :14:31: note: additional initializer here
|
||||
// :1:12: note: union declared here
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ pub export fn entry3() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :11:21: error: cannot initialize 'noreturn' field of union
|
||||
// :11:14: error: cannot initialize 'noreturn' field of union
|
||||
// :4:9: note: field 'b' declared here
|
||||
// :2:15: note: union declared here
|
||||
// :19:10: error: cannot initialize 'noreturn' field of union
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ comptime {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:51: error: expected type 'builtin.GlobalLinkage', found 'u32'
|
||||
// :3:41: error: expected type 'builtin.GlobalLinkage', found 'u32'
|
||||
// :?:?: note: enum declared here
|
||||
|
|
|
|||
|
|
@ -207,10 +207,8 @@ pub fn addCases(ctx: *Cases) !void {
|
|||
":1:38: note: declared comptime here",
|
||||
":8:36: error: runtime-known argument passed to comptime parameter",
|
||||
":2:41: note: declared comptime here",
|
||||
":13:29: error: runtime-known argument passed to parameter of comptime-only type",
|
||||
":3:24: note: declared here",
|
||||
":12:35: note: struct requires comptime because of this field",
|
||||
":12:35: note: types are not available at runtime",
|
||||
":13:32: error: unable to resolve comptime value",
|
||||
":13:32: note: initializer of comptime only struct must be comptime-known",
|
||||
});
|
||||
|
||||
case.addSourceFile("import.zig",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue