| author | |
| committer | |
| log | 153c97ac9ec8deafb0777ae424f00695c18e3bd9 |
| tree | 4bc0b2c23e2d4844252efd98f453a2100043b14f |
| parent | 7edb204edfa41e11776ac009da5a20fb1c907f5f |
* add error_union value tag.
* add analyzeIsErr
* add Value.isError
* add TZIR wrap_errunion_payload and wrap_errunion_err for
wrapping from T -> E!T and E -> E!T
* add anlyzeInstUnwrapErrCode and analyzeInstUnwrapErr
* add analyzeInstEnsureErrPayloadVoid:
* add wrapErrorUnion
* add comptime error comparison for tests
* tests!7 files changed, 479 insertions(+), 12 deletions(-)
src/Module.zig+63-3| ... | @@ -2871,7 +2871,15 @@ pub fn analyzeIsNull( | ... | @@ -2871,7 +2871,15 @@ pub fn analyzeIsNull( |
| 2871 | } | 2871 | } |
| 2872 | 2872 | ||
| 2873 | pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst { | 2873 | pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst { |
| 2874 | return self.fail(scope, src, "TODO implement analysis of iserr", .{}); | 2874 | const ot = operand.ty.zigTypeTag(); |
| 2875 | if (ot != .ErrorSet and ot != .ErrorUnion) return self.constBool(scope, src, false); | ||
| 2876 | if (ot == .ErrorSet) return self.constBool(scope, src, true); | ||
| 2877 | assert(ot == .ErrorUnion); | ||
| 2878 | if (operand.value()) |err_union| { | ||
| 2879 | return self.constBool(scope, src, err_union.getError() != null); | ||
| 2880 | } | ||
| 2881 | const b = try self.requireRuntimeBlock(scope, src); | ||
| 2882 | return self.addUnOp(b, src, Type.initTag(.bool), .is_err, operand); | ||
| 2875 | } | 2883 | } |
| 2876 | 2884 | ||
| 2877 | pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst { | 2885 | pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst { |
| ... | @@ -3174,6 +3182,52 @@ fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*In | ... | @@ -3174,6 +3182,52 @@ fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*In |
| 3174 | return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst); | 3182 | return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst); |
| 3175 | } | 3183 | } |
| 3176 | 3184 | ||
| 3185 | fn wrapErrorUnion(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { | ||
| 3186 | // TODO deal with inferred error sets | ||
| 3187 | const err_union = dest_type.castTag(.error_union).?; | ||
| 3188 | if (inst.value()) |val| { | ||
| 3189 | const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: { | ||
| 3190 | _ = try self.coerce(scope, err_union.data.payload, inst); | ||
| 3191 | break :blk val; | ||
| 3192 | } else switch (err_union.data.error_set.tag()) { | ||
| 3193 | .anyerror => val, | ||
| 3194 | .error_set_single => blk: { | ||
| 3195 | const n = err_union.data.error_set.castTag(.error_set_single).?.data; | ||
| 3196 | if (!mem.eql(u8, val.castTag(.@"error").?.data.name, n)) | ||
| 3197 | return self.fail(scope, inst.src, "expected type '{}', found type '{}'", .{ err_union.data.error_set, inst.ty }); | ||
| 3198 | break :blk val; | ||
| 3199 | }, | ||
| 3200 | .error_set => blk: { | ||
| 3201 | const f = err_union.data.error_set.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields; | ||
| 3202 | if (f.get(val.castTag(.@"error").?.data.name) == null) | ||
| 3203 | return self.fail(scope, inst.src, "expected type '{}', found type '{}'", .{ err_union.data.error_set, inst.ty }); | ||
| 3204 | break :blk val; | ||
| 3205 | }, | ||
| 3206 | else => unreachable, | ||
| 3207 | }; | ||
| 3208 | |||
| 3209 | return self.constInst(scope, inst.src, .{ | ||
| 3210 | .ty = dest_type, | ||
| 3211 | // creating a SubValue for the error_union payload | ||
| 3212 | .val = try Value.Tag.error_union.create( | ||
| 3213 | scope.arena(), | ||
| 3214 | to_wrap, | ||
| 3215 | ), | ||
| 3216 | }); | ||
| 3217 | } | ||
| 3218 | |||
| 3219 | const b = try self.requireRuntimeBlock(scope, inst.src); | ||
| 3220 | |||
| 3221 | // we are coercing from E to E!T | ||
| 3222 | if (inst.ty.zigTypeTag() == .ErrorSet) { | ||
| 3223 | var coerced = try self.coerce(scope, err_union.data.error_set, inst); | ||
| 3224 | return self.addUnOp(b, inst.src, dest_type, .wrap_errunion_err, coerced); | ||
| 3225 | } else { | ||
| 3226 | var coerced = try self.coerce(scope, err_union.data.payload, inst); | ||
| 3227 | return self.addUnOp(b, inst.src, dest_type, .wrap_errunion_payload, coerced); | ||
| 3228 | } | ||
| 3229 | } | ||
| 3230 | |||
| 3177 | fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { | 3231 | fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { |
| 3178 | const int_payload = try scope.arena().create(Type.Payload.Bits); | 3232 | const int_payload = try scope.arena().create(Type.Payload.Bits); |
| 3179 | int_payload.* = .{ | 3233 | int_payload.* = .{ |
| ... | @@ -3240,7 +3294,7 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty | ... | @@ -3240,7 +3294,7 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty |
| 3240 | return chosen.ty; | 3294 | return chosen.ty; |
| 3241 | } | 3295 | } |
| 3242 | 3296 | ||
| 3243 | pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { | 3297 | pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!*Inst { |
| 3244 | // If the types are the same, we can return the operand. | 3298 | // If the types are the same, we can return the operand. |
| 3245 | if (dest_type.eql(inst.ty)) | 3299 | if (dest_type.eql(inst.ty)) |
| 3246 | return inst; | 3300 | return inst; |
| ... | @@ -3274,6 +3328,11 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst | ... | @@ -3274,6 +3328,11 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst |
| 3274 | } | 3328 | } |
| 3275 | } | 3329 | } |
| 3276 | 3330 | ||
| 3331 | // T to E!T or E to E!T | ||
| 3332 | if (dest_type.tag() == .error_union) { | ||
| 3333 | return try self.wrapErrorUnion(scope, dest_type, inst); | ||
| 3334 | } | ||
| 3335 | |||
| 3277 | // Coercions where the source is a single pointer to an array. | 3336 | // Coercions where the source is a single pointer to an array. |
| 3278 | src_array_ptr: { | 3337 | src_array_ptr: { |
| 3279 | if (!inst.ty.isSinglePointer()) break :src_array_ptr; | 3338 | if (!inst.ty.isSinglePointer()) break :src_array_ptr; |
| ... | @@ -3352,7 +3411,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst | ... | @@ -3352,7 +3411,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst |
| 3352 | return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty }); | 3411 | return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty }); |
| 3353 | } | 3412 | } |
| 3354 | 3413 | ||
| 3355 | pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*Inst { | 3414 | pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!?*Inst { |
| 3356 | const val = inst.value() orelse return null; | 3415 | const val = inst.value() orelse return null; |
| 3357 | const src_zig_tag = inst.ty.zigTypeTag(); | 3416 | const src_zig_tag = inst.ty.zigTypeTag(); |
| 3358 | const dst_zig_tag = dest_type.zigTypeTag(); | 3417 | const dst_zig_tag = dest_type.zigTypeTag(); |
| ... | @@ -3843,6 +3902,7 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { | ... | @@ -3843,6 +3902,7 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { |
| 3843 | pub const PanicId = enum { | 3902 | pub const PanicId = enum { |
| 3844 | unreach, | 3903 | unreach, |
| 3845 | unwrap_null, | 3904 | unwrap_null, |
| 3905 | unwrap_errunion, | ||
| 3846 | }; | 3906 | }; |
| 3847 | 3907 | ||
| 3848 | pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void { | 3908 | pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void { |
src/codegen.zig+62| ... | @@ -909,7 +909,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -909,7 +909,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 909 | .unreach => return MCValue{ .unreach = {} }, | 909 | .unreach => return MCValue{ .unreach = {} }, |
| 910 | .optional_payload => return self.genOptionalPayload(inst.castTag(.optional_payload).?), | 910 | .optional_payload => return self.genOptionalPayload(inst.castTag(.optional_payload).?), |
| 911 | .optional_payload_ptr => return self.genOptionalPayloadPtr(inst.castTag(.optional_payload_ptr).?), | 911 | .optional_payload_ptr => return self.genOptionalPayloadPtr(inst.castTag(.optional_payload_ptr).?), |
| 912 | .unwrap_errunion_err => return self.genUnwrapErrErr(inst.castTag(.unwrap_errunion_err).?), | ||
| 913 | .unwrap_errunion_payload => return self.genUnwrapErrPayload(inst.castTag(.unwrap_errunion_payload).?), | ||
| 914 | .unwrap_errunion_err_ptr => return self.genUnwrapErrErrPtr(inst.castTag(.unwrap_errunion_err_ptr).?), | ||
| 915 | .unwrap_errunion_payload_ptr => return self.genUnwrapErrPayloadPtr(inst.castTag(.unwrap_errunion_payload_ptr).?), | ||
| 912 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), | 916 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 917 | .wrap_errunion_payload => return self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?), | ||
| 918 | .wrap_errunion_err => return self.genWrapErrUnionErr(inst.castTag(.wrap_errunion_err).?), | ||
| 913 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), | 919 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), |
| 914 | .xor => return self.genXor(inst.castTag(.xor).?), | 920 | .xor => return self.genXor(inst.castTag(.xor).?), |
| 915 | } | 921 | } |
| ... | @@ -1170,6 +1176,41 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1170,6 +1176,41 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1170 | } | 1176 | } |
| 1171 | } | 1177 | } |
| 1172 | 1178 | ||
| 1179 | fn genUnwrapErrErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1180 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1181 | if (inst.base.isUnused()) | ||
| 1182 | return MCValue.dead; | ||
| 1183 | switch (arch) { | ||
| 1184 | else => return self.fail(inst.base.src, "TODO implement unwrap error union error for {}", .{self.target.cpu.arch}), | ||
| 1185 | } | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | fn genUnwrapErrPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1189 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1190 | if (inst.base.isUnused()) | ||
| 1191 | return MCValue.dead; | ||
| 1192 | switch (arch) { | ||
| 1193 | else => return self.fail(inst.base.src, "TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}), | ||
| 1194 | } | ||
| 1195 | } | ||
| 1196 | // *(E!T) -> E | ||
| 1197 | fn genUnwrapErrErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1198 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1199 | if (inst.base.isUnused()) | ||
| 1200 | return MCValue.dead; | ||
| 1201 | switch (arch) { | ||
| 1202 | else => return self.fail(inst.base.src, "TODO implement unwrap error union error ptr for {}", .{self.target.cpu.arch}), | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | // *(E!T) -> *T | ||
| 1206 | fn genUnwrapErrPayloadPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1207 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1208 | if (inst.base.isUnused()) | ||
| 1209 | return MCValue.dead; | ||
| 1210 | switch (arch) { | ||
| 1211 | else => return self.fail(inst.base.src, "TODO implement unwrap error union payload ptr for {}", .{self.target.cpu.arch}), | ||
| 1212 | } | ||
| 1213 | } | ||
| 1173 | fn genWrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 1214 | fn genWrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 1174 | const optional_ty = inst.base.ty; | 1215 | const optional_ty = inst.base.ty; |
| 1175 | 1216 | ||
| ... | @@ -1186,6 +1227,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1186,6 +1227,27 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1186 | } | 1227 | } |
| 1187 | } | 1228 | } |
| 1188 | 1229 | ||
| 1230 | /// T to E!T | ||
| 1231 | fn genWrapErrUnionPayload(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1232 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1233 | if (inst.base.isUnused()) | ||
| 1234 | return MCValue.dead; | ||
| 1235 | |||
| 1236 | switch (arch) { | ||
| 1237 | else => return self.fail(inst.base.src, "TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}), | ||
| 1238 | } | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | /// E to E!T | ||
| 1242 | fn genWrapErrUnionErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | ||
| 1243 | // No side effects, so if it's unreferenced, do nothing. | ||
| 1244 | if (inst.base.isUnused()) | ||
| 1245 | return MCValue.dead; | ||
| 1246 | |||
| 1247 | switch (arch) { | ||
| 1248 | else => return self.fail(inst.base.src, "TODO implement wrap errunion error for {}", .{self.target.cpu.arch}), | ||
| 1249 | } | ||
| 1250 | } | ||
| 1189 | fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue { | 1251 | fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue { |
| 1190 | // No side effects, so if it's unreferenced, do nothing. | 1252 | // No side effects, so if it's unreferenced, do nothing. |
| 1191 | if (inst.base.isUnused()) | 1253 | if (inst.base.isUnused()) |
src/ir.zig+18| ... | @@ -114,6 +114,18 @@ pub const Inst = struct { | ... | @@ -114,6 +114,18 @@ pub const Inst = struct { |
| 114 | // *?T => *T | 114 | // *?T => *T |
| 115 | optional_payload_ptr, | 115 | optional_payload_ptr, |
| 116 | wrap_optional, | 116 | wrap_optional, |
| 117 | /// E!T -> T | ||
| 118 | unwrap_errunion_payload, | ||
| 119 | /// E!T -> E | ||
| 120 | unwrap_errunion_err, | ||
| 121 | /// *(E!T) -> *T | ||
| 122 | unwrap_errunion_payload_ptr, | ||
| 123 | /// *(E!T) -> E | ||
| 124 | unwrap_errunion_err_ptr, | ||
| 125 | /// wrap from T to E!T | ||
| 126 | wrap_errunion_payload, | ||
| 127 | /// wrap from E to E!T | ||
| 128 | wrap_errunion_err, | ||
| 117 | xor, | 129 | xor, |
| 118 | switchbr, | 130 | switchbr, |
| 119 | 131 | ||
| ... | @@ -143,6 +155,12 @@ pub const Inst = struct { | ... | @@ -143,6 +155,12 @@ pub const Inst = struct { |
| 143 | .optional_payload, | 155 | .optional_payload, |
| 144 | .optional_payload_ptr, | 156 | .optional_payload_ptr, |
| 145 | .wrap_optional, | 157 | .wrap_optional, |
| 158 | .unwrap_errunion_payload, | ||
| 159 | .unwrap_errunion_err, | ||
| 160 | .unwrap_errunion_payload_ptr, | ||
| 161 | .unwrap_errunion_err_ptr, | ||
| 162 | .wrap_errunion_payload, | ||
| 163 | .wrap_errunion_err, | ||
| 146 | => UnOp, | 164 | => UnOp, |
| 147 | 165 | ||
| 148 | .add, | 166 | .add, |
src/value.zig+116-2| ... | @@ -102,6 +102,7 @@ pub const Value = extern union { | ... | @@ -102,6 +102,7 @@ pub const Value = extern union { |
| 102 | enum_literal, | 102 | enum_literal, |
| 103 | error_set, | 103 | error_set, |
| 104 | @"error", | 104 | @"error", |
| 105 | error_union, | ||
| 105 | /// This is a special value that tracks a set of types that have been stored | 106 | /// This is a special value that tracks a set of types that have been stored |
| 106 | /// to an inferred allocation. It does not support any of the normal value queries. | 107 | /// to an inferred allocation. It does not support any of the normal value queries. |
| 107 | inferred_alloc, | 108 | inferred_alloc, |
| ... | @@ -174,6 +175,7 @@ pub const Value = extern union { | ... | @@ -174,6 +175,7 @@ pub const Value = extern union { |
| 174 | 175 | ||
| 175 | .ref_val, | 176 | .ref_val, |
| 176 | .repeated, | 177 | .repeated, |
| 178 | .error_union, | ||
| 177 | => Payload.SubValue, | 179 | => Payload.SubValue, |
| 178 | 180 | ||
| 179 | .bytes, | 181 | .bytes, |
| ... | @@ -388,9 +390,17 @@ pub const Value = extern union { | ... | @@ -388,9 +390,17 @@ pub const Value = extern union { |
| 388 | return Value{ .ptr_otherwise = &new_payload.base }; | 390 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 389 | }, | 391 | }, |
| 390 | .@"error" => return self.copyPayloadShallow(allocator, Payload.Error), | 392 | .@"error" => return self.copyPayloadShallow(allocator, Payload.Error), |
| 393 | .error_union => { | ||
| 394 | const payload = self.castTag(.error_union).?; | ||
| 395 | const new_payload = try allocator.create(Payload.SubValue); | ||
| 396 | new_payload.* = .{ | ||
| 397 | .base = payload.base, | ||
| 398 | .data = try payload.data.copy(allocator), | ||
| 399 | }; | ||
| 400 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 401 | }, | ||
| 391 | 402 | ||
| 392 | .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), | 403 | .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), |
| 393 | |||
| 394 | .inferred_alloc => unreachable, | 404 | .inferred_alloc => unreachable, |
| 395 | } | 405 | } |
| 396 | } | 406 | } |
| ... | @@ -510,6 +520,8 @@ pub const Value = extern union { | ... | @@ -510,6 +520,8 @@ pub const Value = extern union { |
| 510 | return out_stream.writeAll("}"); | 520 | return out_stream.writeAll("}"); |
| 511 | }, | 521 | }, |
| 512 | .@"error" => return out_stream.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | 522 | .@"error" => return out_stream.print("error.{s}", .{val.castTag(.@"error").?.data.name}), |
| 523 | // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that | ||
| 524 | .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}), | ||
| 513 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), | 525 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), |
| 514 | }; | 526 | }; |
| 515 | } | 527 | } |
| ... | @@ -622,6 +634,7 @@ pub const Value = extern union { | ... | @@ -622,6 +634,7 @@ pub const Value = extern union { |
| 622 | .float_128, | 634 | .float_128, |
| 623 | .enum_literal, | 635 | .enum_literal, |
| 624 | .@"error", | 636 | .@"error", |
| 637 | .error_union, | ||
| 625 | .empty_struct_value, | 638 | .empty_struct_value, |
| 626 | .inferred_alloc, | 639 | .inferred_alloc, |
| 627 | => unreachable, | 640 | => unreachable, |
| ... | @@ -692,6 +705,7 @@ pub const Value = extern union { | ... | @@ -692,6 +705,7 @@ pub const Value = extern union { |
| 692 | .empty_array, | 705 | .empty_array, |
| 693 | .enum_literal, | 706 | .enum_literal, |
| 694 | .error_set, | 707 | .error_set, |
| 708 | .error_union, | ||
| 695 | .@"error", | 709 | .@"error", |
| 696 | .empty_struct_value, | 710 | .empty_struct_value, |
| 697 | .inferred_alloc, | 711 | .inferred_alloc, |
| ... | @@ -779,6 +793,7 @@ pub const Value = extern union { | ... | @@ -779,6 +793,7 @@ pub const Value = extern union { |
| 779 | .enum_literal, | 793 | .enum_literal, |
| 780 | .error_set, | 794 | .error_set, |
| 781 | .@"error", | 795 | .@"error", |
| 796 | .error_union, | ||
| 782 | .empty_struct_value, | 797 | .empty_struct_value, |
| 783 | .inferred_alloc, | 798 | .inferred_alloc, |
| 784 | => unreachable, | 799 | => unreachable, |
| ... | @@ -865,6 +880,7 @@ pub const Value = extern union { | ... | @@ -865,6 +880,7 @@ pub const Value = extern union { |
| 865 | .enum_literal, | 880 | .enum_literal, |
| 866 | .error_set, | 881 | .error_set, |
| 867 | .@"error", | 882 | .@"error", |
| 883 | .error_union, | ||
| 868 | .empty_struct_value, | 884 | .empty_struct_value, |
| 869 | .inferred_alloc, | 885 | .inferred_alloc, |
| 870 | => unreachable, | 886 | => unreachable, |
| ... | @@ -979,6 +995,7 @@ pub const Value = extern union { | ... | @@ -979,6 +995,7 @@ pub const Value = extern union { |
| 979 | .enum_literal, | 995 | .enum_literal, |
| 980 | .error_set, | 996 | .error_set, |
| 981 | .@"error", | 997 | .@"error", |
| 998 | .error_union, | ||
| 982 | .empty_struct_value, | 999 | .empty_struct_value, |
| 983 | .inferred_alloc, | 1000 | .inferred_alloc, |
| 984 | => unreachable, | 1001 | => unreachable, |
| ... | @@ -1069,6 +1086,7 @@ pub const Value = extern union { | ... | @@ -1069,6 +1086,7 @@ pub const Value = extern union { |
| 1069 | .enum_literal, | 1086 | .enum_literal, |
| 1070 | .error_set, | 1087 | .error_set, |
| 1071 | .@"error", | 1088 | .@"error", |
| 1089 | .error_union, | ||
| 1072 | .empty_struct_value, | 1090 | .empty_struct_value, |
| 1073 | .inferred_alloc, | 1091 | .inferred_alloc, |
| 1074 | => unreachable, | 1092 | => unreachable, |
| ... | @@ -1228,6 +1246,7 @@ pub const Value = extern union { | ... | @@ -1228,6 +1246,7 @@ pub const Value = extern union { |
| 1228 | .enum_literal, | 1246 | .enum_literal, |
| 1229 | .error_set, | 1247 | .error_set, |
| 1230 | .@"error", | 1248 | .@"error", |
| 1249 | .error_union, | ||
| 1231 | .empty_struct_value, | 1250 | .empty_struct_value, |
| 1232 | .inferred_alloc, | 1251 | .inferred_alloc, |
| 1233 | => unreachable, | 1252 | => unreachable, |
| ... | @@ -1305,6 +1324,7 @@ pub const Value = extern union { | ... | @@ -1305,6 +1324,7 @@ pub const Value = extern union { |
| 1305 | .enum_literal, | 1324 | .enum_literal, |
| 1306 | .error_set, | 1325 | .error_set, |
| 1307 | .@"error", | 1326 | .@"error", |
| 1327 | .error_union, | ||
| 1308 | .empty_struct_value, | 1328 | .empty_struct_value, |
| 1309 | .inferred_alloc, | 1329 | .inferred_alloc, |
| 1310 | => unreachable, | 1330 | => unreachable, |
| ... | @@ -1543,7 +1563,10 @@ pub const Value = extern union { | ... | @@ -1543,7 +1563,10 @@ pub const Value = extern union { |
| 1543 | hasher.update(payload.name); | 1563 | hasher.update(payload.name); |
| 1544 | std.hash.autoHash(&hasher, payload.value); | 1564 | std.hash.autoHash(&hasher, payload.value); |
| 1545 | }, | 1565 | }, |
| 1546 | 1566 | .error_union => { | |
| 1567 | const payload = self.castTag(.error_union).?.data; | ||
| 1568 | std.hash.autoHash(&hasher, payload.hash()); | ||
| 1569 | }, | ||
| 1547 | .inferred_alloc => unreachable, | 1570 | .inferred_alloc => unreachable, |
| 1548 | } | 1571 | } |
| 1549 | return hasher.final(); | 1572 | return hasher.final(); |
| ... | @@ -1621,6 +1644,7 @@ pub const Value = extern union { | ... | @@ -1621,6 +1644,7 @@ pub const Value = extern union { |
| 1621 | .enum_literal, | 1644 | .enum_literal, |
| 1622 | .error_set, | 1645 | .error_set, |
| 1623 | .@"error", | 1646 | .@"error", |
| 1647 | .error_union, | ||
| 1624 | .empty_struct_value, | 1648 | .empty_struct_value, |
| 1625 | .inferred_alloc, | 1649 | .inferred_alloc, |
| 1626 | => unreachable, | 1650 | => unreachable, |
| ... | @@ -1707,6 +1731,7 @@ pub const Value = extern union { | ... | @@ -1707,6 +1731,7 @@ pub const Value = extern union { |
| 1707 | .enum_literal, | 1731 | .enum_literal, |
| 1708 | .error_set, | 1732 | .error_set, |
| 1709 | .@"error", | 1733 | .@"error", |
| 1734 | .error_union, | ||
| 1710 | .empty_struct_value, | 1735 | .empty_struct_value, |
| 1711 | .inferred_alloc, | 1736 | .inferred_alloc, |
| 1712 | => unreachable, | 1737 | => unreachable, |
| ... | @@ -1810,6 +1835,7 @@ pub const Value = extern union { | ... | @@ -1810,6 +1835,7 @@ pub const Value = extern union { |
| 1810 | .enum_literal, | 1835 | .enum_literal, |
| 1811 | .error_set, | 1836 | .error_set, |
| 1812 | .@"error", | 1837 | .@"error", |
| 1838 | .error_union, | ||
| 1813 | .empty_struct_value, | 1839 | .empty_struct_value, |
| 1814 | => false, | 1840 | => false, |
| 1815 | 1841 | ||
| ... | @@ -1820,6 +1846,93 @@ pub const Value = extern union { | ... | @@ -1820,6 +1846,93 @@ pub const Value = extern union { |
| 1820 | }; | 1846 | }; |
| 1821 | } | 1847 | } |
| 1822 | 1848 | ||
| 1849 | /// Valid for all types. Asserts the value is not undefined and not unreachable. | ||
| 1850 | pub fn getError(self: Value) ?[]const u8 { | ||
| 1851 | return switch (self.tag()) { | ||
| 1852 | .ty, | ||
| 1853 | .int_type, | ||
| 1854 | .u8_type, | ||
| 1855 | .i8_type, | ||
| 1856 | .u16_type, | ||
| 1857 | .i16_type, | ||
| 1858 | .u32_type, | ||
| 1859 | .i32_type, | ||
| 1860 | .u64_type, | ||
| 1861 | .i64_type, | ||
| 1862 | .usize_type, | ||
| 1863 | .isize_type, | ||
| 1864 | .c_short_type, | ||
| 1865 | .c_ushort_type, | ||
| 1866 | .c_int_type, | ||
| 1867 | .c_uint_type, | ||
| 1868 | .c_long_type, | ||
| 1869 | .c_ulong_type, | ||
| 1870 | .c_longlong_type, | ||
| 1871 | .c_ulonglong_type, | ||
| 1872 | .c_longdouble_type, | ||
| 1873 | .f16_type, | ||
| 1874 | .f32_type, | ||
| 1875 | .f64_type, | ||
| 1876 | .f128_type, | ||
| 1877 | .c_void_type, | ||
| 1878 | .bool_type, | ||
| 1879 | .void_type, | ||
| 1880 | .type_type, | ||
| 1881 | .anyerror_type, | ||
| 1882 | .comptime_int_type, | ||
| 1883 | .comptime_float_type, | ||
| 1884 | .noreturn_type, | ||
| 1885 | .null_type, | ||
| 1886 | .undefined_type, | ||
| 1887 | .fn_noreturn_no_args_type, | ||
| 1888 | .fn_void_no_args_type, | ||
| 1889 | .fn_naked_noreturn_no_args_type, | ||
| 1890 | .fn_ccc_void_no_args_type, | ||
| 1891 | .single_const_pointer_to_comptime_int_type, | ||
| 1892 | .const_slice_u8_type, | ||
| 1893 | .enum_literal_type, | ||
| 1894 | .anyframe_type, | ||
| 1895 | .zero, | ||
| 1896 | .one, | ||
| 1897 | .null_value, | ||
| 1898 | .empty_array, | ||
| 1899 | .bool_true, | ||
| 1900 | .bool_false, | ||
| 1901 | .function, | ||
| 1902 | .extern_fn, | ||
| 1903 | .variable, | ||
| 1904 | .int_u64, | ||
| 1905 | .int_i64, | ||
| 1906 | .int_big_positive, | ||
| 1907 | .int_big_negative, | ||
| 1908 | .ref_val, | ||
| 1909 | .decl_ref, | ||
| 1910 | .elem_ptr, | ||
| 1911 | .bytes, | ||
| 1912 | .repeated, | ||
| 1913 | .float_16, | ||
| 1914 | .float_32, | ||
| 1915 | .float_64, | ||
| 1916 | .float_128, | ||
| 1917 | .void_value, | ||
| 1918 | .enum_literal, | ||
| 1919 | .error_set, | ||
| 1920 | .empty_struct_value, | ||
| 1921 | => null, | ||
| 1922 | |||
| 1923 | .error_union => { | ||
| 1924 | const data = self.castTag(.error_union).?.data; | ||
| 1925 | return if (data.tag() == .@"error") | ||
| 1926 | data.castTag(.@"error").?.data.name | ||
| 1927 | else | ||
| 1928 | null; | ||
| 1929 | }, | ||
| 1930 | .@"error" => self.castTag(.@"error").?.data.name, | ||
| 1931 | .undef => unreachable, | ||
| 1932 | .unreachable_value => unreachable, | ||
| 1933 | .inferred_alloc => unreachable, | ||
| 1934 | }; | ||
| 1935 | } | ||
| 1823 | /// Valid for all types. Asserts the value is not undefined. | 1936 | /// Valid for all types. Asserts the value is not undefined. |
| 1824 | pub fn isFloat(self: Value) bool { | 1937 | pub fn isFloat(self: Value) bool { |
| 1825 | return switch (self.tag()) { | 1938 | return switch (self.tag()) { |
| ... | @@ -1908,6 +2021,7 @@ pub const Value = extern union { | ... | @@ -1908,6 +2021,7 @@ pub const Value = extern union { |
| 1908 | .void_value, | 2021 | .void_value, |
| 1909 | .enum_literal, | 2022 | .enum_literal, |
| 1910 | .@"error", | 2023 | .@"error", |
| 2024 | .error_union, | ||
| 1911 | .empty_struct_value, | 2025 | .empty_struct_value, |
| 1912 | .null_value, | 2026 | .null_value, |
| 1913 | => false, | 2027 | => false, |
src/zir.zig+12| ... | @@ -1622,6 +1622,12 @@ const DumpTzir = struct { | ... | @@ -1622,6 +1622,12 @@ const DumpTzir = struct { |
| 1622 | .optional_payload, | 1622 | .optional_payload, |
| 1623 | .optional_payload_ptr, | 1623 | .optional_payload_ptr, |
| 1624 | .wrap_optional, | 1624 | .wrap_optional, |
| 1625 | .wrap_errunion_payload, | ||
| 1626 | .wrap_errunion_err, | ||
| 1627 | .unwrap_errunion_payload, | ||
| 1628 | .unwrap_errunion_err, | ||
| 1629 | .unwrap_errunion_payload_ptr, | ||
| 1630 | .unwrap_errunion_err_ptr, | ||
| 1625 | => { | 1631 | => { |
| 1626 | const un_op = inst.cast(ir.Inst.UnOp).?; | 1632 | const un_op = inst.cast(ir.Inst.UnOp).?; |
| 1627 | try dtz.findConst(un_op.operand); | 1633 | try dtz.findConst(un_op.operand); |
| ... | @@ -1733,6 +1739,12 @@ const DumpTzir = struct { | ... | @@ -1733,6 +1739,12 @@ const DumpTzir = struct { |
| 1733 | .optional_payload, | 1739 | .optional_payload, |
| 1734 | .optional_payload_ptr, | 1740 | .optional_payload_ptr, |
| 1735 | .wrap_optional, | 1741 | .wrap_optional, |
| 1742 | .wrap_errunion_err, | ||
| 1743 | .wrap_errunion_payload, | ||
| 1744 | .unwrap_errunion_err, | ||
| 1745 | .unwrap_errunion_payload, | ||
| 1746 | .unwrap_errunion_payload_ptr, | ||
| 1747 | .unwrap_errunion_err_ptr, | ||
| 1736 | => { | 1748 | => { |
| 1737 | const un_op = inst.cast(ir.Inst.UnOp).?; | 1749 | const un_op = inst.cast(ir.Inst.UnOp).?; |
| 1738 | const kinky = try dtz.writeInst(writer, un_op.operand); | 1750 | const kinky = try dtz.writeInst(writer, un_op.operand); |
src/zir_sema.zig+101-6| ... | @@ -1263,34 +1263,124 @@ fn zirOptionalPayload( | ... | @@ -1263,34 +1263,124 @@ fn zirOptionalPayload( |
| 1263 | fn zirErrUnionPayload(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | 1263 | fn zirErrUnionPayload(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { |
| 1264 | const tracy = trace(@src()); | 1264 | const tracy = trace(@src()); |
| 1265 | defer tracy.end(); | 1265 | defer tracy.end(); |
| 1266 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionPayload", .{}); | 1266 | |
| 1267 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1268 | if (operand.ty.zigTypeTag() != .ErrorUnion) | ||
| 1269 | return mod.fail(scope, operand.src, "expected error union type, found '{}'", .{operand.ty}); | ||
| 1270 | |||
| 1271 | if (operand.value()) |val| { | ||
| 1272 | if (val.getError()) |name| { | ||
| 1273 | return mod.fail(scope, unwrap.base.src, "caught unexpected error '{s}'", .{name}); | ||
| 1274 | } | ||
| 1275 | const data = val.castTag(.error_union).?.data; | ||
| 1276 | return mod.constInst(scope, unwrap.base.src, .{ | ||
| 1277 | .ty = operand.ty.castTag(.error_union).?.data.payload, | ||
| 1278 | .val = data, | ||
| 1279 | }); | ||
| 1280 | } | ||
| 1281 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | ||
| 1282 | if (safety_check and mod.wantSafety(scope)) { | ||
| 1283 | const is_non_err = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_err, operand); | ||
| 1284 | try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion); | ||
| 1285 | } | ||
| 1286 | return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_payload, operand); | ||
| 1267 | } | 1287 | } |
| 1268 | 1288 | ||
| 1269 | /// Pointer in, pointer out | 1289 | /// Pointer in, pointer out |
| 1270 | fn zirErrUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { | 1290 | fn zirErrUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst { |
| 1271 | const tracy = trace(@src()); | 1291 | const tracy = trace(@src()); |
| 1272 | defer tracy.end(); | 1292 | defer tracy.end(); |
| 1273 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionPayloadPtr", .{}); | 1293 | |
| 1294 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1295 | assert(operand.ty.zigTypeTag() == .Pointer); | ||
| 1296 | |||
| 1297 | if (operand.ty.elemType().zigTypeTag() != .ErrorUnion) | ||
| 1298 | return mod.fail(scope, unwrap.base.src, "expected error union type, found {}", .{operand.ty.elemType()}); | ||
| 1299 | |||
| 1300 | const operand_pointer_ty = try mod.simplePtrType(scope, unwrap.base.src, operand.ty.elemType().castTag(.error_union).?.data.payload, !operand.ty.isConstPtr(), .One); | ||
| 1301 | |||
| 1302 | if (operand.value()) |pointer_val| { | ||
| 1303 | const val = try pointer_val.pointerDeref(scope.arena()); | ||
| 1304 | if (val.getError()) |name| { | ||
| 1305 | return mod.fail(scope, unwrap.base.src, "caught unexpected error '{s}'", .{name}); | ||
| 1306 | } | ||
| 1307 | const data = val.castTag(.error_union).?.data; | ||
| 1308 | // The same Value represents the pointer to the error union and the payload. | ||
| 1309 | return mod.constInst(scope, unwrap.base.src, .{ | ||
| 1310 | .ty = operand_pointer_ty, | ||
| 1311 | .val = try Value.Tag.ref_val.create( | ||
| 1312 | scope.arena(), | ||
| 1313 | data, | ||
| 1314 | ), | ||
| 1315 | }); | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | ||
| 1319 | if (safety_check and mod.wantSafety(scope)) { | ||
| 1320 | const is_non_err = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_err, operand); | ||
| 1321 | try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion); | ||
| 1322 | } | ||
| 1323 | return mod.addUnOp(b, unwrap.base.src, operand_pointer_ty, .unwrap_errunion_payload_ptr, operand); | ||
| 1274 | } | 1324 | } |
| 1275 | 1325 | ||
| 1276 | /// Value in, value out | 1326 | /// Value in, value out |
| 1277 | fn zirErrUnionCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1327 | fn zirErrUnionCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 1278 | const tracy = trace(@src()); | 1328 | const tracy = trace(@src()); |
| 1279 | defer tracy.end(); | 1329 | defer tracy.end(); |
| 1280 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionCode", .{}); | 1330 | |
| 1331 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1332 | if (operand.ty.zigTypeTag() != .ErrorUnion) | ||
| 1333 | return mod.fail(scope, unwrap.base.src, "expected error union type, found '{}'", .{operand.ty}); | ||
| 1334 | |||
| 1335 | if (operand.value()) |val| { | ||
| 1336 | assert(val.getError() != null); | ||
| 1337 | const data = val.castTag(.error_union).?.data; | ||
| 1338 | return mod.constInst(scope, unwrap.base.src, .{ | ||
| 1339 | .ty = operand.ty.castTag(.error_union).?.data.error_set, | ||
| 1340 | .val = data, | ||
| 1341 | }); | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | ||
| 1345 | return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand); | ||
| 1281 | } | 1346 | } |
| 1282 | 1347 | ||
| 1283 | /// Pointer in, value out | 1348 | /// Pointer in, value out |
| 1284 | fn zirErrUnionCodePtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1349 | fn zirErrUnionCodePtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 1285 | const tracy = trace(@src()); | 1350 | const tracy = trace(@src()); |
| 1286 | defer tracy.end(); | 1351 | defer tracy.end(); |
| 1287 | return mod.fail(scope, unwrap.base.src, "TODO implement zir_sema.zirErrUnionCodePtr", .{}); | 1352 | |
| 1353 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1354 | assert(operand.ty.zigTypeTag() == .Pointer); | ||
| 1355 | |||
| 1356 | if (operand.ty.elemType().zigTypeTag() != .ErrorUnion) | ||
| 1357 | return mod.fail(scope, unwrap.base.src, "expected error union type, found {}", .{operand.ty.elemType()}); | ||
| 1358 | |||
| 1359 | if (operand.value()) |pointer_val| { | ||
| 1360 | const val = try pointer_val.pointerDeref(scope.arena()); | ||
| 1361 | assert(val.getError() != null); | ||
| 1362 | const data = val.castTag(.error_union).?.data; | ||
| 1363 | return mod.constInst(scope, unwrap.base.src, .{ | ||
| 1364 | .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set, | ||
| 1365 | .val = data, | ||
| 1366 | }); | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | ||
| 1370 | return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand); | ||
| 1288 | } | 1371 | } |
| 1289 | 1372 | ||
| 1290 | fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { | 1373 | fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst { |
| 1291 | const tracy = trace(@src()); | 1374 | const tracy = trace(@src()); |
| 1292 | defer tracy.end(); | 1375 | defer tracy.end(); |
| 1293 | return mod.fail(scope, unwrap.base.src, "TODO implement zirEnsureErrPayloadVoid", .{}); | 1376 | |
| 1377 | const operand = try resolveInst(mod, scope, unwrap.positionals.operand); | ||
| 1378 | if (operand.ty.zigTypeTag() != .ErrorUnion) | ||
| 1379 | return mod.fail(scope, unwrap.base.src, "expected error union type, found '{}'", .{operand.ty}); | ||
| 1380 | if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) { | ||
| 1381 | return mod.fail(scope, unwrap.base.src, "expression value is ignored", .{}); | ||
| 1382 | } | ||
| 1383 | return mod.constVoid(scope, unwrap.base.src); | ||
| 1294 | } | 1384 | } |
| 1295 | 1385 | ||
| 1296 | fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { | 1386 | fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| ... | @@ -2106,7 +2196,12 @@ fn zirCmp( | ... | @@ -2106,7 +2196,12 @@ fn zirCmp( |
| 2106 | if (!is_equality_cmp) { | 2196 | if (!is_equality_cmp) { |
| 2107 | return mod.fail(scope, inst.base.src, "{s} operator not allowed for errors", .{@tagName(op)}); | 2197 | return mod.fail(scope, inst.base.src, "{s} operator not allowed for errors", .{@tagName(op)}); |
| 2108 | } | 2198 | } |
| 2109 | return mod.fail(scope, inst.base.src, "TODO implement equality comparison between errors", .{}); | 2199 | if (rhs.value()) |rval| { |
| 2200 | if (lhs.value()) |lval| { | ||
| 2201 | return mod.constBool(scope, inst.base.src, (lval.castTag(.@"error").?.data.value == rval.castTag(.@"error").?.data.value) == (op == .eq)); | ||
| 2202 | } | ||
| 2203 | } | ||
| 2204 | return mod.fail(scope, inst.base.src, "TODO implement equality comparison between runtime errors", .{}); | ||
| 2110 | } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) { | 2205 | } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) { |
| 2111 | // This operation allows any combination of integer and float types, regardless of the | 2206 | // This operation allows any combination of integer and float types, regardless of the |
| 2112 | // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for | 2207 | // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for |
test/stage2/test.zig+107-1| ... | @@ -1397,7 +1397,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1397,7 +1397,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1397 | "", | 1397 | "", |
| 1398 | ); | 1398 | ); |
| 1399 | } | 1399 | } |
| 1400 | |||
| 1401 | { | 1400 | { |
| 1402 | var case = ctx.exe("passing u0 to function", linux_x64); | 1401 | var case = ctx.exe("passing u0 to function", linux_x64); |
| 1403 | case.addCompareOutput( | 1402 | case.addCompareOutput( |
| ... | @@ -1419,4 +1418,111 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1419,4 +1418,111 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1419 | "", | 1418 | "", |
| 1420 | ); | 1419 | ); |
| 1421 | } | 1420 | } |
| 1421 | { | ||
| 1422 | var case = ctx.exe("catch at comptime", linux_x64); | ||
| 1423 | case.addCompareOutput( | ||
| 1424 | \\export fn _start() noreturn { | ||
| 1425 | \\ const i: anyerror!u64 = 0; | ||
| 1426 | \\ const caught = i catch 5; | ||
| 1427 | \\ assert(caught == 0); | ||
| 1428 | \\ exit(); | ||
| 1429 | \\} | ||
| 1430 | \\fn assert(b: bool) void { | ||
| 1431 | \\ if (!b) unreachable; | ||
| 1432 | \\} | ||
| 1433 | \\fn exit() noreturn { | ||
| 1434 | \\ asm volatile ("syscall" | ||
| 1435 | \\ : | ||
| 1436 | \\ : [number] "{rax}" (231), | ||
| 1437 | \\ [arg1] "{rdi}" (0) | ||
| 1438 | \\ : "rcx", "r11", "memory" | ||
| 1439 | \\ ); | ||
| 1440 | \\ unreachable; | ||
| 1441 | \\} | ||
| 1442 | , | ||
| 1443 | "", | ||
| 1444 | ); | ||
| 1445 | case.addCompareOutput( | ||
| 1446 | \\export fn _start() noreturn { | ||
| 1447 | \\ const i: anyerror!u64 = error.B; | ||
| 1448 | \\ const caught = i catch 5; | ||
| 1449 | \\ assert(caught == 5); | ||
| 1450 | \\ exit(); | ||
| 1451 | \\} | ||
| 1452 | \\fn assert(b: bool) void { | ||
| 1453 | \\ if (!b) unreachable; | ||
| 1454 | \\} | ||
| 1455 | \\fn exit() noreturn { | ||
| 1456 | \\ asm volatile ("syscall" | ||
| 1457 | \\ : | ||
| 1458 | \\ : [number] "{rax}" (231), | ||
| 1459 | \\ [arg1] "{rdi}" (0) | ||
| 1460 | \\ : "rcx", "r11", "memory" | ||
| 1461 | \\ ); | ||
| 1462 | \\ unreachable; | ||
| 1463 | \\} | ||
| 1464 | , | ||
| 1465 | "", | ||
| 1466 | ); | ||
| 1467 | case.addCompareOutput( | ||
| 1468 | \\export fn _start() noreturn { | ||
| 1469 | \\ const a: anyerror!comptime_int = 42; | ||
| 1470 | \\ const b: *const comptime_int = &(a catch unreachable); | ||
| 1471 | \\ assert(b.* == 42); | ||
| 1472 | \\ | ||
| 1473 | \\ exit(); | ||
| 1474 | \\} | ||
| 1475 | \\fn assert(b: bool) void { | ||
| 1476 | \\ if (!b) unreachable; // assertion failure | ||
| 1477 | \\} | ||
| 1478 | \\fn exit() noreturn { | ||
| 1479 | \\ asm volatile ("syscall" | ||
| 1480 | \\ : | ||
| 1481 | \\ : [number] "{rax}" (231), | ||
| 1482 | \\ [arg1] "{rdi}" (0) | ||
| 1483 | \\ : "rcx", "r11", "memory" | ||
| 1484 | \\ ); | ||
| 1485 | \\ unreachable; | ||
| 1486 | \\} | ||
| 1487 | , ""); | ||
| 1488 | case.addCompareOutput( | ||
| 1489 | \\export fn _start() noreturn { | ||
| 1490 | \\const a: anyerror!u32 = error.B; | ||
| 1491 | \\_ = &(a catch |err| assert(err == error.B)); | ||
| 1492 | \\exit(); | ||
| 1493 | \\} | ||
| 1494 | \\fn assert(b: bool) void { | ||
| 1495 | \\ if (!b) unreachable; | ||
| 1496 | \\} | ||
| 1497 | \\fn exit() noreturn { | ||
| 1498 | \\ asm volatile ("syscall" | ||
| 1499 | \\ : | ||
| 1500 | \\ : [number] "{rax}" (231), | ||
| 1501 | \\ [arg1] "{rdi}" (0) | ||
| 1502 | \\ : "rcx", "r11", "memory" | ||
| 1503 | \\ ); | ||
| 1504 | \\ unreachable; | ||
| 1505 | \\} | ||
| 1506 | , ""); | ||
| 1507 | case.addCompareOutput( | ||
| 1508 | \\export fn _start() noreturn { | ||
| 1509 | \\ const a: anyerror!u32 = error.Bar; | ||
| 1510 | \\ a catch |err| assert(err == error.Bar); | ||
| 1511 | \\ | ||
| 1512 | \\ exit(); | ||
| 1513 | \\} | ||
| 1514 | \\fn assert(b: bool) void { | ||
| 1515 | \\ if (!b) unreachable; | ||
| 1516 | \\} | ||
| 1517 | \\fn exit() noreturn { | ||
| 1518 | \\ asm volatile ("syscall" | ||
| 1519 | \\ : | ||
| 1520 | \\ : [number] "{rax}" (231), | ||
| 1521 | \\ [arg1] "{rdi}" (0) | ||
| 1522 | \\ : "rcx", "r11", "memory" | ||
| 1523 | \\ ); | ||
| 1524 | \\ unreachable; | ||
| 1525 | \\} | ||
| 1526 | , ""); | ||
| 1527 | } | ||
| 1422 | } | 1528 | } |