| ... | ... | @@ -2749,7 +2749,15 @@ fn ensureResultUsed( |
| 2749 | 2749 | const operand_ty = sema.typeOf(operand); |
| 2750 | 2750 | switch (operand_ty.zigTypeTag()) { |
| 2751 | 2751 | .Void, .NoReturn => return, |
| 2752 | | .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is ignored. consider using `try`, `catch`, or `if`", .{}), |
| 2752 | .ErrorSet, .ErrorUnion => { |
| 2753 | const msg = msg: { |
| 2754 | const msg = try sema.errMsg(block, src, "error is ignored", .{}); |
| 2755 | errdefer msg.destroy(sema.gpa); |
| 2756 | try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); |
| 2757 | break :msg msg; |
| 2758 | }; |
| 2759 | return sema.failWithOwnedErrorMsg(block, msg); |
| 2760 | }, |
| 2753 | 2761 | else => return sema.fail(block, src, "expression value is ignored", .{}), |
| 2754 | 2762 | } |
| 2755 | 2763 | } |
| ... | ... | @@ -2763,7 +2771,15 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2763 | 2771 | const src = inst_data.src(); |
| 2764 | 2772 | const operand_ty = sema.typeOf(operand); |
| 2765 | 2773 | switch (operand_ty.zigTypeTag()) { |
| 2766 | | .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is discarded. consider using `try`, `catch`, or `if`", .{}), |
| 2774 | .ErrorSet, .ErrorUnion => { |
| 2775 | const msg = msg: { |
| 2776 | const msg = try sema.errMsg(block, src, "error is discarded", .{}); |
| 2777 | errdefer msg.destroy(sema.gpa); |
| 2778 | try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{}); |
| 2779 | break :msg msg; |
| 2780 | }; |
| 2781 | return sema.failWithOwnedErrorMsg(block, msg); |
| 2782 | }, |
| 2767 | 2783 | else => return, |
| 2768 | 2784 | } |
| 2769 | 2785 | } |
| ... | ... | @@ -4119,23 +4135,24 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 4119 | 4135 | const ptr = try sema.resolveInst(extra.lhs); |
| 4120 | 4136 | const operand = try sema.resolveInst(extra.rhs); |
| 4121 | 4137 | |
| 4138 | const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index| |
| 4139 | zir_tags[ptr_index] == .ret_ptr |
| 4140 | else |
| 4141 | false; |
| 4142 | |
| 4122 | 4143 | // Check for the possibility of this pattern: |
| 4123 | 4144 | // %a = ret_ptr |
| 4124 | 4145 | // %b = store(%a, %c) |
| 4125 | 4146 | // Where %c is an error union or error set. In such case we need to add |
| 4126 | 4147 | // to the current function's inferred error set, if any. |
| 4127 | | if ((sema.typeOf(operand).zigTypeTag() == .ErrorUnion or |
| 4148 | if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or |
| 4128 | 4149 | sema.typeOf(operand).zigTypeTag() == .ErrorSet) and |
| 4129 | 4150 | sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) |
| 4130 | 4151 | { |
| 4131 | | if (Zir.refToIndex(extra.lhs)) |ptr_index| { |
| 4132 | | if (zir_tags[ptr_index] == .ret_ptr) { |
| 4133 | | try sema.addToInferredErrorSet(operand); |
| 4134 | | } |
| 4135 | | } |
| 4152 | try sema.addToInferredErrorSet(operand); |
| 4136 | 4153 | } |
| 4137 | 4154 | |
| 4138 | | return sema.storePtr(block, src, ptr, operand); |
| 4155 | return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store); |
| 4139 | 4156 | } |
| 4140 | 4157 | |
| 4141 | 4158 | fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -5534,7 +5551,7 @@ fn analyzeCall( |
| 5534 | 5551 | try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst) |
| 5535 | 5552 | else |
| 5536 | 5553 | try sema.resolveInst(fn_info.ret_ty_ref); |
| 5537 | | const ret_ty_src = func_src; // TODO better source location |
| 5554 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 5538 | 5555 | const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); |
| 5539 | 5556 | // Create a fresh inferred error set type for inline/comptime calls. |
| 5540 | 5557 | const fn_ret_ty = blk: { |
| ... | ... | @@ -6876,7 +6893,7 @@ fn zirFunc( |
| 6876 | 6893 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6877 | 6894 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); |
| 6878 | 6895 | const target = sema.mod.getTarget(); |
| 6879 | | const ret_ty_src = inst_data.src(); // TODO better source location |
| 6896 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node }; |
| 6880 | 6897 | |
| 6881 | 6898 | var extra_index = extra.end; |
| 6882 | 6899 | |
| ... | ... | @@ -7458,13 +7475,20 @@ fn analyzeAs( |
| 7458 | 7475 | zir_dest_type: Zir.Inst.Ref, |
| 7459 | 7476 | zir_operand: Zir.Inst.Ref, |
| 7460 | 7477 | ) CompileError!Air.Inst.Ref { |
| 7478 | const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| |
| 7479 | sema.code.instructions.items(.tag)[ptr_index] == .ret_type |
| 7480 | else |
| 7481 | false; |
| 7461 | 7482 | const dest_ty = try sema.resolveType(block, src, zir_dest_type); |
| 7462 | 7483 | const operand = try sema.resolveInst(zir_operand); |
| 7463 | 7484 | if (dest_ty.tag() == .var_args_param) return operand; |
| 7464 | 7485 | if (dest_ty.zigTypeTag() == .NoReturn) { |
| 7465 | 7486 | return sema.fail(block, src, "cannot cast to noreturn", .{}); |
| 7466 | 7487 | } |
| 7467 | | return sema.coerce(block, dest_ty, operand, src); |
| 7488 | return sema.coerceExtra(block, dest_ty, operand, src, true, is_ret) catch |err| switch (err) { |
| 7489 | error.NotCoercible => unreachable, |
| 7490 | else => |e| return e, |
| 7491 | }; |
| 7468 | 7492 | } |
| 7469 | 7493 | |
| 7470 | 7494 | fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -13647,7 +13671,10 @@ fn analyzeRet( |
| 13647 | 13671 | if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { |
| 13648 | 13672 | try sema.addToInferredErrorSet(uncasted_operand); |
| 13649 | 13673 | } |
| 13650 | | const operand = try sema.coerce(block, sema.fn_ret_ty, uncasted_operand, src); |
| 13674 | const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, true, true) catch |err| switch (err) { |
| 13675 | error.NotCoercible => unreachable, |
| 13676 | else => |e| return e, |
| 13677 | }; |
| 13651 | 13678 | |
| 13652 | 13679 | if (block.inlining) |inlining| { |
| 13653 | 13680 | if (block.is_comptime) { |
| ... | ... | @@ -19993,6 +20020,27 @@ fn coerce( |
| 19993 | 20020 | inst: Air.Inst.Ref, |
| 19994 | 20021 | inst_src: LazySrcLoc, |
| 19995 | 20022 | ) CompileError!Air.Inst.Ref { |
| 20023 | return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true, false) catch |err| switch (err) { |
| 20024 | error.NotCoercible => unreachable, |
| 20025 | else => |e| return e, |
| 20026 | }; |
| 20027 | } |
| 20028 | |
| 20029 | const CoersionError = CompileError || error{ |
| 20030 | /// When coerce is called recursively, this error should be returned instead of using `fail` |
| 20031 | /// to ensure correct types in compile errors. |
| 20032 | NotCoercible, |
| 20033 | }; |
| 20034 | |
| 20035 | fn coerceExtra( |
| 20036 | sema: *Sema, |
| 20037 | block: *Block, |
| 20038 | dest_ty_unresolved: Type, |
| 20039 | inst: Air.Inst.Ref, |
| 20040 | inst_src: LazySrcLoc, |
| 20041 | report_err: bool, |
| 20042 | is_ret: bool, |
| 20043 | ) CoersionError!Air.Inst.Ref { |
| 19996 | 20044 | switch (dest_ty_unresolved.tag()) { |
| 19997 | 20045 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), |
| 19998 | 20046 | .generic_poison => return inst, |
| ... | ... | @@ -20009,7 +20057,7 @@ fn coerce( |
| 20009 | 20057 | const arena = sema.arena; |
| 20010 | 20058 | const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst); |
| 20011 | 20059 | |
| 20012 | | const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| 20060 | var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| 20013 | 20061 | if (in_memory_result == .ok) { |
| 20014 | 20062 | if (maybe_inst_val) |val| { |
| 20015 | 20063 | // Keep the comptime Value representation; take the new type. |
| ... | ... | @@ -20022,7 +20070,7 @@ fn coerce( |
| 20022 | 20070 | const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; |
| 20023 | 20071 | |
| 20024 | 20072 | switch (dest_ty.zigTypeTag()) { |
| 20025 | | .Optional => { |
| 20073 | .Optional => optional: { |
| 20026 | 20074 | // undefined sets the optional bit also to undefined. |
| 20027 | 20075 | if (is_undef) { |
| 20028 | 20076 | return sema.addConstUndef(dest_ty); |
| ... | ... | @@ -20043,10 +20091,19 @@ fn coerce( |
| 20043 | 20091 | |
| 20044 | 20092 | // T to ?T |
| 20045 | 20093 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); |
| 20046 | | const intermediate = try sema.coerce(block, child_type, inst, inst_src); |
| 20047 | | return sema.wrapOptional(block, dest_ty, intermediate, inst_src); |
| 20094 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false, is_ret) catch |err| switch (err) { |
| 20095 | error.NotCoercible => { |
| 20096 | if (in_memory_result == .no_match) { |
| 20097 | // Try to give more useful notes |
| 20098 | in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src); |
| 20099 | } |
| 20100 | break :optional; |
| 20101 | }, |
| 20102 | else => |e| return e, |
| 20103 | }; |
| 20104 | return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); |
| 20048 | 20105 | }, |
| 20049 | | .Pointer => { |
| 20106 | .Pointer => pointer: { |
| 20050 | 20107 | const dest_info = dest_ty.ptrInfo().data; |
| 20051 | 20108 | |
| 20052 | 20109 | // Function body to function pointer. |
| ... | ... | @@ -20071,7 +20128,7 @@ fn coerce( |
| 20071 | 20128 | if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item; |
| 20072 | 20129 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 20073 | 20130 | .ok => {}, |
| 20074 | | .no_match => break :single_item, |
| 20131 | else => break :single_item, |
| 20075 | 20132 | } |
| 20076 | 20133 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 20077 | 20134 | } |
| ... | ... | @@ -20091,7 +20148,7 @@ fn coerce( |
| 20091 | 20148 | const dst_elem_type = dest_info.pointee_type; |
| 20092 | 20149 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 20093 | 20150 | .ok => {}, |
| 20094 | | .no_match => break :src_array_ptr, |
| 20151 | else => break :src_array_ptr, |
| 20095 | 20152 | } |
| 20096 | 20153 | |
| 20097 | 20154 | switch (dest_info.size) { |
| ... | ... | @@ -20130,7 +20187,7 @@ fn coerce( |
| 20130 | 20187 | const dst_elem_type = dest_info.pointee_type; |
| 20131 | 20188 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 20132 | 20189 | .ok => {}, |
| 20133 | | .no_match => break :src_c_ptr, |
| 20190 | else => break :src_c_ptr, |
| 20134 | 20191 | } |
| 20135 | 20192 | // TODO add safety check for null pointer |
| 20136 | 20193 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| ... | ... | @@ -20151,16 +20208,26 @@ fn coerce( |
| 20151 | 20208 | return sema.addConstant(dest_ty, Value.@"null"); |
| 20152 | 20209 | }, |
| 20153 | 20210 | .ComptimeInt => { |
| 20154 | | const addr = try sema.coerce(block, Type.usize, inst, inst_src); |
| 20155 | | return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 20211 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false, is_ret) catch |err| switch (err) { |
| 20212 | error.NotCoercible => break :pointer, |
| 20213 | else => |e| return e, |
| 20214 | }; |
| 20215 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 20156 | 20216 | }, |
| 20157 | 20217 | .Int => { |
| 20158 | 20218 | const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { |
| 20159 | 20219 | .signed => Type.isize, |
| 20160 | 20220 | .unsigned => Type.usize, |
| 20161 | 20221 | }; |
| 20162 | | const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src); |
| 20163 | | return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 20222 | const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false, is_ret) catch |err| switch (err) { |
| 20223 | error.NotCoercible => { |
| 20224 | // Try to give more useful notes |
| 20225 | in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| 20226 | break :pointer; |
| 20227 | }, |
| 20228 | else => |e| return e, |
| 20229 | }; |
| 20230 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 20164 | 20231 | }, |
| 20165 | 20232 | .Pointer => p: { |
| 20166 | 20233 | const inst_info = inst_ty.ptrInfo().data; |
| ... | ... | @@ -20174,7 +20241,7 @@ fn coerce( |
| 20174 | 20241 | inst_src, |
| 20175 | 20242 | )) { |
| 20176 | 20243 | .ok => {}, |
| 20177 | | .no_match => break :p, |
| 20244 | else => break :p, |
| 20178 | 20245 | } |
| 20179 | 20246 | if (inst_info.size == .Slice) { |
| 20180 | 20247 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| ... | ... | @@ -20264,7 +20331,7 @@ fn coerce( |
| 20264 | 20331 | inst_src, |
| 20265 | 20332 | )) { |
| 20266 | 20333 | .ok => {}, |
| 20267 | | .no_match => break :p, |
| 20334 | else => break :p, |
| 20268 | 20335 | } |
| 20269 | 20336 | |
| 20270 | 20337 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| ... | ... | @@ -20295,6 +20362,7 @@ fn coerce( |
| 20295 | 20362 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { |
| 20296 | 20363 | // comptime known integer to other number |
| 20297 | 20364 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { |
| 20365 | if (!report_err) return error.NotCoercible; |
| 20298 | 20366 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); |
| 20299 | 20367 | } |
| 20300 | 20368 | return try sema.addConstant(dest_ty, val); |
| ... | ... | @@ -20496,14 +20564,396 @@ fn coerce( |
| 20496 | 20564 | return sema.addConstUndef(dest_ty); |
| 20497 | 20565 | } |
| 20498 | 20566 | |
| 20499 | | return sema.fail(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); |
| 20567 | if (!report_err) return error.NotCoercible; |
| 20568 | |
| 20569 | if (is_ret and dest_ty.zigTypeTag() == .NoReturn) { |
| 20570 | const msg = msg: { |
| 20571 | const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); |
| 20572 | errdefer msg.destroy(sema.gpa); |
| 20573 | |
| 20574 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 20575 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); |
| 20576 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{}); |
| 20577 | break :msg msg; |
| 20578 | }; |
| 20579 | return sema.failWithOwnedErrorMsg(block, msg); |
| 20580 | } |
| 20581 | |
| 20582 | const msg = msg: { |
| 20583 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); |
| 20584 | errdefer msg.destroy(sema.gpa); |
| 20585 | |
| 20586 | // E!T to T |
| 20587 | if (inst_ty.zigTypeTag() == .ErrorUnion and |
| 20588 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) |
| 20589 | { |
| 20590 | try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); |
| 20591 | try sema.errNote(block, inst_src, msg, "consider using `try`, `catch`, or `if`", .{}); |
| 20592 | } |
| 20593 | |
| 20594 | // ?T to T |
| 20595 | var buf: Type.Payload.ElemType = undefined; |
| 20596 | if (inst_ty.zigTypeTag() == .Optional and |
| 20597 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) |
| 20598 | { |
| 20599 | try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); |
| 20600 | try sema.errNote(block, inst_src, msg, "consider using `.?`, `orelse`, or `if`", .{}); |
| 20601 | } |
| 20602 | |
| 20603 | try in_memory_result.report(sema, block, inst_src, msg); |
| 20604 | |
| 20605 | // Add notes about function return type |
| 20606 | if (is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) { |
| 20607 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 20608 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); |
| 20609 | if (inst_ty.isError() and !dest_ty.isError()) { |
| 20610 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{}); |
| 20611 | } else { |
| 20612 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{}); |
| 20613 | } |
| 20614 | } |
| 20615 | |
| 20616 | // TODO maybe add "cannot store an error in type '{}'" note |
| 20617 | |
| 20618 | break :msg msg; |
| 20619 | }; |
| 20620 | return sema.failWithOwnedErrorMsg(block, msg); |
| 20500 | 20621 | } |
| 20501 | 20622 | |
| 20502 | | const InMemoryCoercionResult = enum { |
| 20623 | const InMemoryCoercionResult = union(enum) { |
| 20503 | 20624 | ok, |
| 20504 | | no_match, |
| 20625 | no_match: Pair, |
| 20626 | int_not_coercible: Int, |
| 20627 | error_union_payload: PairAndChild, |
| 20628 | array_len: IntPair, |
| 20629 | array_sentinel: Sentinel, |
| 20630 | array_elem: PairAndChild, |
| 20631 | vector_len: IntPair, |
| 20632 | vector_elem: PairAndChild, |
| 20633 | optional_shape: Pair, |
| 20634 | optional_child: PairAndChild, |
| 20635 | from_anyerror, |
| 20636 | missing_error: []const []const u8, |
| 20637 | /// true if wanted is var args |
| 20638 | fn_var_args: bool, |
| 20639 | /// true if wanted is generic |
| 20640 | fn_generic: bool, |
| 20641 | fn_param_count: IntPair, |
| 20642 | fn_param_noalias: IntPair, |
| 20643 | fn_param_comptime: ComptimeParam, |
| 20644 | fn_param: Param, |
| 20645 | fn_cc: CC, |
| 20646 | fn_return_type: PairAndChild, |
| 20647 | ptr_child: PairAndChild, |
| 20648 | ptr_addrspace: AddressSpace, |
| 20649 | ptr_sentinel: Sentinel, |
| 20650 | ptr_size: Size, |
| 20651 | ptr_qualifiers: Qualifiers, |
| 20652 | ptr_allowzero: Pair, |
| 20653 | ptr_bit_range: BitRange, |
| 20654 | ptr_alignment: IntPair, |
| 20655 | |
| 20656 | const Pair = struct { |
| 20657 | actual: Type, |
| 20658 | wanted: Type, |
| 20659 | }; |
| 20660 | |
| 20661 | const PairAndChild = struct { |
| 20662 | child: *InMemoryCoercionResult, |
| 20663 | actual: Type, |
| 20664 | wanted: Type, |
| 20665 | }; |
| 20666 | |
| 20667 | const Param = struct { |
| 20668 | child: *InMemoryCoercionResult, |
| 20669 | actual: Type, |
| 20670 | wanted: Type, |
| 20671 | index: u64, |
| 20672 | }; |
| 20673 | |
| 20674 | const ComptimeParam = struct { |
| 20675 | index: u64, |
| 20676 | wanted: bool, |
| 20677 | }; |
| 20678 | |
| 20679 | const Sentinel = struct { |
| 20680 | // unreachable_value indicates no sentinel |
| 20681 | actual: Value, |
| 20682 | wanted: Value, |
| 20683 | ty: Type, |
| 20684 | }; |
| 20685 | |
| 20686 | const Int = struct { |
| 20687 | actual_signedness: std.builtin.Signedness, |
| 20688 | wanted_signedness: std.builtin.Signedness, |
| 20689 | actual_bits: u16, |
| 20690 | wanted_bits: u16, |
| 20691 | }; |
| 20692 | |
| 20693 | const IntPair = struct { |
| 20694 | actual: u64, |
| 20695 | wanted: u64, |
| 20696 | }; |
| 20697 | |
| 20698 | const Size = struct { |
| 20699 | actual: std.builtin.Type.Pointer.Size, |
| 20700 | wanted: std.builtin.Type.Pointer.Size, |
| 20701 | }; |
| 20702 | |
| 20703 | const Qualifiers = struct { |
| 20704 | actual_const: bool, |
| 20705 | wanted_const: bool, |
| 20706 | actual_volatile: bool, |
| 20707 | wanted_volatile: bool, |
| 20708 | }; |
| 20709 | |
| 20710 | const AddressSpace = struct { |
| 20711 | actual: std.builtin.AddressSpace, |
| 20712 | wanted: std.builtin.AddressSpace, |
| 20713 | }; |
| 20714 | |
| 20715 | const CC = struct { |
| 20716 | actual: std.builtin.CallingConvention, |
| 20717 | wanted: std.builtin.CallingConvention, |
| 20718 | }; |
| 20719 | |
| 20720 | const BitRange = struct { |
| 20721 | actual_host: u16, |
| 20722 | wanted_host: u16, |
| 20723 | actual_offset: u16, |
| 20724 | wanted_offset: u16, |
| 20725 | }; |
| 20726 | |
| 20727 | fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult { |
| 20728 | const res = try arena.create(InMemoryCoercionResult); |
| 20729 | res.* = child.*; |
| 20730 | return res; |
| 20731 | } |
| 20732 | |
| 20733 | fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { |
| 20734 | var cur = res; |
| 20735 | while (true) switch (cur.*) { |
| 20736 | .ok => unreachable, |
| 20737 | .no_match => |types| { |
| 20738 | try sema.addDeclaredHereNote(msg, types.wanted); |
| 20739 | try sema.addDeclaredHereNote(msg, types.actual); |
| 20740 | break; |
| 20741 | }, |
| 20742 | .int_not_coercible => |int| { |
| 20743 | try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{ |
| 20744 | @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits, |
| 20745 | }); |
| 20746 | break; |
| 20747 | }, |
| 20748 | .error_union_payload => |pair| { |
| 20749 | try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ |
| 20750 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20751 | }); |
| 20752 | cur = pair.child; |
| 20753 | }, |
| 20754 | .array_len => |lens| { |
| 20755 | try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{ |
| 20756 | lens.actual, lens.wanted, |
| 20757 | }); |
| 20758 | break; |
| 20759 | }, |
| 20760 | .array_sentinel => |sentinel| { |
| 20761 | if (sentinel.actual.tag() != .unreachable_value) { |
| 20762 | try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ |
| 20763 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20764 | }); |
| 20765 | } else { |
| 20766 | try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ |
| 20767 | sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20768 | }); |
| 20769 | } |
| 20770 | break; |
| 20771 | }, |
| 20772 | .array_elem => |pair| { |
| 20773 | try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ |
| 20774 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20775 | }); |
| 20776 | cur = pair.child; |
| 20777 | }, |
| 20778 | .vector_len => |lens| { |
| 20779 | try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{ |
| 20780 | lens.actual, lens.wanted, |
| 20781 | }); |
| 20782 | break; |
| 20783 | }, |
| 20784 | .vector_elem => |pair| { |
| 20785 | try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ |
| 20786 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20787 | }); |
| 20788 | cur = pair.child; |
| 20789 | }, |
| 20790 | .optional_shape => |pair| { |
| 20791 | var buf_actual: Type.Payload.ElemType = undefined; |
| 20792 | var buf_wanted: Type.Payload.ElemType = undefined; |
| 20793 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ |
| 20794 | pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod), |
| 20795 | }); |
| 20796 | break; |
| 20797 | }, |
| 20798 | .optional_child => |pair| { |
| 20799 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ |
| 20800 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20801 | }); |
| 20802 | cur = pair.child; |
| 20803 | }, |
| 20804 | .from_anyerror => { |
| 20805 | try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{}); |
| 20806 | break; |
| 20807 | }, |
| 20808 | .missing_error => |missing_errors| { |
| 20809 | for (missing_errors) |err| { |
| 20810 | try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); |
| 20811 | } |
| 20812 | break; |
| 20813 | }, |
| 20814 | .fn_var_args => |wanted_var_args| { |
| 20815 | if (wanted_var_args) { |
| 20816 | try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{}); |
| 20817 | } else { |
| 20818 | try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{}); |
| 20819 | } |
| 20820 | break; |
| 20821 | }, |
| 20822 | .fn_generic => |wanted_generic| { |
| 20823 | if (wanted_generic) { |
| 20824 | try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{}); |
| 20825 | } else { |
| 20826 | try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{}); |
| 20827 | } |
| 20828 | break; |
| 20829 | }, |
| 20830 | .fn_param_count => |lens| { |
| 20831 | try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{ |
| 20832 | lens.actual, lens.wanted, |
| 20833 | }); |
| 20834 | break; |
| 20835 | }, |
| 20836 | .fn_param_noalias => |param| { |
| 20837 | var index: u6 = 0; |
| 20838 | var actual_noalias = false; |
| 20839 | while (true) : (index += 1) { |
| 20840 | if (param.actual << index != param.wanted << index) { |
| 20841 | actual_noalias = (param.actual << index) == (1 << 31); |
| 20842 | } |
| 20843 | } |
| 20844 | if (!actual_noalias) { |
| 20845 | try sema.errNote(block, src, msg, "regular paramter {d} cannot cast into a noalias paramter", .{index}); |
| 20846 | } else { |
| 20847 | try sema.errNote(block, src, msg, "noalias paramter {d} cannot cast into a regular paramter", .{index}); |
| 20848 | } |
| 20849 | break; |
| 20850 | }, |
| 20851 | .fn_param_comptime => |param| { |
| 20852 | if (param.wanted) { |
| 20853 | try sema.errNote(block, src, msg, "non-comptime paramter {d} cannot cast into a comptime paramter", .{param.index}); |
| 20854 | } else { |
| 20855 | try sema.errNote(block, src, msg, "comptime paramter {d} cannot cast into a non-comptime paramter", .{param.index}); |
| 20856 | } |
| 20857 | break; |
| 20858 | }, |
| 20859 | .fn_param => |param| { |
| 20860 | try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ |
| 20861 | param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod), |
| 20862 | }); |
| 20863 | cur = param.child; |
| 20864 | }, |
| 20865 | .fn_cc => |cc| { |
| 20866 | try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) }); |
| 20867 | break; |
| 20868 | }, |
| 20869 | .fn_return_type => |pair| { |
| 20870 | try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ |
| 20871 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20872 | }); |
| 20873 | cur = pair.child; |
| 20874 | }, |
| 20875 | .ptr_child => |pair| { |
| 20876 | try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ |
| 20877 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20878 | }); |
| 20879 | cur = pair.child; |
| 20880 | }, |
| 20881 | .ptr_addrspace => |@"addrspace"| { |
| 20882 | try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) }); |
| 20883 | break; |
| 20884 | }, |
| 20885 | .ptr_sentinel => |sentinel| { |
| 20886 | if (sentinel.actual.tag() != .unreachable_value) { |
| 20887 | try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ |
| 20888 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20889 | }); |
| 20890 | } else { |
| 20891 | try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ |
| 20892 | sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 20893 | }); |
| 20894 | } |
| 20895 | break; |
| 20896 | }, |
| 20897 | .ptr_size => |size| { |
| 20898 | try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); |
| 20899 | break; |
| 20900 | }, |
| 20901 | .ptr_qualifiers => |qualifiers| { |
| 20902 | const ok_const = !qualifiers.actual_const or qualifiers.wanted_const; |
| 20903 | const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile; |
| 20904 | if (!ok_const) { |
| 20905 | try sema.errNote(block, src, msg, "cast discards const qualifier", .{}); |
| 20906 | } else if (!ok_volatile) { |
| 20907 | try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{}); |
| 20908 | } |
| 20909 | break; |
| 20910 | }, |
| 20911 | .ptr_allowzero => |pair| { |
| 20912 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(); |
| 20913 | const actual_allow_zero = pair.actual.ptrAllowsZero(); |
| 20914 | if (actual_allow_zero and !wanted_allow_zero) { |
| 20915 | try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ |
| 20916 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20917 | }); |
| 20918 | } else { |
| 20919 | try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ |
| 20920 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), |
| 20921 | }); |
| 20922 | } |
| 20923 | break; |
| 20924 | }, |
| 20925 | .ptr_bit_range => |bit_range| { |
| 20926 | if (bit_range.actual_host != bit_range.wanted_host) { |
| 20927 | try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{ |
| 20928 | bit_range.actual_host, bit_range.wanted_host, |
| 20929 | }); |
| 20930 | } |
| 20931 | if (bit_range.actual_offset != bit_range.wanted_offset) { |
| 20932 | try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{ |
| 20933 | bit_range.actual_offset, bit_range.wanted_offset, |
| 20934 | }); |
| 20935 | } |
| 20936 | break; |
| 20937 | }, |
| 20938 | .ptr_alignment => |pair| { |
| 20939 | try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ |
| 20940 | pair.actual, pair.wanted, |
| 20941 | }); |
| 20942 | break; |
| 20943 | }, |
| 20944 | }; |
| 20945 | } |
| 20505 | 20946 | }; |
| 20506 | 20947 | |
| 20948 | fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { |
| 20949 | return switch (size) { |
| 20950 | .One => "single", |
| 20951 | .Many => "many", |
| 20952 | .C => "C", |
| 20953 | .Slice => unreachable, |
| 20954 | }; |
| 20955 | } |
| 20956 | |
| 20507 | 20957 | /// If pointers have the same representation in runtime memory, a bitcast AIR instruction |
| 20508 | 20958 | /// may be used for the coercion. |
| 20509 | 20959 | /// * `const` attribute can be gained |
| ... | ... | @@ -20513,8 +20963,6 @@ const InMemoryCoercionResult = enum { |
| 20513 | 20963 | /// * bit offset attributes must match exactly |
| 20514 | 20964 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one |
| 20515 | 20965 | /// * sentinel-terminated pointers can coerce into `[*]` |
| 20516 | | /// TODO improve this function to report recursive compile errors like it does in stage1. |
| 20517 | | /// look at the function types_match_const_cast_only |
| 20518 | 20966 | fn coerceInMemoryAllowed( |
| 20519 | 20967 | sema: *Sema, |
| 20520 | 20968 | block: *Block, |
| ... | ... | @@ -20532,11 +20980,25 @@ fn coerceInMemoryAllowed( |
| 20532 | 20980 | if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { |
| 20533 | 20981 | const dest_info = dest_ty.intInfo(target); |
| 20534 | 20982 | const src_info = src_ty.intInfo(target); |
| 20983 | |
| 20535 | 20984 | if (dest_info.signedness == src_info.signedness and |
| 20536 | 20985 | dest_info.bits == src_info.bits) |
| 20537 | 20986 | { |
| 20538 | 20987 | return .ok; |
| 20539 | 20988 | } |
| 20989 | |
| 20990 | if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or |
| 20991 | // small enough unsigned ints can get casted to large enough signed ints |
| 20992 | (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or |
| 20993 | (dest_info.signedness == .unsigned and src_info.signedness == .signed)) |
| 20994 | { |
| 20995 | return InMemoryCoercionResult{ .int_not_coercible = .{ |
| 20996 | .actual_signedness = src_info.signedness, |
| 20997 | .wanted_signedness = dest_info.signedness, |
| 20998 | .actual_bits = src_info.bits, |
| 20999 | .wanted_bits = dest_info.bits, |
| 21000 | } }; |
| 21001 | } |
| 20540 | 21002 | } |
| 20541 | 21003 | |
| 20542 | 21004 | // Differently-named floats with the same number of bits. |
| ... | ... | @@ -20574,9 +21036,15 @@ fn coerceInMemoryAllowed( |
| 20574 | 21036 | |
| 20575 | 21037 | // Error Unions |
| 20576 | 21038 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { |
| 20577 | | const child = try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target, dest_src, src_src); |
| 20578 | | if (child == .no_match) { |
| 20579 | | return child; |
| 21039 | const dest_payload = dest_ty.errorUnionPayload(); |
| 21040 | const src_payload = src_ty.errorUnionPayload(); |
| 21041 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); |
| 21042 | if (child != .ok) { |
| 21043 | return InMemoryCoercionResult{ .error_union_payload = .{ |
| 21044 | .child = try child.dupe(sema.arena), |
| 21045 | .actual = src_payload, |
| 21046 | .wanted = dest_payload, |
| 21047 | } }; |
| 20580 | 21048 | } |
| 20581 | 21049 | return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); |
| 20582 | 21050 | } |
| ... | ... | @@ -20587,57 +21055,89 @@ fn coerceInMemoryAllowed( |
| 20587 | 21055 | } |
| 20588 | 21056 | |
| 20589 | 21057 | // Arrays |
| 20590 | | if (dest_tag == .Array and src_tag == .Array) arrays: { |
| 21058 | if (dest_tag == .Array and src_tag == .Array) { |
| 20591 | 21059 | const dest_info = dest_ty.arrayInfo(); |
| 20592 | 21060 | const src_info = src_ty.arrayInfo(); |
| 20593 | | if (dest_info.len != src_info.len) break :arrays; |
| 21061 | if (dest_info.len != src_info.len) { |
| 21062 | return InMemoryCoercionResult{ .array_len = .{ |
| 21063 | .actual = src_info.len, |
| 21064 | .wanted = dest_info.len, |
| 21065 | } }; |
| 21066 | } |
| 20594 | 21067 | |
| 20595 | 21068 | const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); |
| 20596 | | if (child == .no_match) { |
| 20597 | | return child; |
| 21069 | if (child != .ok) { |
| 21070 | return InMemoryCoercionResult{ .array_elem = .{ |
| 21071 | .child = try child.dupe(sema.arena), |
| 21072 | .actual = src_info.elem_type, |
| 21073 | .wanted = dest_info.elem_type, |
| 21074 | } }; |
| 20598 | 21075 | } |
| 20599 | 21076 | const ok_sent = dest_info.sentinel == null or |
| 20600 | 21077 | (src_info.sentinel != null and |
| 20601 | 21078 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); |
| 20602 | 21079 | if (!ok_sent) { |
| 20603 | | return .no_match; |
| 21080 | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 21081 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), |
| 21082 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), |
| 21083 | .ty = dest_info.elem_type, |
| 21084 | } }; |
| 20604 | 21085 | } |
| 20605 | 21086 | return .ok; |
| 20606 | 21087 | } |
| 20607 | 21088 | |
| 20608 | 21089 | // Vectors |
| 20609 | | if (dest_tag == .Vector and src_tag == .Vector) vectors: { |
| 21090 | if (dest_tag == .Vector and src_tag == .Vector) { |
| 20610 | 21091 | const dest_len = dest_ty.vectorLen(); |
| 20611 | 21092 | const src_len = src_ty.vectorLen(); |
| 20612 | | if (dest_len != src_len) break :vectors; |
| 21093 | if (dest_len != src_len) { |
| 21094 | return InMemoryCoercionResult{ .vector_len = .{ |
| 21095 | .actual = src_len, |
| 21096 | .wanted = dest_len, |
| 21097 | } }; |
| 21098 | } |
| 20613 | 21099 | |
| 20614 | 21100 | const dest_elem_ty = dest_ty.scalarType(); |
| 20615 | 21101 | const src_elem_ty = src_ty.scalarType(); |
| 20616 | 21102 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); |
| 20617 | | if (child == .no_match) break :vectors; |
| 21103 | if (child != .ok) { |
| 21104 | return InMemoryCoercionResult{ .vector_elem = .{ |
| 21105 | .child = try child.dupe(sema.arena), |
| 21106 | .actual = src_elem_ty, |
| 21107 | .wanted = dest_elem_ty, |
| 21108 | } }; |
| 21109 | } |
| 20618 | 21110 | |
| 20619 | 21111 | return .ok; |
| 20620 | 21112 | } |
| 20621 | 21113 | |
| 20622 | 21114 | // Optionals |
| 20623 | | if (dest_tag == .Optional and src_tag == .Optional) optionals: { |
| 21115 | if (dest_tag == .Optional and src_tag == .Optional) { |
| 20624 | 21116 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { |
| 20625 | | // TODO "optional type child '{}' cannot cast into optional type '{}'" |
| 20626 | | return .no_match; |
| 21117 | return InMemoryCoercionResult{ .optional_shape = .{ |
| 21118 | .actual = src_ty, |
| 21119 | .wanted = dest_ty, |
| 21120 | } }; |
| 20627 | 21121 | } |
| 20628 | 21122 | const dest_child_type = dest_ty.optionalChild(&dest_buf); |
| 20629 | 21123 | const src_child_type = src_ty.optionalChild(&src_buf); |
| 20630 | 21124 | |
| 20631 | 21125 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); |
| 20632 | | if (child == .no_match) { |
| 20633 | | // TODO "optional type child '{}' cannot cast into optional type child '{}'" |
| 20634 | | break :optionals; |
| 21126 | if (child != .ok) { |
| 21127 | return InMemoryCoercionResult{ .optional_child = .{ |
| 21128 | .child = try child.dupe(sema.arena), |
| 21129 | .actual = src_child_type, |
| 21130 | .wanted = dest_child_type, |
| 21131 | } }; |
| 20635 | 21132 | } |
| 20636 | 21133 | |
| 20637 | 21134 | return .ok; |
| 20638 | 21135 | } |
| 20639 | 21136 | |
| 20640 | | return .no_match; |
| 21137 | return InMemoryCoercionResult{ .no_match = .{ |
| 21138 | .actual = dest_ty, |
| 21139 | .wanted = src_ty, |
| 21140 | } }; |
| 20641 | 21141 | } |
| 20642 | 21142 | |
| 20643 | 21143 | fn coerceInMemoryAllowedErrorSets( |
| ... | ... | @@ -20704,6 +21204,9 @@ fn coerceInMemoryAllowedErrorSets( |
| 20704 | 21204 | } |
| 20705 | 21205 | } |
| 20706 | 21206 | |
| 21207 | var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa); |
| 21208 | defer missing_error_buf.deinit(); |
| 21209 | |
| 20707 | 21210 | switch (src_ty.tag()) { |
| 20708 | 21211 | .error_set_inferred => { |
| 20709 | 21212 | const src_data = src_ty.castTag(.error_set_inferred).?.data; |
| ... | ... | @@ -20712,15 +21215,21 @@ fn coerceInMemoryAllowedErrorSets( |
| 20712 | 21215 | // src anyerror status might have changed after the resolution. |
| 20713 | 21216 | if (src_ty.isAnyError()) { |
| 20714 | 21217 | // dest_ty.isAnyError() == true is already checked for at this point. |
| 20715 | | return .no_match; |
| 21218 | return .from_anyerror; |
| 20716 | 21219 | } |
| 20717 | 21220 | |
| 20718 | 21221 | for (src_data.errors.keys()) |key| { |
| 20719 | 21222 | if (!dest_ty.errorSetHasField(key)) { |
| 20720 | | return .no_match; |
| 21223 | try missing_error_buf.append(key); |
| 20721 | 21224 | } |
| 20722 | 21225 | } |
| 20723 | 21226 | |
| 21227 | if (missing_error_buf.items.len != 0) { |
| 21228 | return InMemoryCoercionResult{ |
| 21229 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), |
| 21230 | }; |
| 21231 | } |
| 21232 | |
| 20724 | 21233 | return .ok; |
| 20725 | 21234 | }, |
| 20726 | 21235 | .error_set_single => { |
| ... | ... | @@ -20728,37 +21237,52 @@ fn coerceInMemoryAllowedErrorSets( |
| 20728 | 21237 | if (dest_ty.errorSetHasField(name)) { |
| 20729 | 21238 | return .ok; |
| 20730 | 21239 | } |
| 21240 | const list = try sema.arena.alloc([]const u8, 1); |
| 21241 | list[0] = name; |
| 21242 | return InMemoryCoercionResult{ .missing_error = list }; |
| 20731 | 21243 | }, |
| 20732 | 21244 | .error_set_merged => { |
| 20733 | 21245 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); |
| 20734 | 21246 | for (names) |name| { |
| 20735 | 21247 | if (!dest_ty.errorSetHasField(name)) { |
| 20736 | | return .no_match; |
| 21248 | try missing_error_buf.append(name); |
| 20737 | 21249 | } |
| 20738 | 21250 | } |
| 20739 | 21251 | |
| 21252 | if (missing_error_buf.items.len != 0) { |
| 21253 | return InMemoryCoercionResult{ |
| 21254 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), |
| 21255 | }; |
| 21256 | } |
| 21257 | |
| 20740 | 21258 | return .ok; |
| 20741 | 21259 | }, |
| 20742 | 21260 | .error_set => { |
| 20743 | 21261 | const names = src_ty.castTag(.error_set).?.data.names.keys(); |
| 20744 | 21262 | for (names) |name| { |
| 20745 | 21263 | if (!dest_ty.errorSetHasField(name)) { |
| 20746 | | return .no_match; |
| 21264 | try missing_error_buf.append(name); |
| 20747 | 21265 | } |
| 20748 | 21266 | } |
| 20749 | 21267 | |
| 21268 | if (missing_error_buf.items.len != 0) { |
| 21269 | return InMemoryCoercionResult{ |
| 21270 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), |
| 21271 | }; |
| 21272 | } |
| 21273 | |
| 20750 | 21274 | return .ok; |
| 20751 | 21275 | }, |
| 20752 | 21276 | .anyerror => switch (dest_ty.tag()) { |
| 20753 | | .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above. |
| 20754 | | .error_set_single, .error_set_merged, .error_set => {}, |
| 21277 | .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. |
| 21278 | .error_set_single, .error_set_merged, .error_set => return .from_anyerror, |
| 20755 | 21279 | .anyerror => unreachable, // Filtered out above. |
| 20756 | 21280 | else => unreachable, |
| 20757 | 21281 | }, |
| 20758 | 21282 | else => unreachable, |
| 20759 | 21283 | } |
| 20760 | 21284 | |
| 20761 | | return .no_match; |
| 21285 | unreachable; |
| 20762 | 21286 | } |
| 20763 | 21287 | |
| 20764 | 21288 | fn coerceInMemoryAllowedFns( |
| ... | ... | @@ -20774,44 +21298,67 @@ fn coerceInMemoryAllowedFns( |
| 20774 | 21298 | const src_info = src_ty.fnInfo(); |
| 20775 | 21299 | |
| 20776 | 21300 | if (dest_info.is_var_args != src_info.is_var_args) { |
| 20777 | | return .no_match; |
| 21301 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; |
| 20778 | 21302 | } |
| 20779 | 21303 | |
| 20780 | 21304 | if (dest_info.is_generic != src_info.is_generic) { |
| 20781 | | return .no_match; |
| 21305 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; |
| 21306 | } |
| 21307 | |
| 21308 | if (dest_info.cc != src_info.cc) { |
| 21309 | return InMemoryCoercionResult{ .fn_cc = .{ |
| 21310 | .actual = src_info.cc, |
| 21311 | .wanted = dest_info.cc, |
| 21312 | } }; |
| 20782 | 21313 | } |
| 20783 | 21314 | |
| 20784 | 21315 | if (!src_info.return_type.isNoReturn()) { |
| 20785 | 21316 | const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); |
| 20786 | | if (rt == .no_match) { |
| 20787 | | return rt; |
| 21317 | if (rt != .ok) { |
| 21318 | return InMemoryCoercionResult{ .fn_return_type = .{ |
| 21319 | .child = try rt.dupe(sema.arena), |
| 21320 | .actual = src_info.return_type, |
| 21321 | .wanted = dest_info.return_type, |
| 21322 | } }; |
| 20788 | 21323 | } |
| 20789 | 21324 | } |
| 20790 | 21325 | |
| 20791 | 21326 | if (dest_info.param_types.len != src_info.param_types.len) { |
| 20792 | | return .no_match; |
| 21327 | return InMemoryCoercionResult{ .fn_param_count = .{ |
| 21328 | .actual = dest_info.param_types.len, |
| 21329 | .wanted = dest_info.param_types.len, |
| 21330 | } }; |
| 21331 | } |
| 21332 | |
| 21333 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 21334 | return InMemoryCoercionResult{ .fn_param_noalias = .{ |
| 21335 | .actual = dest_info.noalias_bits, |
| 21336 | .wanted = dest_info.noalias_bits, |
| 21337 | } }; |
| 20793 | 21338 | } |
| 20794 | 21339 | |
| 20795 | 21340 | for (dest_info.param_types) |dest_param_ty, i| { |
| 20796 | 21341 | const src_param_ty = src_info.param_types[i]; |
| 20797 | 21342 | |
| 20798 | 21343 | if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { |
| 20799 | | return .no_match; |
| 21344 | return InMemoryCoercionResult{ .fn_param_comptime = .{ |
| 21345 | .index = i, |
| 21346 | .wanted = dest_info.comptime_params[i], |
| 21347 | } }; |
| 20800 | 21348 | } |
| 20801 | 21349 | |
| 20802 | | // TODO: noalias |
| 20803 | | |
| 20804 | 21350 | // Note: Cast direction is reversed here. |
| 20805 | 21351 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); |
| 20806 | | if (param == .no_match) { |
| 20807 | | return param; |
| 21352 | if (param != .ok) { |
| 21353 | return InMemoryCoercionResult{ .fn_param = .{ |
| 21354 | .child = try param.dupe(sema.arena), |
| 21355 | .actual = src_param_ty, |
| 21356 | .wanted = dest_param_ty, |
| 21357 | .index = i, |
| 21358 | } }; |
| 20808 | 21359 | } |
| 20809 | 21360 | } |
| 20810 | 21361 | |
| 20811 | | if (dest_info.cc != src_info.cc) { |
| 20812 | | return .no_match; |
| 20813 | | } |
| 20814 | | |
| 20815 | 21362 | return .ok; |
| 20816 | 21363 | } |
| 20817 | 21364 | |
| ... | ... | @@ -20830,26 +21377,13 @@ fn coerceInMemoryAllowedPtrs( |
| 20830 | 21377 | const dest_info = dest_ptr_ty.ptrInfo().data; |
| 20831 | 21378 | const src_info = src_ptr_ty.ptrInfo().data; |
| 20832 | 21379 | |
| 20833 | | const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); |
| 20834 | | if (child == .no_match) { |
| 20835 | | return child; |
| 20836 | | } |
| 20837 | | |
| 20838 | | if (dest_info.@"addrspace" != src_info.@"addrspace") { |
| 20839 | | return .no_match; |
| 20840 | | } |
| 20841 | | |
| 20842 | | const ok_sent = dest_info.sentinel == null or src_info.size == .C or |
| 20843 | | (src_info.sentinel != null and |
| 20844 | | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); |
| 20845 | | if (!ok_sent) { |
| 20846 | | return .no_match; |
| 20847 | | } |
| 20848 | | |
| 20849 | 21380 | const ok_ptr_size = src_info.size == dest_info.size or |
| 20850 | 21381 | src_info.size == .C or dest_info.size == .C; |
| 20851 | 21382 | if (!ok_ptr_size) { |
| 20852 | | return .no_match; |
| 21383 | return InMemoryCoercionResult{ .ptr_size = .{ |
| 21384 | .actual = src_info.size, |
| 21385 | .wanted = dest_info.size, |
| 21386 | } }; |
| 20853 | 21387 | } |
| 20854 | 21388 | |
| 20855 | 21389 | const ok_cv_qualifiers = |
| ... | ... | @@ -20857,7 +21391,28 @@ fn coerceInMemoryAllowedPtrs( |
| 20857 | 21391 | (!src_info.@"volatile" or dest_info.@"volatile"); |
| 20858 | 21392 | |
| 20859 | 21393 | if (!ok_cv_qualifiers) { |
| 20860 | | return .no_match; |
| 21394 | return InMemoryCoercionResult{ .ptr_qualifiers = .{ |
| 21395 | .actual_const = !src_info.mutable, |
| 21396 | .wanted_const = !dest_info.mutable, |
| 21397 | .actual_volatile = src_info.@"volatile", |
| 21398 | .wanted_volatile = dest_info.@"volatile", |
| 21399 | } }; |
| 21400 | } |
| 21401 | |
| 21402 | if (dest_info.@"addrspace" != src_info.@"addrspace") { |
| 21403 | return InMemoryCoercionResult{ .ptr_addrspace = .{ |
| 21404 | .actual = src_info.@"addrspace", |
| 21405 | .wanted = dest_info.@"addrspace", |
| 21406 | } }; |
| 21407 | } |
| 21408 | |
| 21409 | const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); |
| 21410 | if (child != .ok) { |
| 21411 | return InMemoryCoercionResult{ .ptr_child = .{ |
| 21412 | .child = try child.dupe(sema.arena), |
| 21413 | .actual = src_info.pointee_type, |
| 21414 | .wanted = dest_info.pointee_type, |
| 21415 | } }; |
| 20861 | 21416 | } |
| 20862 | 21417 | |
| 20863 | 21418 | const dest_allow_zero = dest_ty.ptrAllowsZero(); |
| ... | ... | @@ -20867,13 +21422,32 @@ fn coerceInMemoryAllowedPtrs( |
| 20867 | 21422 | (src_allow_zero or !dest_is_mut)) or |
| 20868 | 21423 | (!dest_allow_zero and !src_allow_zero); |
| 20869 | 21424 | if (!ok_allows_zero) { |
| 20870 | | return .no_match; |
| 21425 | return InMemoryCoercionResult{ .ptr_allowzero = .{ |
| 21426 | .actual = src_ty, |
| 21427 | .wanted = dest_ty, |
| 21428 | } }; |
| 20871 | 21429 | } |
| 20872 | 21430 | |
| 20873 | 21431 | if (src_info.host_size != dest_info.host_size or |
| 20874 | 21432 | src_info.bit_offset != dest_info.bit_offset) |
| 20875 | 21433 | { |
| 20876 | | return .no_match; |
| 21434 | return InMemoryCoercionResult{ .ptr_bit_range = .{ |
| 21435 | .actual_host = src_info.host_size, |
| 21436 | .wanted_host = dest_info.host_size, |
| 21437 | .actual_offset = src_info.bit_offset, |
| 21438 | .wanted_offset = dest_info.bit_offset, |
| 21439 | } }; |
| 21440 | } |
| 21441 | |
| 21442 | const ok_sent = dest_info.sentinel == null or src_info.size == .C or |
| 21443 | (src_info.sentinel != null and |
| 21444 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); |
| 21445 | if (!ok_sent) { |
| 21446 | return InMemoryCoercionResult{ .ptr_sentinel = .{ |
| 21447 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), |
| 21448 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), |
| 21449 | .ty = dest_info.pointee_type, |
| 21450 | } }; |
| 20877 | 21451 | } |
| 20878 | 21452 | |
| 20879 | 21453 | // If both pointers have alignment 0, it means they both want ABI alignment. |
| ... | ... | @@ -20898,7 +21472,10 @@ fn coerceInMemoryAllowedPtrs( |
| 20898 | 21472 | dest_info.pointee_type.abiAlignment(target); |
| 20899 | 21473 | |
| 20900 | 21474 | if (dest_align > src_align) { |
| 20901 | | return .no_match; |
| 21475 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 21476 | .actual = src_align, |
| 21477 | .wanted = dest_align, |
| 21478 | } }; |
| 20902 | 21479 | } |
| 20903 | 21480 | |
| 20904 | 21481 | break :alignment; |
| ... | ... | @@ -20974,6 +21551,8 @@ fn storePtr2( |
| 20974 | 21551 | // TODO do the same thing for anon structs as for tuples above. |
| 20975 | 21552 | // However, beware of the need to handle missing/extra fields. |
| 20976 | 21553 | |
| 21554 | const is_ret = air_tag == .ret_ptr; |
| 21555 | |
| 20977 | 21556 | // Detect if we are storing an array operand to a bitcasted vector pointer. |
| 20978 | 21557 | // If so, we instead reach through the bitcasted pointer to the vector pointer, |
| 20979 | 21558 | // bitcast the array operand to a vector, and then lower this as a store of |
| ... | ... | @@ -20982,12 +21561,18 @@ fn storePtr2( |
| 20982 | 21561 | // https://github.com/ziglang/zig/issues/11154 |
| 20983 | 21562 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { |
| 20984 | 21563 | const vector_ty = sema.typeOf(vector_ptr).childType(); |
| 20985 | | const vector = try sema.coerce(block, vector_ty, uncasted_operand, operand_src); |
| 21564 | const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) { |
| 21565 | error.NotCoercible => unreachable, |
| 21566 | else => |e| return e, |
| 21567 | }; |
| 20986 | 21568 | try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); |
| 20987 | 21569 | return; |
| 20988 | 21570 | } |
| 20989 | 21571 | |
| 20990 | | const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src); |
| 21572 | const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) { |
| 21573 | error.NotCoercible => unreachable, |
| 21574 | else => |e| return e, |
| 21575 | }; |
| 20991 | 21576 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); |
| 20992 | 21577 | |
| 20993 | 21578 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| ... | ... | @@ -21017,7 +21602,11 @@ fn storePtr2( |
| 21017 | 21602 | |
| 21018 | 21603 | try sema.requireRuntimeBlock(block, runtime_src); |
| 21019 | 21604 | try sema.queueFullTypeResolution(elem_ty); |
| 21020 | | _ = try block.addBinOp(air_tag, ptr, operand); |
| 21605 | if (is_ret) { |
| 21606 | _ = try block.addBinOp(.store, ptr, operand); |
| 21607 | } else { |
| 21608 | _ = try block.addBinOp(air_tag, ptr, operand); |
| 21609 | } |
| 21021 | 21610 | } |
| 21022 | 21611 | |
| 21023 | 21612 | /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector |