authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-17 04:39:09+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-21 01:41:50+01:00
log9d6c45f6979543607a7064be7155afa409be956a
treec92d89093e998cdca6fbe3c546e290ea00248366
parenta2958a4ede0af4b4559eeb142c0400ae640db63e

stage2: inferred error set coercion


3 files changed, 183 insertions(+), 42 deletions(-)

src/Module.zig+9-6
...@@ -1239,14 +1239,17 @@ pub const Fn = struct {...@@ -1239,14 +1239,17 @@ pub const Fn = struct {
1239 /// When the inferred error set is fully resolved, this map contains all the errors that the function might return.1239 /// When the inferred error set is fully resolved, this map contains all the errors that the function might return.
1240 errors: std.StringHashMapUnmanaged(void) = .{},1240 errors: std.StringHashMapUnmanaged(void) = .{},
12411241
1242 /// Other functions with inferred error sets which the inferred error set of this1242 /// Other inferred error sets which this inferred error set should include.
1243 /// function should include.1243 inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{},
1244 functions: std.AutoHashMapUnmanaged(*Fn, void) = .{},
12451244
1246 /// Whether the function returned anyerror. This is true if either of the dependent functions1245 /// Whether the function returned anyerror. This is true if either of the dependent functions
1247 /// returns anyerror.1246 /// returns anyerror.
1248 is_anyerror: bool = false,1247 is_anyerror: bool = false,
12491248
1249 /// Whether this error set is already fully resolved. If true, resolving can skip resolving any dependents
1250 /// of this inferred error set.
1251 is_resolved: bool = false,
1252
1250 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {1253 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void {
1251 switch (err_set_ty.tag()) {1254 switch (err_set_ty.tag()) {
1252 .error_set => {1255 .error_set => {
...@@ -1260,8 +1263,8 @@ pub const Fn = struct {...@@ -1260,8 +1263,8 @@ pub const Fn = struct {
1260 try self.errors.put(gpa, name, {});1263 try self.errors.put(gpa, name, {});
1261 },1264 },
1262 .error_set_inferred => {1265 .error_set_inferred => {
1263 const dependent_func = err_set_ty.castTag(.error_set_inferred).?.data.func;1266 const set = err_set_ty.castTag(.error_set_inferred).?.data;
1264 try self.functions.put(gpa, dependent_func, {});1267 try self.inferred_error_sets.put(gpa, set, {});
1265 },1268 },
1266 .error_set_merged => {1269 .error_set_merged => {
1267 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();1270 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
...@@ -1285,7 +1288,7 @@ pub const Fn = struct {...@@ -1285,7 +1288,7 @@ pub const Fn = struct {
1285 while (it) |node| {1288 while (it) |node| {
1286 const next = node.next;1289 const next = node.next;
1287 node.data.errors.deinit(gpa);1290 node.data.errors.deinit(gpa);
1288 node.data.functions.deinit(gpa);1291 node.data.inferred_error_sets.deinit(gpa);
1289 gpa.destroy(node);1292 gpa.destroy(node);
1290 it = next;1293 it = next;
1291 }1294 }
src/Sema.zig+144-35
...@@ -5207,9 +5207,6 @@ fn funcCommon(...@@ -5207,9 +5207,6 @@ fn funcCommon(
5207 .rbrace_line = src_locs.rbrace_line,5207 .rbrace_line = src_locs.rbrace_line,
5208 .lbrace_column = @truncate(u16, src_locs.columns),5208 .lbrace_column = @truncate(u16, src_locs.columns),
5209 .rbrace_column = @truncate(u16, src_locs.columns >> 16),5209 .rbrace_column = @truncate(u16, src_locs.columns >> 16),
5210 .inferred_error_sets = .{
5211 .first = maybe_inferred_error_set_node,
5212 },
5213 };5210 };
5214 if (maybe_inferred_error_set_node) |node| {5211 if (maybe_inferred_error_set_node) |node| {
5215 new_func.inferred_error_sets.prepend(node);5212 new_func.inferred_error_sets.prepend(node);
...@@ -12193,7 +12190,7 @@ fn coerce(...@@ -12193,7 +12190,7 @@ fn coerce(
12193 const arena = sema.arena;12190 const arena = sema.arena;
12194 const target = sema.mod.getTarget();12191 const target = sema.mod.getTarget();
1219512192
12196 const in_memory_result = coerceInMemoryAllowed(dest_ty, inst_ty, false, target);12193 const in_memory_result = try sema.coerceInMemoryAllowed(dest_ty, inst_ty, false, target);
12197 if (in_memory_result == .ok) {12194 if (in_memory_result == .ok) {
12198 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {12195 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
12199 // Keep the comptime Value representation; take the new type.12196 // Keep the comptime Value representation; take the new type.
...@@ -12252,7 +12249,7 @@ fn coerce(...@@ -12252,7 +12249,7 @@ fn coerce(
12252 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;12249 if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;
12253 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;12250 if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;
12254 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;12251 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
12255 switch (coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) {12252 switch (try sema.coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) {
12256 .ok => {},12253 .ok => {},
12257 .no_match => break :single_item,12254 .no_match => break :single_item,
12258 }12255 }
...@@ -12271,7 +12268,7 @@ fn coerce(...@@ -12271,7 +12268,7 @@ fn coerce(
12271 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;12268 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;
1227212269
12273 const dst_elem_type = dest_info.pointee_type;12270 const dst_elem_type = dest_info.pointee_type;
12274 switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) {12271 switch (try sema.coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) {
12275 .ok => {},12272 .ok => {},
12276 .no_match => break :src_array_ptr,12273 .no_match => break :src_array_ptr,
12277 }12274 }
...@@ -12310,7 +12307,7 @@ fn coerce(...@@ -12310,7 +12307,7 @@ fn coerce(
12310 const src_elem_ty = inst_ty.childType();12307 const src_elem_ty = inst_ty.childType();
12311 const dest_is_mut = dest_info.mutable;12308 const dest_is_mut = dest_info.mutable;
12312 const dst_elem_type = dest_info.pointee_type;12309 const dst_elem_type = dest_info.pointee_type;
12313 switch (coerceInMemoryAllowed(dst_elem_type, src_elem_ty, dest_is_mut, target)) {12310 switch (try sema.coerceInMemoryAllowed(dst_elem_type, src_elem_ty, dest_is_mut, target)) {
12314 .ok => {},12311 .ok => {},
12315 .no_match => break :src_c_ptr,12312 .no_match => break :src_c_ptr,
12316 }12313 }
...@@ -12453,7 +12450,13 @@ const InMemoryCoercionResult = enum {...@@ -12453,7 +12450,13 @@ const InMemoryCoercionResult = enum {
12453/// * sentinel-terminated pointers can coerce into `[*]`12450/// * sentinel-terminated pointers can coerce into `[*]`
12454/// TODO improve this function to report recursive compile errors like it does in stage1.12451/// TODO improve this function to report recursive compile errors like it does in stage1.
12455/// look at the function types_match_const_cast_only12452/// look at the function types_match_const_cast_only
12456fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: std.Target) InMemoryCoercionResult {12453fn coerceInMemoryAllowed(
12454 sema: *Sema,
12455 dest_ty: Type,
12456 src_ty: Type,
12457 dest_is_mut: bool,
12458 target: std.Target
12459) CompileError!InMemoryCoercionResult {
12457 if (dest_ty.eql(src_ty))12460 if (dest_ty.eql(src_ty))
12458 return .ok;12461 return .ok;
1245912462
...@@ -12462,32 +12465,35 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:...@@ -12462,32 +12465,35 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:
12462 var src_buf: Type.Payload.ElemType = undefined;12465 var src_buf: Type.Payload.ElemType = undefined;
12463 if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {12466 if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| {
12464 if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {12467 if (src_ty.ptrOrOptionalPtrTy(&src_buf)) |src_ptr_ty| {
12465 return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);12468 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target);
12466 }12469 }
12467 }12470 }
1246812471
12469 // Slices12472 // Slices
12470 if (dest_ty.isSlice() and src_ty.isSlice()) {12473 if (dest_ty.isSlice() and src_ty.isSlice()) {
12471 return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);12474 return try sema.coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
12472 }12475 }
1247312476
12477 const dest_tag = dest_ty.zigTypeTag();
12478 const src_tag = src_ty.zigTypeTag();
12479
12474 // Functions12480 // Functions
12475 if (dest_ty.zigTypeTag() == .Fn and src_ty.zigTypeTag() == .Fn) {12481 if (dest_tag == .Fn and src_tag == .Fn) {
12476 return coerceInMemoryAllowedFns(dest_ty, src_ty, target);12482 return try sema.coerceInMemoryAllowedFns(dest_ty, src_ty, target);
12477 }12483 }
1247812484
12479 // Error Unions12485 // Error Unions
12480 if (dest_ty.zigTypeTag() == .ErrorUnion and src_ty.zigTypeTag() == .ErrorUnion) {12486 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
12481 const child = coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target);12487 const child = try sema.coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target);
12482 if (child == .no_match) {12488 if (child == .no_match) {
12483 return child;12489 return child;
12484 }12490 }
12485 return coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);12491 return try sema.coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);
12486 }12492 }
1248712493
12488 // Error Sets12494 // Error Sets
12489 if (dest_ty.zigTypeTag() == .ErrorSet and src_ty.zigTypeTag() == .ErrorSet) {12495 if (dest_tag == .ErrorSet and src_tag == .ErrorSet) {
12490 return coerceInMemoryAllowedErrorSets(dest_ty, src_ty);12496 return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty);
12491 }12497 }
1249212498
12493 // TODO: arrays12499 // TODO: arrays
...@@ -12498,14 +12504,16 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:...@@ -12498,14 +12504,16 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:
12498}12504}
1249912505
12500fn coerceInMemoryAllowedErrorSets(12506fn coerceInMemoryAllowedErrorSets(
12507 sema: *Sema,
12501 dest_ty: Type,12508 dest_ty: Type,
12502 src_ty: Type,12509 src_ty: Type,
12503) InMemoryCoercionResult {12510) !InMemoryCoercionResult {
12504 // Coercion to `anyerror`. Note that this check can return false positives12511 // Coercion to `anyerror`. Note that this check can return false negatives
12505 // in case the error sets did not get resolved.12512 // in case the error sets did not get resolved.
12506 if (dest_ty.isAnyError()) {12513 if (dest_ty.isAnyError()) {
12507 return .ok;12514 return .ok;
12508 }12515 }
12516
12509 // If both are inferred error sets of functions, and12517 // If both are inferred error sets of functions, and
12510 // the dest includes the source function, the coercion is OK.12518 // the dest includes the source function, the coercion is OK.
12511 // This check is important because it works without forcing a full resolution12519 // This check is important because it works without forcing a full resolution
...@@ -12515,21 +12523,85 @@ fn coerceInMemoryAllowedErrorSets(...@@ -12515,21 +12523,85 @@ fn coerceInMemoryAllowedErrorSets(
12515 const src_func = src_payload.data.func;12523 const src_func = src_payload.data.func;
12516 const dst_func = dst_payload.data.func;12524 const dst_func = dst_payload.data.func;
1251712525
12518 if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) {12526 if (src_func == dst_func or dst_payload.data.inferred_error_sets.contains(src_payload.data)) {
12519 return .ok;12527 return .ok;
12520 }12528 }
12529 return .no_match;
12521 }12530 }
12522 }12531 }
1252312532
12524 // TODO full error set resolution and compare sets by names.12533 if (dest_ty.castTag(.error_set_inferred)) |payload| {
12534 try sema.resolveInferredErrorSet(payload.data);
12535 // isAnyError might have changed from a false negative to a true positive after resolution.
12536 if (dest_ty.isAnyError()) {
12537 return .ok;
12538 }
12539 }
12540
12541 switch (src_ty.tag()) {
12542 .error_set_inferred => {
12543 const src_data = src_ty.castTag(.error_set_inferred).?.data;
12544
12545 try sema.resolveInferredErrorSet(src_data);
12546 // src anyerror status might have changed after the resolution.
12547 if (src_ty.isAnyError()) {
12548 // dest_ty.isAnyError() == true is already checked for at this point.
12549 return .no_match;
12550 }
12551
12552 var it = src_data.errors.keyIterator();
12553 while (it.next()) |name_ptr| {
12554 if (!dest_ty.errorSetHasField(name_ptr.*)) {
12555 return .no_match;
12556 }
12557 }
12558
12559 return .ok;
12560 },
12561 .error_set_single => {
12562 const name = src_ty.castTag(.error_set_single).?.data;
12563 if (dest_ty.errorSetHasField(name)) {
12564 return .ok;
12565 }
12566 },
12567 .error_set_merged => {
12568 const names = src_ty.castTag(.error_set_merged).?.data.keys();
12569 for (names) |name| {
12570 if (!dest_ty.errorSetHasField(name)) {
12571 return .no_match;
12572 }
12573 }
12574
12575 return .ok;
12576 },
12577 .error_set => {
12578 const names = src_ty.castTag(.error_set).?.data.names.keys();
12579 for (names) |name| {
12580 if (!dest_ty.errorSetHasField(name)) {
12581 return .no_match;
12582 }
12583 }
12584
12585 return .ok;
12586 },
12587 .anyerror => switch (dest_ty.tag()) {
12588 .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above.
12589 .error_set_single, .error_set_merged, .error_set => {},
12590 .anyerror => unreachable, // Filtered out above.
12591 else => unreachable,
12592 },
12593 else => unreachable,
12594 }
12595
12525 return .no_match;12596 return .no_match;
12526}12597}
1252712598
12528fn coerceInMemoryAllowedFns(12599fn coerceInMemoryAllowedFns(
12600 sema: *Sema,
12529 dest_ty: Type,12601 dest_ty: Type,
12530 src_ty: Type,12602 src_ty: Type,
12531 target: std.Target,12603 target: std.Target,
12532) InMemoryCoercionResult {12604) !InMemoryCoercionResult {
12533 const dest_info = dest_ty.fnInfo();12605 const dest_info = dest_ty.fnInfo();
12534 const src_info = src_ty.fnInfo();12606 const src_info = src_ty.fnInfo();
1253512607
...@@ -12542,7 +12614,7 @@ fn coerceInMemoryAllowedFns(...@@ -12542,7 +12614,7 @@ fn coerceInMemoryAllowedFns(
12542 }12614 }
1254312615
12544 if (!src_info.return_type.isNoReturn()) {12616 if (!src_info.return_type.isNoReturn()) {
12545 const rt = coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);12617 const rt = try sema.coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);
12546 if (rt == .no_match) {12618 if (rt == .no_match) {
12547 return rt;12619 return rt;
12548 }12620 }
...@@ -12562,7 +12634,7 @@ fn coerceInMemoryAllowedFns(...@@ -12562,7 +12634,7 @@ fn coerceInMemoryAllowedFns(
12562 // TODO: nolias12634 // TODO: nolias
1256312635
12564 // Note: Cast direction is reversed here.12636 // Note: Cast direction is reversed here.
12565 const param = coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);12637 const param = try sema.coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);
12566 if (param == .no_match) {12638 if (param == .no_match) {
12567 return param;12639 return param;
12568 }12640 }
...@@ -12576,17 +12648,18 @@ fn coerceInMemoryAllowedFns(...@@ -12576,17 +12648,18 @@ fn coerceInMemoryAllowedFns(
12576}12648}
1257712649
12578fn coerceInMemoryAllowedPtrs(12650fn coerceInMemoryAllowedPtrs(
12651 sema: *Sema,
12579 dest_ty: Type,12652 dest_ty: Type,
12580 src_ty: Type,12653 src_ty: Type,
12581 dest_ptr_ty: Type,12654 dest_ptr_ty: Type,
12582 src_ptr_ty: Type,12655 src_ptr_ty: Type,
12583 dest_is_mut: bool,12656 dest_is_mut: bool,
12584 target: std.Target,12657 target: std.Target,
12585) InMemoryCoercionResult {12658) !InMemoryCoercionResult {
12586 const dest_info = dest_ptr_ty.ptrInfo().data;12659 const dest_info = dest_ptr_ty.ptrInfo().data;
12587 const src_info = src_ptr_ty.ptrInfo().data;12660 const src_info = src_ptr_ty.ptrInfo().data;
1258812661
12589 const child = coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);12662 const child = try sema.coerceInMemoryAllowed(dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target);
12590 if (child == .no_match) {12663 if (child == .no_match) {
12591 return child;12664 return child;
12592 }12665 }
...@@ -13307,7 +13380,7 @@ fn coerceVectorInMemory(...@@ -13307,7 +13380,7 @@ fn coerceVectorInMemory(
13307 const target = sema.mod.getTarget();13380 const target = sema.mod.getTarget();
13308 const dest_elem_ty = dest_ty.childType();13381 const dest_elem_ty = dest_ty.childType();
13309 const inst_elem_ty = inst_ty.childType();13382 const inst_elem_ty = inst_ty.childType();
13310 const in_memory_result = coerceInMemoryAllowed(dest_elem_ty, inst_elem_ty, false, target);13383 const in_memory_result = try sema.coerceInMemoryAllowed(dest_elem_ty, inst_elem_ty, false, target);
13311 if (in_memory_result != .ok) {13384 if (in_memory_result != .ok) {
13312 // TODO recursive error notes for coerceInMemoryAllowed failure13385 // TODO recursive error notes for coerceInMemoryAllowed failure
13313 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });13386 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
...@@ -13910,11 +13983,11 @@ fn wrapErrorUnion(...@@ -13910,11 +13983,11 @@ fn wrapErrorUnion(
13910 }13983 }
13911 },13984 },
13912 .error_set_inferred => ok: {13985 .error_set_inferred => ok: {
13986 const expected_name = val.castTag(.@"error").?.data.name;
13913 const data = dest_err_set_ty.castTag(.error_set_inferred).?.data;13987 const data = dest_err_set_ty.castTag(.error_set_inferred).?.data;
13988 try sema.resolveInferredErrorSet(data);
13914 if (data.is_anyerror) break :ok;13989 if (data.is_anyerror) break :ok;
13915 const expected_name = val.castTag(.@"error").?.data.name;
13916 if (data.errors.contains(expected_name)) break :ok;13990 if (data.errors.contains(expected_name)) break :ok;
13917 // TODO error set resolution here before emitting a compile error
13918 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);13991 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13919 },13992 },
13920 else => unreachable,13993 else => unreachable,
...@@ -14059,12 +14132,12 @@ fn resolvePeerTypes(...@@ -14059,12 +14132,12 @@ fn resolvePeerTypes(
14059 .Optional => {14132 .Optional => {
14060 var opt_child_buf: Type.Payload.ElemType = undefined;14133 var opt_child_buf: Type.Payload.ElemType = undefined;
14061 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);14134 const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
14062 if (coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target) == .ok) {14135 if ((try sema.coerceInMemoryAllowed(opt_child_ty, chosen_ty, false, target)) == .ok) {
14063 chosen = candidate;14136 chosen = candidate;
14064 chosen_i = candidate_i + 1;14137 chosen_i = candidate_i + 1;
14065 continue;14138 continue;
14066 }14139 }
14067 if (coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target) == .ok) {14140 if ((try sema.coerceInMemoryAllowed(chosen_ty, opt_child_ty, false, target)) == .ok) {
14068 any_are_null = true;14141 any_are_null = true;
14069 continue;14142 continue;
14070 }14143 }
...@@ -14087,10 +14160,10 @@ fn resolvePeerTypes(...@@ -14087,10 +14160,10 @@ fn resolvePeerTypes(
14087 .Optional => {14160 .Optional => {
14088 var opt_child_buf: Type.Payload.ElemType = undefined;14161 var opt_child_buf: Type.Payload.ElemType = undefined;
14089 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);14162 const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
14090 if (coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target) == .ok) {14163 if ((try sema.coerceInMemoryAllowed(opt_child_ty, candidate_ty, false, target)) == .ok) {
14091 continue;14164 continue;
14092 }14165 }
14093 if (coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target) == .ok) {14166 if ((try sema.coerceInMemoryAllowed(candidate_ty, opt_child_ty, false, target)) == .ok) {
14094 any_are_null = true;14167 any_are_null = true;
14095 chosen = candidate;14168 chosen = candidate;
14096 chosen_i = candidate_i + 1;14169 chosen_i = candidate_i + 1;
...@@ -14256,6 +14329,42 @@ fn resolveBuiltinTypeFields(...@@ -14256,6 +14329,42 @@ fn resolveBuiltinTypeFields(
14256 return sema.resolveTypeFields(block, src, resolved_ty);14329 return sema.resolveTypeFields(block, src, resolved_ty);
14257}14330}
1425814331
14332fn resolveInferredErrorSet(sema: *Sema, inferred_error_set: *Module.Fn.InferredErrorSet) CompileError!void {
14333 // Ensuring that a particular decl is analyzed does not neccesarily mean that
14334 // it's error set is inferred, so traverse all of them to get the complete
14335 // picture.
14336 // Note: We want to skip re-resolving the current function, as recursion
14337 // doesn't change the error set. We can just check for state == .in_progress for this.
14338 // TODO: Is that correct?
14339
14340 if (inferred_error_set.is_resolved) {
14341 return;
14342 }
14343
14344 var it = inferred_error_set.inferred_error_sets.keyIterator();
14345 while (it.next()) |other_error_set_ptr| {
14346 const func = other_error_set_ptr.*.func;
14347 const decl = func.*.owner_decl;
14348
14349 if (func.*.state == .in_progress) {
14350 // Recursion, doesn't alter current error set, keep going.
14351 continue;
14352 }
14353
14354 try sema.ensureDeclAnalyzed(decl); // To ensure that all dependencies are properly added to the set.
14355 try sema.resolveInferredErrorSet(other_error_set_ptr.*);
14356
14357 var error_it = other_error_set_ptr.*.errors.keyIterator();
14358 while (error_it.next()) |entry| {
14359 try inferred_error_set.errors.put(sema.gpa, entry.*, {});
14360 }
14361 if (other_error_set_ptr.*.is_anyerror)
14362 inferred_error_set.is_anyerror = true;
14363 }
14364
14365 inferred_error_set.is_resolved = true;
14366}
14367
14259fn semaStructFields(14368fn semaStructFields(
14260 mod: *Module,14369 mod: *Module,
14261 struct_obj: *Module.Struct,14370 struct_obj: *Module.Struct,
...@@ -15218,8 +15327,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr...@@ -15218,8 +15327,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
15218 // We have a Value that lines up in virtual memory exactly with what we want to load.15327 // We have a Value that lines up in virtual memory exactly with what we want to load.
15219 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.15328 // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications.
15220 const coerce_in_mem_ok =15329 const coerce_in_mem_ok =
15221 coerceInMemoryAllowed(load_ty, parent.ty, false, target) == .ok or15330 (try sema.coerceInMemoryAllowed(load_ty, parent.ty, false, target)) == .ok or
15222 coerceInMemoryAllowed(parent.ty, load_ty, false, target) == .ok;15331 (try sema.coerceInMemoryAllowed(parent.ty, load_ty, false, target)) == .ok;
15223 if (coerce_in_mem_ok) {15332 if (coerce_in_mem_ok) {
15224 if (parent.is_mutable) {15333 if (parent.is_mutable) {
15225 // The decl whose value we are obtaining here may be overwritten with15334 // The decl whose value we are obtaining here may be overwritten with
src/type.zig+30-1
...@@ -1203,7 +1203,7 @@ pub const Type = extern union {...@@ -1203,7 +1203,7 @@ pub const Type = extern union {
1203 return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0));1203 return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0));
1204 },1204 },
1205 .error_set_inferred => {1205 .error_set_inferred => {
1206 const func = ty.castTag(.error_set_inferred).?.data;1206 const func = ty.castTag(.error_set_inferred).?.data.func;
1207 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});1207 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
1208 },1208 },
1209 .error_set_merged => {1209 .error_set_merged => {
...@@ -2874,6 +2874,35 @@ pub const Type = extern union {...@@ -2874,6 +2874,35 @@ pub const Type = extern union {
2874 };2874 };
2875 }2875 }
28762876
2877 /// Returns whether ty, which must be an error set, includes an error `name`.
2878 /// Might return a false negative if `ty` is an inferred error set and not fully
2879 /// resolved yet.
2880 pub fn errorSetHasField(ty: Type, name: []const u8) bool {
2881 if (ty.isAnyError()) {
2882 return true;
2883 }
2884
2885 switch (ty.tag()) {
2886 .error_set_single => {
2887 const data = ty.castTag(.error_set_single).?.data;
2888 return std.mem.eql(u8, data, name);
2889 },
2890 .error_set_inferred => {
2891 const data = ty.castTag(.error_set_inferred).?.data;
2892 return data.errors.contains(name);
2893 },
2894 .error_set_merged => {
2895 const data = ty.castTag(.error_set_merged).?.data;
2896 return data.contains(name);
2897 },
2898 .error_set => {
2899 const data = ty.castTag(.error_set).?.data;
2900 return data.names.contains(name);
2901 },
2902 else => unreachable,
2903 }
2904 }
2905
2877 /// Asserts the type is an array or vector.2906 /// Asserts the type is an array or vector.
2878 pub fn arrayLen(ty: Type) u64 {2907 pub fn arrayLen(ty: Type) u64 {
2879 return switch (ty.tag()) {2908 return switch (ty.tag()) {