mirror of
https://github.com/ziglang/zig.git
synced 2025-01-26 20:06:39 +00:00
Merge pull request #17205 from mlugg/rls-ref
compiler: preserve result type information through address-of operator
This commit is contained in:
commit
df5f0517b3
@ -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;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
631
src/AstGen.zig
631
src/AstGen.zig
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
@ -45,6 +45,14 @@ ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
|
||||
std.ArrayListUnmanaged(RefPathResumeInfo),
|
||||
) = .{},
|
||||
|
||||
/// A set of ZIR instruction refs which have a meaning other than the
|
||||
/// instruction they refer to. For instance, during analysis of the arguments to
|
||||
/// a `call`, the index of the `call` itself is repurposed to refer to the
|
||||
/// parameter type.
|
||||
/// TODO: there should be some kind of proper handling for these instructions;
|
||||
/// currently we just ignore them!
|
||||
repurposed_insts: std.AutoHashMapUnmanaged(Zir.Inst.Index, void) = .{},
|
||||
|
||||
const RefPathResumeInfo = struct {
|
||||
file: *File,
|
||||
ref_path: []DocData.Expr,
|
||||
@ -954,6 +962,11 @@ fn walkInstruction(
|
||||
const tags = file.zir.instructions.items(.tag);
|
||||
const data = file.zir.instructions.items(.data);
|
||||
|
||||
if (self.repurposed_insts.contains(@intCast(inst_index))) {
|
||||
// TODO: better handling here
|
||||
return .{ .expr = .{ .comptimeExpr = 0 } };
|
||||
}
|
||||
|
||||
// We assume that the topmost ast_node entry corresponds to our decl
|
||||
const self_ast_node_index = self.ast_nodes.items.len - 1;
|
||||
|
||||
@ -2378,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{
|
||||
@ -2696,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);
|
||||
|
||||
@ -2717,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,
|
||||
@ -2857,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,
|
||||
@ -3022,6 +3004,9 @@ fn walkInstruction(
|
||||
var args = try self.arena.alloc(DocData.Expr, args_len);
|
||||
const body = file.zir.extra[extra.end..];
|
||||
|
||||
try self.repurposed_insts.put(self.arena, @intCast(inst_index), {});
|
||||
defer _ = self.repurposed_insts.remove(@intCast(inst_index));
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < args_len) : (i += 1) {
|
||||
const arg_end = file.zir.extra[extra.end + i];
|
||||
|
@ -5075,8 +5075,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
try ip.string_bytes.ensureUnusedCapacity(gpa, @as(usize, @intCast(len_including_sentinel + 1)));
|
||||
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes),
|
||||
.elems => |elems| for (elems) |elem| switch (ip.indexToKey(elem)) {
|
||||
.bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes[0..@intCast(len)]),
|
||||
.elems => |elems| for (elems[0..@intCast(len)]) |elem| switch (ip.indexToKey(elem)) {
|
||||
.undef => {
|
||||
ip.string_bytes.shrinkRetainingCapacity(string_bytes_index);
|
||||
break :bytes;
|
||||
|
931
src/Sema.zig
931
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,
|
||||
};
|
||||
};
|
||||
|
@ -130,6 +130,63 @@ const Writer = struct {
|
||||
recurse_decls: bool,
|
||||
recurse_blocks: bool,
|
||||
|
||||
/// Using `std.zig.findLineColumn` whenever we need to resolve a source location makes ZIR
|
||||
/// printing O(N^2), which can have drastic effects - taking a ZIR dump from a few seconds to
|
||||
/// many minutes. Since we're usually resolving source locations close to one another,
|
||||
/// preserving state across source location resolutions speeds things up a lot.
|
||||
line_col_cursor: struct {
|
||||
line: usize = 0,
|
||||
column: usize = 0,
|
||||
line_start: usize = 0,
|
||||
off: usize = 0,
|
||||
|
||||
fn find(cur: *@This(), source: []const u8, want_offset: usize) std.zig.Loc {
|
||||
if (want_offset < cur.off) {
|
||||
// Go back to the start of this line
|
||||
cur.off = cur.line_start;
|
||||
cur.column = 0;
|
||||
|
||||
while (want_offset < cur.off) {
|
||||
// Go back to the newline
|
||||
cur.off -= 1;
|
||||
|
||||
// Seek to the start of the previous line
|
||||
while (cur.off > 0 and source[cur.off - 1] != '\n') {
|
||||
cur.off -= 1;
|
||||
}
|
||||
cur.line_start = cur.off;
|
||||
cur.line -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// The cursor is now positioned before `want_offset`.
|
||||
// Seek forward as in `std.zig.findLineColumn`.
|
||||
|
||||
while (cur.off < want_offset) : (cur.off += 1) {
|
||||
switch (source[cur.off]) {
|
||||
'\n' => {
|
||||
cur.line += 1;
|
||||
cur.column = 0;
|
||||
cur.line_start = cur.off + 1;
|
||||
},
|
||||
else => {
|
||||
cur.column += 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
while (cur.off < source.len and source[cur.off] != '\n') {
|
||||
cur.off += 1;
|
||||
}
|
||||
|
||||
return .{
|
||||
.line = cur.line,
|
||||
.column = cur.column,
|
||||
.source_line = source[cur.line_start..cur.off],
|
||||
};
|
||||
}
|
||||
} = .{},
|
||||
|
||||
fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index {
|
||||
return @as(Ast.Node.Index, @bitCast(offset + @as(i32, @bitCast(self.parent_decl_node))));
|
||||
}
|
||||
@ -148,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,
|
||||
@ -184,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,
|
||||
@ -224,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,
|
||||
@ -243,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),
|
||||
@ -259,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),
|
||||
@ -273,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),
|
||||
@ -285,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,
|
||||
@ -352,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),
|
||||
|
||||
@ -373,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),
|
||||
@ -395,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,
|
||||
@ -560,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)});
|
||||
@ -915,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;
|
||||
|
||||
@ -947,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);
|
||||
@ -1077,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);
|
||||
@ -2590,8 +2669,8 @@ const Writer = struct {
|
||||
.lazy = src,
|
||||
};
|
||||
const src_span = src_loc.span(self.gpa) catch unreachable;
|
||||
const start = std.zig.findLineColumn(tree.source, src_span.start);
|
||||
const end = std.zig.findLineColumn(tree.source, src_span.end);
|
||||
const start = self.line_col_cursor.find(tree.source, src_span.start);
|
||||
const end = self.line_col_cursor.find(tree.source, src_span.end);
|
||||
try stream.print("{s}:{d}:{d} to :{d}:{d}", .{
|
||||
@tagName(src), start.line + 1, start.column + 1,
|
||||
end.line + 1, end.column + 1,
|
||||
|
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);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ const CPU = packed struct {
|
||||
};
|
||||
|
||||
test {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
|
@ -17,6 +17,7 @@ test {
|
||||
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;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
const timestamp: i64 = value();
|
||||
const id = ID{ .fields = Fields{
|
||||
|
@ -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",
|
||||
|
@ -1034,6 +1034,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
|
||||
|
||||
these_tests.addIncludePath(.{ .path = "test" });
|
||||
|
||||
if (test_target.target.getOs().tag == .wasi) {
|
||||
// WASI's default stack size can be too small for some big tests.
|
||||
these_tests.stack_size = 2 * 1024 * 1024;
|
||||
}
|
||||
|
||||
const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{
|
||||
options.name,
|
||||
triple_txt,
|
||||
|
Loading…
Reference in New Issue
Block a user