authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 14:18:14-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 14:18:14-07:00
log47531b7d9389c45af3e46b623235792f14a40ff2
tree9412cb8c20a690381e58d607e6348028e19ab3d2
parenta7221ef4e902e63e72524559a067afcf6c1dfd17

Sema: support enough to check main calling convention via `@typeInfo`

After this commit, `pub export fn main() c_int { ... }` will be correctly detected as the intended entry point, and therefore start code will not try to export its own conflicting `main` function. * Implement basic union support - lots of stuff is still TODO, including runtime field access - also TODO: resolving the union tag type - comptime field access is implemented * DRY up some code by using the `Zir.DeclIterator` for skipping over decls in structs and unions. * Start to clean up Sema with regards to calling `.value()` to find out a const value. Instead, Sema code should call one of these two: - `resolvePossiblyUndefinedValue` (followed by logic dealing with undefined values) - `resolveDefinedValue` (a compile error will be emitted if the value is undefined) * An exported function with an unspecified calling convention gets the C calling convention. * Implement comptime field access for structs. * Add another implementation of "type has one possible value" in Sema. This is a bit unfortunate since the logic is duplicated, but the one in Type asserts that the types are resolved already, and is appropriate to call from codegen, while the one in Sema performs type resolution if necessary, reporting any compile errors that occur in the process.

6 files changed, 705 insertions(+), 72 deletions(-)

