authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-20 15:23:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-20 15:41:57-07:00
log0cd361219c107bce48f2d7b44c6f3dd05ea6ccf4
treec3de2205e0bb525d61ee78800c118b13efbf1029
parent2f1abd919a8465e515875cd08816778df795aabe

stage2: field type expressions support referencing locals

The big change in this commit is making `semaDecl` resolve the fields if the Decl ends up being a struct or union. It needs to do this while the `Sema` is still in scope, because it will have the resolved AIR instructions that the field type expressions possibly reference. We do this after the decl is populated and set to `complete` so that a `Decl` may reference itself. Everything else is fixes and improvements to make the test suite pass again after making this change. * New AIR instruction: `ptr_elem_ptr` - Implemented for LLVM backend * New Type tag: `type_info` which represents `std.builtin.TypeInfo`. It is used by AstGen for the operand type of `@Type`. * ZIR instruction `set_float_mode` uses `coerced_ty` to avoid superfluous `as` instruction on operand. * ZIR instruction `Type` uses `coerced_ty` to properly handle result location type of operand. * Fix two instances of `enum_nonexhaustive` Value Tag not handled properly - it should generally be handled the same as `enum_full`. * Fix struct and union field resolution not copying Type and Value objects into its Decl arena. * Fix enum tag value resolution discarding the ZIR=>AIR instruction map for the child Sema, when they still needed to be accessed. * Fix `zirResolveInferredAlloc` use-after-free in the AIR instructions data array. * Fix `elemPtrArray` not respecting const/mutable attribute of pointer in the result type. * Fix LLVM backend crashing when `updateDeclExports` is called before `updateDecl`/`updateFunc` (which is, according to the API, perfectly legal for the frontend to do). * Fix LLVM backend handling element pointer of pointer-to-array. It needed another index in the GEP otherwise LLVM saw the wrong type. * Fix LLVM test cases not returning 0 from main, causing test failures. Fixes a regression introduced in 6a5094872f10acc629543cc7f10533b438d0283a. * Implement comptime shift-right. * Implement `@Type` for integers and `@TypeInfo` for integers. * Implement union initialization syntax. * Implement `zirFieldType` for unions. * Implement `elemPtrArray` for a runtime-known operand. * Make `zirLog2IntType` support RHS of shift being `comptime_int`. In this case it returns `comptime_int`. The motivating test case for this commit was originally: ```zig test "example" { var l: List(10) = undefined; l.array[1] = 1; } fn List(comptime L: usize) type { var T = u8; return struct { array: [L]T, }; } ``` However I changed it to: ```zig test "example" { var l: List = undefined; l.array[1] = 1; } const List = blk: { const T = [10]u8; break :blk struct { array: T, }; }; ``` Which ended up being a similar, smaller problem. The former test case will require a similar solution in the implementation of comptime function calls - checking if the result of the function call is a struct or union, and using the child `Sema` before it is destroyed to resolve the fields.

18 files changed, 1294 insertions(+), 986 deletions(-)

