| ... | @@ -504,7 +504,17 @@ pub const Block = struct { | ... | @@ -504,7 +504,17 @@ pub const Block = struct { |
| 504 | }; | 504 | }; |
| 505 | } | 505 | } |
| 506 | | 506 | |
| 507 | pub fn wantSafety(block: *const Block) bool { | 507 | fn wantSafeTypes(block: *const Block) bool { |
| | 508 | return block.want_safety orelse switch (block.sema.pt.zcu.optimizeMode()) { |
| | 509 | .Debug => true, |
| | 510 | .ReleaseSafe => true, |
| | 511 | .ReleaseFast => false, |
| | 512 | .ReleaseSmall => false, |
| | 513 | }; |
| | 514 | } |
| | 515 | |
| | 516 | fn wantSafety(block: *const Block) bool { |
| | 517 | if (block.isComptime()) return false; // runtime safety checks are pointless in comptime blocks |
| 508 | return block.want_safety orelse switch (block.sema.pt.zcu.optimizeMode()) { | 518 | return block.want_safety orelse switch (block.sema.pt.zcu.optimizeMode()) { |
| 509 | .Debug => true, | 519 | .Debug => true, |
| 510 | .ReleaseSafe => true, | 520 | .ReleaseSafe => true, |
| ... | @@ -1197,6 +1207,7 @@ fn analyzeBodyInner( | ... | @@ -1197,6 +1207,7 @@ fn analyzeBodyInner( |
| 1197 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), | 1207 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), |
| 1198 | .slice_start => try sema.zirSliceStart(block, inst), | 1208 | .slice_start => try sema.zirSliceStart(block, inst), |
| 1199 | .slice_length => try sema.zirSliceLength(block, inst), | 1209 | .slice_length => try sema.zirSliceLength(block, inst), |
| | 1210 | .slice_sentinel_ty => try sema.zirSliceSentinelTy(block, inst), |
| 1200 | .str => try sema.zirStr(inst), | 1211 | .str => try sema.zirStr(inst), |
| 1201 | .switch_block => try sema.zirSwitchBlock(block, inst, false), | 1212 | .switch_block => try sema.zirSwitchBlock(block, inst, false), |
| 1202 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), | 1213 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), |
| ... | @@ -3293,7 +3304,7 @@ fn zirUnionDecl( | ... | @@ -3293,7 +3304,7 @@ fn zirUnionDecl( |
| 3293 | .tagged | 3304 | .tagged |
| 3294 | else if (small.layout != .auto) | 3305 | else if (small.layout != .auto) |
| 3295 | .none | 3306 | .none |
| 3296 | else switch (block.wantSafety()) { | 3307 | else switch (block.wantSafeTypes()) { |
| 3297 | true => .safety, | 3308 | true => .safety, |
| 3298 | false => .none, | 3309 | false => .none, |
| 3299 | }, | 3310 | }, |
| ... | @@ -9144,6 +9155,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -9144,6 +9155,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 9144 | return sema.analyzeErrUnionCode(block, src, operand); | 9155 | return sema.analyzeErrUnionCode(block, src, operand); |
| 9145 | } | 9156 | } |
| 9146 | | 9157 | |
| | 9158 | /// If `operand` is comptime-known, asserts that it is an error value rather than a payload value. |
| 9147 | fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref { | 9159 | fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref { |
| 9148 | const pt = sema.pt; | 9160 | const pt = sema.pt; |
| 9149 | const zcu = pt.zcu; | 9161 | const zcu = pt.zcu; |
| ... | @@ -10753,6 +10765,46 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10753,6 +10765,46 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10753 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); | 10765 | return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true); |
| 10754 | } | 10766 | } |
| 10755 | | 10767 | |
| | 10768 | fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| | 10769 | const tracy = trace(@src()); |
| | 10770 | defer tracy.end(); |
| | 10771 | |
| | 10772 | const pt = sema.pt; |
| | 10773 | const zcu = pt.zcu; |
| | 10774 | |
| | 10775 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| | 10776 | |
| | 10777 | const src = block.nodeOffset(inst_data.src_node); |
| | 10778 | const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node }); |
| | 10779 | const sentinel_src = block.src(.{ .node_offset_slice_sentinel = inst_data.src_node }); |
| | 10780 | |
| | 10781 | // This is like the logic in `analyzeSlice`; since we've evaluated the LHS as an lvalue, we will |
| | 10782 | // have a double pointer if it was already a pointer. |
| | 10783 | |
| | 10784 | const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand)); |
| | 10785 | const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) { |
| | 10786 | .pointer => lhs_ptr_ty.childType(zcu), |
| | 10787 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}), |
| | 10788 | }; |
| | 10789 | |
| | 10790 | const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) { |
| | 10791 | .array => lhs_ty.childType(zcu), |
| | 10792 | .pointer => switch (lhs_ty.ptrSize(zcu)) { |
| | 10793 | .many, .c, .slice => lhs_ty.childType(zcu), |
| | 10794 | .one => s: { |
| | 10795 | const lhs_elem_ty = lhs_ty.childType(zcu); |
| | 10796 | break :s switch (lhs_elem_ty.zigTypeTag(zcu)) { |
| | 10797 | .array => lhs_elem_ty.childType(zcu), // array element type |
| | 10798 | else => return sema.fail(block, sentinel_src, "slice of single-item pointer cannot have sentinel", .{}), |
| | 10799 | }; |
| | 10800 | }, |
| | 10801 | }, |
| | 10802 | else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}), |
| | 10803 | }; |
| | 10804 | |
| | 10805 | return Air.internedToRef(sentinel_ty.toIntern()); |
| | 10806 | } |
| | 10807 | |
| 10756 | /// Holds common data used when analyzing or resolving switch prong bodies, | 10808 | /// Holds common data used when analyzing or resolving switch prong bodies, |
| 10757 | /// including setting up captures. | 10809 | /// including setting up captures. |
| 10758 | const SwitchProngAnalysis = struct { | 10810 | const SwitchProngAnalysis = struct { |
| ... | @@ -17558,10 +17610,16 @@ fn analyzeCmp( | ... | @@ -17558,10 +17610,16 @@ fn analyzeCmp( |
| 17558 | return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src); | 17610 | return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src); |
| 17559 | } | 17611 | } |
| 17560 | if (is_equality_cmp and lhs_ty.zigTypeTag(zcu) == .error_union and rhs_ty.zigTypeTag(zcu) == .error_set) { | 17612 | if (is_equality_cmp and lhs_ty.zigTypeTag(zcu) == .error_union and rhs_ty.zigTypeTag(zcu) == .error_set) { |
| | 17613 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { |
| | 17614 | if (lhs_val.errorUnionIsPayload(zcu)) return .bool_false; |
| | 17615 | } |
| 17561 | const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs); | 17616 | const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs); |
| 17562 | return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src); | 17617 | return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src); |
| 17563 | } | 17618 | } |
| 17564 | if (is_equality_cmp and lhs_ty.zigTypeTag(zcu) == .error_set and rhs_ty.zigTypeTag(zcu) == .error_union) { | 17619 | if (is_equality_cmp and lhs_ty.zigTypeTag(zcu) == .error_set and rhs_ty.zigTypeTag(zcu) == .error_union) { |
| | 17620 | if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| { |
| | 17621 | if (rhs_val.errorUnionIsPayload(zcu)) return .bool_false; |
| | 17622 | } |
| 17565 | const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs); | 17623 | const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs); |
| 17566 | return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src); | 17624 | return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src); |
| 17567 | } | 17625 | } |
| ... | @@ -18087,10 +18145,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -18087,10 +18145,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 18087 | | 18145 | |
| 18088 | const ret_ty_opt = try pt.intern(.{ .opt = .{ | 18146 | const ret_ty_opt = try pt.intern(.{ .opt = .{ |
| 18089 | .ty = try pt.intern(.{ .opt_type = .type_type }), | 18147 | .ty = try pt.intern(.{ .opt_type = .type_type }), |
| 18090 | .val = if (func_ty_info.return_type == .generic_poison_type) | 18148 | .val = opt_val: { |
| 18091 | .none | 18149 | const ret_ty: Type = .fromInterned(func_ty_info.return_type); |
| 18092 | else | 18150 | if (ret_ty.toIntern() == .generic_poison_type) break :opt_val .none; |
| 18093 | func_ty_info.return_type, | 18151 | if (ret_ty.zigTypeTag(zcu) == .error_union) { |
| | 18152 | if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) { |
| | 18153 | break :opt_val .none; |
| | 18154 | } |
| | 18155 | } |
| | 18156 | break :opt_val ret_ty.toIntern(); |
| | 18157 | }, |
| 18094 | } }); | 18158 | } }); |
| 18095 | | 18159 | |
| 18096 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); | 18160 | const callconv_ty = try sema.getBuiltinType(src, .CallingConvention); |
| ... | @@ -21401,7 +21465,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -21401,7 +21465,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 21401 | try operand_ty.resolveLayout(pt); | 21465 | try operand_ty.resolveLayout(pt); |
| 21402 | const enum_ty = switch (operand_ty.zigTypeTag(zcu)) { | 21466 | const enum_ty = switch (operand_ty.zigTypeTag(zcu)) { |
| 21403 | .enum_literal => { | 21467 | .enum_literal => { |
| 21404 | const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, operand, undefined); | 21468 | const val = (try sema.resolveDefinedValue(block, operand_src, operand)).?; |
| 21405 | const tag_name = ip.indexToKey(val.toIntern()).enum_literal; | 21469 | const tag_name = ip.indexToKey(val.toIntern()).enum_literal; |
| 21406 | return sema.addNullTerminatedStrLit(tag_name); | 21470 | return sema.addNullTerminatedStrLit(tag_name); |
| 21407 | }, | 21471 | }, |
| ... | @@ -22171,7 +22235,7 @@ fn reifyUnion( | ... | @@ -22171,7 +22235,7 @@ fn reifyUnion( |
| 22171 | .tagged | 22235 | .tagged |
| 22172 | else if (layout != .auto) | 22236 | else if (layout != .auto) |
| 22173 | .none | 22237 | .none |
| 22174 | else switch (block.wantSafety()) { | 22238 | else switch (block.wantSafeTypes()) { |
| 22175 | true => .safety, | 22239 | true => .safety, |
| 22176 | false => .none, | 22240 | false => .none, |
| 22177 | }, | 22241 | }, |
| ... | @@ -23117,11 +23181,12 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -23117,11 +23181,12 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 23117 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 23181 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 23118 | const src = block.nodeOffset(extra.node); | 23182 | const src = block.nodeOffset(extra.node); |
| 23119 | const operand_src = block.builtinCallArgSrc(extra.node, 0); | 23183 | const operand_src = block.builtinCallArgSrc(extra.node, 0); |
| 23120 | const base_dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast"); | 23184 | const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast"); |
| 23121 | const operand = try sema.resolveInst(extra.rhs); | 23185 | const operand = try sema.resolveInst(extra.rhs); |
| 23122 | const base_operand_ty = sema.typeOf(operand); | 23186 | const operand_ty = sema.typeOf(operand); |
| 23123 | const dest_tag = base_dest_ty.zigTypeTag(zcu); | 23187 | |
| 23124 | const operand_tag = base_operand_ty.zigTypeTag(zcu); | 23188 | const dest_tag = dest_ty.zigTypeTag(zcu); |
| | 23189 | const operand_tag = operand_ty.zigTypeTag(zcu); |
| 23125 | | 23190 | |
| 23126 | if (dest_tag != .error_set and dest_tag != .error_union) { | 23191 | if (dest_tag != .error_set and dest_tag != .error_union) { |
| 23127 | return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)}); | 23192 | return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)}); |
| ... | @@ -23133,107 +23198,133 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -23133,107 +23198,133 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 23133 | return sema.fail(block, src, "cannot cast an error union type to error set", .{}); | 23198 | return sema.fail(block, src, "cannot cast an error union type to error set", .{}); |
| 23134 | } | 23199 | } |
| 23135 | if (dest_tag == .error_union and operand_tag == .error_union and | 23200 | if (dest_tag == .error_union and operand_tag == .error_union and |
| 23136 | base_dest_ty.errorUnionPayload(zcu).toIntern() != base_operand_ty.errorUnionPayload(zcu).toIntern()) | 23201 | dest_ty.errorUnionPayload(zcu).toIntern() != operand_ty.errorUnionPayload(zcu).toIntern()) |
| 23137 | { | 23202 | { |
| 23138 | return sema.failWithOwnedErrorMsg(block, msg: { | 23203 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 23139 | const msg = try sema.errMsg(src, "payload types of error unions must match", .{}); | 23204 | const msg = try sema.errMsg(src, "payload types of error unions must match", .{}); |
| 23140 | errdefer msg.destroy(sema.gpa); | 23205 | errdefer msg.destroy(sema.gpa); |
| 23141 | const dest_ty = base_dest_ty.errorUnionPayload(zcu); | 23206 | const dest_payload_ty = dest_ty.errorUnionPayload(zcu); |
| 23142 | const operand_ty = base_operand_ty.errorUnionPayload(zcu); | 23207 | const operand_payload_ty = operand_ty.errorUnionPayload(zcu); |
| 23143 | try sema.errNote(src, msg, "destination payload is '{}'", .{dest_ty.fmt(pt)}); | 23208 | try sema.errNote(src, msg, "destination payload is '{}'", .{dest_payload_ty.fmt(pt)}); |
| 23144 | try sema.errNote(src, msg, "operand payload is '{}'", .{operand_ty.fmt(pt)}); | 23209 | try sema.errNote(src, msg, "operand payload is '{}'", .{operand_payload_ty.fmt(pt)}); |
| 23145 | try addDeclaredHereNote(sema, msg, dest_ty); | 23210 | try addDeclaredHereNote(sema, msg, dest_ty); |
| 23146 | try addDeclaredHereNote(sema, msg, operand_ty); | 23211 | try addDeclaredHereNote(sema, msg, operand_ty); |
| 23147 | break :msg msg; | 23212 | break :msg msg; |
| 23148 | }); | 23213 | }); |
| 23149 | } | 23214 | } |
| 23150 | const dest_ty = if (dest_tag == .error_union) base_dest_ty.errorUnionSet(zcu) else base_dest_ty; | 23215 | const dest_err_ty = switch (dest_tag) { |
| 23151 | const operand_ty = if (operand_tag == .error_union) base_operand_ty.errorUnionSet(zcu) else base_operand_ty; | 23216 | .error_union => dest_ty.errorUnionSet(zcu), |
| 23152 | | 23217 | .error_set => dest_ty, |
| 23153 | // operand must be defined since it can be an invalid error value | 23218 | else => unreachable, |
| 23154 | const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand); | 23219 | }; |
| | 23220 | const operand_err_ty = switch (operand_tag) { |
| | 23221 | .error_union => operand_ty.errorUnionSet(zcu), |
| | 23222 | .error_set => operand_ty, |
| | 23223 | else => unreachable, |
| | 23224 | }; |
| 23155 | | 23225 | |
| 23156 | const disjoint = disjoint: { | 23226 | const disjoint = disjoint: { |
| 23157 | // Try avoiding resolving inferred error sets if we can | 23227 | // Try avoiding resolving inferred error sets if we can |
| 23158 | if (!dest_ty.isAnyError(zcu) and dest_ty.errorSetIsEmpty(zcu)) break :disjoint true; | 23228 | if (!dest_err_ty.isAnyError(zcu) and dest_err_ty.errorSetIsEmpty(zcu)) break :disjoint true; |
| 23159 | if (!operand_ty.isAnyError(zcu) and operand_ty.errorSetIsEmpty(zcu)) break :disjoint true; | 23229 | if (!operand_err_ty.isAnyError(zcu) and operand_err_ty.errorSetIsEmpty(zcu)) break :disjoint true; |
| 23160 | if (dest_ty.isAnyError(zcu)) break :disjoint false; | 23230 | if (dest_err_ty.isAnyError(zcu)) break :disjoint false; |
| 23161 | if (operand_ty.isAnyError(zcu)) break :disjoint false; | 23231 | if (operand_err_ty.isAnyError(zcu)) break :disjoint false; |
| 23162 | const dest_err_names = dest_ty.errorSetNames(zcu); | 23232 | const dest_err_names = dest_err_ty.errorSetNames(zcu); |
| 23163 | for (0..dest_err_names.len) |dest_err_index| { | 23233 | for (0..dest_err_names.len) |dest_err_index| { |
| 23164 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) | 23234 | if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) |
| 23165 | break :disjoint false; | 23235 | break :disjoint false; |
| 23166 | } | 23236 | } |
| 23167 | | 23237 | |
| 23168 | if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and | 23238 | if (!ip.isInferredErrorSetType(dest_err_ty.toIntern()) and |
| 23169 | !ip.isInferredErrorSetType(operand_ty.toIntern())) | 23239 | !ip.isInferredErrorSetType(operand_err_ty.toIntern())) |
| 23170 | { | 23240 | { |
| 23171 | break :disjoint true; | 23241 | break :disjoint true; |
| 23172 | } | 23242 | } |
| 23173 | | 23243 | |
| 23174 | _ = try sema.resolveInferredErrorSetTy(block, src, dest_ty.toIntern()); | 23244 | _ = try sema.resolveInferredErrorSetTy(block, src, dest_err_ty.toIntern()); |
| 23175 | _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty.toIntern()); | 23245 | _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_err_ty.toIntern()); |
| 23176 | for (0..dest_err_names.len) |dest_err_index| { | 23246 | for (0..dest_err_names.len) |dest_err_index| { |
| 23177 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) | 23247 | if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) |
| 23178 | break :disjoint false; | 23248 | break :disjoint false; |
| 23179 | } | 23249 | } |
| 23180 | | 23250 | |
| 23181 | break :disjoint true; | 23251 | break :disjoint true; |
| 23182 | }; | 23252 | }; |
| 23183 | if (disjoint and dest_tag != .error_union) { | 23253 | if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) { |
| 23184 | return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{ | 23254 | return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{ |
| 23185 | operand_ty.fmt(pt), dest_ty.fmt(pt), | 23255 | operand_err_ty.fmt(pt), dest_err_ty.fmt(pt), |
| 23186 | }); | 23256 | }); |
| 23187 | } | 23257 | } |
| 23188 | | 23258 | |
| 23189 | if (maybe_operand_val) |val| { | 23259 | // operand must be defined since it can be an invalid error value |
| 23190 | if (!dest_ty.isAnyError(zcu)) check: { | 23260 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { |
| 23191 | const operand_val = zcu.intern_pool.indexToKey(val.toIntern()); | 23261 | const err_name: InternPool.NullTerminatedString = switch (operand_tag) { |
| 23192 | var error_name: InternPool.NullTerminatedString = undefined; | 23262 | .error_set => ip.indexToKey(operand_val.toIntern()).err.name, |
| 23193 | if (operand_tag == .error_union) { | 23263 | .error_union => switch (ip.indexToKey(operand_val.toIntern()).error_union.val) { |
| 23194 | if (operand_val.error_union.val != .err_name) break :check; | 23264 | .err_name => |name| name, |
| 23195 | error_name = operand_val.error_union.val.err_name; | 23265 | .payload => |payload_val| { |
| 23196 | } else { | 23266 | assert(dest_tag == .error_union); // should be guaranteed from the type checks above |
| 23197 | error_name = operand_val.err.name; | 23267 | return sema.coerce(block, dest_ty, Air.internedToRef(payload_val), operand_src); |
| 23198 | } | 23268 | }, |
| 23199 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), error_name)) { | 23269 | }, |
| 23200 | return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{ | 23270 | else => unreachable, |
| 23201 | error_name.fmt(ip), dest_ty.fmt(pt), | 23271 | }; |
| 23202 | }); | 23272 | |
| 23203 | } | 23273 | if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) { |
| | 23274 | return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{ |
| | 23275 | err_name.fmt(ip), dest_err_ty.fmt(pt), |
| | 23276 | }); |
| 23204 | } | 23277 | } |
| 23205 | | 23278 | |
| 23206 | return Air.internedToRef((try pt.getCoerced(val, base_dest_ty)).toIntern()); | 23279 | return Air.internedToRef(try pt.intern(switch (dest_tag) { |
| | 23280 | .error_set => .{ .err = .{ |
| | 23281 | .ty = dest_ty.toIntern(), |
| | 23282 | .name = err_name, |
| | 23283 | } }, |
| | 23284 | .error_union => .{ .error_union = .{ |
| | 23285 | .ty = dest_ty.toIntern(), |
| | 23286 | .val = .{ .err_name = err_name }, |
| | 23287 | } }, |
| | 23288 | else => unreachable, |
| | 23289 | })); |
| 23207 | } | 23290 | } |
| 23208 | | 23291 | |
| 23209 | try sema.requireRuntimeBlock(block, src, operand_src); | | |
| 23210 | const err_int_ty = try pt.errorIntType(); | 23292 | const err_int_ty = try pt.errorIntType(); |
| 23211 | if (block.wantSafety() and !dest_ty.isAnyError(zcu) and | 23293 | if (block.wantSafety() and !dest_err_ty.isAnyError(zcu) and |
| 23212 | dest_ty.toIntern() != .adhoc_inferred_error_set_type and | 23294 | dest_err_ty.toIntern() != .adhoc_inferred_error_set_type and |
| 23213 | zcu.backendSupportsFeature(.error_set_has_value)) | 23295 | zcu.backendSupportsFeature(.error_set_has_value)) |
| 23214 | { | 23296 | { |
| 23215 | if (dest_tag == .error_union) { | 23297 | const err_code_inst = switch (operand_tag) { |
| 23216 | const err_code = try sema.analyzeErrUnionCode(block, operand_src, operand); | 23298 | .error_set => operand, |
| 23217 | const err_int = try block.addBitCast(err_int_ty, err_code); | 23299 | .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand), |
| 23218 | const zero_err = try pt.intRef(try pt.errorIntType(), 0); | 23300 | else => unreachable, |
| | 23301 | }; |
| | 23302 | const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst); |
| 23219 | | 23303 | |
| 23220 | const is_zero = try block.addBinOp(.cmp_eq, err_int, zero_err); | 23304 | if (dest_tag == .error_union) { |
| | 23305 | const zero_err = try pt.intRef(err_int_ty, 0); |
| | 23306 | const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err); |
| 23221 | if (disjoint) { | 23307 | if (disjoint) { |
| 23222 | // Error must be zero. | 23308 | // Error must be zero. |
| 23223 | try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code); | 23309 | try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code); |
| 23224 | } else { | 23310 | } else { |
| 23225 | // Error must be in destination set or zero. | 23311 | // Error must be in destination set or zero. |
| 23226 | const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code); | 23312 | const has_value = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst); |
| 23227 | const ok = try block.addBinOp(.bool_or, has_value, is_zero); | 23313 | const ok = try block.addBinOp(.bool_or, has_value, is_zero); |
| 23228 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); | 23314 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); |
| 23229 | } | 23315 | } |
| 23230 | } else { | 23316 | } else { |
| 23231 | const err_int_inst = try block.addBitCast(err_int_ty, operand); | 23317 | const ok = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst); |
| 23232 | const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); | | |
| 23233 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); | 23318 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); |
| 23234 | } | 23319 | } |
| 23235 | } | 23320 | } |
| 23236 | return block.addBitCast(base_dest_ty, operand); | 23321 | |
| | 23322 | if (operand_tag == .error_set and dest_tag == .error_union) { |
| | 23323 | const err_val = try block.addBitCast(dest_err_ty, operand); |
| | 23324 | return block.addTyOp(.wrap_errunion_err, dest_ty, err_val); |
| | 23325 | } else { |
| | 23326 | return block.addBitCast(dest_ty, operand); |
| | 23327 | } |
| 23237 | } | 23328 | } |
| 23238 | | 23329 | |
| 23239 | fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 23330 | fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | @@ -28952,6 +29043,7 @@ fn elemValArray( | ... | @@ -28952,6 +29043,7 @@ fn elemValArray( |
| 28952 | } | 29043 | } |
| 28953 | | 29044 | |
| 28954 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); | 29045 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); |
| | 29046 | try sema.validateRuntimeValue(block, array_src, array); |
| 28955 | | 29047 | |
| 28956 | if (oob_safety and block.wantSafety()) { | 29048 | if (oob_safety and block.wantSafety()) { |
| 28957 | // Runtime check is only needed if unable to comptime check. | 29049 | // Runtime check is only needed if unable to comptime check. |
| ... | @@ -29016,6 +29108,7 @@ fn elemPtrArray( | ... | @@ -29016,6 +29108,7 @@ fn elemPtrArray( |
| 29016 | | 29108 | |
| 29017 | if (!init) { | 29109 | if (!init) { |
| 29018 | try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src); | 29110 | try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src); |
| | 29111 | try sema.validateRuntimeValue(block, array_ptr_src, array_ptr); |
| 29019 | } | 29112 | } |
| 29020 | | 29113 | |
| 29021 | // Runtime check is only needed if unable to comptime check. | 29114 | // Runtime check is only needed if unable to comptime check. |
| ... | @@ -29073,6 +29166,7 @@ fn elemValSlice( | ... | @@ -29073,6 +29166,7 @@ fn elemValSlice( |
| 29073 | } | 29166 | } |
| 29074 | | 29167 | |
| 29075 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); | 29168 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); |
| | 29169 | try sema.validateRuntimeValue(block, slice_src, slice); |
| 29076 | | 29170 | |
| 29077 | if (oob_safety and block.wantSafety()) { | 29171 | if (oob_safety and block.wantSafety()) { |
| 29078 | const len_inst = if (maybe_slice_val) |slice_val| | 29172 | const len_inst = if (maybe_slice_val) |slice_val| |
| ... | @@ -29129,6 +29223,7 @@ fn elemPtrSlice( | ... | @@ -29129,6 +29223,7 @@ fn elemPtrSlice( |
| 29129 | } | 29223 | } |
| 29130 | | 29224 | |
| 29131 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); | 29225 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); |
| | 29226 | try sema.validateRuntimeValue(block, slice_src, slice); |
| 29132 | | 29227 | |
| 29133 | if (oob_safety and block.wantSafety()) { | 29228 | if (oob_safety and block.wantSafety()) { |
| 29134 | const len_inst = len: { | 29229 | const len_inst = len: { |
| ... | @@ -33889,6 +33984,17 @@ fn resolvePeerTypes( | ... | @@ -33889,6 +33984,17 @@ fn resolvePeerTypes( |
| 33889 | else => {}, | 33984 | else => {}, |
| 33890 | } | 33985 | } |
| 33891 | | 33986 | |
| | 33987 | // Fast path: check if everything has the same type to bypass the main PTR logic. |
| | 33988 | same_type: { |
| | 33989 | const ty = sema.typeOf(instructions[0]); |
| | 33990 | for (instructions[1..]) |inst| { |
| | 33991 | if (sema.typeOf(inst).toIntern() != ty.toIntern()) { |
| | 33992 | break :same_type; |
| | 33993 | } |
| | 33994 | } |
| | 33995 | return ty; |
| | 33996 | } |
| | 33997 | |
| 33892 | const peer_tys = try sema.arena.alloc(?Type, instructions.len); | 33998 | const peer_tys = try sema.arena.alloc(?Type, instructions.len); |
| 33893 | const peer_vals = try sema.arena.alloc(?Value, instructions.len); | 33999 | const peer_vals = try sema.arena.alloc(?Value, instructions.len); |
| 33894 | | 34000 | |
| ... | @@ -34562,14 +34668,14 @@ fn resolvePeerTypesInner( | ... | @@ -34562,14 +34668,14 @@ fn resolvePeerTypesInner( |
| 34562 | } | 34668 | } |
| 34563 | // Clear existing sentinel | 34669 | // Clear existing sentinel |
| 34564 | ptr_info.sentinel = .none; | 34670 | ptr_info.sentinel = .none; |
| 34565 | switch (ip.indexToKey(ptr_info.child)) { | 34671 | if (ptr_info.flags.size == .one) switch (ip.indexToKey(ptr_info.child)) { |
| 34566 | .array_type => |array_type| ptr_info.child = (try pt.arrayType(.{ | 34672 | .array_type => |array_type| ptr_info.child = (try pt.arrayType(.{ |
| 34567 | .len = array_type.len, | 34673 | .len = array_type.len, |
| 34568 | .child = array_type.child, | 34674 | .child = array_type.child, |
| 34569 | .sentinel = .none, | 34675 | .sentinel = .none, |
| 34570 | })).toIntern(), | 34676 | })).toIntern(), |
| 34571 | else => {}, | 34677 | else => {}, |
| 34572 | } | 34678 | }; |
| 34573 | } | 34679 | } |
| 34574 | | 34680 | |
| 34575 | opt_ptr_info = ptr_info; | 34681 | opt_ptr_info = ptr_info; |