| ... | @@ -2749,7 +2749,15 @@ fn ensureResultUsed( | ... | @@ -2749,7 +2749,15 @@ fn ensureResultUsed( |
| 2749 | const operand_ty = sema.typeOf(operand); | 2749 | const operand_ty = sema.typeOf(operand); |
| 2750 | switch (operand_ty.zigTypeTag()) { | 2750 | switch (operand_ty.zigTypeTag()) { |
| 2751 | .Void, .NoReturn => return, | 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 | else => return sema.fail(block, src, "expression value is ignored", .{}), | 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,7 +2771,15 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2763 | const src = inst_data.src(); | 2771 | const src = inst_data.src(); |
| 2764 | const operand_ty = sema.typeOf(operand); | 2772 | const operand_ty = sema.typeOf(operand); |
| 2765 | switch (operand_ty.zigTypeTag()) { | 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 | else => return, | 2783 | else => return, |
| 2768 | } | 2784 | } |
| 2769 | } | 2785 | } |
| ... | @@ -4119,23 +4135,24 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v | ... | @@ -4119,23 +4135,24 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 4119 | const ptr = try sema.resolveInst(extra.lhs); | 4135 | const ptr = try sema.resolveInst(extra.lhs); |
| 4120 | const operand = try sema.resolveInst(extra.rhs); | 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 | // Check for the possibility of this pattern: | 4143 | // Check for the possibility of this pattern: |
| 4123 | // %a = ret_ptr | 4144 | // %a = ret_ptr |
| 4124 | // %b = store(%a, %c) | 4145 | // %b = store(%a, %c) |
| 4125 | // Where %c is an error union or error set. In such case we need to add | 4146 | // Where %c is an error union or error set. In such case we need to add |
| 4126 | // to the current function's inferred error set, if any. | 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 | sema.typeOf(operand).zigTypeTag() == .ErrorSet) and | 4149 | sema.typeOf(operand).zigTypeTag() == .ErrorSet) and |
| 4129 | sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) | 4150 | sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) |
| 4130 | { | 4151 | { |
| 4131 | if (Zir.refToIndex(extra.lhs)) |ptr_index| { | 4152 | try sema.addToInferredErrorSet(operand); |
| 4132 | if (zir_tags[ptr_index] == .ret_ptr) { | | |
| 4133 | try sema.addToInferredErrorSet(operand); | | |
| 4134 | } | | |
| 4135 | } | | |
| 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 | fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 4158 | fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -5534,7 +5551,7 @@ fn analyzeCall( | ... | @@ -5534,7 +5551,7 @@ fn analyzeCall( |
| 5534 | try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst) | 5551 | try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst) |
| 5535 | else | 5552 | else |
| 5536 | try sema.resolveInst(fn_info.ret_ty_ref); | 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 | const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); | 5555 | const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); |
| 5539 | // Create a fresh inferred error set type for inline/comptime calls. | 5556 | // Create a fresh inferred error set type for inline/comptime calls. |
| 5540 | const fn_ret_ty = blk: { | 5557 | const fn_ret_ty = blk: { |
| ... | @@ -6876,7 +6893,7 @@ fn zirFunc( | ... | @@ -6876,7 +6893,7 @@ fn zirFunc( |
| 6876 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 6893 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6877 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); | 6894 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); |
| 6878 | const target = sema.mod.getTarget(); | 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 | var extra_index = extra.end; | 6898 | var extra_index = extra.end; |
| 6882 | | 6899 | |
| ... | @@ -7458,13 +7475,20 @@ fn analyzeAs( | ... | @@ -7458,13 +7475,20 @@ fn analyzeAs( |
| 7458 | zir_dest_type: Zir.Inst.Ref, | 7475 | zir_dest_type: Zir.Inst.Ref, |
| 7459 | zir_operand: Zir.Inst.Ref, | 7476 | zir_operand: Zir.Inst.Ref, |
| 7460 | ) CompileError!Air.Inst.Ref { | 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 | const dest_ty = try sema.resolveType(block, src, zir_dest_type); | 7482 | const dest_ty = try sema.resolveType(block, src, zir_dest_type); |
| 7462 | const operand = try sema.resolveInst(zir_operand); | 7483 | const operand = try sema.resolveInst(zir_operand); |
| 7463 | if (dest_ty.tag() == .var_args_param) return operand; | 7484 | if (dest_ty.tag() == .var_args_param) return operand; |
| 7464 | if (dest_ty.zigTypeTag() == .NoReturn) { | 7485 | if (dest_ty.zigTypeTag() == .NoReturn) { |
| 7465 | return sema.fail(block, src, "cannot cast to noreturn", .{}); | 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 | fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7494 | fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -13647,7 +13671,10 @@ fn analyzeRet( | ... | @@ -13647,7 +13671,10 @@ fn analyzeRet( |
| 13647 | if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { | 13671 | if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { |
| 13648 | try sema.addToInferredErrorSet(uncasted_operand); | 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 | if (block.inlining) |inlining| { | 13679 | if (block.inlining) |inlining| { |
| 13653 | if (block.is_comptime) { | 13680 | if (block.is_comptime) { |
| ... | @@ -19993,6 +20020,27 @@ fn coerce( | ... | @@ -19993,6 +20020,27 @@ fn coerce( |
| 19993 | inst: Air.Inst.Ref, | 20020 | inst: Air.Inst.Ref, |
| 19994 | inst_src: LazySrcLoc, | 20021 | inst_src: LazySrcLoc, |
| 19995 | ) CompileError!Air.Inst.Ref { | 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 | switch (dest_ty_unresolved.tag()) { | 20044 | switch (dest_ty_unresolved.tag()) { |
| 19997 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), | 20045 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), |
| 19998 | .generic_poison => return inst, | 20046 | .generic_poison => return inst, |
| ... | @@ -20009,7 +20057,7 @@ fn coerce( | ... | @@ -20009,7 +20057,7 @@ fn coerce( |
| 20009 | const arena = sema.arena; | 20057 | const arena = sema.arena; |
| 20010 | const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst); | 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 | if (in_memory_result == .ok) { | 20061 | if (in_memory_result == .ok) { |
| 20014 | if (maybe_inst_val) |val| { | 20062 | if (maybe_inst_val) |val| { |
| 20015 | // Keep the comptime Value representation; take the new type. | 20063 | // Keep the comptime Value representation; take the new type. |
| ... | @@ -20022,7 +20070,7 @@ fn coerce( | ... | @@ -20022,7 +20070,7 @@ fn coerce( |
| 20022 | const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; | 20070 | const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; |
| 20023 | | 20071 | |
| 20024 | switch (dest_ty.zigTypeTag()) { | 20072 | switch (dest_ty.zigTypeTag()) { |
| 20025 | .Optional => { | 20073 | .Optional => optional: { |
| 20026 | // undefined sets the optional bit also to undefined. | 20074 | // undefined sets the optional bit also to undefined. |
| 20027 | if (is_undef) { | 20075 | if (is_undef) { |
| 20028 | return sema.addConstUndef(dest_ty); | 20076 | return sema.addConstUndef(dest_ty); |
| ... | @@ -20043,10 +20091,19 @@ fn coerce( | ... | @@ -20043,10 +20091,19 @@ fn coerce( |
| 20043 | | 20091 | |
| 20044 | // T to ?T | 20092 | // T to ?T |
| 20045 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); | 20093 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); |
| 20046 | const intermediate = try sema.coerce(block, child_type, inst, inst_src); | 20094 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false, is_ret) catch |err| switch (err) { |
| 20047 | return sema.wrapOptional(block, dest_ty, intermediate, inst_src); | 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 | const dest_info = dest_ty.ptrInfo().data; | 20107 | const dest_info = dest_ty.ptrInfo().data; |
| 20051 | | 20108 | |
| 20052 | // Function body to function pointer. | 20109 | // Function body to function pointer. |
| ... | @@ -20071,7 +20128,7 @@ fn coerce( | ... | @@ -20071,7 +20128,7 @@ fn coerce( |
| 20071 | if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item; | 20128 | if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item; |
| 20072 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { | 20129 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 20073 | .ok => {}, | 20130 | .ok => {}, |
| 20074 | .no_match => break :single_item, | 20131 | else => break :single_item, |
| 20075 | } | 20132 | } |
| 20076 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); | 20133 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 20077 | } | 20134 | } |
| ... | @@ -20091,7 +20148,7 @@ fn coerce( | ... | @@ -20091,7 +20148,7 @@ fn coerce( |
| 20091 | const dst_elem_type = dest_info.pointee_type; | 20148 | const dst_elem_type = dest_info.pointee_type; |
| 20092 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) { | 20149 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 20093 | .ok => {}, | 20150 | .ok => {}, |
| 20094 | .no_match => break :src_array_ptr, | 20151 | else => break :src_array_ptr, |
| 20095 | } | 20152 | } |
| 20096 | | 20153 | |
| 20097 | switch (dest_info.size) { | 20154 | switch (dest_info.size) { |
| ... | @@ -20130,7 +20187,7 @@ fn coerce( | ... | @@ -20130,7 +20187,7 @@ fn coerce( |
| 20130 | const dst_elem_type = dest_info.pointee_type; | 20187 | const dst_elem_type = dest_info.pointee_type; |
| 20131 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { | 20188 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 20132 | .ok => {}, | 20189 | .ok => {}, |
| 20133 | .no_match => break :src_c_ptr, | 20190 | else => break :src_c_ptr, |
| 20134 | } | 20191 | } |
| 20135 | // TODO add safety check for null pointer | 20192 | // TODO add safety check for null pointer |
| 20136 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); | 20193 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| ... | @@ -20151,16 +20208,26 @@ fn coerce( | ... | @@ -20151,16 +20208,26 @@ fn coerce( |
| 20151 | return sema.addConstant(dest_ty, Value.@"null"); | 20208 | return sema.addConstant(dest_ty, Value.@"null"); |
| 20152 | }, | 20209 | }, |
| 20153 | .ComptimeInt => { | 20210 | .ComptimeInt => { |
| 20154 | const addr = try sema.coerce(block, Type.usize, inst, inst_src); | 20211 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false, is_ret) catch |err| switch (err) { |
| 20155 | return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); | 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 | .Int => { | 20217 | .Int => { |
| 20158 | const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { | 20218 | const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { |
| 20159 | .signed => Type.isize, | 20219 | .signed => Type.isize, |
| 20160 | .unsigned => Type.usize, | 20220 | .unsigned => Type.usize, |
| 20161 | }; | 20221 | }; |
| 20162 | const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src); | 20222 | const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false, is_ret) catch |err| switch (err) { |
| 20163 | return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); | 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 | .Pointer => p: { | 20232 | .Pointer => p: { |
| 20166 | const inst_info = inst_ty.ptrInfo().data; | 20233 | const inst_info = inst_ty.ptrInfo().data; |
| ... | @@ -20174,7 +20241,7 @@ fn coerce( | ... | @@ -20174,7 +20241,7 @@ fn coerce( |
| 20174 | inst_src, | 20241 | inst_src, |
| 20175 | )) { | 20242 | )) { |
| 20176 | .ok => {}, | 20243 | .ok => {}, |
| 20177 | .no_match => break :p, | 20244 | else => break :p, |
| 20178 | } | 20245 | } |
| 20179 | if (inst_info.size == .Slice) { | 20246 | if (inst_info.size == .Slice) { |
| 20180 | if (dest_info.sentinel == null or inst_info.sentinel == null or | 20247 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| ... | @@ -20264,7 +20331,7 @@ fn coerce( | ... | @@ -20264,7 +20331,7 @@ fn coerce( |
| 20264 | inst_src, | 20331 | inst_src, |
| 20265 | )) { | 20332 | )) { |
| 20266 | .ok => {}, | 20333 | .ok => {}, |
| 20267 | .no_match => break :p, | 20334 | else => break :p, |
| 20268 | } | 20335 | } |
| 20269 | | 20336 | |
| 20270 | if (dest_info.sentinel == null or inst_info.sentinel == null or | 20337 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| ... | @@ -20295,6 +20362,7 @@ fn coerce( | ... | @@ -20295,6 +20362,7 @@ fn coerce( |
| 20295 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { | 20362 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { |
| 20296 | // comptime known integer to other number | 20363 | // comptime known integer to other number |
| 20297 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { | 20364 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { |
| | 20365 | if (!report_err) return error.NotCoercible; |
| 20298 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); | 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 | return try sema.addConstant(dest_ty, val); | 20368 | return try sema.addConstant(dest_ty, val); |
| ... | @@ -20496,14 +20564,396 @@ fn coerce( | ... | @@ -20496,14 +20564,396 @@ fn coerce( |
| 20496 | return sema.addConstUndef(dest_ty); | 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 | ok, | 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 | /// If pointers have the same representation in runtime memory, a bitcast AIR instruction | 20957 | /// If pointers have the same representation in runtime memory, a bitcast AIR instruction |
| 20508 | /// may be used for the coercion. | 20958 | /// may be used for the coercion. |
| 20509 | /// * `const` attribute can be gained | 20959 | /// * `const` attribute can be gained |
| ... | @@ -20513,8 +20963,6 @@ const InMemoryCoercionResult = enum { | ... | @@ -20513,8 +20963,6 @@ const InMemoryCoercionResult = enum { |
| 20513 | /// * bit offset attributes must match exactly | 20963 | /// * bit offset attributes must match exactly |
| 20514 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one | 20964 | /// * `*`/`[*]` must match exactly, but `[*c]` matches either one |
| 20515 | /// * sentinel-terminated pointers can coerce into `[*]` | 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 | fn coerceInMemoryAllowed( | 20966 | fn coerceInMemoryAllowed( |
| 20519 | sema: *Sema, | 20967 | sema: *Sema, |
| 20520 | block: *Block, | 20968 | block: *Block, |
| ... | @@ -20532,11 +20980,25 @@ fn coerceInMemoryAllowed( | ... | @@ -20532,11 +20980,25 @@ fn coerceInMemoryAllowed( |
| 20532 | if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { | 20980 | if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { |
| 20533 | const dest_info = dest_ty.intInfo(target); | 20981 | const dest_info = dest_ty.intInfo(target); |
| 20534 | const src_info = src_ty.intInfo(target); | 20982 | const src_info = src_ty.intInfo(target); |
| | 20983 | |
| 20535 | if (dest_info.signedness == src_info.signedness and | 20984 | if (dest_info.signedness == src_info.signedness and |
| 20536 | dest_info.bits == src_info.bits) | 20985 | dest_info.bits == src_info.bits) |
| 20537 | { | 20986 | { |
| 20538 | return .ok; | 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 | // Differently-named floats with the same number of bits. | 21004 | // Differently-named floats with the same number of bits. |
| ... | @@ -20574,9 +21036,15 @@ fn coerceInMemoryAllowed( | ... | @@ -20574,9 +21036,15 @@ fn coerceInMemoryAllowed( |
| 20574 | | 21036 | |
| 20575 | // Error Unions | 21037 | // Error Unions |
| 20576 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { | 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); | 21039 | const dest_payload = dest_ty.errorUnionPayload(); |
| 20578 | if (child == .no_match) { | 21040 | const src_payload = src_ty.errorUnionPayload(); |
| 20579 | return child; | 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 | return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); | 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,57 +21055,89 @@ fn coerceInMemoryAllowed( |
| 20587 | } | 21055 | } |
| 20588 | | 21056 | |
| 20589 | // Arrays | 21057 | // Arrays |
| 20590 | if (dest_tag == .Array and src_tag == .Array) arrays: { | 21058 | if (dest_tag == .Array and src_tag == .Array) { |
| 20591 | const dest_info = dest_ty.arrayInfo(); | 21059 | const dest_info = dest_ty.arrayInfo(); |
| 20592 | const src_info = src_ty.arrayInfo(); | 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 | const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); | 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) { | 21069 | if (child != .ok) { |
| 20597 | return child; | 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 | const ok_sent = dest_info.sentinel == null or | 21076 | const ok_sent = dest_info.sentinel == null or |
| 20600 | (src_info.sentinel != null and | 21077 | (src_info.sentinel != null and |
| 20601 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); | 21078 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); |
| 20602 | if (!ok_sent) { | 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 | return .ok; | 21086 | return .ok; |
| 20606 | } | 21087 | } |
| 20607 | | 21088 | |
| 20608 | // Vectors | 21089 | // Vectors |
| 20609 | if (dest_tag == .Vector and src_tag == .Vector) vectors: { | 21090 | if (dest_tag == .Vector and src_tag == .Vector) { |
| 20610 | const dest_len = dest_ty.vectorLen(); | 21091 | const dest_len = dest_ty.vectorLen(); |
| 20611 | const src_len = src_ty.vectorLen(); | 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 | const dest_elem_ty = dest_ty.scalarType(); | 21100 | const dest_elem_ty = dest_ty.scalarType(); |
| 20615 | const src_elem_ty = src_ty.scalarType(); | 21101 | const src_elem_ty = src_ty.scalarType(); |
| 20616 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); | 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 | return .ok; | 21111 | return .ok; |
| 20620 | } | 21112 | } |
| 20621 | | 21113 | |
| 20622 | // Optionals | 21114 | // Optionals |
| 20623 | if (dest_tag == .Optional and src_tag == .Optional) optionals: { | 21115 | if (dest_tag == .Optional and src_tag == .Optional) { |
| 20624 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { | 21116 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { |
| 20625 | // TODO "optional type child '{}' cannot cast into optional type '{}'" | 21117 | return InMemoryCoercionResult{ .optional_shape = .{ |
| 20626 | return .no_match; | 21118 | .actual = src_ty, |
| | 21119 | .wanted = dest_ty, |
| | 21120 | } }; |
| 20627 | } | 21121 | } |
| 20628 | const dest_child_type = dest_ty.optionalChild(&dest_buf); | 21122 | const dest_child_type = dest_ty.optionalChild(&dest_buf); |
| 20629 | const src_child_type = src_ty.optionalChild(&src_buf); | 21123 | const src_child_type = src_ty.optionalChild(&src_buf); |
| 20630 | | 21124 | |
| 20631 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); | 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) { | 21126 | if (child != .ok) { |
| 20633 | // TODO "optional type child '{}' cannot cast into optional type child '{}'" | 21127 | return InMemoryCoercionResult{ .optional_child = .{ |
| 20634 | break :optionals; | 21128 | .child = try child.dupe(sema.arena), |
| | 21129 | .actual = src_child_type, |
| | 21130 | .wanted = dest_child_type, |
| | 21131 | } }; |
| 20635 | } | 21132 | } |
| 20636 | | 21133 | |
| 20637 | return .ok; | 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 | fn coerceInMemoryAllowedErrorSets( | 21143 | fn coerceInMemoryAllowedErrorSets( |
| ... | @@ -20704,6 +21204,9 @@ 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 | switch (src_ty.tag()) { | 21210 | switch (src_ty.tag()) { |
| 20708 | .error_set_inferred => { | 21211 | .error_set_inferred => { |
| 20709 | const src_data = src_ty.castTag(.error_set_inferred).?.data; | 21212 | const src_data = src_ty.castTag(.error_set_inferred).?.data; |
| ... | @@ -20712,15 +21215,21 @@ fn coerceInMemoryAllowedErrorSets( | ... | @@ -20712,15 +21215,21 @@ fn coerceInMemoryAllowedErrorSets( |
| 20712 | // src anyerror status might have changed after the resolution. | 21215 | // src anyerror status might have changed after the resolution. |
| 20713 | if (src_ty.isAnyError()) { | 21216 | if (src_ty.isAnyError()) { |
| 20714 | // dest_ty.isAnyError() == true is already checked for at this point. | 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 | for (src_data.errors.keys()) |key| { | 21221 | for (src_data.errors.keys()) |key| { |
| 20719 | if (!dest_ty.errorSetHasField(key)) { | 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 | return .ok; | 21233 | return .ok; |
| 20725 | }, | 21234 | }, |
| 20726 | .error_set_single => { | 21235 | .error_set_single => { |
| ... | @@ -20728,37 +21237,52 @@ fn coerceInMemoryAllowedErrorSets( | ... | @@ -20728,37 +21237,52 @@ fn coerceInMemoryAllowedErrorSets( |
| 20728 | if (dest_ty.errorSetHasField(name)) { | 21237 | if (dest_ty.errorSetHasField(name)) { |
| 20729 | return .ok; | 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 | .error_set_merged => { | 21244 | .error_set_merged => { |
| 20733 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); | 21245 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); |
| 20734 | for (names) |name| { | 21246 | for (names) |name| { |
| 20735 | if (!dest_ty.errorSetHasField(name)) { | 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 | return .ok; | 21258 | return .ok; |
| 20741 | }, | 21259 | }, |
| 20742 | .error_set => { | 21260 | .error_set => { |
| 20743 | const names = src_ty.castTag(.error_set).?.data.names.keys(); | 21261 | const names = src_ty.castTag(.error_set).?.data.names.keys(); |
| 20744 | for (names) |name| { | 21262 | for (names) |name| { |
| 20745 | if (!dest_ty.errorSetHasField(name)) { | 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 | return .ok; | 21274 | return .ok; |
| 20751 | }, | 21275 | }, |
| 20752 | .anyerror => switch (dest_ty.tag()) { | 21276 | .anyerror => switch (dest_ty.tag()) { |
| 20753 | .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above. | 21277 | .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. |
| 20754 | .error_set_single, .error_set_merged, .error_set => {}, | 21278 | .error_set_single, .error_set_merged, .error_set => return .from_anyerror, |
| 20755 | .anyerror => unreachable, // Filtered out above. | 21279 | .anyerror => unreachable, // Filtered out above. |
| 20756 | else => unreachable, | 21280 | else => unreachable, |
| 20757 | }, | 21281 | }, |
| 20758 | else => unreachable, | 21282 | else => unreachable, |
| 20759 | } | 21283 | } |
| 20760 | | 21284 | |
| 20761 | return .no_match; | 21285 | unreachable; |
| 20762 | } | 21286 | } |
| 20763 | | 21287 | |
| 20764 | fn coerceInMemoryAllowedFns( | 21288 | fn coerceInMemoryAllowedFns( |
| ... | @@ -20774,44 +21298,67 @@ fn coerceInMemoryAllowedFns( | ... | @@ -20774,44 +21298,67 @@ fn coerceInMemoryAllowedFns( |
| 20774 | const src_info = src_ty.fnInfo(); | 21298 | const src_info = src_ty.fnInfo(); |
| 20775 | | 21299 | |
| 20776 | if (dest_info.is_var_args != src_info.is_var_args) { | 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 | if (dest_info.is_generic != src_info.is_generic) { | 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 | if (!src_info.return_type.isNoReturn()) { | 21315 | if (!src_info.return_type.isNoReturn()) { |
| 20785 | const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); | 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) { | 21317 | if (rt != .ok) { |
| 20787 | return rt; | 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 | if (dest_info.param_types.len != src_info.param_types.len) { | 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 | for (dest_info.param_types) |dest_param_ty, i| { | 21340 | for (dest_info.param_types) |dest_param_ty, i| { |
| 20796 | const src_param_ty = src_info.param_types[i]; | 21341 | const src_param_ty = src_info.param_types[i]; |
| 20797 | | 21342 | |
| 20798 | if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { | 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 | // Note: Cast direction is reversed here. | 21350 | // Note: Cast direction is reversed here. |
| 20805 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); | 21351 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); |
| 20806 | if (param == .no_match) { | 21352 | if (param != .ok) { |
| 20807 | return param; | 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 | return .ok; | 21362 | return .ok; |
| 20816 | } | 21363 | } |
| 20817 | | 21364 | |
| ... | @@ -20830,26 +21377,13 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -20830,26 +21377,13 @@ fn coerceInMemoryAllowedPtrs( |
| 20830 | const dest_info = dest_ptr_ty.ptrInfo().data; | 21377 | const dest_info = dest_ptr_ty.ptrInfo().data; |
| 20831 | const src_info = src_ptr_ty.ptrInfo().data; | 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 | const ok_ptr_size = src_info.size == dest_info.size or | 21380 | const ok_ptr_size = src_info.size == dest_info.size or |
| 20850 | src_info.size == .C or dest_info.size == .C; | 21381 | src_info.size == .C or dest_info.size == .C; |
| 20851 | if (!ok_ptr_size) { | 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 | const ok_cv_qualifiers = | 21389 | const ok_cv_qualifiers = |
| ... | @@ -20857,7 +21391,28 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -20857,7 +21391,28 @@ fn coerceInMemoryAllowedPtrs( |
| 20857 | (!src_info.@"volatile" or dest_info.@"volatile"); | 21391 | (!src_info.@"volatile" or dest_info.@"volatile"); |
| 20858 | | 21392 | |
| 20859 | if (!ok_cv_qualifiers) { | 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 | const dest_allow_zero = dest_ty.ptrAllowsZero(); | 21418 | const dest_allow_zero = dest_ty.ptrAllowsZero(); |
| ... | @@ -20867,13 +21422,32 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -20867,13 +21422,32 @@ fn coerceInMemoryAllowedPtrs( |
| 20867 | (src_allow_zero or !dest_is_mut)) or | 21422 | (src_allow_zero or !dest_is_mut)) or |
| 20868 | (!dest_allow_zero and !src_allow_zero); | 21423 | (!dest_allow_zero and !src_allow_zero); |
| 20869 | if (!ok_allows_zero) { | 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 | if (src_info.host_size != dest_info.host_size or | 21431 | if (src_info.host_size != dest_info.host_size or |
| 20874 | src_info.bit_offset != dest_info.bit_offset) | 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 | // If both pointers have alignment 0, it means they both want ABI alignment. | 21453 | // If both pointers have alignment 0, it means they both want ABI alignment. |
| ... | @@ -20898,7 +21472,10 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -20898,7 +21472,10 @@ fn coerceInMemoryAllowedPtrs( |
| 20898 | dest_info.pointee_type.abiAlignment(target); | 21472 | dest_info.pointee_type.abiAlignment(target); |
| 20899 | | 21473 | |
| 20900 | if (dest_align > src_align) { | 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 | break :alignment; | 21481 | break :alignment; |
| ... | @@ -20974,6 +21551,8 @@ fn storePtr2( | ... | @@ -20974,6 +21551,8 @@ fn storePtr2( |
| 20974 | // TODO do the same thing for anon structs as for tuples above. | 21551 | // TODO do the same thing for anon structs as for tuples above. |
| 20975 | // However, beware of the need to handle missing/extra fields. | 21552 | // However, beware of the need to handle missing/extra fields. |
| 20976 | | 21553 | |
| | 21554 | const is_ret = air_tag == .ret_ptr; |
| | 21555 | |
| 20977 | // Detect if we are storing an array operand to a bitcasted vector pointer. | 21556 | // Detect if we are storing an array operand to a bitcasted vector pointer. |
| 20978 | // If so, we instead reach through the bitcasted pointer to the vector pointer, | 21557 | // If so, we instead reach through the bitcasted pointer to the vector pointer, |
| 20979 | // bitcast the array operand to a vector, and then lower this as a store of | 21558 | // bitcast the array operand to a vector, and then lower this as a store of |
| ... | @@ -20982,12 +21561,18 @@ fn storePtr2( | ... | @@ -20982,12 +21561,18 @@ fn storePtr2( |
| 20982 | // https://github.com/ziglang/zig/issues/11154 | 21561 | // https://github.com/ziglang/zig/issues/11154 |
| 20983 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { | 21562 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { |
| 20984 | const vector_ty = sema.typeOf(vector_ptr).childType(); | 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 | try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); | 21568 | try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); |
| 20987 | return; | 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 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); | 21576 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); |
| 20992 | | 21577 | |
| 20993 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { | 21578 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| ... | @@ -21017,7 +21602,11 @@ fn storePtr2( | ... | @@ -21017,7 +21602,11 @@ fn storePtr2( |
| 21017 | | 21602 | |
| 21018 | try sema.requireRuntimeBlock(block, runtime_src); | 21603 | try sema.requireRuntimeBlock(block, runtime_src); |
| 21019 | try sema.queueFullTypeResolution(elem_ty); | 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 | /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector | 21612 | /// Traverse an arbitrary number of bitcasted pointers and return the underyling vector |