| ... | @@ -23175,11 +23175,12 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -23175,11 +23175,12 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 23175 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 23175 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 23176 | const src = block.nodeOffset(extra.node); | 23176 | const src = block.nodeOffset(extra.node); |
| 23177 | const operand_src = block.builtinCallArgSrc(extra.node, 0); | 23177 | const operand_src = block.builtinCallArgSrc(extra.node, 0); |
| 23178 | const base_dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast"); | 23178 | const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast"); |
| 23179 | const operand = try sema.resolveInst(extra.rhs); | 23179 | const operand = try sema.resolveInst(extra.rhs); |
| 23180 | const base_operand_ty = sema.typeOf(operand); | 23180 | const operand_ty = sema.typeOf(operand); |
| 23181 | const dest_tag = base_dest_ty.zigTypeTag(zcu); | 23181 | |
| 23182 | const operand_tag = base_operand_ty.zigTypeTag(zcu); | 23182 | const dest_tag = dest_ty.zigTypeTag(zcu); |
| | 23183 | const operand_tag = operand_ty.zigTypeTag(zcu); |
| 23183 | | 23184 | |
| 23184 | if (dest_tag != .error_set and dest_tag != .error_union) { | 23185 | if (dest_tag != .error_set and dest_tag != .error_union) { |
| 23185 | return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)}); | 23186 | return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)}); |
| ... | @@ -23191,107 +23192,133 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -23191,107 +23192,133 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 23191 | return sema.fail(block, src, "cannot cast an error union type to error set", .{}); | 23192 | return sema.fail(block, src, "cannot cast an error union type to error set", .{}); |
| 23192 | } | 23193 | } |
| 23193 | if (dest_tag == .error_union and operand_tag == .error_union and | 23194 | if (dest_tag == .error_union and operand_tag == .error_union and |
| 23194 | base_dest_ty.errorUnionPayload(zcu).toIntern() != base_operand_ty.errorUnionPayload(zcu).toIntern()) | 23195 | dest_ty.errorUnionPayload(zcu).toIntern() != operand_ty.errorUnionPayload(zcu).toIntern()) |
| 23195 | { | 23196 | { |
| 23196 | return sema.failWithOwnedErrorMsg(block, msg: { | 23197 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 23197 | const msg = try sema.errMsg(src, "payload types of error unions must match", .{}); | 23198 | const msg = try sema.errMsg(src, "payload types of error unions must match", .{}); |
| 23198 | errdefer msg.destroy(sema.gpa); | 23199 | errdefer msg.destroy(sema.gpa); |
| 23199 | const dest_ty = base_dest_ty.errorUnionPayload(zcu); | 23200 | const dest_payload_ty = dest_ty.errorUnionPayload(zcu); |
| 23200 | const operand_ty = base_operand_ty.errorUnionPayload(zcu); | 23201 | const operand_payload_ty = operand_ty.errorUnionPayload(zcu); |
| 23201 | try sema.errNote(src, msg, "destination payload is '{}'", .{dest_ty.fmt(pt)}); | 23202 | try sema.errNote(src, msg, "destination payload is '{}'", .{dest_payload_ty.fmt(pt)}); |
| 23202 | try sema.errNote(src, msg, "operand payload is '{}'", .{operand_ty.fmt(pt)}); | 23203 | try sema.errNote(src, msg, "operand payload is '{}'", .{operand_payload_ty.fmt(pt)}); |
| 23203 | try addDeclaredHereNote(sema, msg, dest_ty); | 23204 | try addDeclaredHereNote(sema, msg, dest_ty); |
| 23204 | try addDeclaredHereNote(sema, msg, operand_ty); | 23205 | try addDeclaredHereNote(sema, msg, operand_ty); |
| 23205 | break :msg msg; | 23206 | break :msg msg; |
| 23206 | }); | 23207 | }); |
| 23207 | } | 23208 | } |
| 23208 | const dest_ty = if (dest_tag == .error_union) base_dest_ty.errorUnionSet(zcu) else base_dest_ty; | 23209 | const dest_err_ty = switch (dest_tag) { |
| 23209 | const operand_ty = if (operand_tag == .error_union) base_operand_ty.errorUnionSet(zcu) else base_operand_ty; | 23210 | .error_union => dest_ty.errorUnionSet(zcu), |
| 23210 | | 23211 | .error_set => dest_ty, |
| 23211 | // operand must be defined since it can be an invalid error value | 23212 | else => unreachable, |
| 23212 | const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand); | 23213 | }; |
| | 23214 | const operand_err_ty = switch (operand_tag) { |
| | 23215 | .error_union => operand_ty.errorUnionSet(zcu), |
| | 23216 | .error_set => operand_ty, |
| | 23217 | else => unreachable, |
| | 23218 | }; |
| 23213 | | 23219 | |
| 23214 | const disjoint = disjoint: { | 23220 | const disjoint = disjoint: { |
| 23215 | // Try avoiding resolving inferred error sets if we can | 23221 | // Try avoiding resolving inferred error sets if we can |
| 23216 | if (!dest_ty.isAnyError(zcu) and dest_ty.errorSetIsEmpty(zcu)) break :disjoint true; | 23222 | if (!dest_err_ty.isAnyError(zcu) and dest_err_ty.errorSetIsEmpty(zcu)) break :disjoint true; |
| 23217 | if (!operand_ty.isAnyError(zcu) and operand_ty.errorSetIsEmpty(zcu)) break :disjoint true; | 23223 | if (!operand_err_ty.isAnyError(zcu) and operand_err_ty.errorSetIsEmpty(zcu)) break :disjoint true; |
| 23218 | if (dest_ty.isAnyError(zcu)) break :disjoint false; | 23224 | if (dest_err_ty.isAnyError(zcu)) break :disjoint false; |
| 23219 | if (operand_ty.isAnyError(zcu)) break :disjoint false; | 23225 | if (operand_err_ty.isAnyError(zcu)) break :disjoint false; |
| 23220 | const dest_err_names = dest_ty.errorSetNames(zcu); | 23226 | const dest_err_names = dest_err_ty.errorSetNames(zcu); |
| 23221 | for (0..dest_err_names.len) |dest_err_index| { | 23227 | for (0..dest_err_names.len) |dest_err_index| { |
| 23222 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) | 23228 | if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) |
| 23223 | break :disjoint false; | 23229 | break :disjoint false; |
| 23224 | } | 23230 | } |
| 23225 | | 23231 | |
| 23226 | if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and | 23232 | if (!ip.isInferredErrorSetType(dest_err_ty.toIntern()) and |
| 23227 | !ip.isInferredErrorSetType(operand_ty.toIntern())) | 23233 | !ip.isInferredErrorSetType(operand_err_ty.toIntern())) |
| 23228 | { | 23234 | { |
| 23229 | break :disjoint true; | 23235 | break :disjoint true; |
| 23230 | } | 23236 | } |
| 23231 | | 23237 | |
| 23232 | _ = try sema.resolveInferredErrorSetTy(block, src, dest_ty.toIntern()); | 23238 | _ = try sema.resolveInferredErrorSetTy(block, src, dest_err_ty.toIntern()); |
| 23233 | _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty.toIntern()); | 23239 | _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_err_ty.toIntern()); |
| 23234 | for (0..dest_err_names.len) |dest_err_index| { | 23240 | for (0..dest_err_names.len) |dest_err_index| { |
| 23235 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) | 23241 | if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index])) |
| 23236 | break :disjoint false; | 23242 | break :disjoint false; |
| 23237 | } | 23243 | } |
| 23238 | | 23244 | |
| 23239 | break :disjoint true; | 23245 | break :disjoint true; |
| 23240 | }; | 23246 | }; |
| 23241 | if (disjoint and dest_tag != .error_union) { | 23247 | if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) { |
| 23242 | return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{ | 23248 | return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{ |
| 23243 | operand_ty.fmt(pt), dest_ty.fmt(pt), | 23249 | operand_err_ty.fmt(pt), dest_err_ty.fmt(pt), |
| 23244 | }); | 23250 | }); |
| 23245 | } | 23251 | } |
| 23246 | | 23252 | |
| 23247 | if (maybe_operand_val) |val| { | 23253 | // operand must be defined since it can be an invalid error value |
| 23248 | if (!dest_ty.isAnyError(zcu)) check: { | 23254 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { |
| 23249 | const operand_val = zcu.intern_pool.indexToKey(val.toIntern()); | 23255 | const err_name: InternPool.NullTerminatedString = switch (operand_tag) { |
| 23250 | var error_name: InternPool.NullTerminatedString = undefined; | 23256 | .error_set => ip.indexToKey(operand_val.toIntern()).err.name, |
| 23251 | if (operand_tag == .error_union) { | 23257 | .error_union => switch (ip.indexToKey(operand_val.toIntern()).error_union.val) { |
| 23252 | if (operand_val.error_union.val != .err_name) break :check; | 23258 | .err_name => |name| name, |
| 23253 | error_name = operand_val.error_union.val.err_name; | 23259 | .payload => |payload_val| { |
| 23254 | } else { | 23260 | assert(dest_tag == .error_union); // should be guaranteed from the type checks above |
| 23255 | error_name = operand_val.err.name; | 23261 | return sema.coerce(block, dest_ty, Air.internedToRef(payload_val), operand_src); |
| 23256 | } | 23262 | }, |
| 23257 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), error_name)) { | 23263 | }, |
| 23258 | return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{ | 23264 | else => unreachable, |
| 23259 | error_name.fmt(ip), dest_ty.fmt(pt), | 23265 | }; |
| 23260 | }); | 23266 | |
| 23261 | } | 23267 | if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) { |
| | 23268 | return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{ |
| | 23269 | err_name.fmt(ip), dest_err_ty.fmt(pt), |
| | 23270 | }); |
| 23262 | } | 23271 | } |
| 23263 | | 23272 | |
| 23264 | return Air.internedToRef((try pt.getCoerced(val, base_dest_ty)).toIntern()); | 23273 | return Air.internedToRef(try pt.intern(switch (dest_tag) { |
| | 23274 | .error_set => .{ .err = .{ |
| | 23275 | .ty = dest_ty.toIntern(), |
| | 23276 | .name = err_name, |
| | 23277 | } }, |
| | 23278 | .error_union => .{ .error_union = .{ |
| | 23279 | .ty = dest_ty.toIntern(), |
| | 23280 | .val = .{ .err_name = err_name }, |
| | 23281 | } }, |
| | 23282 | else => unreachable, |
| | 23283 | })); |
| 23265 | } | 23284 | } |
| 23266 | | 23285 | |
| 23267 | try sema.requireRuntimeBlock(block, src, operand_src); | | |
| 23268 | const err_int_ty = try pt.errorIntType(); | 23286 | const err_int_ty = try pt.errorIntType(); |
| 23269 | if (block.wantSafety() and !dest_ty.isAnyError(zcu) and | 23287 | if (block.wantSafety() and !dest_err_ty.isAnyError(zcu) and |
| 23270 | dest_ty.toIntern() != .adhoc_inferred_error_set_type and | 23288 | dest_err_ty.toIntern() != .adhoc_inferred_error_set_type and |
| 23271 | zcu.backendSupportsFeature(.error_set_has_value)) | 23289 | zcu.backendSupportsFeature(.error_set_has_value)) |
| 23272 | { | 23290 | { |
| 23273 | if (dest_tag == .error_union) { | 23291 | const err_code_inst = switch (operand_tag) { |
| 23274 | const err_code = try block.addTyOp(.unwrap_errunion_err, operand_ty, operand); | 23292 | .error_set => operand, |
| 23275 | const err_int = try block.addBitCast(err_int_ty, err_code); | 23293 | .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand), |
| 23276 | const zero_err = try pt.intRef(try pt.errorIntType(), 0); | 23294 | else => unreachable, |
| | 23295 | }; |
| | 23296 | const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst); |
| 23277 | | 23297 | |
| 23278 | const is_zero = try block.addBinOp(.cmp_eq, err_int, zero_err); | 23298 | if (dest_tag == .error_union) { |
| | 23299 | const zero_err = try pt.intRef(err_int_ty, 0); |
| | 23300 | const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err); |
| 23279 | if (disjoint) { | 23301 | if (disjoint) { |
| 23280 | // Error must be zero. | 23302 | // Error must be zero. |
| 23281 | try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code); | 23303 | try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code); |
| 23282 | } else { | 23304 | } else { |
| 23283 | // Error must be in destination set or zero. | 23305 | // Error must be in destination set or zero. |
| 23284 | const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code); | 23306 | const has_value = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst); |
| 23285 | const ok = try block.addBinOp(.bool_or, has_value, is_zero); | 23307 | const ok = try block.addBinOp(.bool_or, has_value, is_zero); |
| 23286 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); | 23308 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); |
| 23287 | } | 23309 | } |
| 23288 | } else { | 23310 | } else { |
| 23289 | const err_int_inst = try block.addBitCast(err_int_ty, operand); | 23311 | const ok = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst); |
| 23290 | const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); | | |
| 23291 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); | 23312 | try sema.addSafetyCheck(block, src, ok, .invalid_error_code); |
| 23292 | } | 23313 | } |
| 23293 | } | 23314 | } |
| 23294 | return block.addBitCast(base_dest_ty, operand); | 23315 | |
| | 23316 | if (operand_tag == .error_set and dest_tag == .error_union) { |
| | 23317 | const err_val = try block.addBitCast(dest_err_ty, operand); |
| | 23318 | return block.addTyOp(.wrap_errunion_err, dest_ty, err_val); |
| | 23319 | } else { |
| | 23320 | return block.addBitCast(dest_ty, operand); |
| | 23321 | } |
| 23295 | } | 23322 | } |
| 23296 | | 23323 | |
| 23297 | fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 23324 | fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |