Merge pull request #17205 from mlugg/rls-ref

compiler: preserve result type information through address-of operator
This commit is contained in:
Andrew Kelley 2023-09-24 15:19:48 -07:00 committed by GitHub
commit df5f0517b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1345 additions and 1039 deletions

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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 {

View File

@ -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];

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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,

View File

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

View File

@ -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);
}

View File

@ -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;

View File

@ -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{

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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,