| author | |
| committer | |
| log | 7c1061784b8b126633cfe84f46280f7bf72beffc |
| tree | eb99e5eb52d22b9f7d17cfd62dcfb19e3c26296a |
| parent | 210ee1067b06c14692432b7887077003e52b2137 |
`const` declarations inside comptime blocks were not getting properly
evaluated at compile-time. To accomplish this there is a new ZIR
instruction, `alloc_inferred_comptime`. Actually we already had one
named that, but it got renamed to `alloc_inferred_comptime_mut` to match
the naming convention with the other similar instructions.8 files changed, 91 insertions(+), 94 deletions(-)
src/AstGen.zig+18-7| ... | @@ -2084,10 +2084,11 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner | ... | @@ -2084,10 +2084,11 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2084 | .param_anytype_comptime, | 2084 | .param_anytype_comptime, |
| 2085 | .alloc, | 2085 | .alloc, |
| 2086 | .alloc_mut, | 2086 | .alloc_mut, |
| 2087 | .alloc_comptime, | 2087 | .alloc_comptime_mut, |
| 2088 | .alloc_inferred, | 2088 | .alloc_inferred, |
| 2089 | .alloc_inferred_mut, | 2089 | .alloc_inferred_mut, |
| 2090 | .alloc_inferred_comptime, | 2090 | .alloc_inferred_comptime, |
| 2091 | .alloc_inferred_comptime_mut, | ||
| 2091 | .array_cat, | 2092 | .array_cat, |
| 2092 | .array_mul, | 2093 | .array_mul, |
| 2093 | .array_type, | 2094 | .array_type, |
| ... | @@ -2613,7 +2614,7 @@ fn varDecl( | ... | @@ -2613,7 +2614,7 @@ fn varDecl( |
| 2613 | .type_inst = type_inst, | 2614 | .type_inst = type_inst, |
| 2614 | .align_inst = align_inst, | 2615 | .align_inst = align_inst, |
| 2615 | .is_const = true, | 2616 | .is_const = true, |
| 2616 | .is_comptime = false, | 2617 | .is_comptime = gz.force_comptime, |
| 2617 | }); | 2618 | }); |
| 2618 | init_scope.instructions_top = gz.instructions.items.len; | 2619 | init_scope.instructions_top = gz.instructions.items.len; |
| 2619 | } | 2620 | } |
| ... | @@ -2621,14 +2622,18 @@ fn varDecl( | ... | @@ -2621,14 +2622,18 @@ fn varDecl( |
| 2621 | } else { | 2622 | } else { |
| 2622 | const alloc = if (align_inst == .none) alloc: { | 2623 | const alloc = if (align_inst == .none) alloc: { |
| 2623 | init_scope.instructions_top = gz.instructions.items.len; | 2624 | init_scope.instructions_top = gz.instructions.items.len; |
| 2624 | break :alloc try init_scope.addNode(.alloc_inferred, node); | 2625 | const tag: Zir.Inst.Tag = if (gz.force_comptime) |
| 2626 | .alloc_inferred_comptime | ||
| 2627 | else | ||
| 2628 | .alloc_inferred; | ||
| 2629 | break :alloc try init_scope.addNode(tag, node); | ||
| 2625 | } else alloc: { | 2630 | } else alloc: { |
| 2626 | const ref = try gz.addAllocExtended(.{ | 2631 | const ref = try gz.addAllocExtended(.{ |
| 2627 | .node = node, | 2632 | .node = node, |
| 2628 | .type_inst = .none, | 2633 | .type_inst = .none, |
| 2629 | .align_inst = align_inst, | 2634 | .align_inst = align_inst, |
| 2630 | .is_const = true, | 2635 | .is_const = true, |
| 2631 | .is_comptime = false, | 2636 | .is_comptime = gz.force_comptime, |
| 2632 | }); | 2637 | }); |
| 2633 | init_scope.instructions_top = gz.instructions.items.len; | 2638 | init_scope.instructions_top = gz.instructions.items.len; |
| 2634 | break :alloc ref; | 2639 | break :alloc ref; |
| ... | @@ -2716,7 +2721,10 @@ fn varDecl( | ... | @@ -2716,7 +2721,10 @@ fn varDecl( |
| 2716 | const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); | 2721 | const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); |
| 2717 | const alloc = alloc: { | 2722 | const alloc = alloc: { |
| 2718 | if (align_inst == .none) { | 2723 | if (align_inst == .none) { |
| 2719 | const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut; | 2724 | const tag: Zir.Inst.Tag = if (is_comptime) |
| 2725 | .alloc_comptime_mut | ||
| 2726 | else | ||
| 2727 | .alloc_mut; | ||
| 2720 | break :alloc try gz.addUnNode(tag, type_inst, node); | 2728 | break :alloc try gz.addUnNode(tag, type_inst, node); |
| 2721 | } else { | 2729 | } else { |
| 2722 | break :alloc try gz.addAllocExtended(.{ | 2730 | break :alloc try gz.addAllocExtended(.{ |
| ... | @@ -2732,7 +2740,10 @@ fn varDecl( | ... | @@ -2732,7 +2740,10 @@ fn varDecl( |
| 2732 | } else a: { | 2740 | } else a: { |
| 2733 | const alloc = alloc: { | 2741 | const alloc = alloc: { |
| 2734 | if (align_inst == .none) { | 2742 | if (align_inst == .none) { |
| 2735 | const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut; | 2743 | const tag: Zir.Inst.Tag = if (is_comptime) |
| 2744 | .alloc_inferred_comptime_mut | ||
| 2745 | else | ||
| 2746 | .alloc_inferred_mut; | ||
| 2736 | break :alloc try gz.addNode(tag, node); | 2747 | break :alloc try gz.addNode(tag, node); |
| 2737 | } else { | 2748 | } else { |
| 2738 | break :alloc try gz.addAllocExtended(.{ | 2749 | break :alloc try gz.addAllocExtended(.{ |
| ... | @@ -5441,7 +5452,7 @@ fn forExpr( | ... | @@ -5441,7 +5452,7 @@ fn forExpr( |
| 5441 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); | 5452 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); |
| 5442 | 5453 | ||
| 5443 | const index_ptr = blk: { | 5454 | const index_ptr = blk: { |
| 5444 | const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime else .alloc; | 5455 | const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; |
| 5445 | const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); | 5456 | const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); |
| 5446 | // initialize to zero | 5457 | // initialize to zero |
| 5447 | _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); | 5458 | _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); |
src/Sema.zig+13-7| ... | @@ -584,9 +584,10 @@ fn analyzeBodyInner( | ... | @@ -584,9 +584,10 @@ fn analyzeBodyInner( |
| 584 | .alloc => try sema.zirAlloc(block, inst), | 584 | .alloc => try sema.zirAlloc(block, inst), |
| 585 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), | 585 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), |
| 586 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), | 586 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), |
| 587 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst), | 587 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_const)), |
| 588 | .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_mut)), | ||
| 588 | .alloc_mut => try sema.zirAllocMut(block, inst), | 589 | .alloc_mut => try sema.zirAllocMut(block, inst), |
| 589 | .alloc_comptime => try sema.zirAllocComptime(block, inst), | 590 | .alloc_comptime_mut => try sema.zirAllocComptime(block, inst), |
| 590 | .anyframe_type => try sema.zirAnyframeType(block, inst), | 591 | .anyframe_type => try sema.zirAnyframeType(block, inst), |
| 591 | .array_cat => try sema.zirArrayCat(block, inst), | 592 | .array_cat => try sema.zirArrayCat(block, inst), |
| 592 | .array_mul => try sema.zirArrayMul(block, inst), | 593 | .array_mul => try sema.zirArrayMul(block, inst), |
| ... | @@ -2368,12 +2369,16 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -2368,12 +2369,16 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 2368 | return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src); | 2369 | return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src); |
| 2369 | } | 2370 | } |
| 2370 | 2371 | ||
| 2371 | fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 2372 | fn zirAllocInferredComptime( |
| 2373 | sema: *Sema, | ||
| 2374 | inst: Zir.Inst.Index, | ||
| 2375 | inferred_alloc_ty: Type, | ||
| 2376 | ) CompileError!Air.Inst.Ref { | ||
| 2372 | const src_node = sema.code.instructions.items(.data)[inst].node; | 2377 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 2373 | const src: LazySrcLoc = .{ .node_offset = src_node }; | 2378 | const src: LazySrcLoc = .{ .node_offset = src_node }; |
| 2374 | sema.src = src; | 2379 | sema.src = src; |
| 2375 | return sema.addConstant( | 2380 | return sema.addConstant( |
| 2376 | Type.initTag(.inferred_alloc_mut), | 2381 | inferred_alloc_ty, |
| 2377 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined), | 2382 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined), |
| 2378 | ); | 2383 | ); |
| 2379 | } | 2384 | } |
| ... | @@ -2480,6 +2485,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -2480,6 +2485,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2480 | const final_elem_ty = try decl.ty.copy(sema.arena); | 2485 | const final_elem_ty = try decl.ty.copy(sema.arena); |
| 2481 | const final_ptr_ty = try Type.ptr(sema.arena, .{ | 2486 | const final_ptr_ty = try Type.ptr(sema.arena, .{ |
| 2482 | .pointee_type = final_elem_ty, | 2487 | .pointee_type = final_elem_ty, |
| 2488 | .mutable = var_is_mut, | ||
| 2483 | .@"align" = iac.data.alignment, | 2489 | .@"align" = iac.data.alignment, |
| 2484 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 2490 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 2485 | }); | 2491 | }); |
| ... | @@ -2500,9 +2506,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -2500,9 +2506,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2500 | const peer_inst_list = inferred_alloc.data.stored_inst_list.items; | 2506 | const peer_inst_list = inferred_alloc.data.stored_inst_list.items; |
| 2501 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); | 2507 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); |
| 2502 | 2508 | ||
| 2503 | try sema.requireRuntimeBlock(block, src); | ||
| 2504 | try sema.resolveTypeLayout(block, ty_src, final_elem_ty); | ||
| 2505 | |||
| 2506 | const final_ptr_ty = try Type.ptr(sema.arena, .{ | 2509 | const final_ptr_ty = try Type.ptr(sema.arena, .{ |
| 2507 | .pointee_type = final_elem_ty, | 2510 | .pointee_type = final_elem_ty, |
| 2508 | .mutable = var_is_mut, | 2511 | .mutable = var_is_mut, |
| ... | @@ -2564,6 +2567,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -2564,6 +2567,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2564 | return; | 2567 | return; |
| 2565 | } | 2568 | } |
| 2566 | 2569 | ||
| 2570 | try sema.requireRuntimeBlock(block, src); | ||
| 2571 | try sema.resolveTypeLayout(block, ty_src, final_elem_ty); | ||
| 2572 | |||
| 2567 | // Change it to a normal alloc. | 2573 | // Change it to a normal alloc. |
| 2568 | sema.air_instructions.set(ptr_inst, .{ | 2574 | sema.air_instructions.set(ptr_inst, .{ |
| 2569 | .tag = .alloc, | 2575 | .tag = .alloc, |
src/Zir.zig+10-4| ... | @@ -909,14 +909,18 @@ pub const Inst = struct { | ... | @@ -909,14 +909,18 @@ pub const Inst = struct { |
| 909 | /// Allocates comptime-mutable memory. | 909 | /// Allocates comptime-mutable memory. |
| 910 | /// Uses the `un_node` union field. The operand is the type of the allocated object. | 910 | /// Uses the `un_node` union field. The operand is the type of the allocated object. |
| 911 | /// The node source location points to a var decl node. | 911 | /// The node source location points to a var decl node. |
| 912 | alloc_comptime, | 912 | alloc_comptime_mut, |
| 913 | /// Same as `alloc` except the type is inferred. | 913 | /// Same as `alloc` except the type is inferred. |
| 914 | /// Uses the `node` union field. | 914 | /// Uses the `node` union field. |
| 915 | alloc_inferred, | 915 | alloc_inferred, |
| 916 | /// Same as `alloc_inferred` except mutable. | 916 | /// Same as `alloc_inferred` except mutable. |
| 917 | alloc_inferred_mut, | 917 | alloc_inferred_mut, |
| 918 | /// Same as `alloc_comptime` except the type is inferred. | 918 | /// Allocates comptime const memory. |
| 919 | /// Uses the `node` union field. The type of the allocated object is inferred. | ||
| 920 | /// The node source location points to a var decl node. | ||
| 919 | alloc_inferred_comptime, | 921 | alloc_inferred_comptime, |
| 922 | /// Same as `alloc_comptime_mut` except the type is inferred. | ||
| 923 | alloc_inferred_comptime_mut, | ||
| 920 | /// Each `store_to_inferred_ptr` puts the type of the stored value into a set, | 924 | /// Each `store_to_inferred_ptr` puts the type of the stored value into a set, |
| 921 | /// and then `resolve_inferred_alloc` triggers peer type resolution on the set. | 925 | /// and then `resolve_inferred_alloc` triggers peer type resolution on the set. |
| 922 | /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which | 926 | /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which |
| ... | @@ -957,10 +961,11 @@ pub const Inst = struct { | ... | @@ -957,10 +961,11 @@ pub const Inst = struct { |
| 957 | .add_sat, | 961 | .add_sat, |
| 958 | .alloc, | 962 | .alloc, |
| 959 | .alloc_mut, | 963 | .alloc_mut, |
| 960 | .alloc_comptime, | 964 | .alloc_comptime_mut, |
| 961 | .alloc_inferred, | 965 | .alloc_inferred, |
| 962 | .alloc_inferred_mut, | 966 | .alloc_inferred_mut, |
| 963 | .alloc_inferred_comptime, | 967 | .alloc_inferred_comptime, |
| 968 | .alloc_inferred_comptime_mut, | ||
| 964 | .array_cat, | 969 | .array_cat, |
| 965 | .array_mul, | 970 | .array_mul, |
| 966 | .array_type, | 971 | .array_type, |
| ... | @@ -1446,10 +1451,11 @@ pub const Inst = struct { | ... | @@ -1446,10 +1451,11 @@ pub const Inst = struct { |
| 1446 | 1451 | ||
| 1447 | .alloc = .un_node, | 1452 | .alloc = .un_node, |
| 1448 | .alloc_mut = .un_node, | 1453 | .alloc_mut = .un_node, |
| 1449 | .alloc_comptime = .un_node, | 1454 | .alloc_comptime_mut = .un_node, |
| 1450 | .alloc_inferred = .node, | 1455 | .alloc_inferred = .node, |
| 1451 | .alloc_inferred_mut = .node, | 1456 | .alloc_inferred_mut = .node, |
| 1452 | .alloc_inferred_comptime = .node, | 1457 | .alloc_inferred_comptime = .node, |
| 1458 | .alloc_inferred_comptime_mut = .node, | ||
| 1453 | .resolve_inferred_alloc = .un_node, | 1459 | .resolve_inferred_alloc = .un_node, |
| 1454 | 1460 | ||
| 1455 | .@"resume" = .un_node, | 1461 | .@"resume" = .un_node, |
src/print_zir.zig+2-1| ... | @@ -155,7 +155,7 @@ const Writer = struct { | ... | @@ -155,7 +155,7 @@ const Writer = struct { |
| 155 | 155 | ||
| 156 | .alloc, | 156 | .alloc, |
| 157 | .alloc_mut, | 157 | .alloc_mut, |
| 158 | .alloc_comptime, | 158 | .alloc_comptime_mut, |
| 159 | .indexable_ptr_len, | 159 | .indexable_ptr_len, |
| 160 | .anyframe_type, | 160 | .anyframe_type, |
| 161 | .bit_not, | 161 | .bit_not, |
| ... | @@ -401,6 +401,7 @@ const Writer = struct { | ... | @@ -401,6 +401,7 @@ const Writer = struct { |
| 401 | .alloc_inferred, | 401 | .alloc_inferred, |
| 402 | .alloc_inferred_mut, | 402 | .alloc_inferred_mut, |
| 403 | .alloc_inferred_comptime, | 403 | .alloc_inferred_comptime, |
| 404 | .alloc_inferred_comptime_mut, | ||
| 404 | => try self.writeNode(stream, inst), | 405 | => try self.writeNode(stream, inst), |
| 405 | 406 | ||
| 406 | .error_value, | 407 | .error_value, |
test/behavior.zig-2| ... | @@ -105,7 +105,6 @@ test { | ... | @@ -105,7 +105,6 @@ test { |
| 105 | _ = @import("behavior/math.zig"); | 105 | _ = @import("behavior/math.zig"); |
| 106 | _ = @import("behavior/maximum_minimum.zig"); | 106 | _ = @import("behavior/maximum_minimum.zig"); |
| 107 | _ = @import("behavior/merge_error_sets.zig"); | 107 | _ = @import("behavior/merge_error_sets.zig"); |
| 108 | _ = @import("behavior/null_llvm.zig"); | ||
| 109 | _ = @import("behavior/popcount.zig"); | 108 | _ = @import("behavior/popcount.zig"); |
| 110 | _ = @import("behavior/saturating_arithmetic.zig"); | 109 | _ = @import("behavior/saturating_arithmetic.zig"); |
| 111 | _ = @import("behavior/sizeof_and_typeof.zig"); | 110 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| ... | @@ -156,7 +155,6 @@ test { | ... | @@ -156,7 +155,6 @@ test { |
| 156 | _ = @import("behavior/ir_block_deps.zig"); | 155 | _ = @import("behavior/ir_block_deps.zig"); |
| 157 | _ = @import("behavior/misc.zig"); | 156 | _ = @import("behavior/misc.zig"); |
| 158 | _ = @import("behavior/muladd.zig"); | 157 | _ = @import("behavior/muladd.zig"); |
| 159 | _ = @import("behavior/null_stage1.zig"); | ||
| 160 | _ = @import("behavior/optional_stage1.zig"); | 158 | _ = @import("behavior/optional_stage1.zig"); |
| 161 | _ = @import("behavior/popcount_stage1.zig"); | 159 | _ = @import("behavior/popcount_stage1.zig"); |
| 162 | _ = @import("behavior/reflection.zig"); | 160 | _ = @import("behavior/reflection.zig"); |
test/behavior/null.zig+48| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("std"); | 2 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 3 | 4 | ||
| ... | @@ -140,3 +141,50 @@ const Particle = struct { | ... | @@ -140,3 +141,50 @@ const Particle = struct { |
| 140 | c: u64, | 141 | c: u64, |
| 141 | d: u64, | 142 | d: u64, |
| 142 | }; | 143 | }; |
| 144 | |||
| 145 | test "null literal outside function" { | ||
| 146 | const is_null = here_is_a_null_literal.context == null; | ||
| 147 | try expect(is_null); | ||
| 148 | |||
| 149 | const is_non_null = here_is_a_null_literal.context != null; | ||
| 150 | try expect(!is_non_null); | ||
| 151 | } | ||
| 152 | |||
| 153 | const SillyStruct = struct { | ||
| 154 | context: ?i32, | ||
| 155 | }; | ||
| 156 | |||
| 157 | const here_is_a_null_literal = SillyStruct{ .context = null }; | ||
| 158 | |||
| 159 | test "unwrap optional which is field of global var" { | ||
| 160 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 161 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 162 | |||
| 163 | struct_with_optional.field = null; | ||
| 164 | if (struct_with_optional.field) |payload| { | ||
| 165 | _ = payload; | ||
| 166 | unreachable; | ||
| 167 | } | ||
| 168 | struct_with_optional.field = 1234; | ||
| 169 | if (struct_with_optional.field) |payload| { | ||
| 170 | try expect(payload == 1234); | ||
| 171 | } else { | ||
| 172 | unreachable; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | const StructWithOptional = struct { | ||
| 176 | field: ?i32, | ||
| 177 | }; | ||
| 178 | |||
| 179 | var struct_with_optional: StructWithOptional = undefined; | ||
| 180 | |||
| 181 | test "optional types" { | ||
| 182 | comptime { | ||
| 183 | const opt_type_struct = StructWithOptionalType{ .t = u8 }; | ||
| 184 | try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | const StructWithOptionalType = struct { | ||
| 189 | t: ?type, | ||
| 190 | }; |
test/behavior/null_llvm.zig deleted-36| ... | @@ -1,36 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | test "null literal outside function" { | ||
| 5 | const is_null = here_is_a_null_literal.context == null; | ||
| 6 | try expect(is_null); | ||
| 7 | |||
| 8 | const is_non_null = here_is_a_null_literal.context != null; | ||
| 9 | try expect(!is_non_null); | ||
| 10 | } | ||
| 11 | |||
| 12 | const SillyStruct = struct { | ||
| 13 | context: ?i32, | ||
| 14 | }; | ||
| 15 | |||
| 16 | const here_is_a_null_literal = SillyStruct{ .context = null }; | ||
| 17 | |||
| 18 | const StructWithOptional = struct { | ||
| 19 | field: ?i32, | ||
| 20 | }; | ||
| 21 | |||
| 22 | var struct_with_optional: StructWithOptional = undefined; | ||
| 23 | |||
| 24 | test "unwrap optional which is field of global var" { | ||
| 25 | struct_with_optional.field = null; | ||
| 26 | if (struct_with_optional.field) |payload| { | ||
| 27 | _ = payload; | ||
| 28 | unreachable; | ||
| 29 | } | ||
| 30 | struct_with_optional.field = 1234; | ||
| 31 | if (struct_with_optional.field) |payload| { | ||
| 32 | try expect(payload == 1234); | ||
| 33 | } else { | ||
| 34 | unreachable; | ||
| 35 | } | ||
| 36 | } | ||
test/behavior/null_stage1.zig deleted-37| ... | @@ -1,37 +0,0 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "if var maybe pointer" { | ||
| 4 | try expect(shouldBeAPlus1(Particle{ | ||
| 5 | .a = 14, | ||
| 6 | .b = 1, | ||
| 7 | .c = 1, | ||
| 8 | .d = 1, | ||
| 9 | }) == 15); | ||
| 10 | } | ||
| 11 | fn shouldBeAPlus1(p: Particle) u64 { | ||
| 12 | var maybe_particle: ?Particle = p; | ||
| 13 | if (maybe_particle) |*particle| { | ||
| 14 | particle.a += 1; | ||
| 15 | } | ||
| 16 | if (maybe_particle) |particle| { | ||
| 17 | return particle.a; | ||
| 18 | } | ||
| 19 | return 0; | ||
| 20 | } | ||
| 21 | const Particle = struct { | ||
| 22 | a: u64, | ||
| 23 | b: u64, | ||
| 24 | c: u64, | ||
| 25 | d: u64, | ||
| 26 | }; | ||
| 27 | |||
| 28 | test "optional types" { | ||
| 29 | comptime { | ||
| 30 | const opt_type_struct = StructWithOptionalType{ .t = u8 }; | ||
| 31 | try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | const StructWithOptionalType = struct { | ||
| 36 | t: ?type, | ||
| 37 | }; | ||