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;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
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,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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