lib/std/builtin.zig+1-1
...@@ -237,7 +237,7 @@ pub const TypeInfo = union(enum) {...@@ -237,7 +237,7 @@ pub const TypeInfo = union(enum) {
237 /// This field is an optional type.237 /// This field is an optional type.
238 /// The type of the sentinel is the element type of the pointer, which is238 /// The type of the sentinel is the element type of the pointer, which is
239 /// the value of the `child` field in this struct. However there is no way239 /// the value of the `child` field in this struct. However there is no way
240 /// to refer to that type here, so we use `var`.240 /// to refer to that type here, so we use `anytype`.
241 sentinel: anytype,241 sentinel: anytype,
242242
243 /// This data structure is used by the Zig language code generation and243 /// This data structure is used by the Zig language code generation and
src/Air.zig+12-2
...@@ -286,6 +286,10 @@ pub const Inst = struct {...@@ -286,6 +286,10 @@ pub const Inst = struct {
286 /// Result type is the element type of the pointer operand.286 /// Result type is the element type of the pointer operand.
287 /// Uses the `bin_op` field.287 /// Uses the `bin_op` field.
288 ptr_elem_val,288 ptr_elem_val,
289 /// Given a pointer value, and element index, return the element pointer at that index.
290 /// Result type is pointer to the element type of the pointer operand.
291 /// Uses the `ty_pl` field with payload `Bin`.
292 ptr_elem_ptr,
289 /// Given a pointer to a pointer, and element index, return the element value of the inner293 /// Given a pointer to a pointer, and element index, return the element value of the inner
290 /// pointer at that index.294 /// pointer at that index.
291 /// Result type is the element type of the inner pointer operand.295 /// Result type is the element type of the inner pointer operand.
...@@ -410,6 +414,11 @@ pub const StructField = struct {...@@ -410,6 +414,11 @@ pub const StructField = struct {
410 field_index: u32,414 field_index: u32,
411};415};
412416
417pub const Bin = struct {
418 lhs: Inst.Ref,
419 rhs: Inst.Ref,
420};
421
413/// Trailing:422/// Trailing:
414/// 0. `Inst.Ref` for every outputs_len423/// 0. `Inst.Ref` for every outputs_len
415/// 1. `Inst.Ref` for every inputs_len424/// 1. `Inst.Ref` for every inputs_len
...@@ -482,6 +491,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -482,6 +491,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
482 .constant,491 .constant,
483 .struct_field_ptr,492 .struct_field_ptr,
484 .struct_field_val,493 .struct_field_val,
494 .ptr_elem_ptr,
485 => return air.getRefType(datas[inst].ty_pl.ty),495 => return air.getRefType(datas[inst].ty_pl.ty),
486496
487 .not,497 .not,
...@@ -527,8 +537,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -527,8 +537,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
527 },537 },
528538
529 .slice_elem_val, .ptr_elem_val => {539 .slice_elem_val, .ptr_elem_val => {
530 const slice_ty = air.typeOf(datas[inst].bin_op.lhs);540 const ptr_ty = air.typeOf(datas[inst].bin_op.lhs);
531 return slice_ty.elemType();541 return ptr_ty.elemType();
532 },542 },
533 .ptr_slice_elem_val, .ptr_ptr_elem_val => {543 .ptr_slice_elem_val, .ptr_ptr_elem_val => {
534 const outer_ptr_ty = air.typeOf(datas[inst].bin_op.lhs);544 const outer_ptr_ty = air.typeOf(datas[inst].bin_op.lhs);
src/AstGen.zig+32-32
...@@ -7102,38 +7102,38 @@ fn builtinCall(...@@ -7102,38 +7102,38 @@ fn builtinCall(
7102 .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of),7102 .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of),
7103 .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of),7103 .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of),
71047104
7105 .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int),7105 .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int),
7106 .error_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .error_to_int),7106 .error_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .error_to_int),
7107 .int_to_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type }, params[0], .int_to_error),7107 .int_to_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type }, params[0], .int_to_error),
7108 .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error),7108 .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error),
7109 .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type }, params[0], .set_eval_branch_quota),7109 .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type }, params[0], .set_eval_branch_quota),
7110 .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int),7110 .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int),
7111 .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int),7111 .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int),
7112 .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file),7112 .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file),
7113 .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name),7113 .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name),
7114 .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic),7114 .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic),
7115 .set_align_stack => return simpleUnOp(gz, scope, rl, node, align_rl, params[0], .set_align_stack),7115 .set_align_stack => return simpleUnOp(gz, scope, rl, node, align_rl, params[0], .set_align_stack),
7116 .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold),7116 .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold),
7117 .set_float_mode => return simpleUnOp(gz, scope, rl, node, .{ .ty = .float_mode_type }, params[0], .set_float_mode),7117 .set_float_mode => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .float_mode_type }, params[0], .set_float_mode),
7118 .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety),7118 .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety),
7119 .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt),7119 .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt),
7120 .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin),7120 .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin),
7121 .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos),7121 .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos),
7122 .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp),7122 .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp),
7123 .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2),7123 .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2),
7124 .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log),7124 .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log),
7125 .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2),7125 .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2),
7126 .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10),7126 .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10),
7127 .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs),7127 .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs),
7128 .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor),7128 .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor),
7129 .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil),7129 .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil),
7130 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc),7130 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc),
7131 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round),7131 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round),
7132 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name),7132 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name),
7133 .Type => return simpleUnOp(gz, scope, rl, node, .none, params[0], .reify),7133 .Type => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type }, params[0], .reify),
7134 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name),7134 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name),
7135 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type),7135 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type),
7136 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size),7136 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size),
71377137
7138 .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int),7138 .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int),
7139 .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float),7139 .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float),
src/Liveness.zig+4
...@@ -330,6 +330,10 @@ fn analyzeInst(...@@ -330,6 +330,10 @@ fn analyzeInst(
330 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;330 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
331 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });331 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
332 },332 },
333 .ptr_elem_ptr => {
334 const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;
335 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
336 },
333 .br => {337 .br => {
334 const br = inst_datas[inst].br;338 const br = inst_datas[inst].br;
335 return trackOperands(a, new_set, inst, main_tomb, .{ br.operand, .none, .none });339 return trackOperands(a, new_set, inst, main_tomb, .{ br.operand, .none, .none });
src/Module.zig+15-305
...@@ -554,8 +554,8 @@ pub const Decl = struct {...@@ -554,8 +554,8 @@ pub const Decl = struct {
554 assert(struct_obj.owner_decl == decl);554 assert(struct_obj.owner_decl == decl);
555 return &struct_obj.namespace;555 return &struct_obj.namespace;
556 },556 },
557 .enum_full => {557 .enum_full, .enum_nonexhaustive => {
558 const enum_obj = ty.castTag(.enum_full).?.data;558 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;
559 assert(enum_obj.owner_decl == decl);559 assert(enum_obj.owner_decl == decl);
560 return &enum_obj.namespace;560 return &enum_obj.namespace;
561 },561 },
...@@ -660,6 +660,7 @@ pub const Struct = struct {...@@ -660,6 +660,7 @@ pub const Struct = struct {
660 /// is necessary to determine whether it has bits at runtime.660 /// is necessary to determine whether it has bits at runtime.
661 known_has_bits: bool,661 known_has_bits: bool,
662662
663 /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl.
663 pub const Field = struct {664 pub const Field = struct {
664 /// Uses `noreturn` to indicate `anytype`.665 /// Uses `noreturn` to indicate `anytype`.
665 /// undefined until `status` is `have_field_types` or `have_layout`.666 /// undefined until `status` is `have_field_types` or `have_layout`.
...@@ -3091,6 +3092,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3091,6 +3092,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3091 if (linksection_ref == .none) break :blk Value.initTag(.null_value);3092 if (linksection_ref == .none) break :blk Value.initTag(.null_value);
3092 break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;3093 break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;
3093 };3094 };
3095 // Note this resolves the type of the Decl, not the value; if this Decl
3096 // is a struct, for example, this resolves `type` (which needs no resolution),
3097 // not the struct itself.
3094 try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty);3098 try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty);
30953099
3096 // We need the memory for the Type to go into the arena for the Decl3100 // We need the memory for the Type to go into the arena for the Decl
...@@ -3193,6 +3197,15 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3193,6 +3197,15 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3193 if (type_changed and mod.emit_h != null) {3197 if (type_changed and mod.emit_h != null) {
3194 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });3198 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
3195 }3199 }
3200 } else if (decl_tv.ty.zigTypeTag() == .Type) {
3201 // In case this Decl is a struct or union, we need to resolve the fields
3202 // while we still have the `Sema` in scope, so that the field type expressions
3203 // can use the resolved AIR instructions that they possibly reference.
3204 // We do this after the decl is populated and set to `complete` so that a `Decl`
3205 // may reference itself.
3206 var buffer: Value.ToTypeBuffer = undefined;
3207 const ty = decl.val.toType(&buffer);
3208 try sema.resolveDeclFields(&block_scope, src, ty);
3196 }3209 }
31973210
3198 if (decl.is_exported) {3211 if (decl.is_exported) {
...@@ -4450,309 +4463,6 @@ pub const PeerTypeCandidateSrc = union(enum) {...@@ -4450,309 +4463,6 @@ pub const PeerTypeCandidateSrc = union(enum) {
4450 }4463 }
4451};4464};
44524465
4453pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void {
4454 const tracy = trace(@src());
4455 defer tracy.end();
4456
4457 const gpa = mod.gpa;
4458 const zir = struct_obj.owner_decl.namespace.file_scope.zir;
4459 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
4460 assert(extended.opcode == .struct_decl);
4461 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
4462 var extra_index: usize = extended.operand;
4463
4464 const src: LazySrcLoc = .{ .node_offset = struct_obj.node_offset };
4465 extra_index += @boolToInt(small.has_src_node);
4466
4467 const body_len = if (small.has_body_len) blk: {
4468 const body_len = zir.extra[extra_index];
4469 extra_index += 1;
4470 break :blk body_len;
4471 } else 0;
4472
4473 const fields_len = if (small.has_fields_len) blk: {
4474 const fields_len = zir.extra[extra_index];
4475 extra_index += 1;
4476 break :blk fields_len;
4477 } else 0;
4478
4479 const decls_len = if (small.has_decls_len) decls_len: {
4480 const decls_len = zir.extra[extra_index];
4481 extra_index += 1;
4482 break :decls_len decls_len;
4483 } else 0;
4484
4485 // Skip over decls.
4486 var decls_it = zir.declIteratorInner(extra_index, decls_len);
4487 while (decls_it.next()) |_| {}
4488 extra_index = decls_it.extra_index;
4489
4490 const body = zir.extra[extra_index..][0..body_len];
4491 if (fields_len == 0) {
4492 assert(body.len == 0);
4493 return;
4494 }
4495 extra_index += body.len;
4496
4497 var decl_arena = struct_obj.owner_decl.value_arena.?.promote(gpa);
4498 defer struct_obj.owner_decl.value_arena.?.* = decl_arena.state;
4499
4500 try struct_obj.fields.ensureCapacity(&decl_arena.allocator, fields_len);
4501
4502 // We create a block for the field type instructions because they
4503 // may need to reference Decls from inside the struct namespace.
4504 // Within the field type, default value, and alignment expressions, the "owner decl"
4505 // should be the struct itself. Thus we need a new Sema.
4506 var sema: Sema = .{
4507 .mod = mod,
4508 .gpa = gpa,
4509 .arena = &decl_arena.allocator,
4510 .code = zir,
4511 .owner_decl = struct_obj.owner_decl,
4512 .namespace = &struct_obj.namespace,
4513 .owner_func = null,
4514 .func = null,
4515 .fn_ret_ty = Type.initTag(.void),
4516 };
4517 defer sema.deinit();
4518
4519 var block: Scope.Block = .{
4520 .parent = null,
4521 .sema = &sema,
4522 .src_decl = struct_obj.owner_decl,
4523 .instructions = .{},
4524 .inlining = null,
4525 .is_comptime = true,
4526 };
4527 defer assert(block.instructions.items.len == 0); // should all be comptime instructions
4528
4529 if (body.len != 0) {
4530 _ = try sema.analyzeBody(&block, body);
4531 }
4532
4533 const bits_per_field = 4;
4534 const fields_per_u32 = 32 / bits_per_field;
4535 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
4536 var bit_bag_index: usize = extra_index;
4537 extra_index += bit_bags_count;
4538 var cur_bit_bag: u32 = undefined;
4539 var field_i: u32 = 0;
4540 while (field_i < fields_len) : (field_i += 1) {
4541 if (field_i % fields_per_u32 == 0) {
4542 cur_bit_bag = zir.extra[bit_bag_index];
4543 bit_bag_index += 1;
4544 }
4545 const has_align = @truncate(u1, cur_bit_bag) != 0;
4546 cur_bit_bag >>= 1;
4547 const has_default = @truncate(u1, cur_bit_bag) != 0;
4548 cur_bit_bag >>= 1;
4549 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
4550 cur_bit_bag >>= 1;
4551 const unused = @truncate(u1, cur_bit_bag) != 0;
4552 cur_bit_bag >>= 1;
4553
4554 _ = unused;
4555
4556 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
4557 extra_index += 1;
4558 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4559 extra_index += 1;
4560
4561 // This string needs to outlive the ZIR code.
4562 const field_name = try decl_arena.allocator.dupe(u8, field_name_zir);
4563 if (field_type_ref == .none) {
4564 return mod.fail(&block.base, src, "TODO: implement anytype struct field", .{});
4565 }
4566 const field_ty: Type = if (field_type_ref == .none)
4567 Type.initTag(.noreturn)
4568 else
4569 // TODO: if we need to report an error here, use a source location
4570 // that points to this type expression rather than the struct.
4571 // But only resolve the source location if we need to emit a compile error.
4572 try sema.resolveType(&block, src, field_type_ref);
4573
4574 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
4575 assert(!gop.found_existing);
4576 gop.value_ptr.* = .{
4577 .ty = field_ty,
4578 .abi_align = Value.initTag(.abi_align_default),
4579 .default_val = Value.initTag(.unreachable_value),
4580 .is_comptime = is_comptime,
4581 .offset = undefined,
4582 };
4583
4584 if (has_align) {
4585 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4586 extra_index += 1;
4587 // TODO: if we need to report an error here, use a source location
4588 // that points to this alignment expression rather than the struct.
4589 // But only resolve the source location if we need to emit a compile error.
4590 gop.value_ptr.abi_align = (try sema.resolveInstConst(&block, src, align_ref)).val;
4591 }
4592 if (has_default) {
4593 const default_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4594 extra_index += 1;
4595 // TODO: if we need to report an error here, use a source location
4596 // that points to this default value expression rather than the struct.
4597 // But only resolve the source location if we need to emit a compile error.
4598 gop.value_ptr.default_val = (try sema.resolveInstConst(&block, src, default_ref)).val;
4599 }
4600 }
4601}
4602
4603pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) CompileError!void {
4604 const tracy = trace(@src());
4605 defer tracy.end();
4606
4607 const gpa = mod.gpa;
4608 const zir = union_obj.owner_decl.namespace.file_scope.zir;
4609 const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;
4610 assert(extended.opcode == .union_decl);
4611 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
4612 var extra_index: usize = extended.operand;
4613
4614 const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };
4615 extra_index += @boolToInt(small.has_src_node);
4616
4617 if (small.has_tag_type) {
4618 extra_index += 1;
4619 }
4620
4621 const body_len = if (small.has_body_len) blk: {
4622 const body_len = zir.extra[extra_index];
4623 extra_index += 1;
4624 break :blk body_len;
4625 } else 0;
4626
4627 const fields_len = if (small.has_fields_len) blk: {
4628 const fields_len = zir.extra[extra_index];
4629 extra_index += 1;
4630 break :blk fields_len;
4631 } else 0;
4632
4633 const decls_len = if (small.has_decls_len) decls_len: {
4634 const decls_len = zir.extra[extra_index];
4635 extra_index += 1;
4636 break :decls_len decls_len;
4637 } else 0;
4638
4639 // Skip over decls.
4640 var decls_it = zir.declIteratorInner(extra_index, decls_len);
4641 while (decls_it.next()) |_| {}
4642 extra_index = decls_it.extra_index;
4643
4644 const body = zir.extra[extra_index..][0..body_len];
4645 if (fields_len == 0) {
4646 assert(body.len == 0);
4647 return;
4648 }
4649 extra_index += body.len;
4650
4651 var decl_arena = union_obj.owner_decl.value_arena.?.promote(gpa);
4652 defer union_obj.owner_decl.value_arena.?.* = decl_arena.state;
4653
4654 try union_obj.fields.ensureCapacity(&decl_arena.allocator, fields_len);
4655
4656 // We create a block for the field type instructions because they
4657 // may need to reference Decls from inside the struct namespace.
4658 // Within the field type, default value, and alignment expressions, the "owner decl"
4659 // should be the struct itself. Thus we need a new Sema.
4660 var sema: Sema = .{
4661 .mod = mod,
4662 .gpa = gpa,
4663 .arena = &decl_arena.allocator,
4664 .code = zir,
4665 .owner_decl = union_obj.owner_decl,
4666 .namespace = &union_obj.namespace,
4667 .owner_func = null,
4668 .func = null,
4669 .fn_ret_ty = Type.initTag(.void),
4670 };
4671 defer sema.deinit();
4672
4673 var block: Scope.Block = .{
4674 .parent = null,
4675 .sema = &sema,
4676 .src_decl = union_obj.owner_decl,
4677 .instructions = .{},
4678 .inlining = null,
4679 .is_comptime = true,
4680 };
4681 defer assert(block.instructions.items.len == 0); // should all be comptime instructions
4682
4683 if (body.len != 0) {
4684 _ = try sema.analyzeBody(&block, body);
4685 }
4686
4687 const bits_per_field = 4;
4688 const fields_per_u32 = 32 / bits_per_field;
4689 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
4690 var bit_bag_index: usize = extra_index;
4691 extra_index += bit_bags_count;
4692 var cur_bit_bag: u32 = undefined;
4693 var field_i: u32 = 0;
4694 while (field_i < fields_len) : (field_i += 1) {
4695 if (field_i % fields_per_u32 == 0) {
4696 cur_bit_bag = zir.extra[bit_bag_index];
4697 bit_bag_index += 1;
4698 }
4699 const has_type = @truncate(u1, cur_bit_bag) != 0;
4700 cur_bit_bag >>= 1;
4701 const has_align = @truncate(u1, cur_bit_bag) != 0;
4702 cur_bit_bag >>= 1;
4703 const has_tag = @truncate(u1, cur_bit_bag) != 0;
4704 cur_bit_bag >>= 1;
4705 const unused = @truncate(u1, cur_bit_bag) != 0;
4706 cur_bit_bag >>= 1;
4707 _ = unused;
4708
4709 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
4710 extra_index += 1;
4711
4712 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
4713 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4714 extra_index += 1;
4715 break :blk field_type_ref;
4716 } else .none;
4717
4718 const align_ref: Zir.Inst.Ref = if (has_align) blk: {
4719 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4720 extra_index += 1;
4721 break :blk align_ref;
4722 } else .none;
4723
4724 if (has_tag) {
4725 extra_index += 1;
4726 }
4727
4728 // This string needs to outlive the ZIR code.
4729 const field_name = try decl_arena.allocator.dupe(u8, field_name_zir);
4730 const field_ty: Type = if (field_type_ref == .none)
4731 Type.initTag(.void)
4732 else
4733 // TODO: if we need to report an error here, use a source location
4734 // that points to this type expression rather than the union.
4735 // But only resolve the source location if we need to emit a compile error.
4736 try sema.resolveType(&block, src, field_type_ref);
4737
4738 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
4739 assert(!gop.found_existing);
4740 gop.value_ptr.* = .{
4741 .ty = field_ty,
4742 .abi_align = Value.initTag(.abi_align_default),
4743 };
4744
4745 if (align_ref != .none) {
4746 // TODO: if we need to report an error here, use a source location
4747 // that points to this alignment expression rather than the struct.
4748 // But only resolve the source location if we need to emit a compile error.
4749 gop.value_ptr.abi_align = (try sema.resolveInstConst(&block, src, align_ref)).val;
4750 }
4751 }
4752
4753 // TODO resolve the union tag_type_ref
4754}
4755
4756/// Called from `performAllTheWork`, after all AstGen workers have finished,4466/// Called from `performAllTheWork`, after all AstGen workers have finished,
4757/// and before the main semantic analysis loop begins.4467/// and before the main semantic analysis loop begins.
4758pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {4468pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+576-149
...@@ -1032,25 +1032,27 @@ fn zirEnumDecl(...@@ -1032,25 +1032,27 @@ fn zirEnumDecl(
1032 // We create a block for the field type instructions because they1032 // We create a block for the field type instructions because they
1033 // may need to reference Decls from inside the enum namespace.1033 // may need to reference Decls from inside the enum namespace.
1034 // Within the field type, default value, and alignment expressions, the "owner decl"1034 // Within the field type, default value, and alignment expressions, the "owner decl"
1035 // should be the enum itself. Thus we need a new Sema.1035 // should be the enum itself.
1036 var enum_sema: Sema = .{1036
1037 .mod = mod,1037 const prev_owner_decl = sema.owner_decl;
1038 .gpa = gpa,1038 sema.owner_decl = new_decl;
1039 .arena = &new_decl_arena.allocator,1039 defer sema.owner_decl = prev_owner_decl;
1040 .code = sema.code,1040
1041 .inst_map = sema.inst_map,1041 const prev_namespace = sema.namespace;
1042 .owner_decl = new_decl,1042 sema.namespace = &enum_obj.namespace;
1043 .namespace = &enum_obj.namespace,1043 defer sema.namespace = prev_namespace;
1044 .owner_func = null,1044
1045 .func = null,1045 const prev_owner_func = sema.owner_func;
1046 .fn_ret_ty = Type.initTag(.void),1046 sema.owner_func = null;
1047 .branch_quota = sema.branch_quota,1047 defer sema.owner_func = prev_owner_func;
1048 .branch_count = sema.branch_count,1048
1049 };1049 const prev_func = sema.func;
1050 sema.func = null;
1051 defer sema.func = prev_func;
10501052
1051 var enum_block: Scope.Block = .{1053 var enum_block: Scope.Block = .{
1052 .parent = null,1054 .parent = null,
1053 .sema = &enum_sema,1055 .sema = sema,
1054 .src_decl = new_decl,1056 .src_decl = new_decl,
1055 .instructions = .{},1057 .instructions = .{},
1056 .inlining = null,1058 .inlining = null,
...@@ -1059,11 +1061,8 @@ fn zirEnumDecl(...@@ -1059,11 +1061,8 @@ fn zirEnumDecl(
1059 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions1061 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions
10601062
1061 if (body.len != 0) {1063 if (body.len != 0) {
1062 _ = try enum_sema.analyzeBody(&enum_block, body);1064 _ = try sema.analyzeBody(&enum_block, body);
1063 }1065 }
1064
1065 sema.branch_count = enum_sema.branch_count;
1066 sema.branch_quota = enum_sema.branch_quota;
1067 }1066 }
1068 var bit_bag_index: usize = body_end;1067 var bit_bag_index: usize = body_end;
1069 var cur_bit_bag: u32 = undefined;1068 var cur_bit_bag: u32 = undefined;
...@@ -1466,8 +1465,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde...@@ -1466,8 +1465,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
1466 const ptr = sema.resolveInst(inst_data.operand);1465 const ptr = sema.resolveInst(inst_data.operand);
1467 const ptr_inst = Air.refToIndex(ptr).?;1466 const ptr_inst = Air.refToIndex(ptr).?;
1468 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);1467 assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
1469 const air_datas = sema.air_instructions.items(.data);1468 const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload;
1470 const value_index = air_datas[ptr_inst].ty_pl.payload;
1471 const ptr_val = sema.air_values.items[value_index];1469 const ptr_val = sema.air_values.items[value_index];
1472 const var_is_mut = switch (sema.typeOf(ptr).tag()) {1470 const var_is_mut = switch (sema.typeOf(ptr).tag()) {
1473 .inferred_alloc_const => false,1471 .inferred_alloc_const => false,
...@@ -1481,7 +1479,8 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde...@@ -1481,7 +1479,8 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
14811479
1482 const final_elem_ty = try decl.ty.copy(sema.arena);1480 const final_elem_ty = try decl.ty.copy(sema.arena);
1483 const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One);1481 const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One);
1484 air_datas[ptr_inst].ty_pl.ty = try sema.addType(final_ptr_ty);1482 const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
1483 sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;
14851484
1486 if (var_is_mut) {1485 if (var_is_mut) {
1487 sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{1486 sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{
...@@ -5329,10 +5328,16 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A...@@ -5329,10 +5328,16 @@ fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
53295328
5330 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {5329 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
5331 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {5330 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
5331 const lhs_ty = sema.typeOf(lhs);
5332 if (lhs_val.isUndef() or rhs_val.isUndef()) {5332 if (lhs_val.isUndef() or rhs_val.isUndef()) {
5333 return sema.addConstUndef(sema.typeOf(lhs));5333 return sema.addConstUndef(lhs_ty);
5334 }
5335 // If rhs is 0, return lhs without doing any calculations.
5336 if (rhs_val.compareWithZero(.eq)) {
5337 return sema.addConstant(lhs_ty, lhs_val);
5334 }5338 }
5335 return sema.mod.fail(&block.base, src, "TODO implement comptime shr", .{});5339 const val = try lhs_val.shr(rhs_val, sema.arena);
5340 return sema.addConstant(lhs_ty, val);
5336 }5341 }
5337 }5342 }
53385343
...@@ -6008,6 +6013,28 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -6008,6 +6013,28 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
6008 }),6013 }),
6009 );6014 );
6010 },6015 },
6016 .Int => {
6017 const info = ty.intInfo(target);
6018 const field_values = try sema.arena.alloc(Value, 2);
6019 // signedness: Signedness,
6020 field_values[0] = try Value.Tag.enum_field_index.create(
6021 sema.arena,
6022 @enumToInt(info.signedness),
6023 );
6024 // bits: comptime_int,
6025 field_values[1] = try Value.Tag.int_u64.create(sema.arena, info.bits);
6026
6027 return sema.addConstant(
6028 type_info_ty,
6029 try Value.Tag.@"union".create(sema.arena, .{
6030 .tag = try Value.Tag.enum_field_index.create(
6031 sema.arena,
6032 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Int),
6033 ),
6034 .val = try Value.Tag.@"struct".create(sema.arena, field_values.ptr),
6035 }),
6036 );
6037 },
6011 else => |t| return sema.mod.fail(&block.base, src, "TODO: implement zirTypeInfo for {s}", .{6038 else => |t| return sema.mod.fail(&block.base, src, "TODO: implement zirTypeInfo for {s}", .{
6012 @tagName(t),6039 @tagName(t),
6013 }),6040 }),
...@@ -6047,20 +6074,24 @@ fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compil...@@ -6047,20 +6074,24 @@ fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compil
6047}6074}
60486075
6049fn log2IntType(sema: *Sema, block: *Scope.Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref {6076fn log2IntType(sema: *Sema, block: *Scope.Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref {
6050 if (operand.zigTypeTag() != .Int) return sema.mod.fail(6077 switch (operand.zigTypeTag()) {
6051 &block.base,6078 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
6052 src,6079 .Int => {
6053 "bit shifting operation expected integer type, found '{}'",6080 var count: u16 = 0;
6054 .{operand},6081 var s = operand.bitSize(sema.mod.getTarget()) - 1;
6055 );6082 while (s != 0) : (s >>= 1) {
60566083 count += 1;
6057 var count: u16 = 0;6084 }
6058 var s = operand.bitSize(sema.mod.getTarget()) - 1;6085 const res = try Module.makeIntType(sema.arena, .unsigned, count);
6059 while (s != 0) : (s >>= 1) {6086 return sema.addType(res);
6060 count += 1;6087 },
6088 else => return sema.mod.fail(
6089 &block.base,
6090 src,
6091 "bit shifting operation expected integer type, found '{}'",
6092 .{operand},
6093 ),
6061 }6094 }
6062 const res = try Module.makeIntType(sema.arena, .unsigned, count);
6063 return sema.addType(res);
6064}6095}
60656096
6066fn zirTypeofPeer(6097fn zirTypeofPeer(
...@@ -6517,99 +6548,134 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:...@@ -6517,99 +6548,134 @@ fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref:
6517 const first_field_type_data = zir_datas[first_item.field_type].pl_node;6548 const first_field_type_data = zir_datas[first_item.field_type].pl_node;
6518 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;6549 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
6519 const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);6550 const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);
6520 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);6551 const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);
6521 const struct_obj = struct_ty.castTag(.@"struct").?.data;6552
65226553 if (resolved_ty.castTag(.@"struct")) |struct_payload| {
6523 // Maps field index to field_type index of where it was already initialized.6554 const struct_obj = struct_payload.data;
6524 // For making sure all fields are accounted for and no fields are duplicated.6555
6525 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.count());6556 // Maps field index to field_type index of where it was already initialized.
6526 defer gpa.free(found_fields);6557 // For making sure all fields are accounted for and no fields are duplicated.
6527 mem.set(Zir.Inst.Index, found_fields, 0);6558 const found_fields = try gpa.alloc(Zir.Inst.Index, struct_obj.fields.count());
65286559 defer gpa.free(found_fields);
6529 // The init values to use for the struct instance.6560 mem.set(Zir.Inst.Index, found_fields, 0);
6530 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_obj.fields.count());6561
6531 defer gpa.free(field_inits);6562 // The init values to use for the struct instance.
6563 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_obj.fields.count());
6564 defer gpa.free(field_inits);
6565
6566 var field_i: u32 = 0;
6567 var extra_index = extra.end;
6568
6569 while (field_i < extra.data.fields_len) : (field_i += 1) {
6570 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
6571 extra_index = item.end;
6572
6573 const field_type_data = zir_datas[item.data.field_type].pl_node;
6574 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
6575 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
6576 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
6577 const field_index = struct_obj.fields.getIndex(field_name) orelse
6578 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);
6579 if (found_fields[field_index] != 0) {
6580 const other_field_type = found_fields[field_index];
6581 const other_field_type_data = zir_datas[other_field_type].pl_node;
6582 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node };
6583 const msg = msg: {
6584 const msg = try mod.errMsg(&block.base, field_src, "duplicate field", .{});
6585 errdefer msg.destroy(gpa);
6586 try mod.errNote(&block.base, other_field_src, msg, "other field here", .{});
6587 break :msg msg;
6588 };
6589 return mod.failWithOwnedErrorMsg(&block.base, msg);
6590 }
6591 found_fields[field_index] = item.data.field_type;
6592 field_inits[field_index] = sema.resolveInst(item.data.init);
6593 }
65326594
6533 var field_i: u32 = 0;6595 var root_msg: ?*Module.ErrorMsg = null;
6534 var extra_index = extra.end;
65356596
6536 while (field_i < extra.data.fields_len) : (field_i += 1) {6597 for (found_fields) |field_type_inst, i| {
6537 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);6598 if (field_type_inst != 0) continue;
6538 extra_index = item.end;
65396599
6540 const field_type_data = zir_datas[item.data.field_type].pl_node;6600 // Check if the field has a default init.
6541 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };6601 const field = struct_obj.fields.values()[i];
6542 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;6602 if (field.default_val.tag() == .unreachable_value) {
6543 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);6603 const field_name = struct_obj.fields.keys()[i];
6544 const field_index = struct_obj.fields.getIndex(field_name) orelse6604 const template = "missing struct field: {s}";
6545 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);6605 const args = .{field_name};
6546 if (found_fields[field_index] != 0) {6606 if (root_msg) |msg| {
6547 const other_field_type = found_fields[field_index];6607 try mod.errNote(&block.base, src, msg, template, args);
6548 const other_field_type_data = zir_datas[other_field_type].pl_node;6608 } else {
6549 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_type_data.src_node };6609 root_msg = try mod.errMsg(&block.base, src, template, args);
6550 const msg = msg: {6610 }
6551 const msg = try mod.errMsg(&block.base, field_src, "duplicate field", .{});6611 } else {
6552 errdefer msg.destroy(gpa);6612 field_inits[i] = try sema.addConstant(field.ty, field.default_val);
6553 try mod.errNote(&block.base, other_field_src, msg, "other field here", .{});6613 }
6554 break :msg msg;6614 }
6555 };6615 if (root_msg) |msg| {
6616 const fqn = try struct_obj.getFullyQualifiedName(gpa);
6617 defer gpa.free(fqn);
6618 try mod.errNoteNonLazy(
6619 struct_obj.srcLoc(),
6620 msg,
6621 "struct '{s}' declared here",
6622 .{fqn},
6623 );
6556 return mod.failWithOwnedErrorMsg(&block.base, msg);6624 return mod.failWithOwnedErrorMsg(&block.base, msg);
6557 }6625 }
6558 found_fields[field_index] = item.data.field_type;
6559 field_inits[field_index] = sema.resolveInst(item.data.init);
6560 }
65616626
6562 var root_msg: ?*Module.ErrorMsg = null;6627 if (is_ref) {
6628 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit is_ref=true", .{});
6629 }
65636630
6564 for (found_fields) |field_type_inst, i| {6631 const is_comptime = for (field_inits) |field_init| {
6565 if (field_type_inst != 0) continue;6632 if (!(try sema.isComptimeKnown(block, src, field_init))) {
65666633 break false;
6567 // Check if the field has a default init.
6568 const field = struct_obj.fields.values()[i];
6569 if (field.default_val.tag() == .unreachable_value) {
6570 const field_name = struct_obj.fields.keys()[i];
6571 const template = "missing struct field: {s}";
6572 const args = .{field_name};
6573 if (root_msg) |msg| {
6574 try mod.errNote(&block.base, src, msg, template, args);
6575 } else {
6576 root_msg = try mod.errMsg(&block.base, src, template, args);
6577 }6634 }
6578 } else {6635 } else true;
6579 field_inits[i] = try sema.addConstant(field.ty, field.default_val);6636
6637 if (is_comptime) {
6638 const values = try sema.arena.alloc(Value, field_inits.len);
6639 for (field_inits) |field_init, i| {
6640 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;
6641 }
6642 return sema.addConstant(resolved_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));
6580 }6643 }
6581 }
6582 if (root_msg) |msg| {
6583 const fqn = try struct_obj.getFullyQualifiedName(gpa);
6584 defer gpa.free(fqn);
6585 try mod.errNoteNonLazy(
6586 struct_obj.srcLoc(),
6587 msg,
6588 "struct '{s}' declared here",
6589 .{fqn},
6590 );
6591 return mod.failWithOwnedErrorMsg(&block.base, msg);
6592 }
65936644
6594 if (is_ref) {6645 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{});
6595 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit is_ref=true", .{});6646 } else if (resolved_ty.cast(Type.Payload.Union)) |union_payload| {
6596 }6647 const union_obj = union_payload.data;
65976648
6598 const is_comptime = for (field_inits) |field_init| {6649 if (extra.data.fields_len != 1) {
6599 if (!(try sema.isComptimeKnown(block, src, field_init))) {6650 return sema.mod.fail(&block.base, src, "union initialization expects exactly one field", .{});
6600 break false;
6601 }6651 }
6602 } else true;
66036652
6604 if (is_comptime) {6653 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end);
6605 const values = try sema.arena.alloc(Value, field_inits.len);6654
6606 for (field_inits) |field_init, i| {6655 const field_type_data = zir_datas[item.data.field_type].pl_node;
6607 values[i] = (sema.resolveMaybeUndefVal(block, src, field_init) catch unreachable).?;6656 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_type_data.src_node };
6657 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
6658 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
6659 const field_index = union_obj.fields.getIndex(field_name) orelse
6660 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
6661
6662 if (is_ref) {
6663 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit is_ref=true union", .{});
6608 }6664 }
6609 return sema.addConstant(struct_ty, try Value.Tag.@"struct".create(sema.arena, values.ptr));
6610 }
66116665
6612 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known struct values", .{});6666 const init_inst = sema.resolveInst(item.data.init);
6667 if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
6668 return sema.addConstant(
6669 resolved_ty,
6670 try Value.Tag.@"union".create(sema.arena, .{
6671 .tag = try Value.Tag.int_u64.create(sema.arena, field_index),
6672 .val = val,
6673 }),
6674 );
6675 }
6676 return mod.fail(&block.base, src, "TODO: Sema.zirStructInit for runtime-known union values", .{});
6677 }
6678 unreachable;
6613}6679}
66146680
6615fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {6681fn zirStructInitAnon(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
...@@ -6647,17 +6713,25 @@ fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE...@@ -6647,17 +6713,25 @@ fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
6647 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;6713 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
6648 const src = inst_data.src();6714 const src = inst_data.src();
6649 const field_name = sema.code.nullTerminatedString(extra.name_start);6715 const field_name = sema.code.nullTerminatedString(extra.name_start);
6650 const unresolved_struct_type = try sema.resolveType(block, src, extra.container_type);6716 const unresolved_ty = try sema.resolveType(block, src, extra.container_type);
6651 if (unresolved_struct_type.zigTypeTag() != .Struct) {6717 const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_ty);
6652 return sema.mod.fail(&block.base, src, "expected struct; found '{}'", .{6718 switch (resolved_ty.zigTypeTag()) {
6653 unresolved_struct_type,6719 .Struct => {
6654 });6720 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
6721 const field = struct_obj.fields.get(field_name) orelse
6722 return sema.failWithBadFieldAccess(block, struct_obj, src, field_name);
6723 return sema.addType(field.ty);
6724 },
6725 .Union => {
6726 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
6727 const field = union_obj.fields.get(field_name) orelse
6728 return sema.failWithBadUnionFieldAccess(block, union_obj, src, field_name);
6729 return sema.addType(field.ty);
6730 },
6731 else => return sema.mod.fail(&block.base, src, "expected struct or union; found '{}'", .{
6732 resolved_ty,
6733 }),
6655 }6734 }
6656 const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);
6657 const struct_obj = struct_ty.castTag(.@"struct").?.data;
6658 const field = struct_obj.fields.get(field_name) orelse
6659 return sema.failWithBadFieldAccess(block, struct_obj, src, field_name);
6660 return sema.addType(field.ty);
6661}6735}
66626736
6663fn zirErrorReturnTrace(6737fn zirErrorReturnTrace(
...@@ -6732,7 +6806,54 @@ fn zirTagName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr...@@ -6732,7 +6806,54 @@ fn zirTagName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
6732fn zirReify(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6806fn zirReify(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6733 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6807 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6734 const src = inst_data.src();6808 const src = inst_data.src();
6735 return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify", .{});6809 const type_info_ty = try sema.getBuiltinType(block, src, "TypeInfo");
6810 const uncasted_operand = sema.resolveInst(inst_data.operand);
6811 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
6812 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
6813 const val = try sema.resolveConstValue(block, operand_src, type_info);
6814 const union_val = val.cast(Value.Payload.Union).?.data;
6815 const TypeInfoTag = std.meta.Tag(std.builtin.TypeInfo);
6816 const tag_index = @intCast(std.meta.Tag(TypeInfoTag), union_val.tag.toUnsignedInt());
6817 switch (@intToEnum(std.builtin.TypeId, tag_index)) {
6818 .Type => return Air.Inst.Ref.type_type,
6819 .Void => return Air.Inst.Ref.void_type,
6820 .Bool => return Air.Inst.Ref.bool_type,
6821 .NoReturn => return Air.Inst.Ref.noreturn_type,
6822 .Int => {
6823 const struct_val = union_val.val.castTag(.@"struct").?.data;
6824 // TODO use reflection instead of magic numbers here
6825 const signedness_val = struct_val[0];
6826 const bits_val = struct_val[1];
6827
6828 const signedness = signedness_val.toEnum(std.builtin.Signedness);
6829 const bits = @intCast(u16, bits_val.toUnsignedInt());
6830 const ty = switch (signedness) {
6831 .signed => try Type.Tag.int_signed.create(sema.arena, bits),
6832 .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits),
6833 };
6834 return sema.addType(ty);
6835 },
6836 .Float => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Float", .{}),
6837 .Pointer => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Pointer", .{}),
6838 .Array => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Array", .{}),
6839 .Struct => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Struct", .{}),
6840 .ComptimeFloat => return Air.Inst.Ref.comptime_float_type,
6841 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
6842 .Undefined => return Air.Inst.Ref.undefined_type,
6843 .Null => return Air.Inst.Ref.null_type,
6844 .Optional => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Optional", .{}),
6845 .ErrorUnion => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for ErrorUnion", .{}),
6846 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for ErrorSet", .{}),
6847 .Enum => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Enum", .{}),
6848 .Union => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Union", .{}),
6849 .Fn => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Fn", .{}),
6850 .BoundFn => @panic("TODO delete BoundFn from the language"),
6851 .Opaque => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Opaque", .{}),
6852 .Frame => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Frame", .{}),
6853 .AnyFrame => return Air.Inst.Ref.anyframe_type,
6854 .Vector => return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify for Vector", .{}),
6855 .EnumLiteral => return Air.Inst.Ref.enum_literal_type,
6856 }
6736}6857}
67376858
6738fn zirTypeName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6859fn zirTypeName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -8152,24 +8273,35 @@ fn elemPtrArray(...@@ -8152,24 +8273,35 @@ fn elemPtrArray(
8152 elem_index: Air.Inst.Ref,8273 elem_index: Air.Inst.Ref,
8153 elem_index_src: LazySrcLoc,8274 elem_index_src: LazySrcLoc,
8154) CompileError!Air.Inst.Ref {8275) CompileError!Air.Inst.Ref {
8276 const array_ptr_ty = sema.typeOf(array_ptr);
8277 const pointee_type = array_ptr_ty.elemType().elemType();
8278 const result_ty = if (array_ptr_ty.ptrIsMutable())
8279 try Type.Tag.single_mut_pointer.create(sema.arena, pointee_type)
8280 else
8281 try Type.Tag.single_const_pointer.create(sema.arena, pointee_type);
8282
8155 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {8283 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
8156 if (try sema.resolveDefinedValue(block, src, elem_index)) |index_val| {8284 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {
8157 // Both array pointer and index are compile-time known.8285 // Both array pointer and index are compile-time known.
8158 const index_u64 = index_val.toUnsignedInt();8286 const index_u64 = index_val.toUnsignedInt();
8159 // @intCast here because it would have been impossible to construct a value that8287 // @intCast here because it would have been impossible to construct a value that
8160 // required a larger index.8288 // required a larger index.
8161 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));8289 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
8162 const pointee_type = sema.typeOf(array_ptr).elemType().elemType();8290 return sema.addConstant(result_ty, elem_ptr);
8163
8164 return sema.addConstant(
8165 try Type.Tag.single_const_pointer.create(sema.arena, pointee_type),
8166 elem_ptr,
8167 );
8168 }8291 }
8169 }8292 }
8170 _ = elem_index;8293 // TODO safety check for array bounds
8171 _ = elem_index_src;8294 try sema.requireRuntimeBlock(block, src);
8172 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr for arrays", .{});8295 return block.addInst(.{
8296 .tag = .ptr_elem_ptr,
8297 .data = .{ .ty_pl = .{
8298 .ty = try sema.addType(result_ty),
8299 .payload = try sema.addExtra(Air.Bin{
8300 .lhs = array_ptr,
8301 .rhs = elem_index,
8302 }),
8303 } },
8304 });
8173}8305}
81748306
8175fn coerce(8307fn coerce(
...@@ -9177,22 +9309,62 @@ pub fn resolveTypeLayout(...@@ -9177,22 +9309,62 @@ pub fn resolveTypeLayout(
9177 }9309 }
9178}9310}
91799311
9180fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!Type {9312/// `sema` and `block` are expected to be the same ones used for the `Decl`.
9313pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !void {
9181 switch (ty.tag()) {9314 switch (ty.tag()) {
9182 .@"struct" => {9315 .@"struct" => {
9183 const struct_obj = ty.castTag(.@"struct").?.data;9316 const struct_obj = ty.castTag(.@"struct").?.data;
9317 if (struct_obj.owner_decl.namespace != sema.owner_decl.namespace) return;
9184 switch (struct_obj.status) {9318 switch (struct_obj.status) {
9185 .none => {},9319 .none => {},
9186 .field_types_wip => {9320 .field_types_wip => {
9187 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{ty});9321 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{ty});
9188 },9322 },
9189 .have_field_types, .have_layout, .layout_wip => return ty,9323 .have_field_types, .have_layout, .layout_wip => return,
9190 }9324 }
9325 const prev_namespace = sema.namespace;
9326 sema.namespace = &struct_obj.namespace;
9327 defer sema.namespace = prev_namespace;
9328
9191 struct_obj.status = .field_types_wip;9329 struct_obj.status = .field_types_wip;
9192 try sema.mod.analyzeStructFields(struct_obj);9330 try sema.analyzeStructFields(block, struct_obj);
9193 struct_obj.status = .have_field_types;9331 struct_obj.status = .have_field_types;
9194 return ty;
9195 },9332 },
9333 .@"union", .union_tagged => {
9334 const union_obj = ty.cast(Type.Payload.Union).?.data;
9335 if (union_obj.owner_decl.namespace != sema.owner_decl.namespace) return;
9336 switch (union_obj.status) {
9337 .none => {},
9338 .field_types_wip => {
9339 return sema.mod.fail(&block.base, src, "union {} depends on itself", .{ty});
9340 },
9341 .have_field_types, .have_layout, .layout_wip => return,
9342 }
9343 const prev_namespace = sema.namespace;
9344 sema.namespace = &union_obj.namespace;
9345 defer sema.namespace = prev_namespace;
9346
9347 union_obj.status = .field_types_wip;
9348 try sema.analyzeUnionFields(block, union_obj);
9349 union_obj.status = .have_field_types;
9350 },
9351 else => return,
9352 }
9353}
9354
9355fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!Type {
9356 switch (ty.tag()) {
9357 .@"struct" => {
9358 const struct_obj = ty.castTag(.@"struct").?.data;
9359 switch (struct_obj.status) {
9360 .none => unreachable,
9361 .field_types_wip => {
9362 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{ty});
9363 },
9364 .have_field_types, .have_layout, .layout_wip => return ty,
9365 }
9366 },
9367 .type_info => return sema.resolveBuiltinTypeFields(block, src, "TypeInfo"),
9196 .extern_options => return sema.resolveBuiltinTypeFields(block, src, "ExternOptions"),9368 .extern_options => return sema.resolveBuiltinTypeFields(block, src, "ExternOptions"),
9197 .export_options => return sema.resolveBuiltinTypeFields(block, src, "ExportOptions"),9369 .export_options => return sema.resolveBuiltinTypeFields(block, src, "ExportOptions"),
9198 .atomic_ordering => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrdering"),9370 .atomic_ordering => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrdering"),
...@@ -9205,18 +9377,12 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type...@@ -9205,18 +9377,12 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type
9205 .@"union", .union_tagged => {9377 .@"union", .union_tagged => {
9206 const union_obj = ty.cast(Type.Payload.Union).?.data;9378 const union_obj = ty.cast(Type.Payload.Union).?.data;
9207 switch (union_obj.status) {9379 switch (union_obj.status) {
9208 .none => {},9380 .none => unreachable,
9209 .field_types_wip => {9381 .field_types_wip => {
9210 return sema.mod.fail(&block.base, src, "union {} depends on itself", .{9382 return sema.mod.fail(&block.base, src, "union {} depends on itself", .{ty});
9211 ty,
9212 });
9213 },9383 },
9214 .have_field_types, .have_layout, .layout_wip => return ty,9384 .have_field_types, .have_layout, .layout_wip => return ty,
9215 }9385 }
9216 union_obj.status = .field_types_wip;
9217 try sema.mod.analyzeUnionFields(union_obj);
9218 union_obj.status = .have_field_types;
9219 return ty;
9220 },9386 },
9221 else => return ty,9387 else => return ty,
9222 }9388 }
...@@ -9232,6 +9398,265 @@ fn resolveBuiltinTypeFields(...@@ -9232,6 +9398,265 @@ fn resolveBuiltinTypeFields(
9232 return sema.resolveTypeFields(block, src, resolved_ty);9398 return sema.resolveTypeFields(block, src, resolved_ty);
9233}9399}
92349400
9401fn analyzeStructFields(
9402 sema: *Sema,
9403 block: *Scope.Block,
9404 struct_obj: *Module.Struct,
9405) CompileError!void {
9406 const tracy = trace(@src());
9407 defer tracy.end();
9408
9409 const gpa = sema.gpa;
9410 const zir = sema.code;
9411 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
9412 assert(extended.opcode == .struct_decl);
9413 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
9414 var extra_index: usize = extended.operand;
9415
9416 const src: LazySrcLoc = .{ .node_offset = struct_obj.node_offset };
9417 extra_index += @boolToInt(small.has_src_node);
9418
9419 const body_len = if (small.has_body_len) blk: {
9420 const body_len = zir.extra[extra_index];
9421 extra_index += 1;
9422 break :blk body_len;
9423 } else 0;
9424
9425 const fields_len = if (small.has_fields_len) blk: {
9426 const fields_len = zir.extra[extra_index];
9427 extra_index += 1;
9428 break :blk fields_len;
9429 } else 0;
9430
9431 const decls_len = if (small.has_decls_len) decls_len: {
9432 const decls_len = zir.extra[extra_index];
9433 extra_index += 1;
9434 break :decls_len decls_len;
9435 } else 0;
9436
9437 // Skip over decls.
9438 var decls_it = zir.declIteratorInner(extra_index, decls_len);
9439 while (decls_it.next()) |_| {}
9440 extra_index = decls_it.extra_index;
9441
9442 const body = zir.extra[extra_index..][0..body_len];
9443 if (fields_len == 0) {
9444 assert(body.len == 0);
9445 return;
9446 }
9447 extra_index += body.len;
9448
9449 var decl_arena = struct_obj.owner_decl.value_arena.?.promote(gpa);
9450 defer struct_obj.owner_decl.value_arena.?.* = decl_arena.state;
9451
9452 try struct_obj.fields.ensureTotalCapacity(&decl_arena.allocator, fields_len);
9453
9454 if (body.len != 0) {
9455 _ = try sema.analyzeBody(block, body);
9456 }
9457
9458 const bits_per_field = 4;
9459 const fields_per_u32 = 32 / bits_per_field;
9460 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
9461 var bit_bag_index: usize = extra_index;
9462 extra_index += bit_bags_count;
9463 var cur_bit_bag: u32 = undefined;
9464 var field_i: u32 = 0;
9465 while (field_i < fields_len) : (field_i += 1) {
9466 if (field_i % fields_per_u32 == 0) {
9467 cur_bit_bag = zir.extra[bit_bag_index];
9468 bit_bag_index += 1;
9469 }
9470 const has_align = @truncate(u1, cur_bit_bag) != 0;
9471 cur_bit_bag >>= 1;
9472 const has_default = @truncate(u1, cur_bit_bag) != 0;
9473 cur_bit_bag >>= 1;
9474 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
9475 cur_bit_bag >>= 1;
9476 const unused = @truncate(u1, cur_bit_bag) != 0;
9477 cur_bit_bag >>= 1;
9478
9479 _ = unused;
9480
9481 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
9482 extra_index += 1;
9483 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
9484 extra_index += 1;
9485
9486 // This string needs to outlive the ZIR code.
9487 const field_name = try decl_arena.allocator.dupe(u8, field_name_zir);
9488 const field_ty: Type = if (field_type_ref == .none)
9489 Type.initTag(.noreturn)
9490 else
9491 // TODO: if we need to report an error here, use a source location
9492 // that points to this type expression rather than the struct.
9493 // But only resolve the source location if we need to emit a compile error.
9494 try sema.resolveType(block, src, field_type_ref);
9495
9496 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
9497 assert(!gop.found_existing);
9498 gop.value_ptr.* = .{
9499 .ty = try field_ty.copy(&decl_arena.allocator),
9500 .abi_align = Value.initTag(.abi_align_default),
9501 .default_val = Value.initTag(.unreachable_value),
9502 .is_comptime = is_comptime,
9503 .offset = undefined,
9504 };
9505
9506 if (has_align) {
9507 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
9508 extra_index += 1;
9509 // TODO: if we need to report an error here, use a source location
9510 // that points to this alignment expression rather than the struct.
9511 // But only resolve the source location if we need to emit a compile error.
9512 const abi_align_val = (try sema.resolveInstConst(block, src, align_ref)).val;
9513 gop.value_ptr.abi_align = try abi_align_val.copy(&decl_arena.allocator);
9514 }
9515 if (has_default) {
9516 const default_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
9517 extra_index += 1;
9518 const default_inst = sema.resolveInst(default_ref);
9519 // TODO: if we need to report an error here, use a source location
9520 // that points to this default value expression rather than the struct.
9521 // But only resolve the source location if we need to emit a compile error.
9522 const default_val = (try sema.resolveMaybeUndefVal(block, src, default_inst)) orelse
9523 return sema.failWithNeededComptime(block, src);
9524 gop.value_ptr.default_val = try default_val.copy(&decl_arena.allocator);
9525 }
9526 }
9527}
9528
9529fn analyzeUnionFields(
9530 sema: *Sema,
9531 block: *Scope.Block,
9532 union_obj: *Module.Union,
9533) CompileError!void {
9534 const tracy = trace(@src());
9535 defer tracy.end();
9536
9537 const gpa = sema.gpa;
9538 const zir = sema.code;
9539 const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;
9540 assert(extended.opcode == .union_decl);
9541 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
9542 var extra_index: usize = extended.operand;
9543
9544 const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };
9545 extra_index += @boolToInt(small.has_src_node);
9546
9547 if (small.has_tag_type) {
9548 extra_index += 1;
9549 }
9550
9551 const body_len = if (small.has_body_len) blk: {
9552 const body_len = zir.extra[extra_index];
9553 extra_index += 1;
9554 break :blk body_len;
9555 } else 0;
9556
9557 const fields_len = if (small.has_fields_len) blk: {
9558 const fields_len = zir.extra[extra_index];
9559 extra_index += 1;
9560 break :blk fields_len;
9561 } else 0;
9562
9563 const decls_len = if (small.has_decls_len) decls_len: {
9564 const decls_len = zir.extra[extra_index];
9565 extra_index += 1;
9566 break :decls_len decls_len;
9567 } else 0;
9568
9569 // Skip over decls.
9570 var decls_it = zir.declIteratorInner(extra_index, decls_len);
9571 while (decls_it.next()) |_| {}
9572 extra_index = decls_it.extra_index;
9573
9574 const body = zir.extra[extra_index..][0..body_len];
9575 if (fields_len == 0) {
9576 assert(body.len == 0);
9577 return;
9578 }
9579 extra_index += body.len;
9580
9581 var decl_arena = union_obj.owner_decl.value_arena.?.promote(gpa);
9582 defer union_obj.owner_decl.value_arena.?.* = decl_arena.state;
9583
9584 try union_obj.fields.ensureCapacity(&decl_arena.allocator, fields_len);
9585
9586 if (body.len != 0) {
9587 _ = try sema.analyzeBody(block, body);
9588 }
9589
9590 const bits_per_field = 4;
9591 const fields_per_u32 = 32 / bits_per_field;
9592 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
9593 var bit_bag_index: usize = extra_index;
9594 extra_index += bit_bags_count;
9595 var cur_bit_bag: u32 = undefined;
9596 var field_i: u32 = 0;
9597 while (field_i < fields_len) : (field_i += 1) {
9598 if (field_i % fields_per_u32 == 0) {
9599 cur_bit_bag = zir.extra[bit_bag_index];
9600 bit_bag_index += 1;
9601 }
9602 const has_type = @truncate(u1, cur_bit_bag) != 0;
9603 cur_bit_bag >>= 1;
9604 const has_align = @truncate(u1, cur_bit_bag) != 0;
9605 cur_bit_bag >>= 1;
9606 const has_tag = @truncate(u1, cur_bit_bag) != 0;
9607 cur_bit_bag >>= 1;
9608 const unused = @truncate(u1, cur_bit_bag) != 0;
9609 cur_bit_bag >>= 1;
9610 _ = unused;
9611
9612 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
9613 extra_index += 1;
9614
9615 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
9616 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
9617 extra_index += 1;
9618 break :blk field_type_ref;
9619 } else .none;
9620
9621 const align_ref: Zir.Inst.Ref = if (has_align) blk: {
9622 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
9623 extra_index += 1;
9624 break :blk align_ref;
9625 } else .none;
9626
9627 if (has_tag) {
9628 extra_index += 1;
9629 }
9630
9631 // This string needs to outlive the ZIR code.
9632 const field_name = try decl_arena.allocator.dupe(u8, field_name_zir);
9633 const field_ty: Type = if (field_type_ref == .none)
9634 Type.initTag(.void)
9635 else
9636 // TODO: if we need to report an error here, use a source location
9637 // that points to this type expression rather than the union.
9638 // But only resolve the source location if we need to emit a compile error.
9639 try sema.resolveType(block, src, field_type_ref);
9640
9641 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
9642 assert(!gop.found_existing);
9643 gop.value_ptr.* = .{
9644 .ty = try field_ty.copy(&decl_arena.allocator),
9645 .abi_align = Value.initTag(.abi_align_default),
9646 };
9647
9648 if (align_ref != .none) {
9649 // TODO: if we need to report an error here, use a source location
9650 // that points to this alignment expression rather than the struct.
9651 // But only resolve the source location if we need to emit a compile error.
9652 const abi_align_val = (try sema.resolveInstConst(block, src, align_ref)).val;
9653 gop.value_ptr.abi_align = try abi_align_val.copy(&decl_arena.allocator);
9654 }
9655 }
9656
9657 // TODO resolve the union tag_type_ref
9658}
9659
9235fn getBuiltin(9660fn getBuiltin(
9236 sema: *Sema,9661 sema: *Sema,
9237 block: *Scope.Block,9662 block: *Scope.Block,
...@@ -9344,6 +9769,7 @@ fn typeHasOnePossibleValue(...@@ -9344,6 +9769,7 @@ fn typeHasOnePossibleValue(
9344 .call_options,9769 .call_options,
9345 .export_options,9770 .export_options,
9346 .extern_options,9771 .extern_options,
9772 .type_info,
9347 .@"anyframe",9773 .@"anyframe",
9348 .anyframe_T,9774 .anyframe_T,
9349 .many_const_pointer,9775 .many_const_pointer,
...@@ -9528,6 +9954,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {...@@ -9528,6 +9954,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
9528 .call_options => return .call_options_type,9954 .call_options => return .call_options_type,
9529 .export_options => return .export_options_type,9955 .export_options => return .export_options_type,
9530 .extern_options => return .extern_options_type,9956 .extern_options => return .extern_options_type,
9957 .type_info => return .type_info_type,
9531 .manyptr_u8 => return .manyptr_u8_type,9958 .manyptr_u8 => return .manyptr_u8_type,
9532 .manyptr_const_u8 => return .manyptr_const_u8_type,9959 .manyptr_const_u8 => return .manyptr_const_u8_type,
9533 .fn_noreturn_no_args => return .fn_noreturn_no_args_type,9960 .fn_noreturn_no_args => return .fn_noreturn_no_args_type,
src/Zir.zig+9-4
...@@ -687,14 +687,14 @@ pub const Inst = struct {...@@ -687,14 +687,14 @@ pub const Inst = struct {
687 /// A struct literal with a specified type, with no fields.687 /// A struct literal with a specified type, with no fields.
688 /// Uses the `un_node` field.688 /// Uses the `un_node` field.
689 struct_init_empty,689 struct_init_empty,
690 /// Given a struct, union, or enum, and a field name as a string index,690 /// Given a struct or union, and a field name as a string index,
691 /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`.691 /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`.
692 field_type,692 field_type,
693 /// Given a struct, union, or enum, and a field name as a Ref,693 /// Given a struct or union, and a field name as a Ref,
694 /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.694 /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.
695 field_type_ref,695 field_type_ref,
696 /// Finalizes a typed struct initialization, performs validation, and returns the696 /// Finalizes a typed struct or union initialization, performs validation, and returns the
697 /// struct value.697 /// struct or union value.
698 /// Uses the `pl_node` field. Payload is `StructInit`.698 /// Uses the `pl_node` field. Payload is `StructInit`.
699 struct_init,699 struct_init,
700 /// Struct initialization syntax, make the result a pointer.700 /// Struct initialization syntax, make the result a pointer.
...@@ -1703,6 +1703,7 @@ pub const Inst = struct {...@@ -1703,6 +1703,7 @@ pub const Inst = struct {
1703 call_options_type,1703 call_options_type,
1704 export_options_type,1704 export_options_type,
1705 extern_options_type,1705 extern_options_type,
1706 type_info_type,
1706 manyptr_u8_type,1707 manyptr_u8_type,
1707 manyptr_const_u8_type,1708 manyptr_const_u8_type,
1708 fn_noreturn_no_args_type,1709 fn_noreturn_no_args_type,
...@@ -1973,6 +1974,10 @@ pub const Inst = struct {...@@ -1973,6 +1974,10 @@ pub const Inst = struct {
1973 .ty = Type.initTag(.type),1974 .ty = Type.initTag(.type),
1974 .val = Value.initTag(.extern_options_type),1975 .val = Value.initTag(.extern_options_type),
1975 },1976 },
1977 .type_info_type = .{
1978 .ty = Type.initTag(.type),
1979 .val = Value.initTag(.type_info_type),
1980 },
19761981
1977 .undef = .{1982 .undef = .{
1978 .ty = Type.initTag(.@"undefined"),1983 .ty = Type.initTag(.@"undefined"),
src/codegen.zig+10
...@@ -862,6 +862,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -862,6 +862,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
862 .slice_elem_val => try self.airSliceElemVal(inst),862 .slice_elem_val => try self.airSliceElemVal(inst),
863 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),863 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
864 .ptr_elem_val => try self.airPtrElemVal(inst),864 .ptr_elem_val => try self.airPtrElemVal(inst),
865 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
865 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),866 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
866867
867 .constant => unreachable, // excluded from function bodies868 .constant => unreachable, // excluded from function bodies
...@@ -1419,6 +1420,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1419,6 +1420,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1419 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1420 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1420 }1421 }
14211422
1423 fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1424 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1425 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1426 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1427 else => return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch}),
1428 };
1429 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1430 }
1431
1422 fn airPtrPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {1432 fn airPtrPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
1423 const is_volatile = false; // TODO1433 const is_volatile = false; // TODO
1424 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1434 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
src/codegen/c.zig+8
...@@ -913,6 +913,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -913,6 +913,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
913913
914 .ptr_elem_val => try airPtrElemVal(o, inst, "["),914 .ptr_elem_val => try airPtrElemVal(o, inst, "["),
915 .ptr_ptr_elem_val => try airPtrElemVal(o, inst, "[0]["),915 .ptr_ptr_elem_val => try airPtrElemVal(o, inst, "[0]["),
916 .ptr_elem_ptr => try airPtrElemPtr(o, inst),
916 .slice_elem_val => try airSliceElemVal(o, inst, "["),917 .slice_elem_val => try airSliceElemVal(o, inst, "["),
917 .ptr_slice_elem_val => try airSliceElemVal(o, inst, "[0]["),918 .ptr_slice_elem_val => try airSliceElemVal(o, inst, "[0]["),
918919
...@@ -960,6 +961,13 @@ fn airPtrElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {...@@ -960,6 +961,13 @@ fn airPtrElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {
960 return o.dg.fail("TODO: C backend: airPtrElemVal", .{});961 return o.dg.fail("TODO: C backend: airPtrElemVal", .{});
961}962}
962963
964fn airPtrElemPtr(o: *Object, inst: Air.Inst.Index) !CValue {
965 if (o.liveness.isUnused(inst))
966 return CValue.none;
967
968 return o.dg.fail("TODO: C backend: airPtrElemPtr", .{});
969}
970
963fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {971fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {
964 const is_volatile = false; // TODO972 const is_volatile = false; // TODO
965 if (!is_volatile and o.liveness.isUnused(inst))973 if (!is_volatile and o.liveness.isUnused(inst))
src/codegen/llvm.zig+32-3
...@@ -432,6 +432,8 @@ pub const Object = struct {...@@ -432,6 +432,8 @@ pub const Object = struct {
432 },432 },
433 else => |e| return e,433 else => |e| return e,
434 };434 };
435 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
436 try self.updateDeclExports(module, decl, decl_exports);
435 }437 }
436438
437 pub fn updateDeclExports(439 pub fn updateDeclExports(
...@@ -440,7 +442,9 @@ pub const Object = struct {...@@ -440,7 +442,9 @@ pub const Object = struct {
440 decl: *const Module.Decl,442 decl: *const Module.Decl,
441 exports: []const *Module.Export,443 exports: []const *Module.Export,
442 ) !void {444 ) !void {
443 const llvm_fn = self.llvm_module.getNamedFunction(decl.name).?;445 // If the module does not already have the function, we ignore this function call
446 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
447 const llvm_fn = self.llvm_module.getNamedFunction(decl.name) orelse return;
444 const is_extern = decl.val.tag() == .extern_fn;448 const is_extern = decl.val.tag() == .extern_fn;
445 if (is_extern or exports.len != 0) {449 if (is_extern or exports.len != 0) {
446 llvm_fn.setLinkage(.External);450 llvm_fn.setLinkage(.External);
...@@ -1041,6 +1045,7 @@ pub const FuncGen = struct {...@@ -1041,6 +1045,7 @@ pub const FuncGen = struct {
1041 .slice_elem_val => try self.airSliceElemVal(inst),1045 .slice_elem_val => try self.airSliceElemVal(inst),
1042 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),1046 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
1043 .ptr_elem_val => try self.airPtrElemVal(inst),1047 .ptr_elem_val => try self.airPtrElemVal(inst),
1048 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
1044 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),1049 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
10451050
1046 .optional_payload => try self.airOptionalPayload(inst, false),1051 .optional_payload => try self.airOptionalPayload(inst, false),
...@@ -1296,11 +1301,35 @@ pub const FuncGen = struct {...@@ -1296,11 +1301,35 @@ pub const FuncGen = struct {
1296 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1301 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1297 const base_ptr = try self.resolveInst(bin_op.lhs);1302 const base_ptr = try self.resolveInst(bin_op.lhs);
1298 const rhs = try self.resolveInst(bin_op.rhs);1303 const rhs = try self.resolveInst(bin_op.rhs);
1299 const indices: [1]*const llvm.Value = .{rhs};1304 const ptr = if (self.air.typeOf(bin_op.lhs).isSinglePointer()) ptr: {
1300 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");1305 // If this is a single-item pointer to an array, we need another index in the GEP.
1306 const indices: [2]*const llvm.Value = .{ self.context.intType(32).constNull(), rhs };
1307 break :ptr self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
1308 } else ptr: {
1309 const indices: [1]*const llvm.Value = .{rhs};
1310 break :ptr self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
1311 };
1301 return self.builder.buildLoad(ptr, "");1312 return self.builder.buildLoad(ptr, "");
1302 }1313 }
13031314
1315 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1316 if (self.liveness.isUnused(inst))
1317 return null;
1318
1319 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1320 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1321 const base_ptr = try self.resolveInst(bin_op.lhs);
1322 const rhs = try self.resolveInst(bin_op.rhs);
1323 if (self.air.typeOf(bin_op.lhs).isSinglePointer()) {
1324 // If this is a single-item pointer to an array, we need another index in the GEP.
1325 const indices: [2]*const llvm.Value = .{ self.context.intType(32).constNull(), rhs };
1326 return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
1327 } else {
1328 const indices: [1]*const llvm.Value = .{rhs};
1329 return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
1330 }
1331 }
1332
1304 fn airPtrPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1333 fn airPtrPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1305 const is_volatile = false; // TODO1334 const is_volatile = false; // TODO
1306 if (!is_volatile and self.liveness.isUnused(inst))1335 if (!is_volatile and self.liveness.isUnused(inst))
src/print_air.zig+13-3
...@@ -175,6 +175,7 @@ const Writer = struct {...@@ -175,6 +175,7 @@ const Writer = struct {
175 .loop,175 .loop,
176 => try w.writeBlock(s, inst),176 => try w.writeBlock(s, inst),
177177
178 .ptr_elem_ptr => try w.writePtrElemPtr(s, inst),
178 .struct_field_ptr => try w.writeStructField(s, inst),179 .struct_field_ptr => try w.writeStructField(s, inst),
179 .struct_field_val => try w.writeStructField(s, inst),180 .struct_field_val => try w.writeStructField(s, inst),
180 .constant => try w.writeConstant(s, inst),181 .constant => try w.writeConstant(s, inst),
...@@ -239,10 +240,19 @@ const Writer = struct {...@@ -239,10 +240,19 @@ const Writer = struct {
239240
240 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {241 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
241 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;242 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
242 const extra = w.air.extraData(Air.StructField, ty_pl.payload);243 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
243244
244 try w.writeOperand(s, inst, 0, extra.data.struct_operand);245 try w.writeOperand(s, inst, 0, extra.struct_operand);
245 try s.print(", {d}", .{extra.data.field_index});246 try s.print(", {d}", .{extra.field_index});
247 }
248
249 fn writePtrElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
250 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
251 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
252
253 try w.writeOperand(s, inst, 0, extra.lhs);
254 try s.writeAll(", ");
255 try w.writeOperand(s, inst, 0, extra.rhs);
246 }256 }
247257
248 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {258 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
src/type.zig+39
...@@ -133,6 +133,7 @@ pub const Type = extern union {...@@ -133,6 +133,7 @@ pub const Type = extern union {
133133
134 .@"union",134 .@"union",
135 .union_tagged,135 .union_tagged,
136 .type_info,
136 => return .Union,137 => return .Union,
137138
138 .var_args_param => unreachable, // can be any type139 .var_args_param => unreachable, // can be any type
...@@ -248,6 +249,30 @@ pub const Type = extern union {...@@ -248,6 +249,30 @@ pub const Type = extern union {
248 };249 };
249 }250 }
250251
252 pub fn ptrIsMutable(ty: Type) bool {
253 return switch (ty.tag()) {
254 .single_const_pointer_to_comptime_int,
255 .const_slice_u8,
256 .single_const_pointer,
257 .many_const_pointer,
258 .manyptr_const_u8,
259 .c_const_pointer,
260 .const_slice,
261 => false,
262
263 .single_mut_pointer,
264 .many_mut_pointer,
265 .manyptr_u8,
266 .c_mut_pointer,
267 .mut_slice,
268 => true,
269
270 .pointer => ty.castTag(.pointer).?.data.mutable,
271
272 else => unreachable,
273 };
274 }
275
251 pub fn ptrInfo(self: Type) Payload.Pointer {276 pub fn ptrInfo(self: Type) Payload.Pointer {
252 switch (self.tag()) {277 switch (self.tag()) {
253 .single_const_pointer_to_comptime_int => return .{ .data = .{278 .single_const_pointer_to_comptime_int => return .{ .data = .{
...@@ -717,6 +742,7 @@ pub const Type = extern union {...@@ -717,6 +742,7 @@ pub const Type = extern union {
717 .call_options,742 .call_options,
718 .export_options,743 .export_options,
719 .extern_options,744 .extern_options,
745 .type_info,
720 .@"anyframe",746 .@"anyframe",
721 .generic_poison,747 .generic_poison,
722 => unreachable,748 => unreachable,
...@@ -928,6 +954,7 @@ pub const Type = extern union {...@@ -928,6 +954,7 @@ pub const Type = extern union {
928 .call_options => return writer.writeAll("std.builtin.CallOptions"),954 .call_options => return writer.writeAll("std.builtin.CallOptions"),
929 .export_options => return writer.writeAll("std.builtin.ExportOptions"),955 .export_options => return writer.writeAll("std.builtin.ExportOptions"),
930 .extern_options => return writer.writeAll("std.builtin.ExternOptions"),956 .extern_options => return writer.writeAll("std.builtin.ExternOptions"),
957 .type_info => return writer.writeAll("std.builtin.TypeInfo"),
931 .function => {958 .function => {
932 const payload = ty.castTag(.function).?.data;959 const payload = ty.castTag(.function).?.data;
933 try writer.writeAll("fn(");960 try writer.writeAll("fn(");
...@@ -1178,6 +1205,7 @@ pub const Type = extern union {...@@ -1178,6 +1205,7 @@ pub const Type = extern union {
1178 .comptime_int,1205 .comptime_int,
1179 .comptime_float,1206 .comptime_float,
1180 .enum_literal,1207 .enum_literal,
1208 .type_info,
1181 => true,1209 => true,
11821210
1183 .var_args_param => unreachable,1211 .var_args_param => unreachable,
...@@ -1269,6 +1297,7 @@ pub const Type = extern union {...@@ -1269,6 +1297,7 @@ pub const Type = extern union {
1269 .call_options => return Value.initTag(.call_options_type),1297 .call_options => return Value.initTag(.call_options_type),
1270 .export_options => return Value.initTag(.export_options_type),1298 .export_options => return Value.initTag(.export_options_type),
1271 .extern_options => return Value.initTag(.extern_options_type),1299 .extern_options => return Value.initTag(.extern_options_type),
1300 .type_info => return Value.initTag(.type_info_type),
1272 .inferred_alloc_const => unreachable,1301 .inferred_alloc_const => unreachable,
1273 .inferred_alloc_mut => unreachable,1302 .inferred_alloc_mut => unreachable,
1274 else => return Value.Tag.ty.create(allocator, self),1303 else => return Value.Tag.ty.create(allocator, self),
...@@ -1409,6 +1438,7 @@ pub const Type = extern union {...@@ -1409,6 +1438,7 @@ pub const Type = extern union {
1409 .empty_struct,1438 .empty_struct,
1410 .empty_struct_literal,1439 .empty_struct_literal,
1411 .@"opaque",1440 .@"opaque",
1441 .type_info,
1412 => false,1442 => false,
14131443
1414 .inferred_alloc_const => unreachable,1444 .inferred_alloc_const => unreachable,
...@@ -1636,6 +1666,7 @@ pub const Type = extern union {...@@ -1636,6 +1666,7 @@ pub const Type = extern union {
1636 .inferred_alloc_mut,1666 .inferred_alloc_mut,
1637 .@"opaque",1667 .@"opaque",
1638 .var_args_param,1668 .var_args_param,
1669 .type_info,
1639 => unreachable,1670 => unreachable,
16401671
1641 .generic_poison => unreachable,1672 .generic_poison => unreachable,
...@@ -1667,6 +1698,7 @@ pub const Type = extern union {...@@ -1667,6 +1698,7 @@ pub const Type = extern union {
1667 .@"opaque" => unreachable,1698 .@"opaque" => unreachable,
1668 .var_args_param => unreachable,1699 .var_args_param => unreachable,
1669 .generic_poison => unreachable,1700 .generic_poison => unreachable,
1701 .type_info => unreachable,
16701702
1671 .@"struct" => {1703 .@"struct" => {
1672 const s = self.castTag(.@"struct").?.data;1704 const s = self.castTag(.@"struct").?.data;
...@@ -1978,6 +2010,7 @@ pub const Type = extern union {...@@ -1978,6 +2010,7 @@ pub const Type = extern union {
1978 .call_options,2010 .call_options,
1979 .export_options,2011 .export_options,
1980 .extern_options,2012 .extern_options,
2013 .type_info,
1981 => @panic("TODO at some point we gotta resolve builtin types"),2014 => @panic("TODO at some point we gotta resolve builtin types"),
1982 };2015 };
1983 }2016 }
...@@ -2691,6 +2724,7 @@ pub const Type = extern union {...@@ -2691,6 +2724,7 @@ pub const Type = extern union {
2691 .call_options,2724 .call_options,
2692 .export_options,2725 .export_options,
2693 .extern_options,2726 .extern_options,
2727 .type_info,
2694 .@"anyframe",2728 .@"anyframe",
2695 .anyframe_T,2729 .anyframe_T,
2696 .many_const_pointer,2730 .many_const_pointer,
...@@ -2778,6 +2812,7 @@ pub const Type = extern union {...@@ -2778,6 +2812,7 @@ pub const Type = extern union {
2778 return switch (self.tag()) {2812 return switch (self.tag()) {
2779 .@"struct" => &self.castTag(.@"struct").?.data.namespace,2813 .@"struct" => &self.castTag(.@"struct").?.data.namespace,
2780 .enum_full => &self.castTag(.enum_full).?.data.namespace,2814 .enum_full => &self.castTag(.enum_full).?.data.namespace,
2815 .enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace,
2781 .empty_struct => self.castTag(.empty_struct).?.data,2816 .empty_struct => self.castTag(.empty_struct).?.data,
2782 .@"opaque" => &self.castTag(.@"opaque").?.data,2817 .@"opaque" => &self.castTag(.@"opaque").?.data,
2783 .@"union" => &self.castTag(.@"union").?.data.namespace,2818 .@"union" => &self.castTag(.@"union").?.data.namespace,
...@@ -3022,6 +3057,7 @@ pub const Type = extern union {...@@ -3022,6 +3057,7 @@ pub const Type = extern union {
3022 .call_options,3057 .call_options,
3023 .export_options,3058 .export_options,
3024 .extern_options,3059 .extern_options,
3060 .type_info,
3025 => @panic("TODO resolve std.builtin types"),3061 => @panic("TODO resolve std.builtin types"),
3026 else => unreachable,3062 else => unreachable,
3027 }3063 }
...@@ -3058,6 +3094,7 @@ pub const Type = extern union {...@@ -3058,6 +3094,7 @@ pub const Type = extern union {
3058 .call_options,3094 .call_options,
3059 .export_options,3095 .export_options,
3060 .extern_options,3096 .extern_options,
3097 .type_info,
3061 => @panic("TODO resolve std.builtin types"),3098 => @panic("TODO resolve std.builtin types"),
3062 else => unreachable,3099 else => unreachable,
3063 }3100 }
...@@ -3167,6 +3204,7 @@ pub const Type = extern union {...@@ -3167,6 +3204,7 @@ pub const Type = extern union {
3167 call_options,3204 call_options,
3168 export_options,3205 export_options,
3169 extern_options,3206 extern_options,
3207 type_info,
3170 manyptr_u8,3208 manyptr_u8,
3171 manyptr_const_u8,3209 manyptr_const_u8,
3172 fn_noreturn_no_args,3210 fn_noreturn_no_args,
...@@ -3289,6 +3327,7 @@ pub const Type = extern union {...@@ -3289,6 +3327,7 @@ pub const Type = extern union {
3289 .call_options,3327 .call_options,
3290 .export_options,3328 .export_options,
3291 .extern_options,3329 .extern_options,
3330 .type_info,
3292 .@"anyframe",3331 .@"anyframe",
3293 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),3332 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
32943333
src/value.zig+30
...@@ -68,6 +68,7 @@ pub const Value = extern union {...@@ -68,6 +68,7 @@ pub const Value = extern union {
68 call_options_type,68 call_options_type,
69 export_options_type,69 export_options_type,
70 extern_options_type,70 extern_options_type,
71 type_info_type,
71 manyptr_u8_type,72 manyptr_u8_type,
72 manyptr_const_u8_type,73 manyptr_const_u8_type,
73 fn_noreturn_no_args_type,74 fn_noreturn_no_args_type,
...@@ -221,6 +222,7 @@ pub const Value = extern union {...@@ -221,6 +222,7 @@ pub const Value = extern union {
221 .call_options_type,222 .call_options_type,
222 .export_options_type,223 .export_options_type,
223 .extern_options_type,224 .extern_options_type,
225 .type_info_type,
224 .generic_poison,226 .generic_poison,
225 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),227 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
226228
...@@ -402,6 +404,7 @@ pub const Value = extern union {...@@ -402,6 +404,7 @@ pub const Value = extern union {
402 .call_options_type,404 .call_options_type,
403 .export_options_type,405 .export_options_type,
404 .extern_options_type,406 .extern_options_type,
407 .type_info_type,
405 .generic_poison,408 .generic_poison,
406 => unreachable,409 => unreachable,
407410
...@@ -585,6 +588,7 @@ pub const Value = extern union {...@@ -585,6 +588,7 @@ pub const Value = extern union {
585 .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"),588 .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"),
586 .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"),589 .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"),
587 .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"),590 .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"),
591 .type_info_type => return out_stream.writeAll("std.builtin.TypeInfo"),
588 .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),592 .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),
589593
590 .empty_struct_value => return out_stream.writeAll("struct {}{}"),594 .empty_struct_value => return out_stream.writeAll("struct {}{}"),
...@@ -743,6 +747,7 @@ pub const Value = extern union {...@@ -743,6 +747,7 @@ pub const Value = extern union {
743 .call_options_type => Type.initTag(.call_options),747 .call_options_type => Type.initTag(.call_options),
744 .export_options_type => Type.initTag(.export_options),748 .export_options_type => Type.initTag(.export_options),
745 .extern_options_type => Type.initTag(.extern_options),749 .extern_options_type => Type.initTag(.extern_options),
750 .type_info_type => Type.initTag(.type_info),
746751
747 .int_type => {752 .int_type => {
748 const payload = self.castTag(.int_type).?.data;753 const payload = self.castTag(.int_type).?.data;
...@@ -1514,6 +1519,31 @@ pub const Value = extern union {...@@ -1514,6 +1519,31 @@ pub const Value = extern union {
1514 return Tag.int_u64.create(arena, truncated);1519 return Tag.int_u64.create(arena, truncated);
1515 }1520 }
15161521
1522 pub fn shr(lhs: Value, rhs: Value, allocator: *Allocator) !Value {
1523 // TODO is this a performance issue? maybe we should try the operation without
1524 // resorting to BigInt first.
1525 var lhs_space: Value.BigIntSpace = undefined;
1526 const lhs_bigint = lhs.toBigInt(&lhs_space);
1527 const shift = rhs.toUnsignedInt();
1528 const limbs = try allocator.alloc(
1529 std.math.big.Limb,
1530 lhs_bigint.limbs.len - (shift / (@sizeOf(std.math.big.Limb) * 8)),
1531 );
1532 var result_bigint = BigIntMutable{
1533 .limbs = limbs,
1534 .positive = undefined,
1535 .len = undefined,
1536 };
1537 result_bigint.shiftRight(lhs_bigint, shift);
1538 const result_limbs = result_bigint.limbs[0..result_bigint.len];
1539
1540 if (result_bigint.positive) {
1541 return Value.Tag.int_big_positive.create(allocator, result_limbs);
1542 } else {
1543 return Value.Tag.int_big_negative.create(allocator, result_limbs);
1544 }
1545 }
1546
1517 pub fn floatAdd(1547 pub fn floatAdd(
1518 lhs: Value,1548 lhs: Value,
1519 rhs: Value,1549 rhs: Value,
test/behavior.zig+2-1
...@@ -9,12 +9,13 @@ test {...@@ -9,12 +9,13 @@ test {
9 _ = @import("behavior/pointers.zig");9 _ = @import("behavior/pointers.zig");
10 _ = @import("behavior/if.zig");10 _ = @import("behavior/if.zig");
11 _ = @import("behavior/cast.zig");11 _ = @import("behavior/cast.zig");
12 _ = @import("behavior/array.zig");
1213
13 if (!builtin.zig_is_stage2) {14 if (!builtin.zig_is_stage2) {
14 // Tests that only pass for stage1.15 // Tests that only pass for stage1.
15 _ = @import("behavior/align.zig");16 _ = @import("behavior/align.zig");
16 _ = @import("behavior/alignof.zig");17 _ = @import("behavior/alignof.zig");
17 _ = @import("behavior/array.zig");18 _ = @import("behavior/array_stage1.zig");
18 if (builtin.os.tag != .wasi) {19 if (builtin.os.tag != .wasi) {
19 _ = @import("behavior/asm.zig");20 _ = @import("behavior/asm.zig");
20 _ = @import("behavior/async_fn.zig");21 _ = @import("behavior/async_fn.zig");
test/behavior/array.zig-484
...@@ -3,487 +3,3 @@ const testing = std.testing;...@@ -3,487 +3,3 @@ const testing = std.testing;
3const mem = std.mem;3const mem = std.mem;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
6
7test "arrays" {
8 var array: [5]u32 = undefined;
9
10 var i: u32 = 0;
11 while (i < 5) {
12 array[i] = i + 1;
13 i = array[i];
14 }
15
16 i = 0;
17 var accumulator = @as(u32, 0);
18 while (i < 5) {
19 accumulator += array[i];
20
21 i += 1;
22 }
23
24 try expect(accumulator == 15);
25 try expect(getArrayLen(&array) == 5);
26}
27fn getArrayLen(a: []const u32) usize {
28 return a.len;
29}
30
31test "array with sentinels" {
32 const S = struct {
33 fn doTheTest(is_ct: bool) !void {
34 if (is_ct) {
35 var zero_sized: [0:0xde]u8 = [_:0xde]u8{};
36 // Disabled at runtime because of
37 // https://github.com/ziglang/zig/issues/4372
38 try expectEqual(@as(u8, 0xde), zero_sized[0]);
39 var reinterpreted = @ptrCast(*[1]u8, &zero_sized);
40 try expectEqual(@as(u8, 0xde), reinterpreted[0]);
41 }
42 var arr: [3:0x55]u8 = undefined;
43 // Make sure the sentinel pointer is pointing after the last element
44 if (!is_ct) {
45 const sentinel_ptr = @ptrToInt(&arr[3]);
46 const last_elem_ptr = @ptrToInt(&arr[2]);
47 try expectEqual(@as(usize, 1), sentinel_ptr - last_elem_ptr);
48 }
49 // Make sure the sentinel is writeable
50 arr[3] = 0x55;
51 }
52 };
53
54 try S.doTheTest(false);
55 comptime try S.doTheTest(true);
56}
57
58test "void arrays" {
59 var array: [4]void = undefined;
60 array[0] = void{};
61 array[1] = array[2];
62 try expect(@sizeOf(@TypeOf(array)) == 0);
63 try expect(array.len == 4);
64}
65
66test "array literal" {
67 const hex_mult = [_]u16{
68 4096,
69 256,
70 16,
71 1,
72 };
73
74 try expect(hex_mult.len == 4);
75 try expect(hex_mult[1] == 256);
76}
77
78test "array dot len const expr" {
79 try expect(comptime x: {
80 break :x some_array.len == 4;
81 });
82}
83
84const ArrayDotLenConstExpr = struct {
85 y: [some_array.len]u8,
86};
87const some_array = [_]u8{
88 0,
89 1,
90 2,
91 3,
92};
93
94test "nested arrays" {
95 const array_of_strings = [_][]const u8{
96 "hello",
97 "this",
98 "is",
99 "my",
100 "thing",
101 };
102 for (array_of_strings) |s, i| {
103 if (i == 0) try expect(mem.eql(u8, s, "hello"));
104 if (i == 1) try expect(mem.eql(u8, s, "this"));
105 if (i == 2) try expect(mem.eql(u8, s, "is"));
106 if (i == 3) try expect(mem.eql(u8, s, "my"));
107 if (i == 4) try expect(mem.eql(u8, s, "thing"));
108 }
109}
110
111var s_array: [8]Sub = undefined;
112const Sub = struct {
113 b: u8,
114};
115const Str = struct {
116 a: []Sub,
117};
118test "set global var array via slice embedded in struct" {
119 var s = Str{ .a = s_array[0..] };
120
121 s.a[0].b = 1;
122 s.a[1].b = 2;
123 s.a[2].b = 3;
124
125 try expect(s_array[0].b == 1);
126 try expect(s_array[1].b == 2);
127 try expect(s_array[2].b == 3);
128}
129
130test "array literal with specified size" {
131 var array = [2]u8{
132 1,
133 2,
134 };
135 try expect(array[0] == 1);
136 try expect(array[1] == 2);
137}
138
139test "array len field" {
140 var arr = [4]u8{ 0, 0, 0, 0 };
141 var ptr = &arr;
142 try expect(arr.len == 4);
143 comptime try expect(arr.len == 4);
144 try expect(ptr.len == 4);
145 comptime try expect(ptr.len == 4);
146}
147
148test "single-item pointer to array indexing and slicing" {
149 try testSingleItemPtrArrayIndexSlice();
150 comptime try testSingleItemPtrArrayIndexSlice();
151}
152
153fn testSingleItemPtrArrayIndexSlice() !void {
154 {
155 var array: [4]u8 = "aaaa".*;
156 doSomeMangling(&array);
157 try expect(mem.eql(u8, "azya", &array));
158 }
159 {
160 var array = "aaaa".*;
161 doSomeMangling(&array);
162 try expect(mem.eql(u8, "azya", &array));
163 }
164}
165
166fn doSomeMangling(array: *[4]u8) void {
167 array[1] = 'z';
168 array[2..3][0] = 'y';
169}
170
171test "implicit cast single-item pointer" {
172 try testImplicitCastSingleItemPtr();
173 comptime try testImplicitCastSingleItemPtr();
174}
175
176fn testImplicitCastSingleItemPtr() !void {
177 var byte: u8 = 100;
178 const slice = @as(*[1]u8, &byte)[0..];
179 slice[0] += 1;
180 try expect(byte == 101);
181}
182
183fn testArrayByValAtComptime(b: [2]u8) u8 {
184 return b[0];
185}
186
187test "comptime evalutating function that takes array by value" {
188 const arr = [_]u8{ 0, 1 };
189 _ = comptime testArrayByValAtComptime(arr);
190 _ = comptime testArrayByValAtComptime(arr);
191}
192
193test "implicit comptime in array type size" {
194 var arr: [plusOne(10)]bool = undefined;
195 try expect(arr.len == 11);
196}
197
198fn plusOne(x: u32) u32 {
199 return x + 1;
200}
201
202test "runtime initialize array elem and then implicit cast to slice" {
203 var two: i32 = 2;
204 const x: []const i32 = &[_]i32{two};
205 try expect(x[0] == 2);
206}
207
208test "array literal as argument to function" {
209 const S = struct {
210 fn entry(two: i32) !void {
211 try foo(&[_]i32{
212 1,
213 2,
214 3,
215 });
216 try foo(&[_]i32{
217 1,
218 two,
219 3,
220 });
221 try foo2(true, &[_]i32{
222 1,
223 2,
224 3,
225 });
226 try foo2(true, &[_]i32{
227 1,
228 two,
229 3,
230 });
231 }
232 fn foo(x: []const i32) !void {
233 try expect(x[0] == 1);
234 try expect(x[1] == 2);
235 try expect(x[2] == 3);
236 }
237 fn foo2(trash: bool, x: []const i32) !void {
238 try expect(trash);
239 try expect(x[0] == 1);
240 try expect(x[1] == 2);
241 try expect(x[2] == 3);
242 }
243 };
244 try S.entry(2);
245 comptime try S.entry(2);
246}
247
248test "double nested array to const slice cast in array literal" {
249 const S = struct {
250 fn entry(two: i32) !void {
251 const cases = [_][]const []const i32{
252 &[_][]const i32{&[_]i32{1}},
253 &[_][]const i32{&[_]i32{ 2, 3 }},
254 &[_][]const i32{
255 &[_]i32{4},
256 &[_]i32{ 5, 6, 7 },
257 },
258 };
259 try check(&cases);
260
261 const cases2 = [_][]const i32{
262 &[_]i32{1},
263 &[_]i32{ two, 3 },
264 };
265 try expect(cases2.len == 2);
266 try expect(cases2[0].len == 1);
267 try expect(cases2[0][0] == 1);
268 try expect(cases2[1].len == 2);
269 try expect(cases2[1][0] == 2);
270 try expect(cases2[1][1] == 3);
271
272 const cases3 = [_][]const []const i32{
273 &[_][]const i32{&[_]i32{1}},
274 &[_][]const i32{&[_]i32{ two, 3 }},
275 &[_][]const i32{
276 &[_]i32{4},
277 &[_]i32{ 5, 6, 7 },
278 },
279 };
280 try check(&cases3);
281 }
282
283 fn check(cases: []const []const []const i32) !void {
284 try expect(cases.len == 3);
285 try expect(cases[0].len == 1);
286 try expect(cases[0][0].len == 1);
287 try expect(cases[0][0][0] == 1);
288 try expect(cases[1].len == 1);
289 try expect(cases[1][0].len == 2);
290 try expect(cases[1][0][0] == 2);
291 try expect(cases[1][0][1] == 3);
292 try expect(cases[2].len == 2);
293 try expect(cases[2][0].len == 1);
294 try expect(cases[2][0][0] == 4);
295 try expect(cases[2][1].len == 3);
296 try expect(cases[2][1][0] == 5);
297 try expect(cases[2][1][1] == 6);
298 try expect(cases[2][1][2] == 7);
299 }
300 };
301 try S.entry(2);
302 comptime try S.entry(2);
303}
304
305test "read/write through global variable array of struct fields initialized via array mult" {
306 const S = struct {
307 fn doTheTest() !void {
308 try expect(storage[0].term == 1);
309 storage[0] = MyStruct{ .term = 123 };
310 try expect(storage[0].term == 123);
311 }
312
313 pub const MyStruct = struct {
314 term: usize,
315 };
316
317 var storage: [1]MyStruct = [_]MyStruct{MyStruct{ .term = 1 }} ** 1;
318 };
319 try S.doTheTest();
320}
321
322test "implicit cast zero sized array ptr to slice" {
323 {
324 var b = "".*;
325 const c: []const u8 = &b;
326 try expect(c.len == 0);
327 }
328 {
329 var b: [0]u8 = "".*;
330 const c: []const u8 = &b;
331 try expect(c.len == 0);
332 }
333}
334
335test "anonymous list literal syntax" {
336 const S = struct {
337 fn doTheTest() !void {
338 var array: [4]u8 = .{ 1, 2, 3, 4 };
339 try expect(array[0] == 1);
340 try expect(array[1] == 2);
341 try expect(array[2] == 3);
342 try expect(array[3] == 4);
343 }
344 };
345 try S.doTheTest();
346 comptime try S.doTheTest();
347}
348
349test "anonymous literal in array" {
350 const S = struct {
351 const Foo = struct {
352 a: usize = 2,
353 b: usize = 4,
354 };
355 fn doTheTest() !void {
356 var array: [2]Foo = .{
357 .{ .a = 3 },
358 .{ .b = 3 },
359 };
360 try expect(array[0].a == 3);
361 try expect(array[0].b == 4);
362 try expect(array[1].a == 2);
363 try expect(array[1].b == 3);
364 }
365 };
366 try S.doTheTest();
367 comptime try S.doTheTest();
368}
369
370test "access the null element of a null terminated array" {
371 const S = struct {
372 fn doTheTest() !void {
373 var array: [4:0]u8 = .{ 'a', 'o', 'e', 'u' };
374 try expect(array[4] == 0);
375 var len: usize = 4;
376 try expect(array[len] == 0);
377 }
378 };
379 try S.doTheTest();
380 comptime try S.doTheTest();
381}
382
383test "type deduction for array subscript expression" {
384 const S = struct {
385 fn doTheTest() !void {
386 var array = [_]u8{ 0x55, 0xAA };
387 var v0 = true;
388 try expectEqual(@as(u8, 0xAA), array[if (v0) 1 else 0]);
389 var v1 = false;
390 try expectEqual(@as(u8, 0x55), array[if (v1) 1 else 0]);
391 }
392 };
393 try S.doTheTest();
394 comptime try S.doTheTest();
395}
396
397test "sentinel element count towards the ABI size calculation" {
398 const S = struct {
399 fn doTheTest() !void {
400 const T = packed struct {
401 fill_pre: u8 = 0x55,
402 data: [0:0]u8 = undefined,
403 fill_post: u8 = 0xAA,
404 };
405 var x = T{};
406 var as_slice = mem.asBytes(&x);
407 try expectEqual(@as(usize, 3), as_slice.len);
408 try expectEqual(@as(u8, 0x55), as_slice[0]);
409 try expectEqual(@as(u8, 0xAA), as_slice[2]);
410 }
411 };
412
413 try S.doTheTest();
414 comptime try S.doTheTest();
415}
416
417test "zero-sized array with recursive type definition" {
418 const U = struct {
419 fn foo(comptime T: type, comptime n: usize) type {
420 return struct {
421 s: [n]T,
422 x: usize = n,
423 };
424 }
425 };
426
427 const S = struct {
428 list: U.foo(@This(), 0),
429 };
430
431 var t: S = .{ .list = .{ .s = undefined } };
432 try expectEqual(@as(usize, 0), t.list.x);
433}
434
435test "type coercion of anon struct literal to array" {
436 const S = struct {
437 const U = union {
438 a: u32,
439 b: bool,
440 c: []const u8,
441 };
442
443 fn doTheTest() !void {
444 var x1: u8 = 42;
445 const t1 = .{ x1, 56, 54 };
446 var arr1: [3]u8 = t1;
447 try expect(arr1[0] == 42);
448 try expect(arr1[1] == 56);
449 try expect(arr1[2] == 54);
450
451 var x2: U = .{ .a = 42 };
452 const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } };
453 var arr2: [3]U = t2;
454 try expect(arr2[0].a == 42);
455 try expect(arr2[1].b == true);
456 try expect(mem.eql(u8, arr2[2].c, "hello"));
457 }
458 };
459 try S.doTheTest();
460 comptime try S.doTheTest();
461}
462
463test "type coercion of pointer to anon struct literal to pointer to array" {
464 const S = struct {
465 const U = union {
466 a: u32,
467 b: bool,
468 c: []const u8,
469 };
470
471 fn doTheTest() !void {
472 var x1: u8 = 42;
473 const t1 = &.{ x1, 56, 54 };
474 var arr1: *const [3]u8 = t1;
475 try expect(arr1[0] == 42);
476 try expect(arr1[1] == 56);
477 try expect(arr1[2] == 54);
478
479 var x2: U = .{ .a = 42 };
480 const t2 = &.{ x2, .{ .b = true }, .{ .c = "hello" } };
481 var arr2: *const [3]U = t2;
482 try expect(arr2[0].a == 42);
483 try expect(arr2[1].b == true);
484 try expect(mem.eql(u8, arr2[2].c, "hello"));
485 }
486 };
487 try S.doTheTest();
488 comptime try S.doTheTest();
489}
test/behavior/array_stage1.zig created+489
...@@ -0,0 +1,489 @@
1const std = @import("std");
2const testing = std.testing;
3const mem = std.mem;
4const expect = testing.expect;
5const expectEqual = testing.expectEqual;
6
7test "arrays" {
8 var array: [5]u32 = undefined;
9
10 var i: u32 = 0;
11 while (i < 5) {
12 array[i] = i + 1;
13 i = array[i];
14 }
15
16 i = 0;
17 var accumulator = @as(u32, 0);
18 while (i < 5) {
19 accumulator += array[i];
20
21 i += 1;
22 }
23
24 try expect(accumulator == 15);
25 try expect(getArrayLen(&array) == 5);
26}
27fn getArrayLen(a: []const u32) usize {
28 return a.len;
29}
30
31test "array with sentinels" {
32 const S = struct {
33 fn doTheTest(is_ct: bool) !void {
34 if (is_ct) {
35 var zero_sized: [0:0xde]u8 = [_:0xde]u8{};
36 // Disabled at runtime because of
37 // https://github.com/ziglang/zig/issues/4372
38 try expectEqual(@as(u8, 0xde), zero_sized[0]);
39 var reinterpreted = @ptrCast(*[1]u8, &zero_sized);
40 try expectEqual(@as(u8, 0xde), reinterpreted[0]);
41 }
42 var arr: [3:0x55]u8 = undefined;
43 // Make sure the sentinel pointer is pointing after the last element
44 if (!is_ct) {
45 const sentinel_ptr = @ptrToInt(&arr[3]);
46 const last_elem_ptr = @ptrToInt(&arr[2]);
47 try expectEqual(@as(usize, 1), sentinel_ptr - last_elem_ptr);
48 }
49 // Make sure the sentinel is writeable
50 arr[3] = 0x55;
51 }
52 };
53
54 try S.doTheTest(false);
55 comptime try S.doTheTest(true);
56}
57
58test "void arrays" {
59 var array: [4]void = undefined;
60 array[0] = void{};
61 array[1] = array[2];
62 try expect(@sizeOf(@TypeOf(array)) == 0);
63 try expect(array.len == 4);
64}
65
66test "array literal" {
67 const hex_mult = [_]u16{
68 4096,
69 256,
70 16,
71 1,
72 };
73
74 try expect(hex_mult.len == 4);
75 try expect(hex_mult[1] == 256);
76}
77
78test "array dot len const expr" {
79 try expect(comptime x: {
80 break :x some_array.len == 4;
81 });
82}
83
84const ArrayDotLenConstExpr = struct {
85 y: [some_array.len]u8,
86};
87const some_array = [_]u8{
88 0,
89 1,
90 2,
91 3,
92};
93
94test "nested arrays" {
95 const array_of_strings = [_][]const u8{
96 "hello",
97 "this",
98 "is",
99 "my",
100 "thing",
101 };
102 for (array_of_strings) |s, i| {
103 if (i == 0) try expect(mem.eql(u8, s, "hello"));
104 if (i == 1) try expect(mem.eql(u8, s, "this"));
105 if (i == 2) try expect(mem.eql(u8, s, "is"));
106 if (i == 3) try expect(mem.eql(u8, s, "my"));
107 if (i == 4) try expect(mem.eql(u8, s, "thing"));
108 }
109}
110
111var s_array: [8]Sub = undefined;
112const Sub = struct {
113 b: u8,
114};
115const Str = struct {
116 a: []Sub,
117};
118test "set global var array via slice embedded in struct" {
119 var s = Str{ .a = s_array[0..] };
120
121 s.a[0].b = 1;
122 s.a[1].b = 2;
123 s.a[2].b = 3;
124
125 try expect(s_array[0].b == 1);
126 try expect(s_array[1].b == 2);
127 try expect(s_array[2].b == 3);
128}
129
130test "array literal with specified size" {
131 var array = [2]u8{
132 1,
133 2,
134 };
135 try expect(array[0] == 1);
136 try expect(array[1] == 2);
137}
138
139test "array len field" {
140 var arr = [4]u8{ 0, 0, 0, 0 };
141 var ptr = &arr;
142 try expect(arr.len == 4);
143 comptime try expect(arr.len == 4);
144 try expect(ptr.len == 4);
145 comptime try expect(ptr.len == 4);
146}
147
148test "single-item pointer to array indexing and slicing" {
149 try testSingleItemPtrArrayIndexSlice();
150 comptime try testSingleItemPtrArrayIndexSlice();
151}
152
153fn testSingleItemPtrArrayIndexSlice() !void {
154 {
155 var array: [4]u8 = "aaaa".*;
156 doSomeMangling(&array);
157 try expect(mem.eql(u8, "azya", &array));
158 }
159 {
160 var array = "aaaa".*;
161 doSomeMangling(&array);
162 try expect(mem.eql(u8, "azya", &array));
163 }
164}
165
166fn doSomeMangling(array: *[4]u8) void {
167 array[1] = 'z';
168 array[2..3][0] = 'y';
169}
170
171test "implicit cast single-item pointer" {
172 try testImplicitCastSingleItemPtr();
173 comptime try testImplicitCastSingleItemPtr();
174}
175
176fn testImplicitCastSingleItemPtr() !void {
177 var byte: u8 = 100;
178 const slice = @as(*[1]u8, &byte)[0..];
179 slice[0] += 1;
180 try expect(byte == 101);
181}
182
183fn testArrayByValAtComptime(b: [2]u8) u8 {
184 return b[0];
185}
186
187test "comptime evalutating function that takes array by value" {
188 const arr = [_]u8{ 0, 1 };
189 _ = comptime testArrayByValAtComptime(arr);
190 _ = comptime testArrayByValAtComptime(arr);
191}
192
193test "implicit comptime in array type size" {
194 var arr: [plusOne(10)]bool = undefined;
195 try expect(arr.len == 11);
196}
197
198fn plusOne(x: u32) u32 {
199 return x + 1;
200}
201
202test "runtime initialize array elem and then implicit cast to slice" {
203 var two: i32 = 2;
204 const x: []const i32 = &[_]i32{two};
205 try expect(x[0] == 2);
206}
207
208test "array literal as argument to function" {
209 const S = struct {
210 fn entry(two: i32) !void {
211 try foo(&[_]i32{
212 1,
213 2,
214 3,
215 });
216 try foo(&[_]i32{
217 1,
218 two,
219 3,
220 });
221 try foo2(true, &[_]i32{
222 1,
223 2,
224 3,
225 });
226 try foo2(true, &[_]i32{
227 1,
228 two,
229 3,
230 });
231 }
232 fn foo(x: []const i32) !void {
233 try expect(x[0] == 1);
234 try expect(x[1] == 2);
235 try expect(x[2] == 3);
236 }
237 fn foo2(trash: bool, x: []const i32) !void {
238 try expect(trash);
239 try expect(x[0] == 1);
240 try expect(x[1] == 2);
241 try expect(x[2] == 3);
242 }
243 };
244 try S.entry(2);
245 comptime try S.entry(2);
246}
247
248test "double nested array to const slice cast in array literal" {
249 const S = struct {
250 fn entry(two: i32) !void {
251 const cases = [_][]const []const i32{
252 &[_][]const i32{&[_]i32{1}},
253 &[_][]const i32{&[_]i32{ 2, 3 }},
254 &[_][]const i32{
255 &[_]i32{4},
256 &[_]i32{ 5, 6, 7 },
257 },
258 };
259 try check(&cases);
260
261 const cases2 = [_][]const i32{
262 &[_]i32{1},
263 &[_]i32{ two, 3 },
264 };
265 try expect(cases2.len == 2);
266 try expect(cases2[0].len == 1);
267 try expect(cases2[0][0] == 1);
268 try expect(cases2[1].len == 2);
269 try expect(cases2[1][0] == 2);
270 try expect(cases2[1][1] == 3);
271
272 const cases3 = [_][]const []const i32{
273 &[_][]const i32{&[_]i32{1}},
274 &[_][]const i32{&[_]i32{ two, 3 }},
275 &[_][]const i32{
276 &[_]i32{4},
277 &[_]i32{ 5, 6, 7 },
278 },
279 };
280 try check(&cases3);
281 }
282
283 fn check(cases: []const []const []const i32) !void {
284 try expect(cases.len == 3);
285 try expect(cases[0].len == 1);
286 try expect(cases[0][0].len == 1);
287 try expect(cases[0][0][0] == 1);
288 try expect(cases[1].len == 1);
289 try expect(cases[1][0].len == 2);
290 try expect(cases[1][0][0] == 2);
291 try expect(cases[1][0][1] == 3);
292 try expect(cases[2].len == 2);
293 try expect(cases[2][0].len == 1);
294 try expect(cases[2][0][0] == 4);
295 try expect(cases[2][1].len == 3);
296 try expect(cases[2][1][0] == 5);
297 try expect(cases[2][1][1] == 6);
298 try expect(cases[2][1][2] == 7);
299 }
300 };
301 try S.entry(2);
302 comptime try S.entry(2);
303}
304
305test "read/write through global variable array of struct fields initialized via array mult" {
306 const S = struct {
307 fn doTheTest() !void {
308 try expect(storage[0].term == 1);
309 storage[0] = MyStruct{ .term = 123 };
310 try expect(storage[0].term == 123);
311 }
312
313 pub const MyStruct = struct {
314 term: usize,
315 };
316
317 var storage: [1]MyStruct = [_]MyStruct{MyStruct{ .term = 1 }} ** 1;
318 };
319 try S.doTheTest();
320}
321
322test "implicit cast zero sized array ptr to slice" {
323 {
324 var b = "".*;
325 const c: []const u8 = &b;
326 try expect(c.len == 0);
327 }
328 {
329 var b: [0]u8 = "".*;
330 const c: []const u8 = &b;
331 try expect(c.len == 0);
332 }
333}
334
335test "anonymous list literal syntax" {
336 const S = struct {
337 fn doTheTest() !void {
338 var array: [4]u8 = .{ 1, 2, 3, 4 };
339 try expect(array[0] == 1);
340 try expect(array[1] == 2);
341 try expect(array[2] == 3);
342 try expect(array[3] == 4);
343 }
344 };
345 try S.doTheTest();
346 comptime try S.doTheTest();
347}
348
349test "anonymous literal in array" {
350 const S = struct {
351 const Foo = struct {
352 a: usize = 2,
353 b: usize = 4,
354 };
355 fn doTheTest() !void {
356 var array: [2]Foo = .{
357 .{ .a = 3 },
358 .{ .b = 3 },
359 };
360 try expect(array[0].a == 3);
361 try expect(array[0].b == 4);
362 try expect(array[1].a == 2);
363 try expect(array[1].b == 3);
364 }
365 };
366 try S.doTheTest();
367 comptime try S.doTheTest();
368}
369
370test "access the null element of a null terminated array" {
371 const S = struct {
372 fn doTheTest() !void {
373 var array: [4:0]u8 = .{ 'a', 'o', 'e', 'u' };
374 try expect(array[4] == 0);
375 var len: usize = 4;
376 try expect(array[len] == 0);
377 }
378 };
379 try S.doTheTest();
380 comptime try S.doTheTest();
381}
382
383test "type deduction for array subscript expression" {
384 const S = struct {
385 fn doTheTest() !void {
386 var array = [_]u8{ 0x55, 0xAA };
387 var v0 = true;
388 try expectEqual(@as(u8, 0xAA), array[if (v0) 1 else 0]);
389 var v1 = false;
390 try expectEqual(@as(u8, 0x55), array[if (v1) 1 else 0]);
391 }
392 };
393 try S.doTheTest();
394 comptime try S.doTheTest();
395}
396
397test "sentinel element count towards the ABI size calculation" {
398 const S = struct {
399 fn doTheTest() !void {
400 const T = packed struct {
401 fill_pre: u8 = 0x55,
402 data: [0:0]u8 = undefined,
403 fill_post: u8 = 0xAA,
404 };
405 var x = T{};
406 var as_slice = mem.asBytes(&x);
407 try expectEqual(@as(usize, 3), as_slice.len);
408 try expectEqual(@as(u8, 0x55), as_slice[0]);
409 try expectEqual(@as(u8, 0xAA), as_slice[2]);
410 }
411 };
412
413 try S.doTheTest();
414 comptime try S.doTheTest();
415}
416
417test "zero-sized array with recursive type definition" {
418 const U = struct {
419 fn foo(comptime T: type, comptime n: usize) type {
420 return struct {
421 s: [n]T,
422 x: usize = n,
423 };
424 }
425 };
426
427 const S = struct {
428 list: U.foo(@This(), 0),
429 };
430
431 var t: S = .{ .list = .{ .s = undefined } };
432 try expectEqual(@as(usize, 0), t.list.x);
433}
434
435test "type coercion of anon struct literal to array" {
436 const S = struct {
437 const U = union {
438 a: u32,
439 b: bool,
440 c: []const u8,
441 };
442
443 fn doTheTest() !void {
444 var x1: u8 = 42;
445 const t1 = .{ x1, 56, 54 };
446 var arr1: [3]u8 = t1;
447 try expect(arr1[0] == 42);
448 try expect(arr1[1] == 56);
449 try expect(arr1[2] == 54);
450
451 var x2: U = .{ .a = 42 };
452 const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } };
453 var arr2: [3]U = t2;
454 try expect(arr2[0].a == 42);
455 try expect(arr2[1].b == true);
456 try expect(mem.eql(u8, arr2[2].c, "hello"));
457 }
458 };
459 try S.doTheTest();
460 comptime try S.doTheTest();
461}
462
463test "type coercion of pointer to anon struct literal to pointer to array" {
464 const S = struct {
465 const U = union {
466 a: u32,
467 b: bool,
468 c: []const u8,
469 };
470
471 fn doTheTest() !void {
472 var x1: u8 = 42;
473 const t1 = &.{ x1, 56, 54 };
474 var arr1: *const [3]u8 = t1;
475 try expect(arr1[0] == 42);
476 try expect(arr1[1] == 56);
477 try expect(arr1[2] == 54);
478
479 var x2: U = .{ .a = 42 };
480 const t2 = &.{ x2, .{ .b = true }, .{ .c = "hello" } };
481 var arr2: *const [3]U = t2;
482 try expect(arr2[0].a == 42);
483 try expect(arr2[1].b == true);
484 try expect(mem.eql(u8, arr2[2].c, "hello"));
485 }
486 };
487 try S.doTheTest();
488 comptime try S.doTheTest();
489}
test/behavior/eval.zig+18
...@@ -130,3 +130,21 @@ test "no undeclared identifier error in unanalyzed branches" {...@@ -130,3 +130,21 @@ test "no undeclared identifier error in unanalyzed branches" {
130 lol_this_doesnt_exist = nonsense;130 lol_this_doesnt_exist = nonsense;
131 }131 }
132}132}
133
134test "a type constructed in a global expression" {
135 var l: List = undefined;
136 l.array[0] = 10;
137 l.array[1] = 11;
138 l.array[2] = 12;
139 const ptr = @ptrCast([*]u8, &l.array);
140 try expect(ptr[0] == 10);
141 try expect(ptr[1] == 11);
142 try expect(ptr[2] == 12);
143}
144
145const List = blk: {
146 const T = [10]u8;
147 break :blk struct {
148 array: T,
149 };
150};
test/stage2/llvm.zig+4-2
...@@ -32,18 +32,20 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -32,18 +32,20 @@ pub fn addCases(ctx: *TestContext) !void {
32 var case = ctx.exeUsingLlvmBackend("shift right + left", linux_x64);32 var case = ctx.exeUsingLlvmBackend("shift right + left", linux_x64);
3333
34 case.addCompareOutput(34 case.addCompareOutput(
35 \\pub export fn main() void {35 \\pub export fn main() c_int {
36 \\ var i: u32 = 16;36 \\ var i: u32 = 16;
37 \\ assert(i >> 1, 8);37 \\ assert(i >> 1, 8);
38 \\ return 0;
38 \\}39 \\}
39 \\fn assert(a: u32, b: u32) void {40 \\fn assert(a: u32, b: u32) void {
40 \\ if (a != b) unreachable;41 \\ if (a != b) unreachable;
41 \\}42 \\}
42 , "");43 , "");
43 case.addCompareOutput(44 case.addCompareOutput(
44 \\pub export fn main() void {45 \\pub export fn main() c_int {
45 \\ var i: u32 = 16;46 \\ var i: u32 = 16;
46 \\ assert(i << 1, 32);47 \\ assert(i << 1, 32);
48 \\ return 0;
47 \\}49 \\}
48 \\fn assert(a: u32, b: u32) void {50 \\fn assert(a: u32, b: u32) void {
49 \\ if (a != b) unreachable;51 \\ if (a != b) unreachable;