| author | |
| committer | |
| log | df389b62de4430434a6518580e27208101ae2fc8 |
| tree | d6acb3165d8475643acba4bd7942f4bd5d285b52 |
| parent | d07149c56d202c3503c4f5505e8b003b3e161145 |
| parent | fec7565da6e27334de63c3635dd2e32325c39c98 |
| signature |
Follow-up to cast builtin result type inference10 files changed, 318 insertions(+), 28 deletions(-)
doc/langref.html.in+1-1| ... | ... | @@ -10267,7 +10267,7 @@ pub fn main() void { |
| 10267 | 10267 | foo(Set1.B); |
| 10268 | 10268 | } |
| 10269 | 10269 | fn foo(set1: Set1) void { |
| 10270 | const x = @as(Set2, @errSetCast(set1)); | |
| 10270 | const x: Set2 = @errSetCast(set1); | |
| 10271 | 10271 | std.debug.print("value: {}\n", .{x}); |
| 10272 | 10272 | } |
| 10273 | 10273 | {#code_end#} |
src/AstGen.zig+3-11| ... | ... | @@ -6483,11 +6483,11 @@ fn forExpr( |
| 6483 | 6483 | return astgen.failTok(ident_tok, "cannot capture reference to range", .{}); |
| 6484 | 6484 | } |
| 6485 | 6485 | const start_node = node_data[input].lhs; |
| 6486 | const start_val = try expr(parent_gz, scope, .{ .rl = .none }, start_node); | |
| 6486 | const start_val = try expr(parent_gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, start_node); | |
| 6487 | 6487 | |
| 6488 | 6488 | const end_node = node_data[input].rhs; |
| 6489 | 6489 | const end_val = if (end_node != 0) |
| 6490 | try expr(parent_gz, scope, .{ .rl = .none }, node_data[input].rhs) | |
| 6490 | try expr(parent_gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_data[input].rhs) | |
| 6491 | 6491 | else |
| 6492 | 6492 | .none; |
| 6493 | 6493 | |
| ... | ... | @@ -8053,17 +8053,9 @@ fn ptrCast( |
| 8053 | 8053 | } |
| 8054 | 8054 | |
| 8055 | 8055 | // Full cast including result type |
| 8056 | const need_result_type_builtin = if (flags.ptr_cast) | |
| 8057 | "@ptrCast" | |
| 8058 | else if (flags.align_cast) | |
| 8059 | "@alignCast" | |
| 8060 | else if (flags.addrspace_cast) | |
| 8061 | "@addrSpaceCast" | |
| 8062 | else | |
| 8063 | unreachable; | |
| 8064 | 8056 | |
| 8065 | 8057 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node); |
| 8066 | const result_type = try ri.rl.resultType(gz, root_node, need_result_type_builtin); | |
| 8058 | const result_type = try ri.rl.resultType(gz, root_node, flags.needResultTypeBuiltinName()); | |
| 8067 | 8059 | const operand = try expr(gz, scope, .{ .rl = .none }, node); |
| 8068 | 8060 | try emitDbgStmt(gz, cursor); |
| 8069 | 8061 | const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{ |
src/Module.zig+40| ... | ... | @@ -34,6 +34,7 @@ const isUpDir = @import("introspect.zig").isUpDir; |
| 34 | 34 | const clang = @import("clang.zig"); |
| 35 | 35 | const InternPool = @import("InternPool.zig"); |
| 36 | 36 | const Alignment = InternPool.Alignment; |
| 37 | const BuiltinFn = @import("BuiltinFn.zig"); | |
| 37 | 38 | |
| 38 | 39 | comptime { |
| 39 | 40 | @setEvalBranchQuota(4000); |
| ... | ... | @@ -2273,6 +2274,41 @@ pub const SrcLoc = struct { |
| 2273 | 2274 | .node_offset_builtin_call_arg3 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 3), |
| 2274 | 2275 | .node_offset_builtin_call_arg4 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 4), |
| 2275 | 2276 | .node_offset_builtin_call_arg5 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 5), |
| 2277 | .node_offset_ptrcast_operand => |node_off| { | |
| 2278 | const tree = try src_loc.file_scope.getTree(gpa); | |
| 2279 | const main_tokens = tree.nodes.items(.main_token); | |
| 2280 | const node_datas = tree.nodes.items(.data); | |
| 2281 | const node_tags = tree.nodes.items(.tag); | |
| 2282 | ||
| 2283 | var node = src_loc.declRelativeToNodeIndex(node_off); | |
| 2284 | while (true) { | |
| 2285 | switch (node_tags[node]) { | |
| 2286 | .builtin_call_two, .builtin_call_two_comma => {}, | |
| 2287 | else => break, | |
| 2288 | } | |
| 2289 | ||
| 2290 | if (node_datas[node].lhs == 0) break; // 0 args | |
| 2291 | if (node_datas[node].rhs != 0) break; // 2 args | |
| 2292 | ||
| 2293 | const builtin_token = main_tokens[node]; | |
| 2294 | const builtin_name = tree.tokenSlice(builtin_token); | |
| 2295 | const info = BuiltinFn.list.get(builtin_name) orelse break; | |
| 2296 | ||
| 2297 | switch (info.tag) { | |
| 2298 | else => break, | |
| 2299 | .ptr_cast, | |
| 2300 | .align_cast, | |
| 2301 | .addrspace_cast, | |
| 2302 | .const_cast, | |
| 2303 | .volatile_cast, | |
| 2304 | => {}, | |
| 2305 | } | |
| 2306 | ||
| 2307 | node = node_datas[node].lhs; | |
| 2308 | } | |
| 2309 | ||
| 2310 | return nodeToSpan(tree, node); | |
| 2311 | }, | |
| 2276 | 2312 | .node_offset_array_access_index => |node_off| { |
| 2277 | 2313 | const tree = try src_loc.file_scope.getTree(gpa); |
| 2278 | 2314 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -2887,6 +2923,9 @@ pub const LazySrcLoc = union(enum) { |
| 2887 | 2923 | node_offset_builtin_call_arg3: i32, |
| 2888 | 2924 | node_offset_builtin_call_arg4: i32, |
| 2889 | 2925 | node_offset_builtin_call_arg5: i32, |
| 2926 | /// Like `node_offset_builtin_call_arg0` but recurses through arbitrarily many calls | |
| 2927 | /// to pointer cast builtins. | |
| 2928 | node_offset_ptrcast_operand: i32, | |
| 2890 | 2929 | /// The source location points to the index expression of an array access |
| 2891 | 2930 | /// expression, found by taking this AST node index offset from the containing |
| 2892 | 2931 | /// Decl AST node, which points to an array access AST node. Next, navigate |
| ... | ... | @@ -3145,6 +3184,7 @@ pub const LazySrcLoc = union(enum) { |
| 3145 | 3184 | .node_offset_builtin_call_arg3, |
| 3146 | 3185 | .node_offset_builtin_call_arg4, |
| 3147 | 3186 | .node_offset_builtin_call_arg5, |
| 3187 | .node_offset_ptrcast_operand, | |
| 3148 | 3188 | .node_offset_array_access_index, |
| 3149 | 3189 | .node_offset_slice_ptr, |
| 3150 | 3190 | .node_offset_slice_start, |
src/Sema.zig+45-16| ... | ... | @@ -1820,8 +1820,25 @@ pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Ins |
| 1820 | 1820 | return ty; |
| 1821 | 1821 | } |
| 1822 | 1822 | |
| 1823 | fn resolveCastDestType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref, builtin_name: []const u8) !Type { | |
| 1824 | return sema.resolveType(block, src, zir_ref) catch |err| switch (err) { | |
| 1823 | fn resolveCastDestType( | |
| 1824 | sema: *Sema, | |
| 1825 | block: *Block, | |
| 1826 | src: LazySrcLoc, | |
| 1827 | zir_ref: Zir.Inst.Ref, | |
| 1828 | strat: enum { remove_eu_opt, remove_eu, remove_opt }, | |
| 1829 | builtin_name: []const u8, | |
| 1830 | ) !Type { | |
| 1831 | const mod = sema.mod; | |
| 1832 | const remove_eu = switch (strat) { | |
| 1833 | .remove_eu_opt, .remove_eu => true, | |
| 1834 | .remove_opt => false, | |
| 1835 | }; | |
| 1836 | const remove_opt = switch (strat) { | |
| 1837 | .remove_eu_opt, .remove_opt => true, | |
| 1838 | .remove_eu => false, | |
| 1839 | }; | |
| 1840 | ||
| 1841 | const raw_ty = sema.resolveType(block, src, zir_ref) catch |err| switch (err) { | |
| 1825 | 1842 | error.GenericPoison => { |
| 1826 | 1843 | // Cast builtins use their result type as the destination type, but |
| 1827 | 1844 | // it could be an anytype argument, which we can't catch in AstGen. |
| ... | ... | @@ -1836,6 +1853,18 @@ fn resolveCastDestType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir |
| 1836 | 1853 | }, |
| 1837 | 1854 | else => |e| return e, |
| 1838 | 1855 | }; |
| 1856 | ||
| 1857 | if (remove_eu and raw_ty.zigTypeTag(mod) == .ErrorUnion) { | |
| 1858 | const eu_child = raw_ty.errorUnionPayload(mod); | |
| 1859 | if (remove_opt and eu_child.zigTypeTag(mod) == .Optional) { | |
| 1860 | return eu_child.childType(mod); | |
| 1861 | } | |
| 1862 | return eu_child; | |
| 1863 | } | |
| 1864 | if (remove_opt and raw_ty.zigTypeTag(mod) == .Optional) { | |
| 1865 | return raw_ty.childType(mod); | |
| 1866 | } | |
| 1867 | return raw_ty; | |
| 1839 | 1868 | } |
| 1840 | 1869 | |
| 1841 | 1870 | fn analyzeAsType( |
| ... | ... | @@ -8304,7 +8333,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8304 | 8333 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 8305 | 8334 | const src = inst_data.src(); |
| 8306 | 8335 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 8307 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@enumFromInt"); | |
| 8336 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@enumFromInt"); | |
| 8308 | 8337 | const operand = try sema.resolveInst(extra.rhs); |
| 8309 | 8338 | |
| 8310 | 8339 | if (dest_ty.zigTypeTag(mod) != .Enum) { |
| ... | ... | @@ -9600,7 +9629,7 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9600 | 9629 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9601 | 9630 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 9602 | 9631 | |
| 9603 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@intCast"); | |
| 9632 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@intCast"); | |
| 9604 | 9633 | const operand = try sema.resolveInst(extra.rhs); |
| 9605 | 9634 | |
| 9606 | 9635 | return sema.intCast(block, inst_data.src(), dest_ty, src, operand, operand_src, true); |
| ... | ... | @@ -9761,7 +9790,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9761 | 9790 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9762 | 9791 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 9763 | 9792 | |
| 9764 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@bitCast"); | |
| 9793 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@bitCast"); | |
| 9765 | 9794 | const operand = try sema.resolveInst(extra.rhs); |
| 9766 | 9795 | const operand_ty = sema.typeOf(operand); |
| 9767 | 9796 | switch (dest_ty.zigTypeTag(mod)) { |
| ... | ... | @@ -9904,7 +9933,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 9904 | 9933 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9905 | 9934 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 9906 | 9935 | |
| 9907 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@floatCast"); | |
| 9936 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@floatCast"); | |
| 9908 | 9937 | const operand = try sema.resolveInst(extra.rhs); |
| 9909 | 9938 | |
| 9910 | 9939 | const target = mod.getTarget(); |
| ... | ... | @@ -20706,7 +20735,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 20706 | 20735 | const src = inst_data.src(); |
| 20707 | 20736 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20708 | 20737 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20709 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@intFromFloat"); | |
| 20738 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@intFromFloat"); | |
| 20710 | 20739 | const operand = try sema.resolveInst(extra.rhs); |
| 20711 | 20740 | const operand_ty = sema.typeOf(operand); |
| 20712 | 20741 | |
| ... | ... | @@ -20746,7 +20775,7 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 20746 | 20775 | const src = inst_data.src(); |
| 20747 | 20776 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20748 | 20777 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20749 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@floatFromInt"); | |
| 20778 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@floatFromInt"); | |
| 20750 | 20779 | const operand = try sema.resolveInst(extra.rhs); |
| 20751 | 20780 | const operand_ty = sema.typeOf(operand); |
| 20752 | 20781 | |
| ... | ... | @@ -20775,7 +20804,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 20775 | 20804 | const operand_res = try sema.resolveInst(extra.rhs); |
| 20776 | 20805 | const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src); |
| 20777 | 20806 | |
| 20778 | const ptr_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@ptrFromInt"); | |
| 20807 | const ptr_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu, "@ptrFromInt"); | |
| 20779 | 20808 | try sema.checkPtrType(block, src, ptr_ty); |
| 20780 | 20809 | const elem_ty = ptr_ty.elemType2(mod); |
| 20781 | 20810 | const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema); |
| ... | ... | @@ -20833,7 +20862,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 20833 | 20862 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 20834 | 20863 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 20835 | 20864 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 20836 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@errSetCast"); | |
| 20865 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@errSetCast"); | |
| 20837 | 20866 | const operand = try sema.resolveInst(extra.rhs); |
| 20838 | 20867 | const operand_ty = sema.typeOf(operand); |
| 20839 | 20868 | try sema.checkErrorSetType(block, src, dest_ty); |
| ... | ... | @@ -20915,12 +20944,12 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 20915 | 20944 | } |
| 20916 | 20945 | |
| 20917 | 20946 | fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20918 | const flags = @as(Zir.Inst.FullPtrCastFlags, @bitCast(@as(u5, @truncate(extended.small)))); | |
| 20947 | const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(u5, @truncate(extended.small))); | |
| 20919 | 20948 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 20920 | 20949 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 20921 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 20950 | const operand_src: LazySrcLoc = .{ .node_offset_ptrcast_operand = extra.node }; | |
| 20922 | 20951 | const operand = try sema.resolveInst(extra.rhs); |
| 20923 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@ptrCast"); // TODO: better error message (builtin name) | |
| 20952 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu, flags.needResultTypeBuiltinName()); | |
| 20924 | 20953 | return sema.ptrCastFull( |
| 20925 | 20954 | block, |
| 20926 | 20955 | flags, |
| ... | ... | @@ -20936,7 +20965,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20936 | 20965 | const src = inst_data.src(); |
| 20937 | 20966 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20938 | 20967 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20939 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@ptrCast"); | |
| 20968 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu, "@ptrCast"); | |
| 20940 | 20969 | const operand = try sema.resolveInst(extra.rhs); |
| 20941 | 20970 | |
| 20942 | 20971 | return sema.ptrCastFull( |
| ... | ... | @@ -21325,7 +21354,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 21325 | 21354 | const flags = @as(Zir.Inst.FullPtrCastFlags, @bitCast(@as(u5, @truncate(extended.small)))); |
| 21326 | 21355 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 21327 | 21356 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 21328 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | |
| 21357 | const operand_src: LazySrcLoc = .{ .node_offset_ptrcast_operand = extra.node }; | |
| 21329 | 21358 | const operand = try sema.resolveInst(extra.operand); |
| 21330 | 21359 | const operand_ty = sema.typeOf(operand); |
| 21331 | 21360 | try sema.checkPtrOperand(block, operand_src, operand_ty); |
| ... | ... | @@ -21349,7 +21378,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 21349 | 21378 | const src = inst_data.src(); |
| 21350 | 21379 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 21351 | 21380 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 21352 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, "@truncate"); | |
| 21381 | const dest_ty = try sema.resolveCastDestType(block, src, extra.lhs, .remove_eu_opt, "@truncate"); | |
| 21353 | 21382 | const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, src); |
| 21354 | 21383 | const operand = try sema.resolveInst(extra.rhs); |
| 21355 | 21384 | const operand_ty = sema.typeOf(operand); |
src/Zir.zig+7| ... | ... | @@ -2820,6 +2820,13 @@ pub const Inst = struct { |
| 2820 | 2820 | addrspace_cast: bool = false, |
| 2821 | 2821 | const_cast: bool = false, |
| 2822 | 2822 | volatile_cast: bool = false, |
| 2823 | ||
| 2824 | pub inline fn needResultTypeBuiltinName(flags: FullPtrCastFlags) []const u8 { | |
| 2825 | if (flags.ptr_cast) return "@ptrCast"; | |
| 2826 | if (flags.align_cast) return "@alignCast"; | |
| 2827 | if (flags.addrspace_cast) return "@addrSpaceCast"; | |
| 2828 | unreachable; | |
| 2829 | } | |
| 2823 | 2830 | }; |
| 2824 | 2831 | |
| 2825 | 2832 | /// Trailing: |
test/behavior/cast.zig+122| ... | ... | @@ -2219,3 +2219,125 @@ test "peer type resolution: pointer attributes are combined correctly" { |
| 2219 | 2219 | try expectEqualSlices(u8, std.mem.span(@volatileCast(r2)), "bar"); |
| 2220 | 2220 | try expectEqualSlices(u8, std.mem.span(@volatileCast(r3)), "baz"); |
| 2221 | 2221 | } |
| 2222 | ||
| 2223 | test "cast builtins can wrap result in optional" { | |
| 2224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2225 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 2226 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 2227 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 2228 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 2229 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO | |
| 2230 | ||
| 2231 | const S = struct { | |
| 2232 | const MyEnum = enum(u32) { _ }; | |
| 2233 | fn a() ?MyEnum { | |
| 2234 | return @enumFromInt(123); | |
| 2235 | } | |
| 2236 | fn b() ?u32 { | |
| 2237 | return @intFromFloat(42.50); | |
| 2238 | } | |
| 2239 | fn c() ?*const f32 { | |
| 2240 | const x: u32 = 1; | |
| 2241 | return @ptrCast(&x); | |
| 2242 | } | |
| 2243 | ||
| 2244 | fn doTheTest() !void { | |
| 2245 | const ra = a() orelse return error.ImpossibleError; | |
| 2246 | const rb = b() orelse return error.ImpossibleError; | |
| 2247 | const rc = c() orelse return error.ImpossibleError; | |
| 2248 | ||
| 2249 | comptime assert(@TypeOf(ra) == MyEnum); | |
| 2250 | comptime assert(@TypeOf(rb) == u32); | |
| 2251 | comptime assert(@TypeOf(rc) == *const f32); | |
| 2252 | ||
| 2253 | try expect(@intFromEnum(ra) == 123); | |
| 2254 | try expect(rb == 42); | |
| 2255 | try expect(@as(*const u32, @ptrCast(rc)).* == 1); | |
| 2256 | } | |
| 2257 | }; | |
| 2258 | ||
| 2259 | try S.doTheTest(); | |
| 2260 | try comptime S.doTheTest(); | |
| 2261 | } | |
| 2262 | ||
| 2263 | test "cast builtins can wrap result in error union" { | |
| 2264 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2265 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 2266 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 2267 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 2268 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 2269 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO | |
| 2270 | ||
| 2271 | const S = struct { | |
| 2272 | const MyEnum = enum(u32) { _ }; | |
| 2273 | const E = error{ImpossibleError}; | |
| 2274 | fn a() E!MyEnum { | |
| 2275 | return @enumFromInt(123); | |
| 2276 | } | |
| 2277 | fn b() E!u32 { | |
| 2278 | return @intFromFloat(42.50); | |
| 2279 | } | |
| 2280 | fn c() E!*const f32 { | |
| 2281 | const x: u32 = 1; | |
| 2282 | return @ptrCast(&x); | |
| 2283 | } | |
| 2284 | ||
| 2285 | fn doTheTest() !void { | |
| 2286 | const ra = try a(); | |
| 2287 | const rb = try b(); | |
| 2288 | const rc = try c(); | |
| 2289 | ||
| 2290 | comptime assert(@TypeOf(ra) == MyEnum); | |
| 2291 | comptime assert(@TypeOf(rb) == u32); | |
| 2292 | comptime assert(@TypeOf(rc) == *const f32); | |
| 2293 | ||
| 2294 | try expect(@intFromEnum(ra) == 123); | |
| 2295 | try expect(rb == 42); | |
| 2296 | try expect(@as(*const u32, @ptrCast(rc)).* == 1); | |
| 2297 | } | |
| 2298 | }; | |
| 2299 | ||
| 2300 | try S.doTheTest(); | |
| 2301 | try comptime S.doTheTest(); | |
| 2302 | } | |
| 2303 | ||
| 2304 | test "cast builtins can wrap result in error union and optional" { | |
| 2305 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2306 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 2307 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 2308 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 2309 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 2310 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO | |
| 2311 | ||
| 2312 | const S = struct { | |
| 2313 | const MyEnum = enum(u32) { _ }; | |
| 2314 | const E = error{ImpossibleError}; | |
| 2315 | fn a() E!?MyEnum { | |
| 2316 | return @enumFromInt(123); | |
| 2317 | } | |
| 2318 | fn b() E!?u32 { | |
| 2319 | return @intFromFloat(42.50); | |
| 2320 | } | |
| 2321 | fn c() E!?*const f32 { | |
| 2322 | const x: u32 = 1; | |
| 2323 | return @ptrCast(&x); | |
| 2324 | } | |
| 2325 | ||
| 2326 | fn doTheTest() !void { | |
| 2327 | const ra = try a() orelse return error.ImpossibleError; | |
| 2328 | const rb = try b() orelse return error.ImpossibleError; | |
| 2329 | const rc = try c() orelse return error.ImpossibleError; | |
| 2330 | ||
| 2331 | comptime assert(@TypeOf(ra) == MyEnum); | |
| 2332 | comptime assert(@TypeOf(rb) == u32); | |
| 2333 | comptime assert(@TypeOf(rc) == *const f32); | |
| 2334 | ||
| 2335 | try expect(@intFromEnum(ra) == 123); | |
| 2336 | try expect(rb == 42); | |
| 2337 | try expect(@as(*const u32, @ptrCast(rc)).* == 1); | |
| 2338 | } | |
| 2339 | }; | |
| 2340 | ||
| 2341 | try S.doTheTest(); | |
| 2342 | try comptime S.doTheTest(); | |
| 2343 | } |
test/cases/compile_errors/cast_without_result_type.zig created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | export fn a() void { | |
| 2 | _ = @ptrFromInt(123); | |
| 3 | } | |
| 4 | export fn b() void { | |
| 5 | const x = @ptrCast(@alignCast(@as(*u8, undefined))); | |
| 6 | _ = x; | |
| 7 | } | |
| 8 | export fn c() void { | |
| 9 | _ = &@intCast(@as(u64, 123)); | |
| 10 | _ = S; | |
| 11 | } | |
| 12 | export fn d() void { | |
| 13 | var x: f32 = 0; | |
| 14 | _ = x + @floatFromInt(123); | |
| 15 | } | |
| 16 | ||
| 17 | // error | |
| 18 | // backend=stage2 | |
| 19 | // target=native | |
| 20 | // | |
| 21 | // :2:9: error: @ptrFromInt must have a known result type | |
| 22 | // :2:9: note: use @as to provide explicit result type | |
| 23 | // :5:15: error: @ptrCast must have a known result type | |
| 24 | // :5:15: note: use @as to provide explicit result type | |
| 25 | // :9:10: error: @intCast must have a known result type | |
| 26 | // :9:10: note: use @as to provide explicit result type | |
| 27 | // :14:13: error: @floatFromInt must have a known result type | |
| 28 | // :14:13: note: use @as to provide explicit result type |
test/cases/compile_errors/cast_without_result_type_due_to_generic_parameter.zig created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | export fn a() void { | |
| 2 | bar(@ptrFromInt(123)); | |
| 3 | } | |
| 4 | export fn b() void { | |
| 5 | bar(@ptrCast(@alignCast(@as(*u8, undefined)))); | |
| 6 | } | |
| 7 | export fn c() void { | |
| 8 | bar(@intCast(@as(u64, 123))); | |
| 9 | } | |
| 10 | export fn d() void { | |
| 11 | bar(@floatFromInt(123)); | |
| 12 | } | |
| 13 | ||
| 14 | fn bar(_: anytype) void {} | |
| 15 | ||
| 16 | // error | |
| 17 | // backend=stage2 | |
| 18 | // target=native | |
| 19 | // | |
| 20 | // :2:9: error: @ptrFromInt must have a known result type | |
| 21 | // :2:9: note: result type is unknown due to anytype parameter | |
| 22 | // :2:9: note: use @as to provide explicit result type | |
| 23 | // :5:9: error: @ptrCast must have a known result type | |
| 24 | // :5:9: note: result type is unknown due to anytype parameter | |
| 25 | // :5:9: note: use @as to provide explicit result type | |
| 26 | // :8:9: error: @intCast must have a known result type | |
| 27 | // :8:9: note: result type is unknown due to anytype parameter | |
| 28 | // :8:9: note: use @as to provide explicit result type | |
| 29 | // :11:9: error: @floatFromInt must have a known result type | |
| 30 | // :11:9: note: result type is unknown due to anytype parameter | |
| 31 | // :11:9: note: use @as to provide explicit result type |
test/cases/compile_errors/nested_ptr_cast_bad_operand.zig created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | const p: ?*const u8 = null; | |
| 2 | export fn a() void { | |
| 3 | _ = @as(*const u32, @ptrCast(@alignCast(p))); | |
| 4 | } | |
| 5 | export fn b() void { | |
| 6 | _ = @constCast(@volatileCast(123)); | |
| 7 | } | |
| 8 | export fn c() void { | |
| 9 | const x: ?*f32 = @constCast(@ptrCast(@addrSpaceCast(@volatileCast(p)))); | |
| 10 | _ = x; | |
| 11 | } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :3:45: error: null pointer casted to type '*const u32' | |
| 18 | // :6:34: error: expected pointer type, found 'comptime_int' | |
| 19 | // :9:22: error: cast increases pointer alignment | |
| 20 | // :9:71: note: '?*const u8' has alignment '1' | |
| 21 | // :9:22: note: '?*f32' has alignment '4' | |
| 22 | // :9:22: note: use @alignCast to assert pointer alignment |
test/cases/compile_errors/redundant_ptr_cast.zig created+19| ... | ... | @@ -0,0 +1,19 @@ |
| 1 | const p: *anyopaque = undefined; | |
| 2 | export fn a() void { | |
| 3 | _ = @ptrCast(@ptrCast(p)); | |
| 4 | } | |
| 5 | export fn b() void { | |
| 6 | const ptr1: *u32 = @alignCast(@ptrCast(@alignCast(p))); | |
| 7 | _ = ptr1; | |
| 8 | } | |
| 9 | export fn c() void { | |
| 10 | _ = @constCast(@alignCast(@ptrCast(@constCast(@volatileCast(p))))); | |
| 11 | } | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :3:18: error: redundant @ptrCast | |
| 18 | // :6:44: error: redundant @alignCast | |
| 19 | // :10:40: error: redundant @constCast |