| ... | ... | @@ -5207,9 +5207,6 @@ fn funcCommon( |
| 5207 | 5207 | .rbrace_line = src_locs.rbrace_line, |
| 5208 | 5208 | .lbrace_column = @truncate(u16, src_locs.columns), |
| 5209 | 5209 | .rbrace_column = @truncate(u16, src_locs.columns >> 16), |
| 5210 | | .inferred_error_sets = .{ |
| 5211 | | .first = maybe_inferred_error_set_node, |
| 5212 | | }, |
| 5213 | 5210 | }; |
| 5214 | 5211 | if (maybe_inferred_error_set_node) |node| { |
| 5215 | 5212 | new_func.inferred_error_sets.prepend(node); |
| ... | ... | @@ -12193,7 +12190,7 @@ fn coerce( |
| 12193 | 12190 | const arena = sema.arena; |
| 12194 | 12191 | const target = sema.mod.getTarget(); |
| 12195 | 12192 | |
| 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 | 12194 | if (in_memory_result == .ok) { |
| 12198 | 12195 | if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| { |
| 12199 | 12196 | // Keep the comptime Value representation; take the new type. |
| ... | ... | @@ -12252,7 +12249,7 @@ fn coerce( |
| 12252 | 12249 | if (inst_ty.isConstPtr() and dest_is_mut) break :single_item; |
| 12253 | 12250 | if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item; |
| 12254 | 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 | 12253 | .ok => {}, |
| 12257 | 12254 | .no_match => break :single_item, |
| 12258 | 12255 | } |
| ... | ... | @@ -12271,7 +12268,7 @@ fn coerce( |
| 12271 | 12268 | if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr; |
| 12272 | 12269 | |
| 12273 | 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 | 12272 | .ok => {}, |
| 12276 | 12273 | .no_match => break :src_array_ptr, |
| 12277 | 12274 | } |
| ... | ... | @@ -12310,7 +12307,7 @@ fn coerce( |
| 12310 | 12307 | const src_elem_ty = inst_ty.childType(); |
| 12311 | 12308 | const dest_is_mut = dest_info.mutable; |
| 12312 | 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 | 12311 | .ok => {}, |
| 12315 | 12312 | .no_match => break :src_c_ptr, |
| 12316 | 12313 | } |
| ... | ... | @@ -12453,7 +12450,13 @@ const InMemoryCoercionResult = enum { |
| 12453 | 12450 | /// * sentinel-terminated pointers can coerce into `[*]` |
| 12454 | 12451 | /// TODO improve this function to report recursive compile errors like it does in stage1. |
| 12455 | 12452 | /// look at the function types_match_const_cast_only |
| 12456 | | fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: std.Target) InMemoryCoercionResult { |
| 12453 | fn 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 | 12460 | if (dest_ty.eql(src_ty)) |
| 12458 | 12461 | return .ok; |
| 12459 | 12462 | |
| ... | ... | @@ -12462,32 +12465,35 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: |
| 12462 | 12465 | var src_buf: Type.Payload.ElemType = undefined; |
| 12463 | 12466 | if (dest_ty.ptrOrOptionalPtrTy(&dest_buf)) |dest_ptr_ty| { |
| 12464 | 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 | } |
| 12468 | 12471 | |
| 12469 | 12472 | // Slices |
| 12470 | 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 | } |
| 12473 | 12476 | |
| 12477 | const dest_tag = dest_ty.zigTypeTag(); |
| 12478 | const src_tag = src_ty.zigTypeTag(); |
| 12479 | |
| 12474 | 12480 | // Functions |
| 12475 | | if (dest_ty.zigTypeTag() == .Fn and src_ty.zigTypeTag() == .Fn) { |
| 12476 | | return coerceInMemoryAllowedFns(dest_ty, src_ty, target); |
| 12481 | if (dest_tag == .Fn and src_tag == .Fn) { |
| 12482 | return try sema.coerceInMemoryAllowedFns(dest_ty, src_ty, target); |
| 12477 | 12483 | } |
| 12478 | 12484 | |
| 12479 | 12485 | // Error Unions |
| 12480 | | if (dest_ty.zigTypeTag() == .ErrorUnion and src_ty.zigTypeTag() == .ErrorUnion) { |
| 12481 | | const child = coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target); |
| 12486 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { |
| 12487 | const child = try sema.coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target); |
| 12482 | 12488 | if (child == .no_match) { |
| 12483 | 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 | } |
| 12487 | 12493 | |
| 12488 | 12494 | // Error Sets |
| 12489 | | if (dest_ty.zigTypeTag() == .ErrorSet and src_ty.zigTypeTag() == .ErrorSet) { |
| 12490 | | return coerceInMemoryAllowedErrorSets(dest_ty, src_ty); |
| 12495 | if (dest_tag == .ErrorSet and src_tag == .ErrorSet) { |
| 12496 | return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty); |
| 12491 | 12497 | } |
| 12492 | 12498 | |
| 12493 | 12499 | // TODO: arrays |
| ... | ... | @@ -12498,14 +12504,16 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target: |
| 12498 | 12504 | } |
| 12499 | 12505 | |
| 12500 | 12506 | fn coerceInMemoryAllowedErrorSets( |
| 12507 | sema: *Sema, |
| 12501 | 12508 | dest_ty: Type, |
| 12502 | 12509 | src_ty: Type, |
| 12503 | | ) InMemoryCoercionResult { |
| 12504 | | // Coercion to `anyerror`. Note that this check can return false positives |
| 12510 | ) !InMemoryCoercionResult { |
| 12511 | // Coercion to `anyerror`. Note that this check can return false negatives |
| 12505 | 12512 | // in case the error sets did not get resolved. |
| 12506 | 12513 | if (dest_ty.isAnyError()) { |
| 12507 | 12514 | return .ok; |
| 12508 | 12515 | } |
| 12516 | |
| 12509 | 12517 | // If both are inferred error sets of functions, and |
| 12510 | 12518 | // the dest includes the source function, the coercion is OK. |
| 12511 | 12519 | // This check is important because it works without forcing a full resolution |
| ... | ... | @@ -12515,21 +12523,85 @@ fn coerceInMemoryAllowedErrorSets( |
| 12515 | 12523 | const src_func = src_payload.data.func; |
| 12516 | 12524 | const dst_func = dst_payload.data.func; |
| 12517 | 12525 | |
| 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 | 12527 | return .ok; |
| 12520 | 12528 | } |
| 12529 | return .no_match; |
| 12521 | 12530 | } |
| 12522 | 12531 | } |
| 12523 | 12532 | |
| 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 | 12596 | return .no_match; |
| 12526 | 12597 | } |
| 12527 | 12598 | |
| 12528 | 12599 | fn coerceInMemoryAllowedFns( |
| 12600 | sema: *Sema, |
| 12529 | 12601 | dest_ty: Type, |
| 12530 | 12602 | src_ty: Type, |
| 12531 | 12603 | target: std.Target, |
| 12532 | | ) InMemoryCoercionResult { |
| 12604 | ) !InMemoryCoercionResult { |
| 12533 | 12605 | const dest_info = dest_ty.fnInfo(); |
| 12534 | 12606 | const src_info = src_ty.fnInfo(); |
| 12535 | 12607 | |
| ... | ... | @@ -12542,7 +12614,7 @@ fn coerceInMemoryAllowedFns( |
| 12542 | 12614 | } |
| 12543 | 12615 | |
| 12544 | 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 | 12618 | if (rt == .no_match) { |
| 12547 | 12619 | return rt; |
| 12548 | 12620 | } |
| ... | ... | @@ -12562,7 +12634,7 @@ fn coerceInMemoryAllowedFns( |
| 12562 | 12634 | // TODO: nolias |
| 12563 | 12635 | |
| 12564 | 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 | 12638 | if (param == .no_match) { |
| 12567 | 12639 | return param; |
| 12568 | 12640 | } |
| ... | ... | @@ -12576,17 +12648,18 @@ fn coerceInMemoryAllowedFns( |
| 12576 | 12648 | } |
| 12577 | 12649 | |
| 12578 | 12650 | fn coerceInMemoryAllowedPtrs( |
| 12651 | sema: *Sema, |
| 12579 | 12652 | dest_ty: Type, |
| 12580 | 12653 | src_ty: Type, |
| 12581 | 12654 | dest_ptr_ty: Type, |
| 12582 | 12655 | src_ptr_ty: Type, |
| 12583 | 12656 | dest_is_mut: bool, |
| 12584 | 12657 | target: std.Target, |
| 12585 | | ) InMemoryCoercionResult { |
| 12658 | ) !InMemoryCoercionResult { |
| 12586 | 12659 | const dest_info = dest_ptr_ty.ptrInfo().data; |
| 12587 | 12660 | const src_info = src_ptr_ty.ptrInfo().data; |
| 12588 | 12661 | |
| 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 | 12663 | if (child == .no_match) { |
| 12591 | 12664 | return child; |
| 12592 | 12665 | } |
| ... | ... | @@ -13307,7 +13380,7 @@ fn coerceVectorInMemory( |
| 13307 | 13380 | const target = sema.mod.getTarget(); |
| 13308 | 13381 | const dest_elem_ty = dest_ty.childType(); |
| 13309 | 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 | 13384 | if (in_memory_result != .ok) { |
| 13312 | 13385 | // TODO recursive error notes for coerceInMemoryAllowed failure |
| 13313 | 13386 | return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty }); |
| ... | ... | @@ -13910,11 +13983,11 @@ fn wrapErrorUnion( |
| 13910 | 13983 | } |
| 13911 | 13984 | }, |
| 13912 | 13985 | .error_set_inferred => ok: { |
| 13986 | const expected_name = val.castTag(.@"error").?.data.name; |
| 13913 | 13987 | const data = dest_err_set_ty.castTag(.error_set_inferred).?.data; |
| 13988 | try sema.resolveInferredErrorSet(data); |
| 13914 | 13989 | if (data.is_anyerror) break :ok; |
| 13915 | | const expected_name = val.castTag(.@"error").?.data.name; |
| 13916 | 13990 | if (data.errors.contains(expected_name)) break :ok; |
| 13917 | | // TODO error set resolution here before emitting a compile error |
| 13918 | 13991 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); |
| 13919 | 13992 | }, |
| 13920 | 13993 | else => unreachable, |
| ... | ... | @@ -14059,12 +14132,12 @@ fn resolvePeerTypes( |
| 14059 | 14132 | .Optional => { |
| 14060 | 14133 | var opt_child_buf: Type.Payload.ElemType = undefined; |
| 14061 | 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 | 14136 | chosen = candidate; |
| 14064 | 14137 | chosen_i = candidate_i + 1; |
| 14065 | 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 | 14141 | any_are_null = true; |
| 14069 | 14142 | continue; |
| 14070 | 14143 | } |
| ... | ... | @@ -14087,10 +14160,10 @@ fn resolvePeerTypes( |
| 14087 | 14160 | .Optional => { |
| 14088 | 14161 | var opt_child_buf: Type.Payload.ElemType = undefined; |
| 14089 | 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 | 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 | 14167 | any_are_null = true; |
| 14095 | 14168 | chosen = candidate; |
| 14096 | 14169 | chosen_i = candidate_i + 1; |
| ... | ... | @@ -14256,6 +14329,42 @@ fn resolveBuiltinTypeFields( |
| 14256 | 14329 | return sema.resolveTypeFields(block, src, resolved_ty); |
| 14257 | 14330 | } |
| 14258 | 14331 | |
| 14332 | fn 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 | |
| 14259 | 14368 | fn semaStructFields( |
| 14260 | 14369 | mod: *Module, |
| 14261 | 14370 | struct_obj: *Module.Struct, |
| ... | ... | @@ -15218,8 +15327,8 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr |
| 15218 | 15327 | // We have a Value that lines up in virtual memory exactly with what we want to load. |
| 15219 | 15328 | // If the Type is in-memory coercable to `load_ty`, it may be returned without modifications. |
| 15220 | 15329 | const coerce_in_mem_ok = |
| 15221 | | coerceInMemoryAllowed(load_ty, parent.ty, false, target) == .ok or |
| 15222 | | coerceInMemoryAllowed(parent.ty, load_ty, false, target) == .ok; |
| 15330 | (try sema.coerceInMemoryAllowed(load_ty, parent.ty, false, target)) == .ok or |
| 15331 | (try sema.coerceInMemoryAllowed(parent.ty, load_ty, false, target)) == .ok; |
| 15223 | 15332 | if (coerce_in_mem_ok) { |
| 15224 | 15333 | if (parent.is_mutable) { |
| 15225 | 15334 | // The decl whose value we are obtaining here may be overwritten with |