BRANCH_TODO-4
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1 * start.zig should support pub export fn main with -ofmt=c
2 * get stage2 tests passing1 * get stage2 tests passing
3 * modify stage2 tests so that only 1 uses _start and the rest use2 * modify stage2 tests so that only 1 uses _start and the rest use
4 pub fn main3 pub fn main
...@@ -61,6 +60,3 @@...@@ -61,6 +60,3 @@
6160
62 * AstGen threadlocal61 * AstGen threadlocal
63 * extern "foo" for vars62 * extern "foo" for vars
64
65 * TODO all decls should probably store source hash. Without this,
66 we currently unnecessarily mark all anon decls outdated here.
src/Module.zig+216-22
...@@ -456,6 +456,16 @@ pub const Decl = struct {...@@ -456,6 +456,16 @@ pub const Decl = struct {
456 return struct_obj;456 return struct_obj;
457 }457 }
458458
459 /// If the Decl has a value and it is a union, return it,
460 /// otherwise null.
461 pub fn getUnion(decl: *Decl) ?*Union {
462 if (!decl.has_tv) return null;
463 const ty = (decl.val.castTag(.ty) orelse return null).data;
464 const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data;
465 if (union_obj.owner_decl != decl) return null;
466 return union_obj;
467 }
468
459 /// If the Decl has a value and it is a function, return it,469 /// If the Decl has a value and it is a function, return it,
460 /// otherwise null.470 /// otherwise null.
461 pub fn getFunction(decl: *Decl) ?*Fn {471 pub fn getFunction(decl: *Decl) ?*Fn {
...@@ -571,6 +581,18 @@ pub const Struct = struct {...@@ -571,6 +581,18 @@ pub const Struct = struct {
571 .lazy = .{ .node_offset = s.node_offset },581 .lazy = .{ .node_offset = s.node_offset },
572 };582 };
573 }583 }
584
585 pub fn haveFieldTypes(s: Struct) bool {
586 return switch (s.status) {
587 .none,
588 .field_types_wip,
589 => false,
590 .have_field_types,
591 .layout_wip,
592 .have_layout,
593 => true,
594 };
595 }
574};596};
575597
576/// Represents the data that an enum declaration provides, when the fields598/// Represents the data that an enum declaration provides, when the fields
...@@ -624,6 +646,52 @@ pub const EnumFull = struct {...@@ -624,6 +646,52 @@ pub const EnumFull = struct {
624 }646 }
625};647};
626648
649pub const Union = struct {
650 /// The Decl that corresponds to the union itself.
651 owner_decl: *Decl,
652 /// An enum type which is used for the tag of the union.
653 /// This type is created even for untagged unions, even when the memory
654 /// layout does not store the tag.
655 /// Whether zig chooses this type or the user specifies it, it is stored here.
656 /// This will be set to the null type until status is `have_field_types`.
657 tag_ty: Type,
658 /// Set of field names in declaration order.
659 fields: std.StringArrayHashMapUnmanaged(Field),
660 /// Represents the declarations inside this union.
661 namespace: Scope.Namespace,
662 /// Offset from `owner_decl`, points to the union decl AST node.
663 node_offset: i32,
664 /// Index of the union_decl ZIR instruction.
665 zir_index: Zir.Inst.Index,
666
667 layout: std.builtin.TypeInfo.ContainerLayout,
668 status: enum {
669 none,
670 field_types_wip,
671 have_field_types,
672 layout_wip,
673 have_layout,
674 },
675
676 pub const Field = struct {
677 /// undefined until `status` is `have_field_types` or `have_layout`.
678 ty: Type,
679 abi_align: Value,
680 };
681
682 pub fn getFullyQualifiedName(s: *Union, gpa: *Allocator) ![]u8 {
683 return s.owner_decl.getFullyQualifiedName(gpa);
684 }
685
686 pub fn srcLoc(self: Union) SrcLoc {
687 return .{
688 .file_scope = self.owner_decl.getFileScope(),
689 .parent_decl_node = self.owner_decl.src_node,
690 .lazy = .{ .node_offset = self.node_offset },
691 };
692 }
693};
694
627/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.695/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
628/// Extern functions do not have this data structure; they are represented by696/// Extern functions do not have this data structure; they are represented by
629/// the `Decl` only, with a `Value` tag of `extern_fn`.697/// the `Decl` only, with a `Value` tag of `extern_fn`.
...@@ -2401,6 +2469,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2401,6 +2469,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
24012469
2402/// Patch ups:2470/// Patch ups:
2403/// * Struct.zir_index2471/// * Struct.zir_index
2472/// * Decl.zir_index
2404/// * Fn.zir_body_inst2473/// * Fn.zir_body_inst
2405/// * Decl.zir_decl_index2474/// * Decl.zir_decl_index
2406/// * Decl.name2475/// * Decl.name
...@@ -2479,6 +2548,13 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {...@@ -2479,6 +2548,13 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
2479 };2548 };
2480 }2549 }
24812550
2551 if (decl.getUnion()) |union_obj| {
2552 union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {
2553 try file.deleted_decls.append(gpa, decl);
2554 continue;
2555 };
2556 }
2557
2482 if (decl.getFunction()) |func| {2558 if (decl.getFunction()) |func| {
2483 func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse {2559 func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse {
2484 try file.deleted_decls.append(gpa, decl);2560 try file.deleted_decls.append(gpa, decl);
...@@ -2769,7 +2845,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2769,7 +2845,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2769 };2845 };
27702846
2771 if (decl.isRoot()) {2847 if (decl.isRoot()) {
2772 log.debug("semaDecl root {*} ({s})", .{decl, decl.name});2848 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name });
2773 const main_struct_inst = zir.getMainStruct();2849 const main_struct_inst = zir.getMainStruct();
2774 const struct_obj = decl.getStruct().?;2850 const struct_obj = decl.getStruct().?;
2775 try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj);2851 try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj);
...@@ -4271,7 +4347,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -4271,7 +4347,7 @@ pub const SwitchProngSrc = union(enum) {
4271 }4347 }
4272};4348};
42734349
4274pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError!void {4350pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) InnerError!void {
4275 const tracy = trace(@src());4351 const tracy = trace(@src());
4276 defer tracy.end();4352 defer tracy.end();
42774353
...@@ -4284,26 +4360,9 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError!...@@ -4284,26 +4360,9 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError!
4284 const decls_len = extra.data.decls_len;4360 const decls_len = extra.data.decls_len;
42854361
4286 // Skip over decls.4362 // Skip over decls.
4287 var extra_index = extra.end;4363 var decls_it = zir.declIterator(struct_obj.zir_index);
4288 {4364 while (decls_it.next()) |_| {}
4289 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;4365 var extra_index = decls_it.extra_index;
4290 var bit_bag_index: usize = extra_index;
4291 extra_index += bit_bags_count;
4292 var cur_bit_bag: u32 = undefined;
4293 var decl_i: u32 = 0;
4294 while (decl_i < decls_len) : (decl_i += 1) {
4295 if (decl_i % 8 == 0) {
4296 cur_bit_bag = zir.extra[bit_bag_index];
4297 bit_bag_index += 1;
4298 }
4299 const flags = @truncate(u4, cur_bit_bag);
4300 cur_bit_bag >>= 4;
4301
4302 extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1)
4303 extra_index += @truncate(u1, flags >> 2);
4304 extra_index += @truncate(u1, flags >> 3);
4305 }
4306 }
43074366
4308 const body = zir.extra[extra_index..][0..extra.data.body_len];4367 const body = zir.extra[extra_index..][0..extra.data.body_len];
4309 if (fields_len == 0) {4368 if (fields_len == 0) {
...@@ -4417,6 +4476,141 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError!...@@ -4417,6 +4476,141 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError!
4417 }4476 }
4418}4477}
44194478
4479pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) InnerError!void {
4480 const tracy = trace(@src());
4481 defer tracy.end();
4482
4483 const gpa = mod.gpa;
4484 const zir = union_obj.owner_decl.namespace.file_scope.zir;
4485 const inst_data = zir.instructions.items(.data)[union_obj.zir_index].pl_node;
4486 const src = inst_data.src();
4487 const extra = zir.extraData(Zir.Inst.UnionDecl, inst_data.payload_index);
4488 const fields_len = extra.data.fields_len;
4489 const decls_len = extra.data.decls_len;
4490
4491 // Skip over decls.
4492 var decls_it = zir.declIterator(union_obj.zir_index);
4493 while (decls_it.next()) |_| {}
4494 var extra_index = decls_it.extra_index;
4495
4496 const body = zir.extra[extra_index..][0..extra.data.body_len];
4497 if (fields_len == 0) {
4498 assert(body.len == 0);
4499 return;
4500 }
4501 extra_index += body.len;
4502
4503 var decl_arena = union_obj.owner_decl.value_arena.?.promote(gpa);
4504 defer union_obj.owner_decl.value_arena.?.* = decl_arena.state;
4505
4506 try union_obj.fields.ensureCapacity(&decl_arena.allocator, fields_len);
4507
4508 // We create a block for the field type instructions because they
4509 // may need to reference Decls from inside the struct namespace.
4510 // Within the field type, default value, and alignment expressions, the "owner decl"
4511 // should be the struct itself. Thus we need a new Sema.
4512 var sema: Sema = .{
4513 .mod = mod,
4514 .gpa = gpa,
4515 .arena = &decl_arena.allocator,
4516 .code = zir,
4517 .inst_map = try gpa.alloc(*ir.Inst, zir.instructions.len),
4518 .owner_decl = union_obj.owner_decl,
4519 .namespace = &union_obj.namespace,
4520 .owner_func = null,
4521 .func = null,
4522 .param_inst_list = &.{},
4523 };
4524 defer gpa.free(sema.inst_map);
4525
4526 var block: Scope.Block = .{
4527 .parent = null,
4528 .sema = &sema,
4529 .src_decl = union_obj.owner_decl,
4530 .instructions = .{},
4531 .inlining = null,
4532 .is_comptime = true,
4533 };
4534 defer assert(block.instructions.items.len == 0); // should all be comptime instructions
4535
4536 _ = try sema.analyzeBody(&block, body);
4537
4538 var auto_enum_tag: ?bool = null;
4539
4540 const bits_per_field = 4;
4541 const fields_per_u32 = 32 / bits_per_field;
4542 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
4543 var bit_bag_index: usize = extra_index;
4544 extra_index += bit_bags_count;
4545 var cur_bit_bag: u32 = undefined;
4546 var field_i: u32 = 0;
4547 while (field_i < fields_len) : (field_i += 1) {
4548 if (field_i % fields_per_u32 == 0) {
4549 cur_bit_bag = zir.extra[bit_bag_index];
4550 bit_bag_index += 1;
4551 }
4552 const has_type = @truncate(u1, cur_bit_bag) != 0;
4553 cur_bit_bag >>= 1;
4554 const has_align = @truncate(u1, cur_bit_bag) != 0;
4555 cur_bit_bag >>= 1;
4556 const has_tag = @truncate(u1, cur_bit_bag) != 0;
4557 cur_bit_bag >>= 1;
4558 const unused = @truncate(u1, cur_bit_bag) != 0;
4559 cur_bit_bag >>= 1;
4560
4561 if (auto_enum_tag == null) {
4562 auto_enum_tag = unused;
4563 }
4564
4565 const field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
4566 extra_index += 1;
4567
4568 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
4569 const field_type_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4570 extra_index += 1;
4571 break :blk field_type_ref;
4572 } else .none;
4573
4574 const align_ref: Zir.Inst.Ref = if (has_align) blk: {
4575 const align_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4576 extra_index += 1;
4577 break :blk align_ref;
4578 } else .none;
4579
4580 const tag_ref: Zir.Inst.Ref = if (has_tag) blk: {
4581 const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
4582 extra_index += 1;
4583 break :blk tag_ref;
4584 } else .none;
4585
4586 // This string needs to outlive the ZIR code.
4587 const field_name = try decl_arena.allocator.dupe(u8, field_name_zir);
4588 const field_ty: Type = if (field_type_ref == .none)
4589 Type.initTag(.void)
4590 else
4591 // TODO: if we need to report an error here, use a source location
4592 // that points to this type expression rather than the union.
4593 // But only resolve the source location if we need to emit a compile error.
4594 try sema.resolveType(&block, src, field_type_ref);
4595
4596 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
4597 assert(!gop.found_existing);
4598 gop.entry.value = .{
4599 .ty = field_ty,
4600 .abi_align = Value.initTag(.abi_align_default),
4601 };
4602
4603 if (align_ref != .none) {
4604 // TODO: if we need to report an error here, use a source location
4605 // that points to this alignment expression rather than the struct.
4606 // But only resolve the source location if we need to emit a compile error.
4607 gop.entry.value.abi_align = (try sema.resolveInstConst(&block, src, align_ref)).val;
4608 }
4609 }
4610
4611 // TODO resolve the union tag type
4612}
4613
4420/// Called from `performAllTheWork`, after all AstGen workers have finished,4614/// Called from `performAllTheWork`, after all AstGen workers have finished,
4421/// and before the main semantic analysis loop begins.4615/// and before the main semantic analysis loop begins.
4422pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {4616pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
src/Sema.zig+322-31
...@@ -591,7 +591,7 @@ fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *i...@@ -591,7 +591,7 @@ fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *i
591}591}
592592
593fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value {593fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value {
594 if (base.value()) |val| {594 if (try sema.resolvePossiblyUndefinedValue(block, src, base)) |val| {
595 if (val.isUndef()) {595 if (val.isUndef()) {
596 return sema.failWithUseOfUndef(block, src);596 return sema.failWithUseOfUndef(block, src);
597 }597 }
...@@ -600,6 +600,19 @@ fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base:...@@ -600,6 +600,19 @@ fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base:
600 return null;600 return null;
601}601}
602602
603fn resolvePossiblyUndefinedValue(
604 sema: *Sema,
605 block: *Scope.Block,
606 src: LazySrcLoc,
607 base: *ir.Inst,
608) !?Value {
609 if (try sema.typeHasOnePossibleValue(block, src, base.ty)) |opv| {
610 return opv;
611 }
612 const inst = base.castTag(.constant) orelse return null;
613 return inst.val;
614}
615
603fn failWithNeededComptime(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError {616fn failWithNeededComptime(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError {
604 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});617 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
605}618}
...@@ -889,9 +902,40 @@ fn zirUnionDecl(...@@ -889,9 +902,40 @@ fn zirUnionDecl(
889902
890 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;903 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
891 const src = inst_data.src();904 const src = inst_data.src();
892 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);905 const extra = sema.code.extraData(Zir.Inst.UnionDecl, inst_data.payload_index);
906 const decls_len = extra.data.decls_len;
893907
894 return sema.mod.fail(&block.base, sema.src, "TODO implement zirUnionDecl", .{});908 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
909
910 const union_obj = try new_decl_arena.allocator.create(Module.Union);
911 const union_ty = try Type.Tag.@"union".create(&new_decl_arena.allocator, union_obj);
912 const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty);
913 const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{
914 .ty = Type.initTag(.type),
915 .val = union_val,
916 });
917 union_obj.* = .{
918 .owner_decl = new_decl,
919 .tag_ty = Type.initTag(.@"null"),
920 .fields = .{},
921 .node_offset = inst_data.src_node,
922 .zir_index = inst,
923 .layout = layout,
924 .status = .none,
925 .namespace = .{
926 .parent = sema.owner_decl.namespace,
927 .ty = union_ty,
928 .file_scope = block.getFileScope(),
929 },
930 };
931 std.log.scoped(.module).debug("create union {*} owned by {*} ({s})", .{
932 &union_obj.namespace, new_decl, new_decl.name,
933 });
934
935 _ = try sema.mod.scanNamespace(&union_obj.namespace, extra.end, decls_len, new_decl);
936
937 try new_decl.finalizeNewArena(&new_decl_arena);
938 return sema.analyzeDeclVal(block, src, new_decl);
895}939}
896940
897fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {941fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
...@@ -1277,6 +1321,33 @@ fn failWithBadFieldAccess(...@@ -1277,6 +1321,33 @@ fn failWithBadFieldAccess(
1277 return mod.failWithOwnedErrorMsg(&block.base, msg);1321 return mod.failWithOwnedErrorMsg(&block.base, msg);
1278}1322}
12791323
1324fn failWithBadUnionFieldAccess(
1325 sema: *Sema,
1326 block: *Scope.Block,
1327 union_obj: *Module.Union,
1328 field_src: LazySrcLoc,
1329 field_name: []const u8,
1330) InnerError {
1331 const mod = sema.mod;
1332 const gpa = sema.gpa;
1333
1334 const fqn = try union_obj.getFullyQualifiedName(gpa);
1335 defer gpa.free(fqn);
1336
1337 const msg = msg: {
1338 const msg = try mod.errMsg(
1339 &block.base,
1340 field_src,
1341 "no field named '{s}' in union '{s}'",
1342 .{ field_name, fqn },
1343 );
1344 errdefer msg.destroy(gpa);
1345 try mod.errNoteNonLazy(union_obj.srcLoc(), msg, "union declared here", .{});
1346 break :msg msg;
1347 };
1348 return mod.failWithOwnedErrorMsg(&block.base, msg);
1349}
1350
1280fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {1351fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
1281 const tracy = trace(@src());1352 const tracy = trace(@src());
1282 defer tracy.end();1353 defer tracy.end();
...@@ -1484,7 +1555,7 @@ fn zirCompileLog(...@@ -1484,7 +1555,7 @@ fn zirCompileLog(
1484 if (i != 0) try writer.print(", ", .{});1555 if (i != 0) try writer.print(", ", .{});
14851556
1486 const arg = try sema.resolveInst(arg_ref);1557 const arg = try sema.resolveInst(arg_ref);
1487 if (arg.value()) |val| {1558 if (try sema.resolvePossiblyUndefinedValue(block, src, arg)) |val| {
1488 try writer.print("@as({}, {})", .{ arg.ty, val });1559 try writer.print("@as({}, {})", .{ arg.ty, val });
1489 } else {1560 } else {
1490 try writer.print("@as({}, [runtime value])", .{arg.ty});1561 try writer.print("@as({}, [runtime value])", .{arg.ty});
...@@ -2204,21 +2275,25 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr...@@ -2204,21 +2275,25 @@ fn zirErrorToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
2204 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };2275 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2205 const op = try sema.resolveInst(inst_data.operand);2276 const op = try sema.resolveInst(inst_data.operand);
2206 const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);2277 const op_coerced = try sema.coerce(block, Type.initTag(.anyerror), op, operand_src);
2278 const result_ty = Type.initTag(.u16);
22072279
2208 if (op_coerced.value()) |val| {2280 if (try sema.resolvePossiblyUndefinedValue(block, src, op_coerced)) |val| {
2281 if (val.isUndef()) {
2282 return sema.mod.constUndef(sema.arena, src, result_ty);
2283 }
2209 const payload = try sema.arena.create(Value.Payload.U64);2284 const payload = try sema.arena.create(Value.Payload.U64);
2210 payload.* = .{2285 payload.* = .{
2211 .base = .{ .tag = .int_u64 },2286 .base = .{ .tag = .int_u64 },
2212 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,2287 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
2213 };2288 };
2214 return sema.mod.constInst(sema.arena, src, .{2289 return sema.mod.constInst(sema.arena, src, .{
2215 .ty = Type.initTag(.u16),2290 .ty = result_ty,
2216 .val = Value.initPayload(&payload.base),2291 .val = Value.initPayload(&payload.base),
2217 });2292 });
2218 }2293 }
22192294
2220 try sema.requireRuntimeBlock(block, src);2295 try sema.requireRuntimeBlock(block, src);
2221 return block.addUnOp(src, Type.initTag(.u16), .error_to_int, op_coerced);2296 return block.addUnOp(src, result_ty, .error_to_int, op_coerced);
2222}2297}
22232298
2224fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {2299fn zirIntToError(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
...@@ -2377,7 +2452,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr...@@ -2377,7 +2452,7 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr
2377 var int_tag_type_buffer: Type.Payload.Bits = undefined;2452 var int_tag_type_buffer: Type.Payload.Bits = undefined;
2378 const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena);2453 const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena);
23792454
2380 if (enum_tag.ty.onePossibleValue()) |opv| {2455 if (try sema.typeHasOnePossibleValue(block, src, enum_tag.ty)) |opv| {
2381 return mod.constInst(arena, src, .{2456 return mod.constInst(arena, src, .{
2382 .ty = int_tag_ty,2457 .ty = int_tag_ty,
2383 .val = opv,2458 .val = opv,
...@@ -2729,13 +2804,18 @@ fn zirFunc(...@@ -2729,13 +2804,18 @@ fn zirFunc(
2729 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;2804 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
2730 }2805 }
27312806
2807 const cc: std.builtin.CallingConvention = if (sema.owner_decl.is_exported)
2808 .C
2809 else
2810 .Unspecified;
2811
2732 return sema.funcCommon(2812 return sema.funcCommon(
2733 block,2813 block,
2734 inst_data.src_node,2814 inst_data.src_node,
2735 param_types,2815 param_types,
2736 body_inst,2816 body_inst,
2737 extra.data.return_type,2817 extra.data.return_type,
2738 .Unspecified,2818 cc,
2739 Value.initTag(.null_value),2819 Value.initTag(.null_value),
2740 false,2820 false,
2741 inferred_error_set,2821 inferred_error_set,
...@@ -4268,10 +4348,7 @@ fn zirBitwise(...@@ -4268,10 +4348,7 @@ fn zirBitwise(
4268 if (casted_lhs.value()) |lhs_val| {4348 if (casted_lhs.value()) |lhs_val| {
4269 if (casted_rhs.value()) |rhs_val| {4349 if (casted_rhs.value()) |rhs_val| {
4270 if (lhs_val.isUndef() or rhs_val.isUndef()) {4350 if (lhs_val.isUndef() or rhs_val.isUndef()) {
4271 return sema.mod.constInst(sema.arena, src, .{4351 return sema.mod.constUndef(sema.arena, src, resolved_type);
4272 .ty = resolved_type,
4273 .val = Value.initTag(.undef),
4274 });
4275 }4352 }
4276 return sema.mod.fail(&block.base, src, "TODO implement comptime bitwise operations", .{});4353 return sema.mod.fail(&block.base, src, "TODO implement comptime bitwise operations", .{});
4277 }4354 }
...@@ -4395,10 +4472,7 @@ fn analyzeArithmetic(...@@ -4395,10 +4472,7 @@ fn analyzeArithmetic(
4395 if (casted_lhs.value()) |lhs_val| {4472 if (casted_lhs.value()) |lhs_val| {
4396 if (casted_rhs.value()) |rhs_val| {4473 if (casted_rhs.value()) |rhs_val| {
4397 if (lhs_val.isUndef() or rhs_val.isUndef()) {4474 if (lhs_val.isUndef() or rhs_val.isUndef()) {
4398 return sema.mod.constInst(sema.arena, src, .{4475 return sema.mod.constUndef(sema.arena, src, resolved_type);
4399 .ty = resolved_type,
4400 .val = Value.initTag(.undef),
4401 });
4402 }4476 }
4403 // incase rhs is 0, simply return lhs without doing any calculations4477 // incase rhs is 0, simply return lhs without doing any calculations
4404 // TODO Once division is implemented we should throw an error when dividing by 0.4478 // TODO Once division is implemented we should throw an error when dividing by 0.
...@@ -4635,10 +4709,7 @@ fn zirCmp(...@@ -4635,10 +4709,7 @@ fn zirCmp(
4635 if (casted_lhs.value()) |lhs_val| {4709 if (casted_lhs.value()) |lhs_val| {
4636 if (casted_rhs.value()) |rhs_val| {4710 if (casted_rhs.value()) |rhs_val| {
4637 if (lhs_val.isUndef() or rhs_val.isUndef()) {4711 if (lhs_val.isUndef() or rhs_val.isUndef()) {
4638 return sema.mod.constInst(sema.arena, src, .{4712 return sema.mod.constUndef(sema.arena, src, resolved_type);
4639 .ty = resolved_type,
4640 .val = Value.initTag(.undef),
4641 });
4642 }4713 }
4643 const result = lhs_val.compare(op, rhs_val);4714 const result = lhs_val.compare(op, rhs_val);
4644 return sema.mod.constBool(sema.arena, src, result);4715 return sema.mod.constBool(sema.arena, src, result);
...@@ -4721,7 +4792,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro...@@ -4721,7 +4792,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
4721 @enumToInt(ty.fnCallingConvention()),4792 @enumToInt(ty.fnCallingConvention()),
4722 );4793 );
4723 // alignment: comptime_int,4794 // alignment: comptime_int,
4724 field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.ptrAlignment(target));4795 field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target));
4725 // is_generic: bool,4796 // is_generic: bool,
4726 field_values[2] = Value.initTag(.bool_false); // TODO4797 field_values[2] = Value.initTag(.bool_false); // TODO
4727 // is_var_args: bool,4798 // is_var_args: bool,
...@@ -6033,6 +6104,7 @@ fn namedFieldPtr(...@@ -6033,6 +6104,7 @@ fn namedFieldPtr(
6033 }6104 }
6034 },6105 },
6035 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),6106 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
6107 .Union => return sema.analyzeUnionFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
6036 else => {},6108 else => {},
6037 }6109 }
6038 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});6110 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
...@@ -6083,11 +6155,58 @@ fn analyzeStructFieldPtr(...@@ -6083,11 +6155,58 @@ fn analyzeStructFieldPtr(
6083 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);6155 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
6084 const field = struct_obj.fields.entries.items[field_index].value;6156 const field = struct_obj.fields.entries.items[field_index].value;
6085 const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);6157 const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);
6086 // TODO comptime field access6158
6159 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
6160 return mod.constInst(arena, src, .{
6161 .ty = ptr_field_ty,
6162 .val = try Value.Tag.field_ptr.create(arena, .{
6163 .container_ptr = struct_ptr_val,
6164 .field_index = field_index,
6165 }),
6166 });
6167 }
6168
6087 try sema.requireRuntimeBlock(block, src);6169 try sema.requireRuntimeBlock(block, src);
6088 return block.addStructFieldPtr(src, ptr_field_ty, struct_ptr, @intCast(u32, field_index));6170 return block.addStructFieldPtr(src, ptr_field_ty, struct_ptr, @intCast(u32, field_index));
6089}6171}
60906172
6173fn analyzeUnionFieldPtr(
6174 sema: *Sema,
6175 block: *Scope.Block,
6176 src: LazySrcLoc,
6177 union_ptr: *Inst,
6178 field_name: []const u8,
6179 field_name_src: LazySrcLoc,
6180 unresolved_union_ty: Type,
6181) InnerError!*Inst {
6182 const mod = sema.mod;
6183 const arena = sema.arena;
6184 assert(unresolved_union_ty.zigTypeTag() == .Union);
6185
6186 const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
6187 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
6188
6189 const field_index = union_obj.fields.getIndex(field_name) orelse
6190 return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
6191
6192 const field = union_obj.fields.entries.items[field_index].value;
6193 const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);
6194
6195 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| {
6196 // TODO detect inactive union field and emit compile error
6197 return mod.constInst(arena, src, .{
6198 .ty = ptr_field_ty,
6199 .val = try Value.Tag.field_ptr.create(arena, .{
6200 .container_ptr = union_ptr_val,
6201 .field_index = field_index,
6202 }),
6203 });
6204 }
6205
6206 try sema.requireRuntimeBlock(block, src);
6207 return mod.fail(&block.base, src, "TODO implement runtime union field access", .{});
6208}
6209
6091fn elemPtr(6210fn elemPtr(
6092 sema: *Sema,6211 sema: *Sema,
6093 block: *Scope.Block,6212 block: *Scope.Block,
...@@ -6382,7 +6501,7 @@ fn storePtr(...@@ -6382,7 +6501,7 @@ fn storePtr(
63826501
6383 const elem_ty = ptr.ty.elemType();6502 const elem_ty = ptr.ty.elemType();
6384 const value = try sema.coerce(block, elem_ty, uncasted_value, src);6503 const value = try sema.coerce(block, elem_ty, uncasted_value, src);
6385 if (elem_ty.onePossibleValue() != null)6504 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
6386 return;6505 return;
63876506
6388 // TODO handle comptime pointer writes6507 // TODO handle comptime pointer writes
...@@ -6477,7 +6596,7 @@ fn analyzeRef(...@@ -6477,7 +6596,7 @@ fn analyzeRef(
6477) InnerError!*Inst {6596) InnerError!*Inst {
6478 const ptr_type = try sema.mod.simplePtrType(sema.arena, operand.ty, false, .One);6597 const ptr_type = try sema.mod.simplePtrType(sema.arena, operand.ty, false, .One);
64796598
6480 if (operand.value()) |val| {6599 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |val| {
6481 return sema.mod.constInst(sema.arena, src, .{6600 return sema.mod.constInst(sema.arena, src, .{
6482 .ty = ptr_type,6601 .ty = ptr_type,
6483 .val = try Value.Tag.ref_val.create(sema.arena, val),6602 .val = try Value.Tag.ref_val.create(sema.arena, val),
...@@ -6499,10 +6618,10 @@ fn analyzeLoad(...@@ -6499,10 +6618,10 @@ fn analyzeLoad(
6499 .Pointer => ptr.ty.elemType(),6618 .Pointer => ptr.ty.elemType(),
6500 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),6619 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
6501 };6620 };
6502 if (ptr.value()) |val| {6621 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
6503 return sema.mod.constInst(sema.arena, src, .{6622 return sema.mod.constInst(sema.arena, src, .{
6504 .ty = elem_ty,6623 .ty = elem_ty,
6505 .val = try val.pointerDeref(sema.arena),6624 .val = try ptr_val.pointerDeref(sema.arena),
6506 });6625 });
6507 }6626 }
65086627
...@@ -6517,14 +6636,18 @@ fn analyzeIsNull(...@@ -6517,14 +6636,18 @@ fn analyzeIsNull(
6517 operand: *Inst,6636 operand: *Inst,
6518 invert_logic: bool,6637 invert_logic: bool,
6519) InnerError!*Inst {6638) InnerError!*Inst {
6520 if (operand.value()) |opt_val| {6639 const result_ty = Type.initTag(.bool);
6640 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |opt_val| {
6641 if (opt_val.isUndef()) {
6642 return sema.mod.constUndef(sema.arena, src, result_ty);
6643 }
6521 const is_null = opt_val.isNull();6644 const is_null = opt_val.isNull();
6522 const bool_value = if (invert_logic) !is_null else is_null;6645 const bool_value = if (invert_logic) !is_null else is_null;
6523 return sema.mod.constBool(sema.arena, src, bool_value);6646 return sema.mod.constBool(sema.arena, src, bool_value);
6524 }6647 }
6525 try sema.requireRuntimeBlock(block, src);6648 try sema.requireRuntimeBlock(block, src);
6526 const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null;6649 const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null;
6527 return block.addUnOp(src, Type.initTag(.bool), inst_tag, operand);6650 return block.addUnOp(src, result_ty, inst_tag, operand);
6528}6651}
65296652
6530fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst {6653fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst {
...@@ -6532,11 +6655,15 @@ fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Ins...@@ -6532,11 +6655,15 @@ fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Ins
6532 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false);6655 if (ot != .ErrorSet and ot != .ErrorUnion) return sema.mod.constBool(sema.arena, src, false);
6533 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true);6656 if (ot == .ErrorSet) return sema.mod.constBool(sema.arena, src, true);
6534 assert(ot == .ErrorUnion);6657 assert(ot == .ErrorUnion);
6535 if (operand.value()) |err_union| {6658 const result_ty = Type.initTag(.bool);
6659 if (try sema.resolvePossiblyUndefinedValue(block, src, operand)) |err_union| {
6660 if (err_union.isUndef()) {
6661 return sema.mod.constUndef(sema.arena, src, result_ty);
6662 }
6536 return sema.mod.constBool(sema.arena, src, err_union.getError() != null);6663 return sema.mod.constBool(sema.arena, src, err_union.getError() != null);
6537 }6664 }
6538 try sema.requireRuntimeBlock(block, src);6665 try sema.requireRuntimeBlock(block, src);
6539 return block.addUnOp(src, Type.initTag(.bool), .is_err, operand);6666 return block.addUnOp(src, result_ty, .is_err, operand);
6540}6667}
65416668
6542fn analyzeSlice(6669fn analyzeSlice(
...@@ -6953,6 +7080,23 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type...@@ -6953,6 +7080,23 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type
6953 .float_mode => return sema.resolveBuiltinTypeFields(block, src, ty, "FloatMode"),7080 .float_mode => return sema.resolveBuiltinTypeFields(block, src, ty, "FloatMode"),
6954 .reduce_op => return sema.resolveBuiltinTypeFields(block, src, ty, "ReduceOp"),7081 .reduce_op => return sema.resolveBuiltinTypeFields(block, src, ty, "ReduceOp"),
6955 .call_options => return sema.resolveBuiltinTypeFields(block, src, ty, "CallOptions"),7082 .call_options => return sema.resolveBuiltinTypeFields(block, src, ty, "CallOptions"),
7083
7084 .@"union", .union_tagged => {
7085 const union_obj = ty.cast(Type.Payload.Union).?.data;
7086 switch (union_obj.status) {
7087 .none => {},
7088 .field_types_wip => {
7089 return sema.mod.fail(&block.base, src, "union {} depends on itself", .{
7090 ty,
7091 });
7092 },
7093 .have_field_types, .have_layout, .layout_wip => return ty,
7094 }
7095 union_obj.status = .field_types_wip;
7096 try sema.mod.analyzeUnionFields(union_obj);
7097 union_obj.status = .have_field_types;
7098 return ty;
7099 },
6956 else => return ty,7100 else => return ty,
6957 }7101 }
6958}7102}
...@@ -6994,3 +7138,150 @@ fn getBuiltinType(...@@ -6994,3 +7138,150 @@ fn getBuiltinType(
6994 const ty_inst = try sema.analyzeLoad(block, src, opt_ty_inst.?, src);7138 const ty_inst = try sema.analyzeLoad(block, src, opt_ty_inst.?, src);
6995 return sema.resolveAirAsType(block, src, ty_inst);7139 return sema.resolveAirAsType(block, src, ty_inst);
6996}7140}
7141
7142/// There is another implementation of this in `Type.onePossibleValue`. This one
7143/// in `Sema` is for calling during semantic analysis, and peforms field resolution
7144/// to get the answer. The one in `Type` is for calling during codegen and asserts
7145/// that the types are already resolved.
7146fn typeHasOnePossibleValue(
7147 sema: *Sema,
7148 block: *Scope.Block,
7149 src: LazySrcLoc,
7150 starting_type: Type,
7151) InnerError!?Value {
7152 var ty = starting_type;
7153 while (true) switch (ty.tag()) {
7154 .f16,
7155 .f32,
7156 .f64,
7157 .f128,
7158 .c_longdouble,
7159 .comptime_int,
7160 .comptime_float,
7161 .u8,
7162 .i8,
7163 .u16,
7164 .i16,
7165 .u32,
7166 .i32,
7167 .u64,
7168 .i64,
7169 .u128,
7170 .i128,
7171 .usize,
7172 .isize,
7173 .c_short,
7174 .c_ushort,
7175 .c_int,
7176 .c_uint,
7177 .c_long,
7178 .c_ulong,
7179 .c_longlong,
7180 .c_ulonglong,
7181 .bool,
7182 .type,
7183 .anyerror,
7184 .fn_noreturn_no_args,
7185 .fn_void_no_args,
7186 .fn_naked_noreturn_no_args,
7187 .fn_ccc_void_no_args,
7188 .function,
7189 .single_const_pointer_to_comptime_int,
7190 .array_sentinel,
7191 .array_u8_sentinel_0,
7192 .const_slice_u8,
7193 .const_slice,
7194 .mut_slice,
7195 .c_void,
7196 .optional,
7197 .optional_single_mut_pointer,
7198 .optional_single_const_pointer,
7199 .enum_literal,
7200 .anyerror_void_error_union,
7201 .error_union,
7202 .error_set,
7203 .error_set_single,
7204 .@"opaque",
7205 .var_args_param,
7206 .manyptr_u8,
7207 .manyptr_const_u8,
7208 .atomic_ordering,
7209 .atomic_rmw_op,
7210 .calling_convention,
7211 .float_mode,
7212 .reduce_op,
7213 .call_options,
7214 .export_options,
7215 .extern_options,
7216 .@"anyframe",
7217 .anyframe_T,
7218 .many_const_pointer,
7219 .many_mut_pointer,
7220 .c_const_pointer,
7221 .c_mut_pointer,
7222 .single_const_pointer,
7223 .single_mut_pointer,
7224 .pointer,
7225 => return null,
7226
7227 .@"struct" => {
7228 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
7229 const s = resolved_ty.castTag(.@"struct").?.data;
7230 for (s.fields.entries.items) |entry| {
7231 const field_ty = entry.value.ty;
7232 if ((try sema.typeHasOnePossibleValue(block, src, field_ty)) == null) {
7233 return null;
7234 }
7235 }
7236 return Value.initTag(.empty_struct_value);
7237 },
7238 .enum_full => {
7239 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
7240 const enum_full = resolved_ty.castTag(.enum_full).?.data;
7241 if (enum_full.fields.count() == 1) {
7242 return enum_full.values.entries.items[0].key;
7243 } else {
7244 return null;
7245 }
7246 },
7247 .enum_simple => {
7248 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
7249 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
7250 if (enum_simple.fields.count() == 1) {
7251 return Value.initTag(.zero);
7252 } else {
7253 return null;
7254 }
7255 },
7256 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
7257 .@"union" => {
7258 return null; // TODO
7259 },
7260 .union_tagged => {
7261 return null; // TODO
7262 },
7263
7264 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
7265 .void => return Value.initTag(.void_value),
7266 .noreturn => return Value.initTag(.unreachable_value),
7267 .@"null" => return Value.initTag(.null_value),
7268 .@"undefined" => return Value.initTag(.undef),
7269
7270 .int_unsigned, .int_signed => {
7271 if (ty.cast(Type.Payload.Bits).?.data == 0) {
7272 return Value.initTag(.zero);
7273 } else {
7274 return null;
7275 }
7276 },
7277 .vector, .array, .array_u8 => {
7278 if (ty.arrayLen() == 0)
7279 return Value.initTag(.empty_array);
7280 ty = ty.elemType();
7281 continue;
7282 },
7283
7284 .inferred_alloc_const => unreachable,
7285 .inferred_alloc_mut => unreachable,
7286 };
7287}
src/ir.zig+3
...@@ -255,6 +255,9 @@ pub const Inst = struct {...@@ -255,6 +255,9 @@ pub const Inst = struct {
255 }255 }
256256
257 /// Returns `null` if runtime-known.257 /// Returns `null` if runtime-known.
258 /// Should be called by codegen, not by Sema. Sema functions should call
259 /// `resolvePossiblyUndefinedValue` or `resolveDefinedValue` instead.
260 /// TODO audit Sema code for violations to the above guidance.
258 pub fn value(base: *Inst) ?Value {261 pub fn value(base: *Inst) ?Value {
259 if (base.ty.onePossibleValue()) |opv| return opv;262 if (base.ty.onePossibleValue()) |opv| return opv;
260263
src/type.zig+107-15
...@@ -122,6 +122,10 @@ pub const Type = extern union {...@@ -122,6 +122,10 @@ pub const Type = extern union {
122 .reduce_op,122 .reduce_op,
123 => return .Enum,123 => return .Enum,
124124
125 .@"union",
126 .union_tagged,
127 => return .Union,
128
125 .var_args_param => unreachable, // can be any type129 .var_args_param => unreachable, // can be any type
126 }130 }
127 }131 }
...@@ -506,11 +510,18 @@ pub const Type = extern union {...@@ -506,11 +510,18 @@ pub const Type = extern union {
506 }510 }
507 return a.tag() == b.tag();511 return a.tag() == b.tag();
508 },512 },
513 .Union => {
514 if (a.cast(Payload.Union)) |a_payload| {
515 if (b.cast(Payload.Union)) |b_payload| {
516 return a_payload.data == b_payload.data;
517 }
518 }
519 return a.tag() == b.tag();
520 },
509 .Opaque,521 .Opaque,
510 .Float,522 .Float,
511 .ErrorUnion,523 .ErrorUnion,
512 .ErrorSet,524 .ErrorSet,
513 .Union,
514 .BoundFn,525 .BoundFn,
515 .Frame,526 .Frame,
516 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),527 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
...@@ -735,6 +746,7 @@ pub const Type = extern union {...@@ -735,6 +746,7 @@ pub const Type = extern union {
735 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),746 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
736 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),747 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
737 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),748 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
749 .@"union", .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union),
738 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),750 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
739 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),751 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
740 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),752 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
...@@ -806,6 +818,10 @@ pub const Type = extern union {...@@ -806,6 +818,10 @@ pub const Type = extern union {
806 const struct_obj = ty.castTag(.@"struct").?.data;818 const struct_obj = ty.castTag(.@"struct").?.data;
807 return struct_obj.owner_decl.renderFullyQualifiedName(writer);819 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
808 },820 },
821 .@"union", .union_tagged => {
822 const union_obj = ty.cast(Payload.Union).?.data;
823 return union_obj.owner_decl.renderFullyQualifiedName(writer);
824 },
809 .enum_full, .enum_nonexhaustive => {825 .enum_full, .enum_nonexhaustive => {
810 const enum_full = ty.cast(Payload.EnumFull).?.data;826 const enum_full = ty.cast(Payload.EnumFull).?.data;
811 return enum_full.owner_decl.renderFullyQualifiedName(writer);827 return enum_full.owner_decl.renderFullyQualifiedName(writer);
...@@ -1151,6 +1167,27 @@ pub const Type = extern union {...@@ -1151,6 +1167,27 @@ pub const Type = extern union {
1151 const int_tag_ty = self.intTagType(&buffer);1167 const int_tag_ty = self.intTagType(&buffer);
1152 return int_tag_ty.hasCodeGenBits();1168 return int_tag_ty.hasCodeGenBits();
1153 },1169 },
1170 .@"union" => {
1171 const union_obj = self.castTag(.@"union").?.data;
1172 for (union_obj.fields.entries.items) |entry| {
1173 if (entry.value.ty.hasCodeGenBits())
1174 return true;
1175 } else {
1176 return false;
1177 }
1178 },
1179 .union_tagged => {
1180 const union_obj = self.castTag(.@"union").?.data;
1181 if (union_obj.tag_ty.hasCodeGenBits()) {
1182 return true;
1183 }
1184 for (union_obj.fields.entries.items) |entry| {
1185 if (entry.value.ty.hasCodeGenBits())
1186 return true;
1187 } else {
1188 return false;
1189 }
1190 },
11541191
1155 // TODO lazy types1192 // TODO lazy types
1156 .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,1193 .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
...@@ -1359,6 +1396,34 @@ pub const Type = extern union {...@@ -1359,6 +1396,34 @@ pub const Type = extern union {
1359 const int_tag_ty = self.intTagType(&buffer);1396 const int_tag_ty = self.intTagType(&buffer);
1360 return int_tag_ty.abiAlignment(target);1397 return int_tag_ty.abiAlignment(target);
1361 },1398 },
1399 .union_tagged => {
1400 const union_obj = self.castTag(.union_tagged).?.data;
1401 var biggest: u32 = union_obj.tag_ty.abiAlignment(target);
1402 for (union_obj.fields.entries.items) |entry| {
1403 const field_ty = entry.value.ty;
1404 if (!field_ty.hasCodeGenBits()) continue;
1405 const field_align = field_ty.abiAlignment(target);
1406 if (field_align > biggest) {
1407 return field_align;
1408 }
1409 }
1410 assert(biggest != 0);
1411 return biggest;
1412 },
1413 .@"union" => {
1414 const union_obj = self.castTag(.@"union").?.data;
1415 var biggest: u32 = 0;
1416 for (union_obj.fields.entries.items) |entry| {
1417 const field_ty = entry.value.ty;
1418 if (!field_ty.hasCodeGenBits()) continue;
1419 const field_align = field_ty.abiAlignment(target);
1420 if (field_align > biggest) {
1421 return field_align;
1422 }
1423 }
1424 assert(biggest != 0);
1425 return biggest;
1426 },
1362 .c_void,1427 .c_void,
1363 .void,1428 .void,
1364 .type,1429 .type,
...@@ -1411,6 +1476,9 @@ pub const Type = extern union {...@@ -1411,6 +1476,9 @@ pub const Type = extern union {
1411 const int_tag_ty = self.intTagType(&buffer);1476 const int_tag_ty = self.intTagType(&buffer);
1412 return int_tag_ty.abiSize(target);1477 return int_tag_ty.abiSize(target);
1413 },1478 },
1479 .@"union", .union_tagged => {
1480 @panic("TODO abiSize unions");
1481 },
14141482
1415 .u8,1483 .u8,
1416 .i8,1484 .i8,
...@@ -1570,6 +1638,9 @@ pub const Type = extern union {...@@ -1570,6 +1638,9 @@ pub const Type = extern union {
1570 const int_tag_ty = self.intTagType(&buffer);1638 const int_tag_ty = self.intTagType(&buffer);
1571 return int_tag_ty.bitSize(target);1639 return int_tag_ty.bitSize(target);
1572 },1640 },
1641 .@"union", .union_tagged => {
1642 @panic("TODO bitSize unions");
1643 },
15731644
1574 .u8, .i8 => 8,1645 .u8, .i8 => 8,
15751646
...@@ -2263,6 +2334,8 @@ pub const Type = extern union {...@@ -2263,6 +2334,8 @@ pub const Type = extern union {
2263 };2334 };
2264 }2335 }
22652336
2337 /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which
2338 /// resolves field types rather than asserting they are already resolved.
2266 pub fn onePossibleValue(starting_type: Type) ?Value {2339 pub fn onePossibleValue(starting_type: Type) ?Value {
2267 var ty = starting_type;2340 var ty = starting_type;
2268 while (true) switch (ty.tag()) {2341 while (true) switch (ty.tag()) {
...@@ -2330,10 +2403,18 @@ pub const Type = extern union {...@@ -2330,10 +2403,18 @@ pub const Type = extern union {
2330 .extern_options,2403 .extern_options,
2331 .@"anyframe",2404 .@"anyframe",
2332 .anyframe_T,2405 .anyframe_T,
2406 .many_const_pointer,
2407 .many_mut_pointer,
2408 .c_const_pointer,
2409 .c_mut_pointer,
2410 .single_const_pointer,
2411 .single_mut_pointer,
2412 .pointer,
2333 => return null,2413 => return null,
23342414
2335 .@"struct" => {2415 .@"struct" => {
2336 const s = ty.castTag(.@"struct").?.data;2416 const s = ty.castTag(.@"struct").?.data;
2417 assert(s.haveFieldTypes());
2337 for (s.fields.entries.items) |entry| {2418 for (s.fields.entries.items) |entry| {
2338 const field_ty = entry.value.ty;2419 const field_ty = entry.value.ty;
2339 if (field_ty.onePossibleValue() == null) {2420 if (field_ty.onePossibleValue() == null) {
...@@ -2359,6 +2440,12 @@ pub const Type = extern union {...@@ -2359,6 +2440,12 @@ pub const Type = extern union {
2359 }2440 }
2360 },2441 },
2361 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,2442 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
2443 .@"union" => {
2444 return null; // TODO
2445 },
2446 .union_tagged => {
2447 return null; // TODO
2448 },
23622449
2363 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),2450 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
2364 .void => return Value.initTag(.void_value),2451 .void => return Value.initTag(.void_value),
...@@ -2379,20 +2466,7 @@ pub const Type = extern union {...@@ -2379,20 +2466,7 @@ pub const Type = extern union {
2379 ty = ty.elemType();2466 ty = ty.elemType();
2380 continue;2467 continue;
2381 },2468 },
2382 .many_const_pointer,2469
2383 .many_mut_pointer,
2384 .c_const_pointer,
2385 .c_mut_pointer,
2386 .single_const_pointer,
2387 .single_mut_pointer,
2388 => {
2389 ty = ty.castPointer().?.data;
2390 continue;
2391 },
2392 .pointer => {
2393 ty = ty.castTag(.pointer).?.data.pointee_type;
2394 continue;
2395 },
2396 .inferred_alloc_const => unreachable,2470 .inferred_alloc_const => unreachable,
2397 .inferred_alloc_mut => unreachable,2471 .inferred_alloc_mut => unreachable,
2398 };2472 };
...@@ -2412,6 +2486,8 @@ pub const Type = extern union {...@@ -2412,6 +2486,8 @@ pub const Type = extern union {
2412 .enum_full => &self.castTag(.enum_full).?.data.namespace,2486 .enum_full => &self.castTag(.enum_full).?.data.namespace,
2413 .empty_struct => self.castTag(.empty_struct).?.data,2487 .empty_struct => self.castTag(.empty_struct).?.data,
2414 .@"opaque" => &self.castTag(.@"opaque").?.data,2488 .@"opaque" => &self.castTag(.@"opaque").?.data,
2489 .@"union" => &self.castTag(.@"union").?.data.namespace,
2490 .union_tagged => &self.castTag(.union_tagged).?.data.namespace,
24152491
2416 else => null,2492 else => null,
2417 };2493 };
...@@ -2612,6 +2688,10 @@ pub const Type = extern union {...@@ -2612,6 +2688,10 @@ pub const Type = extern union {
2612 const error_set = ty.castTag(.error_set).?.data;2688 const error_set = ty.castTag(.error_set).?.data;
2613 return error_set.srcLoc();2689 return error_set.srcLoc();
2614 },2690 },
2691 .@"union", .union_tagged => {
2692 const union_obj = ty.cast(Payload.Union).?.data;
2693 return union_obj.srcLoc();
2694 },
2615 .atomic_ordering,2695 .atomic_ordering,
2616 .atomic_rmw_op,2696 .atomic_rmw_op,
2617 .calling_convention,2697 .calling_convention,
...@@ -2643,6 +2723,10 @@ pub const Type = extern union {...@@ -2643,6 +2723,10 @@ pub const Type = extern union {
2643 const error_set = ty.castTag(.error_set).?.data;2723 const error_set = ty.castTag(.error_set).?.data;
2644 return error_set.owner_decl;2724 return error_set.owner_decl;
2645 },2725 },
2726 .@"union", .union_tagged => {
2727 const union_obj = ty.cast(Payload.Union).?.data;
2728 return union_obj.owner_decl;
2729 },
2646 .@"opaque" => @panic("TODO"),2730 .@"opaque" => @panic("TODO"),
2647 .atomic_ordering,2731 .atomic_ordering,
2648 .atomic_rmw_op,2732 .atomic_rmw_op,
...@@ -2801,6 +2885,8 @@ pub const Type = extern union {...@@ -2801,6 +2885,8 @@ pub const Type = extern union {
2801 empty_struct,2885 empty_struct,
2802 @"opaque",2886 @"opaque",
2803 @"struct",2887 @"struct",
2888 @"union",
2889 union_tagged,
2804 enum_simple,2890 enum_simple,
2805 enum_full,2891 enum_full,
2806 enum_nonexhaustive,2892 enum_nonexhaustive,
...@@ -2902,6 +2988,7 @@ pub const Type = extern union {...@@ -2902,6 +2988,7 @@ pub const Type = extern union {
2902 .error_set_single => Payload.Name,2988 .error_set_single => Payload.Name,
2903 .@"opaque" => Payload.Opaque,2989 .@"opaque" => Payload.Opaque,
2904 .@"struct" => Payload.Struct,2990 .@"struct" => Payload.Struct,
2991 .@"union", .union_tagged => Payload.Union,
2905 .enum_full, .enum_nonexhaustive => Payload.EnumFull,2992 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
2906 .enum_simple => Payload.EnumSimple,2993 .enum_simple => Payload.EnumSimple,
2907 .empty_struct => Payload.ContainerScope,2994 .empty_struct => Payload.ContainerScope,
...@@ -3040,6 +3127,11 @@ pub const Type = extern union {...@@ -3040,6 +3127,11 @@ pub const Type = extern union {
3040 data: *Module.Struct,3127 data: *Module.Struct,
3041 };3128 };
30423129
3130 pub const Union = struct {
3131 base: Payload,
3132 data: *Module.Union,
3133 };
3134
3043 pub const EnumFull = struct {3135 pub const EnumFull = struct {
3044 base: Payload,3136 base: Payload,
3045 data: *Module.EnumFull,3137 data: *Module.EnumFull,
src/value.zig+57
...@@ -104,6 +104,7 @@ pub const Value = extern union {...@@ -104,6 +104,7 @@ pub const Value = extern union {
104 /// Represents a pointer to a decl, not the value of the decl.104 /// Represents a pointer to a decl, not the value of the decl.
105 decl_ref,105 decl_ref,
106 elem_ptr,106 elem_ptr,
107 field_ptr,
107 /// A slice of u8 whose memory is managed externally.108 /// A slice of u8 whose memory is managed externally.
108 bytes,109 bytes,
109 /// This value is repeated some number of times. The amount of times to repeat110 /// This value is repeated some number of times. The amount of times to repeat
...@@ -223,6 +224,7 @@ pub const Value = extern union {...@@ -223,6 +224,7 @@ pub const Value = extern union {
223 .function => Payload.Function,224 .function => Payload.Function,
224 .variable => Payload.Variable,225 .variable => Payload.Variable,
225 .elem_ptr => Payload.ElemPtr,226 .elem_ptr => Payload.ElemPtr,
227 .field_ptr => Payload.FieldPtr,
226 .float_16 => Payload.Float_16,228 .float_16 => Payload.Float_16,
227 .float_32 => Payload.Float_32,229 .float_32 => Payload.Float_32,
228 .float_64 => Payload.Float_64,230 .float_64 => Payload.Float_64,
...@@ -414,6 +416,18 @@ pub const Value = extern union {...@@ -414,6 +416,18 @@ pub const Value = extern union {
414 };416 };
415 return Value{ .ptr_otherwise = &new_payload.base };417 return Value{ .ptr_otherwise = &new_payload.base };
416 },418 },
419 .field_ptr => {
420 const payload = self.castTag(.field_ptr).?;
421 const new_payload = try allocator.create(Payload.FieldPtr);
422 new_payload.* = .{
423 .base = payload.base,
424 .data = .{
425 .container_ptr = try payload.data.container_ptr.copy(allocator),
426 .field_index = payload.data.field_index,
427 },
428 };
429 return Value{ .ptr_otherwise = &new_payload.base };
430 },
417 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),431 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
418 .repeated => {432 .repeated => {
419 const payload = self.castTag(.repeated).?;433 const payload = self.castTag(.repeated).?;
...@@ -569,6 +583,11 @@ pub const Value = extern union {...@@ -569,6 +583,11 @@ pub const Value = extern union {
569 try out_stream.print("&[{}] ", .{elem_ptr.index});583 try out_stream.print("&[{}] ", .{elem_ptr.index});
570 val = elem_ptr.array_ptr;584 val = elem_ptr.array_ptr;
571 },585 },
586 .field_ptr => {
587 const field_ptr = val.castTag(.field_ptr).?.data;
588 try out_stream.print("fieldptr({d}) ", .{field_ptr.field_index});
589 val = field_ptr.container_ptr;
590 },
572 .empty_array => return out_stream.writeAll(".{}"),591 .empty_array => return out_stream.writeAll(".{}"),
573 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),592 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),
574 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),593 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),
...@@ -704,6 +723,7 @@ pub const Value = extern union {...@@ -704,6 +723,7 @@ pub const Value = extern union {
704 .ref_val,723 .ref_val,
705 .decl_ref,724 .decl_ref,
706 .elem_ptr,725 .elem_ptr,
726 .field_ptr,
707 .bytes,727 .bytes,
708 .repeated,728 .repeated,
709 .float_16,729 .float_16,
...@@ -1196,6 +1216,11 @@ pub const Value = extern union {...@@ -1196,6 +1216,11 @@ pub const Value = extern union {
1196 std.hash.autoHash(&hasher, payload.array_ptr.hash());1216 std.hash.autoHash(&hasher, payload.array_ptr.hash());
1197 std.hash.autoHash(&hasher, payload.index);1217 std.hash.autoHash(&hasher, payload.index);
1198 },1218 },
1219 .field_ptr => {
1220 const payload = self.castTag(.field_ptr).?.data;
1221 std.hash.autoHash(&hasher, payload.container_ptr.hash());
1222 std.hash.autoHash(&hasher, payload.field_index);
1223 },
1199 .decl_ref => {1224 .decl_ref => {
1200 const decl = self.castTag(.decl_ref).?.data;1225 const decl = self.castTag(.decl_ref).?.data;
1201 std.hash.autoHash(&hasher, decl);1226 std.hash.autoHash(&hasher, decl);
...@@ -1250,6 +1275,11 @@ pub const Value = extern union {...@@ -1250,6 +1275,11 @@ pub const Value = extern union {
1250 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);1275 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
1251 return array_val.elemValue(allocator, elem_ptr.index);1276 return array_val.elemValue(allocator, elem_ptr.index);
1252 },1277 },
1278 .field_ptr => {
1279 const field_ptr = self.castTag(.field_ptr).?.data;
1280 const container_val = try field_ptr.container_ptr.pointerDeref(allocator);
1281 return container_val.fieldValue(allocator, field_ptr.field_index);
1282 },
12531283
1254 else => unreachable,1284 else => unreachable,
1255 };1285 };
...@@ -1270,6 +1300,22 @@ pub const Value = extern union {...@@ -1270,6 +1300,22 @@ pub const Value = extern union {
1270 }1300 }
1271 }1301 }
12721302
1303 pub fn fieldValue(val: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
1304 switch (val.tag()) {
1305 .@"struct" => {
1306 const field_values = val.castTag(.@"struct").?.data;
1307 return field_values[index];
1308 },
1309 .@"union" => {
1310 const payload = val.castTag(.@"union").?.data;
1311 // TODO assert the tag is correct
1312 return payload.val;
1313 },
1314
1315 else => unreachable,
1316 }
1317 }
1318
1273 /// Returns a pointer to the element value at the index.1319 /// Returns a pointer to the element value at the index.
1274 pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {1320 pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
1275 if (self.castTag(.elem_ptr)) |elem_ptr| {1321 if (self.castTag(.elem_ptr)) |elem_ptr| {
...@@ -1409,6 +1455,7 @@ pub const Value = extern union {...@@ -1409,6 +1455,7 @@ pub const Value = extern union {
1409 .ref_val,1455 .ref_val,
1410 .decl_ref,1456 .decl_ref,
1411 .elem_ptr,1457 .elem_ptr,
1458 .field_ptr,
1412 .bytes,1459 .bytes,
1413 .repeated,1460 .repeated,
1414 .float_16,1461 .float_16,
...@@ -1496,6 +1543,16 @@ pub const Value = extern union {...@@ -1496,6 +1543,16 @@ pub const Value = extern union {
1496 },1543 },
1497 };1544 };
14981545
1546 pub const FieldPtr = struct {
1547 pub const base_tag = Tag.field_ptr;
1548
1549 base: Payload = Payload{ .tag = base_tag },
1550 data: struct {
1551 container_ptr: Value,
1552 field_index: usize,
1553 },
1554 };
1555
1499 pub const Bytes = struct {1556 pub const Bytes = struct {
1500 base: Payload,1557 base: Payload,
1501 data: []const u8,1558 data: []const u8,