authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-13 00:40:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-18 19:02:06-07:00
log927f6ec8ca2234e8c4f27174359d5053da63a77d
tree7e09d07b142f12e5ae4ff94ff48fa7e63ba96f87
parent82db06fa673dabc640c4c954df0dee7a8a6d3bfc

frontend: fix inferred error sets of comptime/inline calls

Previously, they shared function index with the owner decl, but that would clobber the data stored for inferred error sets of runtime calls. Now there is an adhoc_inferred_error_set_type which models the problem much more correctly.

5 files changed, 151 insertions(+), 50 deletions(-)

src/Air.zig+1
......@@ -946,6 +946,7 @@ pub const Inst = struct {
946946 slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
947947 optional_noreturn_type = @intFromEnum(InternPool.Index.optional_noreturn_type),
948948 anyerror_void_error_union_type = @intFromEnum(InternPool.Index.anyerror_void_error_union_type),
949 adhoc_inferred_error_set_type = @intFromEnum(InternPool.Index.adhoc_inferred_error_set_type),
949950 generic_poison_type = @intFromEnum(InternPool.Index.generic_poison_type),
950951 empty_struct_type = @intFromEnum(InternPool.Index.empty_struct_type),
951952 undef = @intFromEnum(InternPool.Index.undef),
src/InternPool.zig+14-5
......@@ -1450,6 +1450,8 @@ pub const Index = enum(u32) {
14501450 slice_const_u8_sentinel_0_type,
14511451 optional_noreturn_type,
14521452 anyerror_void_error_union_type,
1453 /// Used for the inferred error set of inline/comptime function calls.
1454 adhoc_inferred_error_set_type,
14531455 generic_poison_type,
14541456 /// `@TypeOf(.{})`
14551457 empty_struct_type,
......@@ -1886,6 +1888,8 @@ pub const static_keys = [_]Key{
18861888 .payload_type = .void_type,
18871889 } },
18881890
1891 // adhoc_inferred_error_set_type
1892 .{ .simple_type = .adhoc_inferred_error_set },
18891893 // generic_poison_type
18901894 .{ .simple_type = .generic_poison },
18911895
......@@ -2496,6 +2500,7 @@ pub const SimpleType = enum(u32) {
24962500 extern_options,
24972501 type_info,
24982502
2503 adhoc_inferred_error_set,
24992504 generic_poison,
25002505};
25012506
......@@ -5812,14 +5817,17 @@ pub fn isOptionalType(ip: *const InternPool, ty: Index) bool {
58125817
58135818/// includes .inferred_error_set_type
58145819pub fn isErrorSetType(ip: *const InternPool, ty: Index) bool {
5815 return ty == .anyerror_type or switch (ip.indexToKey(ty)) {
5816 .error_set_type, .inferred_error_set_type => true,
5817 else => false,
5820 return switch (ty) {
5821 .anyerror_type, .adhoc_inferred_error_set_type => true,
5822 else => switch (ip.indexToKey(ty)) {
5823 .error_set_type, .inferred_error_set_type => true,
5824 else => false,
5825 },
58185826 };
58195827}
58205828
58215829pub fn isInferredErrorSetType(ip: *const InternPool, ty: Index) bool {
5822 return ip.indexToKey(ty) == .inferred_error_set_type;
5830 return ty == .adhoc_inferred_error_set_type or ip.indexToKey(ty) == .inferred_error_set_type;
58235831}
58245832
58255833pub fn isErrorUnionType(ip: *const InternPool, ty: Index) bool {
......@@ -6412,6 +6420,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
64126420 .slice_const_u8_sentinel_0_type,
64136421 .optional_noreturn_type,
64146422 .anyerror_void_error_union_type,
6423 .adhoc_inferred_error_set_type,
64156424 .generic_poison_type,
64166425 .empty_struct_type,
64176426 => .type_type,
......@@ -6688,7 +6697,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
66886697 .bool_type => .Bool,
66896698 .void_type => .Void,
66906699 .type_type => .Type,
6691 .anyerror_type => .ErrorSet,
6700 .anyerror_type, .adhoc_inferred_error_set_type => .ErrorSet,
66926701 .comptime_int_type => .ComptimeInt,
66936702 .comptime_float_type => .ComptimeFloat,
66946703 .noreturn_type => .NoReturn,
src/Sema.zig+121-42
......@@ -134,16 +134,19 @@ pub const default_reference_trace_len = 2;
134134
135135pub const InferredErrorSet = struct {
136136 /// The function body from which this error set originates.
137 /// This is `none` in the case of a comptime/inline function call, corresponding to
138 /// `InternPool.Index.adhoc_inferred_error_set_type`.
139 /// The function's resolved error set is not set until analysis of the
140 /// function body completes.
137141 func: InternPool.Index,
138
139142 /// All currently known errors that this error set contains. This includes
140143 /// direct additions via `return error.Foo;`, and possibly also errors that
141 /// are returned from any dependent functions. When the inferred error set is
142 /// fully resolved, this map contains all the errors that the function might return.
144 /// are returned from any dependent functions.
143145 errors: NameMap = .{},
144
145146 /// Other inferred error sets which this inferred error set should include.
146147 inferred_error_sets: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
148 /// The regular error set created by resolving this inferred error set.
149 resolved: InternPool.Index = .none,
147150
148151 pub const NameMap = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
149152
......@@ -155,7 +158,7 @@ pub const InferredErrorSet = struct {
155158 ) !void {
156159 switch (err_set_ty.toIntern()) {
157160 .anyerror_type => {
158 ip.funcIesResolved(self.func).* = .anyerror_type;
161 self.resolved = .anyerror_type;
159162 },
160163 else => switch (ip.indexToKey(err_set_ty.toIntern())) {
161164 .error_set_type => |error_set_type| {
......@@ -7060,7 +7063,6 @@ fn analyzeCall(
70607063 .error_set_type = error_set_ty,
70617064 .payload_type = bare_return_type.toIntern(),
70627065 } })).toType();
7063 ip.funcIesResolved(module_fn_index).* = .none;
70647066 }
70657067
70667068 // This `res2` is here instead of directly breaking from `res` due to a stage1
......@@ -7123,7 +7125,9 @@ fn analyzeCall(
71237125 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
71247126 };
71257127
7126 if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) {
7128 if (!is_comptime_call and !block.is_typeof and
7129 sema.typeOf(result).zigTypeTag(mod) != .NoReturn)
7130 {
71277131 try sema.emitDbgInline(
71287132 block,
71297133 module_fn_index,
......@@ -7137,13 +7141,23 @@ fn analyzeCall(
71377141 const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, "");
71387142 const result_interned = try result_val.intern(sema.fn_ret_ty, mod);
71397143
7144 // Transform ad-hoc inferred error set types into concrete error sets.
7145 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
7146
71407147 // TODO: check whether any external comptime memory was mutated by the
71417148 // comptime function call. If so, then do not memoize the call here.
71427149 _ = try mod.intern(.{ .memoized_call = .{
71437150 .func = module_fn_index,
71447151 .arg_values = memoized_arg_values,
7145 .result = result_interned,
7152 .result = result_transformed,
71467153 } });
7154
7155 break :res2 Air.internedToRef(result_transformed);
7156 }
7157
7158 if (sema.fn_ret_ty_ies) |ies| {
7159 _ = ies;
7160 @panic("TODO: resolve ad-hoc inferred error set");
71477161 }
71487162
71497163 break :res2 result;
......@@ -18237,19 +18251,30 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)
1823718251
1823818252fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
1823918253 const mod = sema.mod;
18240 const gpa = sema.gpa;
1824118254 const ip = &mod.intern_pool;
1824218255 assert(sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion);
18256 const err_set_ty = sema.fn_ret_ty.errorUnionSet(mod).toIntern();
18257 switch (err_set_ty) {
18258 .adhoc_inferred_error_set_type => {
18259 const ies = sema.fn_ret_ty_ies.?;
18260 assert(ies.func == .none);
18261 try addToInferredErrorSetPtr(mod, ies, sema.typeOf(uncasted_operand));
18262 },
18263 else => if (ip.isInferredErrorSetType(err_set_ty)) {
18264 const ies = sema.fn_ret_ty_ies.?;
18265 assert(ies.func == sema.func_index);
18266 try addToInferredErrorSetPtr(mod, ies, sema.typeOf(uncasted_operand));
18267 },
18268 }
18269}
1824318270
18244 if (ip.isInferredErrorSetType(sema.fn_ret_ty.errorUnionSet(mod).toIntern())) {
18245 const ies = sema.fn_ret_ty_ies.?;
18246 assert(ies.func == sema.func_index);
18247 const op_ty = sema.typeOf(uncasted_operand);
18248 switch (op_ty.zigTypeTag(mod)) {
18249 .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa),
18250 .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa),
18251 else => {},
18252 }
18271fn addToInferredErrorSetPtr(mod: *Module, ies: *InferredErrorSet, op_ty: Type) !void {
18272 const gpa = mod.gpa;
18273 const ip = &mod.intern_pool;
18274 switch (op_ty.zigTypeTag(mod)) {
18275 .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa),
18276 .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa),
18277 else => {},
1825318278 }
1825418279}
1825518280
......@@ -27936,6 +27961,14 @@ fn coerceInMemoryAllowedErrorSets(
2793627961 return .ok;
2793727962 }
2793827963
27964 if (dest_ty.toIntern() == .adhoc_inferred_error_set_type) {
27965 // We are trying to coerce an error set to the current function's
27966 // inferred error set.
27967 const dst_ies = sema.fn_ret_ty_ies.?;
27968 try dst_ies.addErrorSet(src_ty, ip, gpa);
27969 return .ok;
27970 }
27971
2793927972 if (ip.isInferredErrorSetType(dest_ty.toIntern())) {
2794027973 const dst_ies_func_index = ip.iesFuncIndex(dest_ty.toIntern());
2794127974 if (sema.fn_ret_ty_ies) |dst_ies| {
......@@ -27946,7 +27979,6 @@ fn coerceInMemoryAllowedErrorSets(
2794627979 return .ok;
2794727980 }
2794827981 }
27949
2795027982 switch (try sema.resolveInferredErrorSet(block, dest_src, dest_ty.toIntern())) {
2795127983 // isAnyError might have changed from a false negative to a true
2795227984 // positive after resolution.
......@@ -30551,21 +30583,25 @@ fn analyzeIsNonErrComptimeOnly(
3055130583 else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk,
3055230584 }
3055330585 if (maybe_operand_val == null) {
30554 if (sema.fn_ret_ty_ies) |ies| if (ies.func == func_index) {
30555 // Try to avoid resolving inferred error set if possible.
30556 for (ies.inferred_error_sets.keys()) |other_ies_index| {
30557 if (set_ty == other_ies_index) continue;
30558 const other_resolved =
30559 try sema.resolveInferredErrorSet(block, src, other_ies_index);
30560 if (other_resolved == .anyerror_type) {
30561 ip.funcIesResolved(func_index).* = .anyerror_type;
30562 break :blk;
30586 if (sema.fn_ret_ty_ies) |ies| {
30587 if (set_ty == .adhoc_inferred_error_set_type or
30588 ies.func == func_index)
30589 {
30590 // Try to avoid resolving inferred error set if possible.
30591 for (ies.inferred_error_sets.keys()) |other_ies_index| {
30592 if (set_ty == other_ies_index) continue;
30593 const other_resolved =
30594 try sema.resolveInferredErrorSet(block, src, other_ies_index);
30595 if (other_resolved == .anyerror_type) {
30596 ip.funcIesResolved(func_index).* = .anyerror_type;
30597 break :blk;
30598 }
30599 if (ip.indexToKey(other_resolved).error_set_type.names.len != 0)
30600 break :blk;
3056330601 }
30564 if (ip.indexToKey(other_resolved).error_set_type.names.len != 0)
30565 break :blk;
30602 return .bool_true;
3056630603 }
30567 return .bool_true;
30568 };
30604 }
3056930605 const resolved_ty = try sema.resolveInferredErrorSet(block, src, set_ty);
3057030606 if (resolved_ty == .anyerror_type)
3057130607 break :blk;
......@@ -31520,18 +31556,30 @@ fn wrapErrorUnionSet(
3152031556 const inst_ty = sema.typeOf(inst);
3152131557 const dest_err_set_ty = dest_ty.errorUnionSet(mod);
3152231558 if (try sema.resolveMaybeUndefVal(inst)) |val| {
31559 const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
3152331560 switch (dest_err_set_ty.toIntern()) {
3152431561 .anyerror_type => {},
31562 .adhoc_inferred_error_set_type => ok: {
31563 const ies = sema.fn_ret_ty_ies.?;
31564 switch (ies.resolved) {
31565 .anyerror_type => break :ok,
31566 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
31567 break :ok;
31568 },
31569 else => |i| if (ip.indexToKey(i).error_set_type.nameIndex(ip, expected_name) != null) {
31570 break :ok;
31571 },
31572 }
31573 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
31574 },
3152531575 else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) {
3152631576 .error_set_type => |error_set_type| ok: {
31527 const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
3152831577 if (error_set_type.nameIndex(ip, expected_name) != null) break :ok;
3152931578 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
3153031579 },
3153131580 .inferred_error_set_type => |func_index| ok: {
3153231581 // We carefully do this in an order that avoids unnecessarily
3153331582 // resolving the destination error set type.
31534 const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
3153531583 switch (ip.funcIesResolved(func_index).*) {
3153631584 .anyerror_type => break :ok,
3153731585 .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
......@@ -31549,9 +31597,7 @@ fn wrapErrorUnionSet(
3154931597 }
3155031598 return sema.addConstant((try mod.intern(.{ .error_union = .{
3155131599 .ty = dest_ty.toIntern(),
31552 .val = .{
31553 .err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name,
31554 },
31600 .val = .{ .err_name = expected_name },
3155531601 } })).toValue());
3155631602 }
3155731603
......@@ -33033,7 +33079,11 @@ pub fn resolveFnTypes(sema: *Sema, block: *Block, src: LazySrcLoc, fn_ty: Type)
3303333079 const ip = &mod.intern_pool;
3303433080 const fn_ty_info = mod.typeToFunc(fn_ty).?;
3303533081
33036 if (sema.fn_ret_ty_ies) |ies| try sema.resolveInferredErrorSetPtr(block, src, ies);
33082 if (sema.fn_ret_ty_ies) |ies| {
33083 try sema.resolveInferredErrorSetPtr(block, src, ies);
33084 assert(ies.resolved != .none);
33085 ip.funcIesResolved(sema.func_index).* = ies.resolved;
33086 }
3303733087
3303833088 try sema.resolveTypeFully(fn_ty_info.return_type.toType());
3303933089
......@@ -33565,6 +33615,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3356533615 .bool,
3356633616 .void,
3356733617 .anyerror,
33618 .adhoc_inferred_error_set,
3356833619 .noreturn,
3356933620 .generic_poison,
3357033621 .atomic_order,
......@@ -33815,6 +33866,7 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
3381533866 .void_type,
3381633867 .type_type,
3381733868 .anyerror_type,
33869 .adhoc_inferred_error_set_type,
3381833870 .comptime_int_type,
3381933871 .comptime_float_type,
3382033872 .noreturn_type,
......@@ -34032,8 +34084,7 @@ fn resolveInferredErrorSetPtr(
3403234084 const mod = sema.mod;
3403334085 const ip = &mod.intern_pool;
3403434086
34035 const func = mod.funcInfo(ies.func);
34036 if (func.resolvedErrorSet(ip).* != .none) return;
34087 if (ies.resolved != .none) return;
3403734088
3403834089 const ies_index = ip.errorUnionSet(sema.fn_ret_ty.toIntern());
3403934090
......@@ -34041,7 +34092,7 @@ fn resolveInferredErrorSetPtr(
3404134092 if (ies_index == other_ies_index) continue;
3404234093 switch (try sema.resolveInferredErrorSet(block, src, other_ies_index)) {
3404334094 .anyerror_type => {
34044 func.resolvedErrorSet(ip).* = .anyerror_type;
34095 ies.resolved = .anyerror_type;
3404534096 return;
3404634097 },
3404734098 else => |error_set_ty_index| {
......@@ -34054,7 +34105,33 @@ fn resolveInferredErrorSetPtr(
3405434105 }
3405534106
3405634107 const resolved_error_set_ty = try mod.errorSetFromUnsortedNames(ies.errors.keys());
34057 func.resolvedErrorSet(ip).* = resolved_error_set_ty.toIntern();
34108 ies.resolved = resolved_error_set_ty.toIntern();
34109}
34110
34111fn resolveAdHocInferredErrorSet(
34112 sema: *Sema,
34113 block: *Block,
34114 src: LazySrcLoc,
34115 value: InternPool.Index,
34116) CompileError!InternPool.Index {
34117 const ies = sema.fn_ret_ty_ies orelse return value;
34118 const mod = sema.mod;
34119 const gpa = sema.gpa;
34120 const ip = &mod.intern_pool;
34121 const ty = ip.typeOf(value);
34122 const error_union_info = switch (ip.indexToKey(ty)) {
34123 .error_union_type => |x| x,
34124 else => return value,
34125 };
34126 if (error_union_info.error_set_type != .adhoc_inferred_error_set_type)
34127 return value;
34128
34129 try sema.resolveInferredErrorSetPtr(block, src, ies);
34130 const new_ty = try ip.get(gpa, .{ .error_union_type = .{
34131 .error_set_type = ies.resolved,
34132 .payload_type = error_union_info.payload_type,
34133 } });
34134 return ip.getCoerced(gpa, value, new_ty);
3405834135}
3405934136
3406034137fn resolveInferredErrorSetTy(
......@@ -35037,6 +35114,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3503735114 .bool_type,
3503835115 .type_type,
3503935116 .anyerror_type,
35117 .adhoc_inferred_error_set_type,
3504035118 .comptime_int_type,
3504135119 .comptime_float_type,
3504235120 .enum_literal_type,
......@@ -35692,6 +35770,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3569235770 .prefetch_options,
3569335771 .export_options,
3569435772 .extern_options,
35773 .adhoc_inferred_error_set,
3569535774 => false,
3569635775
3569735776 .type,
src/Zir.zig+1
......@@ -2087,6 +2087,7 @@ pub const Inst = struct {
20872087 slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
20882088 optional_noreturn_type = @intFromEnum(InternPool.Index.optional_noreturn_type),
20892089 anyerror_void_error_union_type = @intFromEnum(InternPool.Index.anyerror_void_error_union_type),
2090 adhoc_inferred_error_set_type = @intFromEnum(InternPool.Index.adhoc_inferred_error_set_type),
20902091 generic_poison_type = @intFromEnum(InternPool.Index.generic_poison_type),
20912092 empty_struct_type = @intFromEnum(InternPool.Index.empty_struct_type),
20922093 undef = @intFromEnum(InternPool.Index.undef),
src/type.zig+14-3
......@@ -292,6 +292,7 @@ pub const Type = struct {
292292 .comptime_int,
293293 .comptime_float,
294294 .noreturn,
295 .adhoc_inferred_error_set,
295296 => return writer.writeAll(@tagName(s)),
296297
297298 .null,
......@@ -533,6 +534,7 @@ pub const Type = struct {
533534 .c_longdouble,
534535 .bool,
535536 .anyerror,
537 .adhoc_inferred_error_set,
536538 .anyopaque,
537539 .atomic_order,
538540 .atomic_rmw_op,
......@@ -696,6 +698,7 @@ pub const Type = struct {
696698 => true,
697699
698700 .anyerror,
701 .adhoc_inferred_error_set,
699702 .anyopaque,
700703 .atomic_order,
701704 .atomic_rmw_op,
......@@ -954,7 +957,9 @@ pub const Type = struct {
954957 },
955958
956959 // TODO revisit this when we have the concept of the error tag type
957 .anyerror => return AbiAlignmentAdvanced{ .scalar = 2 },
960 .anyerror,
961 .adhoc_inferred_error_set,
962 => return AbiAlignmentAdvanced{ .scalar = 2 },
958963
959964 .void,
960965 .type,
......@@ -1418,7 +1423,9 @@ pub const Type = struct {
14181423 => return AbiSizeAdvanced{ .scalar = 0 },
14191424
14201425 // TODO revisit this when we have the concept of the error tag type
1421 .anyerror => return AbiSizeAdvanced{ .scalar = 2 },
1426 .anyerror,
1427 .adhoc_inferred_error_set,
1428 => return AbiSizeAdvanced{ .scalar = 2 },
14221429
14231430 .prefetch_options => unreachable, // missing call to resolveTypeFields
14241431 .export_options => unreachable, // missing call to resolveTypeFields
......@@ -1661,7 +1668,9 @@ pub const Type = struct {
16611668 .void => return 0,
16621669
16631670 // TODO revisit this when we have the concept of the error tag type
1664 .anyerror => return 16,
1671 .anyerror,
1672 .adhoc_inferred_error_set,
1673 => return 16,
16651674
16661675 .anyopaque => unreachable,
16671676 .type => unreachable,
......@@ -2503,6 +2512,7 @@ pub const Type = struct {
25032512 .export_options,
25042513 .extern_options,
25052514 .type_info,
2515 .adhoc_inferred_error_set,
25062516 => return null,
25072517
25082518 .void => return Value.void,
......@@ -2697,6 +2707,7 @@ pub const Type = struct {
26972707 .bool,
26982708 .void,
26992709 .anyerror,
2710 .adhoc_inferred_error_set,
27002711 .noreturn,
27012712 .generic_poison,
27022713 .atomic_order,