authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-23 18:45:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-23 18:45:51-07:00
log7378ce67dabf996f2d0927138f826dfb3d6fa05f
tree8db3025dfa20a9120c62b7c56796e75cbcecec3d
parent57539a26b4b1a118c9947116f2873ea3c0ced3da

Sema: introduce a type resolution queue

That happens after a function body is analyzed. This prevents circular dependency compile errors and yet a way to mark types that need to be fully resolved before a given function is sent to the codegen backend.

5 files changed, 82 insertions(+), 44 deletions(-)

src/Air.zig+1-1
...@@ -1072,7 +1072,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1072,7 +1072,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1072 .sub_with_overflow,1072 .sub_with_overflow,
1073 .mul_with_overflow,1073 .mul_with_overflow,
1074 .shl_with_overflow,1074 .shl_with_overflow,
1075 => return Type.initTag(.bool),1075 => return Type.bool,
1076 }1076 }
1077}1077}
10781078
src/Module.zig+17
...@@ -4837,6 +4837,9 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem...@@ -4837,6 +4837,9 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
48374837
4838 // Finally we must resolve the return type and parameter types so that backends4838 // Finally we must resolve the return type and parameter types so that backends
4839 // have full access to type information.4839 // have full access to type information.
4840 // Crucially, this happens *after* we set the function state to success above,
4841 // so that dependencies on the function body will now be satisfied rather than
4842 // result in circular dependency errors.
4840 const src: LazySrcLoc = .{ .node_offset = 0 };4843 const src: LazySrcLoc = .{ .node_offset = 0 };
4841 sema.resolveFnTypes(&inner_block, src, fn_ty_info) catch |err| switch (err) {4844 sema.resolveFnTypes(&inner_block, src, fn_ty_info) catch |err| switch (err) {
4842 error.NeededSourceLocation => unreachable,4845 error.NeededSourceLocation => unreachable,
...@@ -4847,6 +4850,20 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem...@@ -4847,6 +4850,20 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
4847 else => |e| return e,4850 else => |e| return e,
4848 };4851 };
48494852
4853 // Similarly, resolve any queued up types that were requested to be resolved for
4854 // the backends.
4855 for (sema.types_to_resolve.items) |inst_ref| {
4856 const ty = sema.getTmpAir().getRefType(inst_ref);
4857 sema.resolveTypeFully(&inner_block, src, ty) catch |err| switch (err) {
4858 error.NeededSourceLocation => unreachable,
4859 error.GenericPoison => unreachable,
4860 error.ComptimeReturn => unreachable,
4861 error.ComptimeBreak => unreachable,
4862 error.AnalysisFail => {},
4863 else => |e| return e,
4864 };
4865 }
4866
4850 return Air{4867 return Air{
4851 .instructions = sema.air_instructions.toOwnedSlice(),4868 .instructions = sema.air_instructions.toOwnedSlice(),
4852 .extra = sema.air_extra.toOwnedSlice(gpa),4869 .extra = sema.air_extra.toOwnedSlice(gpa),
src/Sema.zig+25-10
...@@ -63,6 +63,11 @@ comptime_args_fn_inst: Zir.Inst.Index = 0,...@@ -63,6 +63,11 @@ comptime_args_fn_inst: Zir.Inst.Index = 0,
63/// extra hash table lookup in the `monomorphed_funcs` set.63/// extra hash table lookup in the `monomorphed_funcs` set.
64/// Sema will set this to null when it takes ownership.64/// Sema will set this to null when it takes ownership.
65preallocated_new_func: ?*Module.Fn = null,65preallocated_new_func: ?*Module.Fn = null,
66/// The key is `constant` AIR instructions to types that must be fully resolved
67/// after the current function body analysis is done.
68/// TODO: after upgrading to use InternPool change the key here to be an
69/// InternPool value index.
70types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
6671
67const std = @import("std");72const std = @import("std");
68const mem = std.mem;73const mem = std.mem;
...@@ -527,6 +532,7 @@ pub fn deinit(sema: *Sema) void {...@@ -527,6 +532,7 @@ pub fn deinit(sema: *Sema) void {
527 sema.air_values.deinit(gpa);532 sema.air_values.deinit(gpa);
528 sema.inst_map.deinit(gpa);533 sema.inst_map.deinit(gpa);
529 sema.decl_val_table.deinit(gpa);534 sema.decl_val_table.deinit(gpa);
535 sema.types_to_resolve.deinit(gpa);
530 sema.* = undefined;536 sema.* = undefined;
531}537}
532538
...@@ -1747,7 +1753,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1747,7 +1753,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1747 return sema.bitCast(block, ptr_ty, new_ptr, src);1753 return sema.bitCast(block, ptr_ty, new_ptr, src);
1748 }1754 }
1749 const ty_op = air_datas[trash_inst].ty_op;1755 const ty_op = air_datas[trash_inst].ty_op;
1750 const operand_ty = sema.getTmpAir().typeOf(ty_op.operand);1756 const operand_ty = sema.typeOf(ty_op.operand);
1751 const ptr_operand_ty = try Type.ptr(sema.arena, target, .{1757 const ptr_operand_ty = try Type.ptr(sema.arena, target, .{
1752 .pointee_type = operand_ty,1758 .pointee_type = operand_ty,
1753 .@"addrspace" = addr_space,1759 .@"addrspace" = addr_space,
...@@ -2592,7 +2598,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -2592,7 +2598,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
2592 .@"addrspace" = target_util.defaultAddressSpace(target, .local),2598 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
2593 });2599 });
2594 try sema.requireRuntimeBlock(block, var_decl_src);2600 try sema.requireRuntimeBlock(block, var_decl_src);
2595 try sema.resolveTypeFully(block, ty_src, var_ty);2601 try sema.queueFullTypeResolution(var_ty);
2596 return block.addTy(.alloc, ptr_type);2602 return block.addTy(.alloc, ptr_type);
2597}2603}
25982604
...@@ -2614,7 +2620,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -2614,7 +2620,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2614 .@"addrspace" = target_util.defaultAddressSpace(target, .local),2620 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
2615 });2621 });
2616 try sema.requireRuntimeBlock(block, var_decl_src);2622 try sema.requireRuntimeBlock(block, var_decl_src);
2617 try sema.resolveTypeFully(block, ty_src, var_ty);2623 try sema.queueFullTypeResolution(var_ty);
2618 return block.addTy(.alloc, ptr_type);2624 return block.addTy(.alloc, ptr_type);
2619}2625}
26202626
...@@ -2770,7 +2776,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2770,7 +2776,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2770 }2776 }
27712777
2772 try sema.requireRuntimeBlock(block, src);2778 try sema.requireRuntimeBlock(block, src);
2773 try sema.resolveTypeFully(block, ty_src, final_elem_ty);2779 try sema.queueFullTypeResolution(final_elem_ty);
27742780
2775 // Change it to a normal alloc.2781 // Change it to a normal alloc.
2776 sema.air_instructions.set(ptr_inst, .{2782 sema.air_instructions.set(ptr_inst, .{
...@@ -4363,6 +4369,8 @@ fn addDbgVar(...@@ -4363,6 +4369,8 @@ fn addDbgVar(
4363 else => unreachable,4369 else => unreachable,
4364 }4370 }
43654371
4372 try sema.queueFullTypeResolution(operand_ty);
4373
4366 // Add the name to the AIR.4374 // Add the name to the AIR.
4367 const name_extra_index = @intCast(u32, sema.air_extra.items.len);4375 const name_extra_index = @intCast(u32, sema.air_extra.items.len);
4368 const elements_used = name.len / 4 + 1;4376 const elements_used = name.len / 4 + 1;
...@@ -5004,7 +5012,7 @@ fn analyzeCall(...@@ -5004,7 +5012,7 @@ fn analyzeCall(
5004 }5012 }
5005 }5013 }
50065014
5007 try sema.resolveTypeFully(block, call_src, func_ty_info.return_type);5015 try sema.queueFullTypeResolution(func_ty_info.return_type);
50085016
5009 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +5017 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
5010 args.len);5018 args.len);
...@@ -5344,7 +5352,7 @@ fn instantiateGenericCall(...@@ -5344,7 +5352,7 @@ fn instantiateGenericCall(
5344 total_i += 1;5352 total_i += 1;
5345 }5353 }
53465354
5347 try sema.resolveTypeFully(block, call_src, new_fn_info.return_type);5355 try sema.queueFullTypeResolution(new_fn_info.return_type);
5348 }5356 }
5349 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +5357 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
5350 runtime_args_len);5358 runtime_args_len);
...@@ -12030,7 +12038,8 @@ fn unionInit(...@@ -12030,7 +12038,8 @@ fn unionInit(
12030 }12038 }
1203112039
12032 try sema.requireRuntimeBlock(block, init_src);12040 try sema.requireRuntimeBlock(block, init_src);
12033 try sema.resolveTypeLayout(block, union_ty_src, union_ty);12041 _ = union_ty_src;
12042 try sema.queueFullTypeResolution(union_ty);
12034 return block.addUnionInit(union_ty, field_index, init);12043 return block.addUnionInit(union_ty, field_index, init);
12035}12044}
1203612045
...@@ -12205,6 +12214,7 @@ fn finishStructInit(...@@ -12205,6 +12214,7 @@ fn finishStructInit(
12205 }12214 }
1220612215
12207 try sema.requireRuntimeBlock(block, src);12216 try sema.requireRuntimeBlock(block, src);
12217 try sema.queueFullTypeResolution(struct_ty);
12208 return block.addAggregateInit(struct_ty, field_inits);12218 return block.addAggregateInit(struct_ty, field_inits);
12209}12219}
1221012220
...@@ -12351,7 +12361,7 @@ fn zirArrayInit(...@@ -12351,7 +12361,7 @@ fn zirArrayInit(
12351 };12361 };
1235212362
12353 try sema.requireRuntimeBlock(block, runtime_src);12363 try sema.requireRuntimeBlock(block, runtime_src);
12354 try sema.resolveTypeLayout(block, src, elem_ty);12364 try sema.queueFullTypeResolution(elem_ty);
1235512365
12356 if (is_ref) {12366 if (is_ref) {
12357 const target = sema.mod.getTarget();12367 const target = sema.mod.getTarget();
...@@ -18339,7 +18349,7 @@ fn storePtr2(...@@ -18339,7 +18349,7 @@ fn storePtr2(
18339 // TODO handle if the element type requires comptime18349 // TODO handle if the element type requires comptime
1834018350
18341 try sema.requireRuntimeBlock(block, runtime_src);18351 try sema.requireRuntimeBlock(block, runtime_src);
18342 try sema.resolveTypeLayout(block, src, elem_ty);18352 try sema.queueFullTypeResolution(elem_ty);
18343 _ = try block.addBinOp(air_tag, ptr, operand);18353 _ = try block.addBinOp(air_tag, ptr, operand);
18344}18354}
1834518355
...@@ -21907,7 +21917,7 @@ fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {...@@ -21907,7 +21917,7 @@ fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
21907 return sema.getTmpAir().typeOf(inst);21917 return sema.getTmpAir().typeOf(inst);
21908}21918}
2190921919
21910fn getTmpAir(sema: Sema) Air {21920pub fn getTmpAir(sema: Sema) Air {
21911 return .{21921 return .{
21912 .instructions = sema.air_instructions.slice(),21922 .instructions = sema.air_instructions.slice(),
21913 .extra = sema.air_extra.items,21923 .extra = sema.air_extra.items,
...@@ -22572,3 +22582,8 @@ fn anonStructFieldIndex(...@@ -22572,3 +22582,8 @@ fn anonStructFieldIndex(
22572fn kit(sema: *Sema, block: *Block, src: LazySrcLoc) Module.WipAnalysis {22582fn kit(sema: *Sema, block: *Block, src: LazySrcLoc) Module.WipAnalysis {
22573 return .{ .sema = sema, .block = block, .src = src };22583 return .{ .sema = sema, .block = block, .src = src };
22574}22584}
22585
22586fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
22587 const inst_ref = try sema.addType(ty);
22588 try sema.types_to_resolve.append(sema.gpa, inst_ref);
22589}
src/arch/wasm/CodeGen.zig+33-33
...@@ -632,7 +632,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {...@@ -632,7 +632,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
632 // means we must generate it from a constant.632 // means we must generate it from a constant.
633 const val = self.air.value(ref).?;633 const val = self.air.value(ref).?;
634 const ty = self.air.typeOf(ref);634 const ty = self.air.typeOf(ref);
635 if (!ty.hasRuntimeBits() and !ty.isInt()) {635 if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt()) {
636 gop.value_ptr.* = WValue{ .none = {} };636 gop.value_ptr.* = WValue{ .none = {} };
637 return gop.value_ptr.*;637 return gop.value_ptr.*;
638 }638 }
...@@ -805,13 +805,13 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {...@@ -805,13 +805,13 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {
805 defer gpa.free(fn_params);805 defer gpa.free(fn_params);
806 fn_ty.fnParamTypes(fn_params);806 fn_ty.fnParamTypes(fn_params);
807 for (fn_params) |param_type| {807 for (fn_params) |param_type| {
808 if (!param_type.hasRuntimeBits()) continue;808 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
809 try params.append(typeToValtype(param_type, target));809 try params.append(typeToValtype(param_type, target));
810 }810 }
811 }811 }
812812
813 // return type813 // return type
814 if (!want_sret and return_type.hasRuntimeBits()) {814 if (!want_sret and return_type.hasRuntimeBitsIgnoreComptime()) {
815 try returns.append(typeToValtype(return_type, target));815 try returns.append(typeToValtype(return_type, target));
816 }816 }
817817
...@@ -970,7 +970,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -970,7 +970,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
970 .Naked => return result,970 .Naked => return result,
971 .Unspecified, .C => {971 .Unspecified, .C => {
972 for (param_types) |ty| {972 for (param_types) |ty| {
973 if (!ty.hasRuntimeBits()) {973 if (!ty.hasRuntimeBitsIgnoreComptime()) {
974 continue;974 continue;
975 }975 }
976976
...@@ -1015,7 +1015,7 @@ fn restoreStackPointer(self: *Self) !void {...@@ -1015,7 +1015,7 @@ fn restoreStackPointer(self: *Self) !void {
1015///1015///
1016/// Asserts Type has codegenbits1016/// Asserts Type has codegenbits
1017fn allocStack(self: *Self, ty: Type) !WValue {1017fn allocStack(self: *Self, ty: Type) !WValue {
1018 assert(ty.hasRuntimeBits());1018 assert(ty.hasRuntimeBitsIgnoreComptime());
1019 if (self.initial_stack_value == .none) {1019 if (self.initial_stack_value == .none) {
1020 try self.initializeStack();1020 try self.initializeStack();
1021 }1021 }
...@@ -1049,7 +1049,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1049,7 +1049,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue {
1049 try self.initializeStack();1049 try self.initializeStack();
1050 }1050 }
10511051
1052 if (!pointee_ty.hasRuntimeBits()) {1052 if (!pointee_ty.hasRuntimeBitsIgnoreComptime()) {
1053 return self.allocStack(Type.usize); // create a value containing just the stack pointer.1053 return self.allocStack(Type.usize); // create a value containing just the stack pointer.
1054 }1054 }
10551055
...@@ -1235,18 +1235,18 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1235,18 +1235,18 @@ fn isByRef(ty: Type, target: std.Target) bool {
1235 .Struct,1235 .Struct,
1236 .Frame,1236 .Frame,
1237 .Union,1237 .Union,
1238 => return ty.hasRuntimeBits(),1238 => return ty.hasRuntimeBitsIgnoreComptime(),
1239 .Int => return if (ty.intInfo(target).bits > 64) true else false,1239 .Int => return if (ty.intInfo(target).bits > 64) true else false,
1240 .ErrorUnion => {1240 .ErrorUnion => {
1241 const has_tag = ty.errorUnionSet().hasRuntimeBits();1241 const has_tag = ty.errorUnionSet().hasRuntimeBitsIgnoreComptime();
1242 const has_pl = ty.errorUnionPayload().hasRuntimeBits();1242 const has_pl = ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime();
1243 if (!has_tag or !has_pl) return false;1243 if (!has_tag or !has_pl) return false;
1244 return ty.hasRuntimeBits();1244 return ty.hasRuntimeBitsIgnoreComptime();
1245 },1245 },
1246 .Optional => {1246 .Optional => {
1247 if (ty.isPtrLikeOptional()) return false;1247 if (ty.isPtrLikeOptional()) return false;
1248 var buf: Type.Payload.ElemType = undefined;1248 var buf: Type.Payload.ElemType = undefined;
1249 return ty.optionalChild(&buf).hasRuntimeBits();1249 return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime();
1250 },1250 },
1251 .Pointer => {1251 .Pointer => {
1252 // Slices act like struct and will be passed by reference1252 // Slices act like struct and will be passed by reference
...@@ -1511,7 +1511,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1511,7 +1511,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1511 const un_op = self.air.instructions.items(.data)[inst].un_op;1511 const un_op = self.air.instructions.items(.data)[inst].un_op;
1512 const operand = try self.resolveInst(un_op);1512 const operand = try self.resolveInst(un_op);
1513 const ret_ty = self.air.typeOf(un_op).childType();1513 const ret_ty = self.air.typeOf(un_op).childType();
1514 if (!ret_ty.hasRuntimeBits()) return WValue.none;1514 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) return WValue.none;
15151515
1516 if (!isByRef(ret_ty, self.target)) {1516 if (!isByRef(ret_ty, self.target)) {
1517 const result = try self.load(operand, ret_ty, 0);1517 const result = try self.load(operand, ret_ty, 0);
...@@ -1567,7 +1567,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1567,7 +1567,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1567 const arg_val = try self.resolveInst(arg_ref);1567 const arg_val = try self.resolveInst(arg_ref);
15681568
1569 const arg_ty = self.air.typeOf(arg_ref);1569 const arg_ty = self.air.typeOf(arg_ref);
1570 if (!arg_ty.hasRuntimeBits()) continue;1570 if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue;
15711571
1572 switch (arg_val) {1572 switch (arg_val) {
1573 .stack_offset => try self.emitWValue(try self.buildPointerOffset(arg_val, 0, .new)),1573 .stack_offset => try self.emitWValue(try self.buildPointerOffset(arg_val, 0, .new)),
...@@ -1591,7 +1591,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1591,7 +1591,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1591 try self.addLabel(.call_indirect, fn_type_index);1591 try self.addLabel(.call_indirect, fn_type_index);
1592 }1592 }
15931593
1594 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBits()) {1594 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBitsIgnoreComptime()) {
1595 return WValue.none;1595 return WValue.none;
1596 } else if (ret_ty.isNoReturn()) {1596 } else if (ret_ty.isNoReturn()) {
1597 try self.addTag(.@"unreachable");1597 try self.addTag(.@"unreachable");
...@@ -1625,7 +1625,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1625,7 +1625,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1625 .ErrorUnion => {1625 .ErrorUnion => {
1626 const err_ty = ty.errorUnionSet();1626 const err_ty = ty.errorUnionSet();
1627 const pl_ty = ty.errorUnionPayload();1627 const pl_ty = ty.errorUnionPayload();
1628 if (!pl_ty.hasRuntimeBits()) {1628 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1629 return self.store(lhs, rhs, err_ty, 0);1629 return self.store(lhs, rhs, err_ty, 0);
1630 }1630 }
16311631
...@@ -1638,7 +1638,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1638,7 +1638,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1638 }1638 }
1639 var buf: Type.Payload.ElemType = undefined;1639 var buf: Type.Payload.ElemType = undefined;
1640 const pl_ty = ty.optionalChild(&buf);1640 const pl_ty = ty.optionalChild(&buf);
1641 if (!pl_ty.hasRuntimeBits()) {1641 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1642 return self.store(lhs, rhs, Type.u8, 0);1642 return self.store(lhs, rhs, Type.u8, 0);
1643 }1643 }
16441644
...@@ -1696,7 +1696,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1696,7 +1696,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1696 const operand = try self.resolveInst(ty_op.operand);1696 const operand = try self.resolveInst(ty_op.operand);
1697 const ty = self.air.getRefType(ty_op.ty);1697 const ty = self.air.getRefType(ty_op.ty);
16981698
1699 if (!ty.hasRuntimeBits()) return WValue{ .none = {} };1699 if (!ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
17001700
1701 if (isByRef(ty, self.target)) {1701 if (isByRef(ty, self.target)) {
1702 const new_local = try self.allocStack(ty);1702 const new_local = try self.allocStack(ty);
...@@ -2200,7 +2200,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2200,7 +2200,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2200 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {2200 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
2201 var buf: Type.Payload.ElemType = undefined;2201 var buf: Type.Payload.ElemType = undefined;
2202 const payload_ty = operand_ty.optionalChild(&buf);2202 const payload_ty = operand_ty.optionalChild(&buf);
2203 if (payload_ty.hasRuntimeBits()) {2203 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
2204 // When we hit this case, we must check the value of optionals2204 // When we hit this case, we must check the value of optionals
2205 // that are not pointers. This means first checking against non-null for2205 // that are not pointers. This means first checking against non-null for
2206 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs2206 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs
...@@ -2257,7 +2257,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2257,7 +2257,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2257 const block = self.blocks.get(br.block_inst).?;2257 const block = self.blocks.get(br.block_inst).?;
22582258
2259 // if operand has codegen bits we should break with a value2259 // if operand has codegen bits we should break with a value
2260 if (self.air.typeOf(br.operand).hasRuntimeBits()) {2260 if (self.air.typeOf(br.operand).hasRuntimeBitsIgnoreComptime()) {
2261 const operand = try self.resolveInst(br.operand);2261 const operand = try self.resolveInst(br.operand);
2262 const op = switch (operand) {2262 const op = switch (operand) {
2263 .stack_offset => try self.buildPointerOffset(operand, 0, .new),2263 .stack_offset => try self.buildPointerOffset(operand, 0, .new),
...@@ -2357,7 +2357,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2357,7 +2357,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2357 const operand = try self.resolveInst(struct_field.struct_operand);2357 const operand = try self.resolveInst(struct_field.struct_operand);
2358 const field_index = struct_field.field_index;2358 const field_index = struct_field.field_index;
2359 const field_ty = struct_ty.structFieldType(field_index);2359 const field_ty = struct_ty.structFieldType(field_index);
2360 if (!field_ty.hasRuntimeBits()) return WValue{ .none = {} };2360 if (!field_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
2361 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {2361 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
2362 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(self.target)});2362 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(self.target)});
2363 };2363 };
...@@ -2544,7 +2544,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W...@@ -2544,7 +2544,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
25442544
2545 // load the error tag value2545 // load the error tag value
2546 try self.emitWValue(operand);2546 try self.emitWValue(operand);
2547 if (pl_ty.hasRuntimeBits()) {2547 if (pl_ty.hasRuntimeBitsIgnoreComptime()) {
2548 try self.addMemArg(.i32_load16_u, .{2548 try self.addMemArg(.i32_load16_u, .{
2549 .offset = operand.offset(),2549 .offset = operand.offset(),
2550 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),2550 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),
...@@ -2567,7 +2567,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -2567,7 +2567,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)
2567 const op_ty = self.air.typeOf(ty_op.operand);2567 const op_ty = self.air.typeOf(ty_op.operand);
2568 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;2568 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
2569 const payload_ty = err_ty.errorUnionPayload();2569 const payload_ty = err_ty.errorUnionPayload();
2570 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };2570 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
2571 const err_align = err_ty.abiAlignment(self.target);2571 const err_align = err_ty.abiAlignment(self.target);
2572 const set_size = err_ty.errorUnionSet().abiSize(self.target);2572 const set_size = err_ty.errorUnionSet().abiSize(self.target);
2573 const offset = mem.alignForwardGeneric(u64, set_size, err_align);2573 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
...@@ -2585,7 +2585,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In...@@ -2585,7 +2585,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In
2585 const op_ty = self.air.typeOf(ty_op.operand);2585 const op_ty = self.air.typeOf(ty_op.operand);
2586 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;2586 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
2587 const payload_ty = err_ty.errorUnionPayload();2587 const payload_ty = err_ty.errorUnionPayload();
2588 if (op_is_ptr or !payload_ty.hasRuntimeBits()) {2588 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime()) {
2589 return operand;2589 return operand;
2590 }2590 }
25912591
...@@ -2599,7 +2599,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2599,7 +2599,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2599 const operand = try self.resolveInst(ty_op.operand);2599 const operand = try self.resolveInst(ty_op.operand);
26002600
2601 const op_ty = self.air.typeOf(ty_op.operand);2601 const op_ty = self.air.typeOf(ty_op.operand);
2602 if (!op_ty.hasRuntimeBits()) return operand;2602 if (!op_ty.hasRuntimeBitsIgnoreComptime()) return operand;
2603 const err_ty = self.air.getRefType(ty_op.ty);2603 const err_ty = self.air.getRefType(ty_op.ty);
2604 const err_align = err_ty.abiAlignment(self.target);2604 const err_align = err_ty.abiAlignment(self.target);
2605 const set_size = err_ty.errorUnionSet().abiSize(self.target);2605 const set_size = err_ty.errorUnionSet().abiSize(self.target);
...@@ -2624,7 +2624,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2624,7 +2624,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2624 const operand = try self.resolveInst(ty_op.operand);2624 const operand = try self.resolveInst(ty_op.operand);
2625 const err_ty = self.air.getRefType(ty_op.ty);2625 const err_ty = self.air.getRefType(ty_op.ty);
26262626
2627 if (!err_ty.errorUnionPayload().hasRuntimeBits()) return operand;2627 if (!err_ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime()) return operand;
26282628
2629 const err_union = try self.allocStack(err_ty);2629 const err_union = try self.allocStack(err_ty);
2630 try self.store(err_union, operand, err_ty.errorUnionSet(), 0);2630 try self.store(err_union, operand, err_ty.errorUnionSet(), 0);
...@@ -2690,7 +2690,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)...@@ -2690,7 +2690,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
2690 const payload_ty = optional_ty.optionalChild(&buf);2690 const payload_ty = optional_ty.optionalChild(&buf);
2691 // When payload is zero-bits, we can treat operand as a value, rather than2691 // When payload is zero-bits, we can treat operand as a value, rather than
2692 // a pointer to the stack value2692 // a pointer to the stack value
2693 if (payload_ty.hasRuntimeBits()) {2693 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
2694 try self.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });2694 try self.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 });
2695 }2695 }
2696 }2696 }
...@@ -2710,7 +2710,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2710,7 +2710,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2710 const operand = try self.resolveInst(ty_op.operand);2710 const operand = try self.resolveInst(ty_op.operand);
2711 const opt_ty = self.air.typeOf(ty_op.operand);2711 const opt_ty = self.air.typeOf(ty_op.operand);
2712 const payload_ty = self.air.typeOfIndex(inst);2712 const payload_ty = self.air.typeOfIndex(inst);
2713 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };2713 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
2714 if (opt_ty.isPtrLikeOptional()) return operand;2714 if (opt_ty.isPtrLikeOptional()) return operand;
27152715
2716 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);2716 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
...@@ -2731,7 +2731,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2731,7 +2731,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27312731
2732 var buf: Type.Payload.ElemType = undefined;2732 var buf: Type.Payload.ElemType = undefined;
2733 const payload_ty = opt_ty.optionalChild(&buf);2733 const payload_ty = opt_ty.optionalChild(&buf);
2734 if (!payload_ty.hasRuntimeBits() or opt_ty.isPtrLikeOptional()) {2734 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.isPtrLikeOptional()) {
2735 return operand;2735 return operand;
2736 }2736 }
27372737
...@@ -2745,7 +2745,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -2745,7 +2745,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
2745 const opt_ty = self.air.typeOf(ty_op.operand).childType();2745 const opt_ty = self.air.typeOf(ty_op.operand).childType();
2746 var buf: Type.Payload.ElemType = undefined;2746 var buf: Type.Payload.ElemType = undefined;
2747 const payload_ty = opt_ty.optionalChild(&buf);2747 const payload_ty = opt_ty.optionalChild(&buf);
2748 if (!payload_ty.hasRuntimeBits()) {2748 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2749 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});2749 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});
2750 }2750 }
27512751
...@@ -2769,7 +2769,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2769,7 +2769,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27692769
2770 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2770 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2771 const payload_ty = self.air.typeOf(ty_op.operand);2771 const payload_ty = self.air.typeOf(ty_op.operand);
2772 if (!payload_ty.hasRuntimeBits()) {2772 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2773 const non_null_bit = try self.allocStack(Type.initTag(.u1));2773 const non_null_bit = try self.allocStack(Type.initTag(.u1));
2774 try self.emitWValue(non_null_bit);2774 try self.emitWValue(non_null_bit);
2775 try self.addImm32(1);2775 try self.addImm32(1);
...@@ -2958,7 +2958,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2958,7 +2958,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2958 const slice_local = try self.allocStack(slice_ty);2958 const slice_local = try self.allocStack(slice_ty);
29592959
2960 // store the array ptr in the slice2960 // store the array ptr in the slice
2961 if (array_ty.hasRuntimeBits()) {2961 if (array_ty.hasRuntimeBitsIgnoreComptime()) {
2962 try self.store(slice_local, operand, Type.usize, 0);2962 try self.store(slice_local, operand, Type.usize, 0);
2963 }2963 }
29642964
...@@ -3408,7 +3408,7 @@ fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -3408,7 +3408,7 @@ fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue {
3408}3408}
34093409
3410fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3410fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3411 assert(operand_ty.hasRuntimeBits());3411 assert(operand_ty.hasRuntimeBitsIgnoreComptime());
3412 assert(op == .eq or op == .neq);3412 assert(op == .eq or op == .neq);
3413 var buf: Type.Payload.ElemType = undefined;3413 var buf: Type.Payload.ElemType = undefined;
3414 const payload_ty = operand_ty.optionalChild(&buf);3414 const payload_ty = operand_ty.optionalChild(&buf);
...@@ -3575,7 +3575,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -3575,7 +3575,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
35753575
3576 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3576 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
35773577
3578 if (!payload_ty.hasRuntimeBits()) {3578 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3579 return operand;3579 return operand;
3580 }3580 }
35813581
test/behavior/eval.zig+6
...@@ -853,3 +853,9 @@ test "comptime pointer load through elem_ptr" {...@@ -853,3 +853,9 @@ test "comptime pointer load through elem_ptr" {
853 assert(ptr[1].x == 2);853 assert(ptr[1].x == 2);
854 }854 }
855}855}
856
857test "debug variable type resolved through indirect zero-bit types" {
858 const T = struct { key: []void };
859 const slice: []const T = &[_]T{};
860 _ = slice;
861}