| author | |
| committer | |
| log | b3aa1ab693ac160a07c44f07c7b90577039860a1 |
| tree | 6c5f4bf623b276963cec98ebbf713d2a752e9e01 |
| parent | db82c1b9820449f2d1e6ef54dd32ec3ffd3c583f |
| parent | 315d4e84425ddff888de8d464f657981e4c45da7 |
| signature |
stage2: `@TypeOf` improvements7 files changed, 158 insertions(+), 52 deletions(-)
src/AstGen.zig+41-15| ... | ... | @@ -2159,6 +2159,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2159 | 2159 | .negate, |
| 2160 | 2160 | .negate_wrap, |
| 2161 | 2161 | .typeof, |
| 2162 | .typeof_builtin, | |
| 2162 | 2163 | .xor, |
| 2163 | 2164 | .optional_type, |
| 2164 | 2165 | .optional_payload_safe, |
| ... | ... | @@ -6875,29 +6876,54 @@ fn typeOf( |
| 6875 | 6876 | scope: *Scope, |
| 6876 | 6877 | rl: ResultLoc, |
| 6877 | 6878 | node: Ast.Node.Index, |
| 6878 | params: []const Ast.Node.Index, | |
| 6879 | args: []const Ast.Node.Index, | |
| 6879 | 6880 | ) InnerError!Zir.Inst.Ref { |
| 6880 | if (params.len < 1) { | |
| 6881 | if (args.len < 1) { | |
| 6881 | 6882 | return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{}); |
| 6882 | 6883 | } |
| 6883 | if (params.len == 1) { | |
| 6884 | const expr_result = try reachableExpr(gz, scope, .none, params[0], node); | |
| 6885 | const result = try gz.addUnNode(.typeof, expr_result, node); | |
| 6886 | return rvalue(gz, rl, result, node); | |
| 6884 | const gpa = gz.astgen.gpa; | |
| 6885 | if (args.len == 1) { | |
| 6886 | const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node); | |
| 6887 | ||
| 6888 | var typeof_scope = gz.makeSubBlock(scope); | |
| 6889 | typeof_scope.force_comptime = false; | |
| 6890 | defer typeof_scope.unstack(); | |
| 6891 | ||
| 6892 | const ty_expr = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, args[0], node); | |
| 6893 | if (!gz.refIsNoReturn(ty_expr)) { | |
| 6894 | _ = try typeof_scope.addBreak(.break_inline, typeof_inst, ty_expr); | |
| 6895 | } | |
| 6896 | try typeof_scope.setBlockBody(typeof_inst); | |
| 6897 | ||
| 6898 | // typeof_scope unstacked now, can add new instructions to gz | |
| 6899 | try gz.instructions.append(gpa, typeof_inst); | |
| 6900 | return rvalue(gz, rl, indexToRef(typeof_inst), node); | |
| 6887 | 6901 | } |
| 6902 | const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len; | |
| 6903 | const payload_index = try reserveExtra(gz.astgen, payload_size + args.len); | |
| 6904 | var args_index = payload_index + payload_size; | |
| 6905 | ||
| 6906 | const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len); | |
| 6888 | 6907 | |
| 6889 | const payload_index = try addExtra(gz.astgen, Zir.Inst.NodeMultiOp{ | |
| 6908 | var typeof_scope = gz.makeSubBlock(scope); | |
| 6909 | typeof_scope.force_comptime = false; | |
| 6910 | ||
| 6911 | for (args) |arg, i| { | |
| 6912 | const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, arg, node); | |
| 6913 | gz.astgen.extra.items[args_index + i] = @enumToInt(param_ref); | |
| 6914 | } | |
| 6915 | _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value); | |
| 6916 | ||
| 6917 | const body = typeof_scope.instructionsSlice(); | |
| 6918 | gz.astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{ | |
| 6919 | .body_len = @intCast(u32, body.len), | |
| 6920 | .body_index = @intCast(u32, gz.astgen.extra.items.len), | |
| 6890 | 6921 | .src_node = gz.nodeIndexToRelative(node), |
| 6891 | 6922 | }); |
| 6892 | var extra_index = try reserveExtra(gz.astgen, params.len); | |
| 6893 | for (params) |param| { | |
| 6894 | const param_ref = try reachableExpr(gz, scope, .none, param, node); | |
| 6895 | gz.astgen.extra.items[extra_index] = @enumToInt(param_ref); | |
| 6896 | extra_index += 1; | |
| 6897 | } | |
| 6923 | try gz.astgen.extra.appendSlice(gpa, body); | |
| 6924 | typeof_scope.unstack(); | |
| 6898 | 6925 | |
| 6899 | const result = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, params.len); | |
| 6900 | return rvalue(gz, rl, result, node); | |
| 6926 | return rvalue(gz, rl, typeof_inst, node); | |
| 6901 | 6927 | } |
| 6902 | 6928 | |
| 6903 | 6929 | fn builtinCall( |
src/Sema.zig+46-3| ... | ... | @@ -124,6 +124,7 @@ pub const Block = struct { |
| 124 | 124 | runtime_index: u32 = 0, |
| 125 | 125 | |
| 126 | 126 | is_comptime: bool, |
| 127 | is_typeof: bool = false, | |
| 127 | 128 | |
| 128 | 129 | /// when null, it is determined by build mode, changed by @setRuntimeSafety |
| 129 | 130 | want_safety: ?bool = null, |
| ... | ... | @@ -181,6 +182,7 @@ pub const Block = struct { |
| 181 | 182 | .label = null, |
| 182 | 183 | .inlining = parent.inlining, |
| 183 | 184 | .is_comptime = parent.is_comptime, |
| 185 | .is_typeof = parent.is_typeof, | |
| 184 | 186 | .runtime_cond = parent.runtime_cond, |
| 185 | 187 | .runtime_loop = parent.runtime_loop, |
| 186 | 188 | .runtime_index = parent.runtime_index, |
| ... | ... | @@ -682,6 +684,7 @@ fn analyzeBodyInner( |
| 682 | 684 | .size_of => try sema.zirSizeOf(block, inst), |
| 683 | 685 | .bit_size_of => try sema.zirBitSizeOf(block, inst), |
| 684 | 686 | .typeof => try sema.zirTypeof(block, inst), |
| 687 | .typeof_builtin => try sema.zirTypeofBuiltin(block, inst), | |
| 685 | 688 | .log2_int_type => try sema.zirLog2IntType(block, inst), |
| 686 | 689 | .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), |
| 687 | 690 | .xor => try sema.zirBitwise(block, inst, .xor), |
| ... | ... | @@ -10574,6 +10577,29 @@ fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 10574 | 10577 | return sema.addType(operand_ty); |
| 10575 | 10578 | } |
| 10576 | 10579 | |
| 10580 | fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10581 | const pl_node = sema.code.instructions.items(.data)[inst].pl_node; | |
| 10582 | const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); | |
| 10583 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | |
| 10584 | ||
| 10585 | var child_block: Block = .{ | |
| 10586 | .parent = block, | |
| 10587 | .sema = sema, | |
| 10588 | .src_decl = block.src_decl, | |
| 10589 | .namespace = block.namespace, | |
| 10590 | .wip_capture_scope = block.wip_capture_scope, | |
| 10591 | .instructions = .{}, | |
| 10592 | .inlining = block.inlining, | |
| 10593 | .is_comptime = false, | |
| 10594 | .is_typeof = true, | |
| 10595 | }; | |
| 10596 | defer child_block.instructions.deinit(sema.gpa); | |
| 10597 | ||
| 10598 | const operand = try sema.resolveBody(&child_block, body, inst); | |
| 10599 | const operand_ty = sema.typeOf(operand); | |
| 10600 | return sema.addType(operand_ty); | |
| 10601 | } | |
| 10602 | ||
| 10577 | 10603 | fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10578 | 10604 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 10579 | 10605 | const src = inst_data.src(); |
| ... | ... | @@ -10624,8 +10650,24 @@ fn zirTypeofPeer( |
| 10624 | 10650 | const tracy = trace(@src()); |
| 10625 | 10651 | defer tracy.end(); |
| 10626 | 10652 | |
| 10627 | const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); | |
| 10653 | const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand); | |
| 10628 | 10654 | const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; |
| 10655 | const body = sema.code.extra[extra.data.body_index..][0..extra.data.body_len]; | |
| 10656 | ||
| 10657 | var child_block: Block = .{ | |
| 10658 | .parent = block, | |
| 10659 | .sema = sema, | |
| 10660 | .src_decl = block.src_decl, | |
| 10661 | .namespace = block.namespace, | |
| 10662 | .wip_capture_scope = block.wip_capture_scope, | |
| 10663 | .instructions = .{}, | |
| 10664 | .inlining = block.inlining, | |
| 10665 | .is_comptime = false, | |
| 10666 | .is_typeof = true, | |
| 10667 | }; | |
| 10668 | defer child_block.instructions.deinit(sema.gpa); | |
| 10669 | _ = try sema.analyzeBody(&child_block, body); | |
| 10670 | ||
| 10629 | 10671 | const args = sema.code.refSlice(extra.end, extended.small); |
| 10630 | 10672 | |
| 10631 | 10673 | const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len); |
| ... | ... | @@ -13385,7 +13427,7 @@ fn zirBuiltinExtern( |
| 13385 | 13427 | } |
| 13386 | 13428 | |
| 13387 | 13429 | fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void { |
| 13388 | if (sema.func == null) { | |
| 13430 | if (sema.func == null and !block.is_typeof) { | |
| 13389 | 13431 | return sema.fail(block, src, "instruction illegal outside function body", .{}); |
| 13390 | 13432 | } |
| 13391 | 13433 | } |
| ... | ... | @@ -14152,7 +14194,8 @@ fn fieldCallBind( |
| 14152 | 14194 | if (first_param_tag == .var_args_param or |
| 14153 | 14195 | first_param_tag == .generic_poison or ( |
| 14154 | 14196 | first_param_type.zigTypeTag() == .Pointer and |
| 14155 | first_param_type.ptrSize() == .One and | |
| 14197 | (first_param_type.ptrSize() == .One or | |
| 14198 | first_param_type.ptrSize() == .C) and | |
| 14156 | 14199 | first_param_type.childType().eql(concrete_ty))) |
| 14157 | 14200 | { |
| 14158 | 14201 | // zig fmt: on |
src/Zir.zig+11| ... | ... | @@ -547,6 +547,9 @@ pub const Inst = struct { |
| 547 | 547 | /// Returns the type of a value. |
| 548 | 548 | /// Uses the `un_node` field. |
| 549 | 549 | typeof, |
| 550 | /// Implements `@TypeOf` for one operand. | |
| 551 | /// Uses the `pl_node` field. | |
| 552 | typeof_builtin, | |
| 550 | 553 | /// Given a value, look at the type of it, which must be an integer type. |
| 551 | 554 | /// Returns the integer type for the RHS of a shift operation. |
| 552 | 555 | /// Uses the `un_node` field. |
| ... | ... | @@ -1067,6 +1070,7 @@ pub const Inst = struct { |
| 1067 | 1070 | .negate, |
| 1068 | 1071 | .negate_wrap, |
| 1069 | 1072 | .typeof, |
| 1073 | .typeof_builtin, | |
| 1070 | 1074 | .xor, |
| 1071 | 1075 | .optional_type, |
| 1072 | 1076 | .optional_payload_safe, |
| ... | ... | @@ -1429,6 +1433,7 @@ pub const Inst = struct { |
| 1429 | 1433 | .ptr_cast = .pl_node, |
| 1430 | 1434 | .truncate = .pl_node, |
| 1431 | 1435 | .align_cast = .pl_node, |
| 1436 | .typeof_builtin = .pl_node, | |
| 1432 | 1437 | |
| 1433 | 1438 | .has_decl = .pl_node, |
| 1434 | 1439 | .has_field = .pl_node, |
| ... | ... | @@ -2391,6 +2396,12 @@ pub const Inst = struct { |
| 2391 | 2396 | }; |
| 2392 | 2397 | }; |
| 2393 | 2398 | |
| 2399 | pub const TypeOfPeer = struct { | |
| 2400 | src_node: i32, | |
| 2401 | body_len: u32, | |
| 2402 | body_index: u32, | |
| 2403 | }; | |
| 2404 | ||
| 2394 | 2405 | pub const BuiltinCall = struct { |
| 2395 | 2406 | options: Ref, |
| 2396 | 2407 | callee: Ref, |
src/print_zir.zig+16-3| ... | ... | @@ -374,6 +374,7 @@ const Writer = struct { |
| 374 | 374 | .validate_array_init, |
| 375 | 375 | .validate_array_init_comptime, |
| 376 | 376 | .c_import, |
| 377 | .typeof_builtin, | |
| 377 | 378 | => try self.writePlNodeBlock(stream, inst), |
| 378 | 379 | |
| 379 | 380 | .condbr, |
| ... | ... | @@ -458,9 +459,8 @@ const Writer = struct { |
| 458 | 459 | .variable => try self.writeVarExtended(stream, extended), |
| 459 | 460 | .alloc => try self.writeAllocExtended(stream, extended), |
| 460 | 461 | |
| 461 | .compile_log, | |
| 462 | .typeof_peer, | |
| 463 | => try self.writeNodeMultiOp(stream, extended), | |
| 462 | .compile_log => try self.writeNodeMultiOp(stream, extended), | |
| 463 | .typeof_peer => try self.writeTypeofPeer(stream, extended), | |
| 464 | 464 | |
| 465 | 465 | .add_with_overflow, |
| 466 | 466 | .sub_with_overflow, |
| ... | ... | @@ -1966,6 +1966,19 @@ const Writer = struct { |
| 1966 | 1966 | try self.writeSrc(stream, src); |
| 1967 | 1967 | } |
| 1968 | 1968 | |
| 1969 | fn writeTypeofPeer(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { | |
| 1970 | const extra = self.code.extraData(Zir.Inst.TypeOfPeer, extended.operand); | |
| 1971 | const body = self.code.extra[extra.data.body_index..][0..extra.data.body_len]; | |
| 1972 | try self.writeBracedBody(stream, body); | |
| 1973 | try stream.writeAll(",["); | |
| 1974 | const args = self.code.refSlice(extra.end, extended.small); | |
| 1975 | for (args) |arg, i| { | |
| 1976 | if (i != 0) try stream.writeAll(", "); | |
| 1977 | try self.writeInstRef(stream, arg); | |
| 1978 | } | |
| 1979 | try stream.writeAll("])"); | |
| 1980 | } | |
| 1981 | ||
| 1969 | 1982 | fn writeBoolBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
| 1970 | 1983 | const inst_data = self.code.instructions.items(.data)[inst].bool_br; |
| 1971 | 1984 | const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
test/behavior.zig+2-2| ... | ... | @@ -38,6 +38,7 @@ test { |
| 38 | 38 | _ = @import("behavior/bugs/3112.zig"); |
| 39 | 39 | _ = @import("behavior/bugs/3367.zig"); |
| 40 | 40 | _ = @import("behavior/bugs/3586.zig"); |
| 41 | _ = @import("behavior/bugs/4328.zig"); | |
| 41 | 42 | _ = @import("behavior/bugs/4560.zig"); |
| 42 | 43 | _ = @import("behavior/bugs/4769_a.zig"); |
| 43 | 44 | _ = @import("behavior/bugs/4769_b.zig"); |
| ... | ... | @@ -102,6 +103,7 @@ test { |
| 102 | 103 | builtin.zig_backend != .stage2_wasm) |
| 103 | 104 | { |
| 104 | 105 | // Tests that pass for stage1, llvm backend, C backend |
| 106 | _ = @import("behavior/bugs/5474.zig"); | |
| 105 | 107 | _ = @import("behavior/bugs/9584.zig"); |
| 106 | 108 | _ = @import("behavior/bugs/10970.zig"); |
| 107 | 109 | _ = @import("behavior/cast_int.zig"); |
| ... | ... | @@ -149,10 +151,8 @@ test { |
| 149 | 151 | _ = @import("behavior/bugs/1851.zig"); |
| 150 | 152 | _ = @import("behavior/bugs/3384.zig"); |
| 151 | 153 | _ = @import("behavior/bugs/3779.zig"); |
| 152 | _ = @import("behavior/bugs/4328.zig"); | |
| 153 | 154 | _ = @import("behavior/bugs/5398.zig"); |
| 154 | 155 | _ = @import("behavior/bugs/5413.zig"); |
| 155 | _ = @import("behavior/bugs/5474.zig"); | |
| 156 | 156 | _ = @import("behavior/bugs/5487.zig"); |
| 157 | 157 | _ = @import("behavior/bugs/6456.zig"); |
| 158 | 158 | _ = @import("behavior/bugs/6781.zig"); |
test/behavior/bugs/4328.zig+16-7| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | const expectEqual = @import("std").testing.expectEqual; | |
| 1 | const expect = @import("std").testing.expect; | |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | const FILE = extern struct { |
| 4 | 5 | dummy_field: u8, |
| ... | ... | @@ -16,18 +17,20 @@ const S = extern struct { |
| 16 | 17 | }; |
| 17 | 18 | |
| 18 | 19 | test "Extern function calls in @TypeOf" { |
| 20 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 21 | ||
| 19 | 22 | const Test = struct { |
| 20 | 23 | fn test_fn_1(a: anytype, b: anytype) @TypeOf(printf("%d %s\n", a, b)) { |
| 21 | 24 | return 0; |
| 22 | 25 | } |
| 23 | 26 | |
| 24 | fn test_fn_2(a: anytype) @TypeOf((S{ .state = 0 }).s_do_thing(a)) { | |
| 27 | fn test_fn_2(s: anytype, a: anytype) @TypeOf(s.s_do_thing(a)) { | |
| 25 | 28 | return 1; |
| 26 | 29 | } |
| 27 | 30 | |
| 28 | 31 | fn doTheTest() !void { |
| 29 | try expectEqual(c_int, @TypeOf(test_fn_1(0, 42))); | |
| 30 | try expectEqual(c_short, @TypeOf(test_fn_2(0))); | |
| 32 | try expect(@TypeOf(test_fn_1(0, 42)) == c_int); | |
| 33 | try expect(@TypeOf(test_fn_2(&S{ .state = 1 }, 0)) == c_short); | |
| 31 | 34 | } |
| 32 | 35 | }; |
| 33 | 36 | |
| ... | ... | @@ -36,13 +39,15 @@ test "Extern function calls in @TypeOf" { |
| 36 | 39 | } |
| 37 | 40 | |
| 38 | 41 | test "Peer resolution of extern function calls in @TypeOf" { |
| 42 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 43 | ||
| 39 | 44 | const Test = struct { |
| 40 | 45 | fn test_fn() @TypeOf(ftell(null), fputs(null, null)) { |
| 41 | 46 | return 0; |
| 42 | 47 | } |
| 43 | 48 | |
| 44 | 49 | fn doTheTest() !void { |
| 45 | try expectEqual(c_long, @TypeOf(test_fn())); | |
| 50 | try expect(@TypeOf(test_fn()) == c_long); | |
| 46 | 51 | } |
| 47 | 52 | }; |
| 48 | 53 | |
| ... | ... | @@ -51,6 +56,10 @@ test "Peer resolution of extern function calls in @TypeOf" { |
| 51 | 56 | } |
| 52 | 57 | |
| 53 | 58 | test "Extern function calls, dereferences and field access in @TypeOf" { |
| 59 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 60 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 61 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 62 | ||
| 54 | 63 | const Test = struct { |
| 55 | 64 | fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) { |
| 56 | 65 | _ = a; |
| ... | ... | @@ -63,8 +72,8 @@ test "Extern function calls, dereferences and field access in @TypeOf" { |
| 63 | 72 | } |
| 64 | 73 | |
| 65 | 74 | fn doTheTest() !void { |
| 66 | try expectEqual(FILE, @TypeOf(test_fn_1(0))); | |
| 67 | try expectEqual(u8, @TypeOf(test_fn_2(0))); | |
| 75 | try expect(@TypeOf(test_fn_1(0)) == FILE); | |
| 76 | try expect(@TypeOf(test_fn_2(0)) == u8); | |
| 68 | 77 | } |
| 69 | 78 | }; |
| 70 | 79 |
test/behavior/bugs/5474.zig+26-22| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | // baseline (control) struct with array of scalar |
| 4 | 5 | const Box0 = struct { |
| ... | ... | @@ -25,33 +26,36 @@ const Box2 = struct { |
| 25 | 26 | }; |
| 26 | 27 | }; |
| 27 | 28 | |
| 28 | fn doTest() !void { | |
| 29 | // var | |
| 30 | { | |
| 31 | var box0: Box0 = .{ .items = undefined }; | |
| 32 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == false); | |
| 29 | fn mutable() !void { | |
| 30 | var box0: Box0 = .{ .items = undefined }; | |
| 31 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == false); | |
| 33 | 32 | |
| 34 | var box1: Box1 = .{ .items = undefined }; | |
| 35 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == false); | |
| 33 | var box1: Box1 = .{ .items = undefined }; | |
| 34 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == false); | |
| 36 | 35 | |
| 37 | var box2: Box2 = .{ .items = undefined }; | |
| 38 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == false); | |
| 39 | } | |
| 36 | var box2: Box2 = .{ .items = undefined }; | |
| 37 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == false); | |
| 38 | } | |
| 39 | ||
| 40 | fn constant() !void { | |
| 41 | const box0: Box0 = .{ .items = undefined }; | |
| 42 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == true); | |
| 40 | 43 | |
| 41 | // const | |
| 42 | { | |
| 43 | const box0: Box0 = .{ .items = undefined }; | |
| 44 | try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).Pointer.is_const == true); | |
| 44 | const box1: Box1 = .{ .items = undefined }; | |
| 45 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == true); | |
| 45 | 46 | |
| 46 | const box1: Box1 = .{ .items = undefined }; | |
| 47 | try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).Pointer.is_const == true); | |
| 47 | const box2: Box2 = .{ .items = undefined }; | |
| 48 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == true); | |
| 49 | } | |
| 48 | 50 | |
| 49 | const box2: Box2 = .{ .items = undefined }; | |
| 50 | try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).Pointer.is_const == true); | |
| 51 | } | |
| 51 | test "pointer-to-array constness for zero-size elements, var" { | |
| 52 | try mutable(); | |
| 53 | comptime try mutable(); | |
| 52 | 54 | } |
| 53 | 55 | |
| 54 | test "pointer-to-array constness for zero-size elements" { | |
| 55 | try doTest(); | |
| 56 | comptime try doTest(); | |
| 56 | test "pointer-to-array constness for zero-size elements, const" { | |
| 57 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 58 | ||
| 59 | try constant(); | |
| 60 | comptime try constant(); | |
| 57 | 61 | } |