authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-08 20:03:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-08 20:03:17-07:00
log7c1061784b8b126633cfe84f46280f7bf72beffc
treeeb99e5eb52d22b9f7d17cfd62dcfb19e3c26296a
parent210ee1067b06c14692432b7887077003e52b2137

stage2: fix inferred comptime constant locals

`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
20842084 .param_anytype_comptime,
20852085 .alloc,
20862086 .alloc_mut,
2087 .alloc_comptime,
2087 .alloc_comptime_mut,
20882088 .alloc_inferred,
20892089 .alloc_inferred_mut,
20902090 .alloc_inferred_comptime,
2091 .alloc_inferred_comptime_mut,
20912092 .array_cat,
20922093 .array_mul,
20932094 .array_type,
......@@ -2613,7 +2614,7 @@ fn varDecl(
26132614 .type_inst = type_inst,
26142615 .align_inst = align_inst,
26152616 .is_const = true,
2616 .is_comptime = false,
2617 .is_comptime = gz.force_comptime,
26172618 });
26182619 init_scope.instructions_top = gz.instructions.items.len;
26192620 }
......@@ -2621,14 +2622,18 @@ fn varDecl(
26212622 } else {
26222623 const alloc = if (align_inst == .none) alloc: {
26232624 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);
26252630 } else alloc: {
26262631 const ref = try gz.addAllocExtended(.{
26272632 .node = node,
26282633 .type_inst = .none,
26292634 .align_inst = align_inst,
26302635 .is_const = true,
2631 .is_comptime = false,
2636 .is_comptime = gz.force_comptime,
26322637 });
26332638 init_scope.instructions_top = gz.instructions.items.len;
26342639 break :alloc ref;
......@@ -2716,7 +2721,10 @@ fn varDecl(
27162721 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
27172722 const alloc = alloc: {
27182723 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;
27202728 break :alloc try gz.addUnNode(tag, type_inst, node);
27212729 } else {
27222730 break :alloc try gz.addAllocExtended(.{
......@@ -2732,7 +2740,10 @@ fn varDecl(
27322740 } else a: {
27332741 const alloc = alloc: {
27342742 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;
27362747 break :alloc try gz.addNode(tag, node);
27372748 } else {
27382749 break :alloc try gz.addAllocExtended(.{
......@@ -5441,7 +5452,7 @@ fn forExpr(
54415452 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
54425453
54435454 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;
54455456 const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node);
54465457 // initialize to zero
54475458 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize);
src/Sema.zig+13-7
......@@ -584,9 +584,10 @@ fn analyzeBodyInner(
584584 .alloc => try sema.zirAlloc(block, inst),
585585 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
586586 .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)),
588589 .alloc_mut => try sema.zirAllocMut(block, inst),
589 .alloc_comptime => try sema.zirAllocComptime(block, inst),
590 .alloc_comptime_mut => try sema.zirAllocComptime(block, inst),
590591 .anyframe_type => try sema.zirAnyframeType(block, inst),
591592 .array_cat => try sema.zirArrayCat(block, inst),
592593 .array_mul => try sema.zirArrayMul(block, inst),
......@@ -2368,12 +2369,16 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
23682369 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
23692370}
23702371
2371fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
2372fn zirAllocInferredComptime(
2373 sema: *Sema,
2374 inst: Zir.Inst.Index,
2375 inferred_alloc_ty: Type,
2376) CompileError!Air.Inst.Ref {
23722377 const src_node = sema.code.instructions.items(.data)[inst].node;
23732378 const src: LazySrcLoc = .{ .node_offset = src_node };
23742379 sema.src = src;
23752380 return sema.addConstant(
2376 Type.initTag(.inferred_alloc_mut),
2381 inferred_alloc_ty,
23772382 try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined),
23782383 );
23792384}
......@@ -2480,6 +2485,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
24802485 const final_elem_ty = try decl.ty.copy(sema.arena);
24812486 const final_ptr_ty = try Type.ptr(sema.arena, .{
24822487 .pointee_type = final_elem_ty,
2488 .mutable = var_is_mut,
24832489 .@"align" = iac.data.alignment,
24842490 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
24852491 });
......@@ -2500,9 +2506,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
25002506 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
25012507 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
25022508
2503 try sema.requireRuntimeBlock(block, src);
2504 try sema.resolveTypeLayout(block, ty_src, final_elem_ty);
2505
25062509 const final_ptr_ty = try Type.ptr(sema.arena, .{
25072510 .pointee_type = final_elem_ty,
25082511 .mutable = var_is_mut,
......@@ -2564,6 +2567,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
25642567 return;
25652568 }
25662569
2570 try sema.requireRuntimeBlock(block, src);
2571 try sema.resolveTypeLayout(block, ty_src, final_elem_ty);
2572
25672573 // Change it to a normal alloc.
25682574 sema.air_instructions.set(ptr_inst, .{
25692575 .tag = .alloc,
src/Zir.zig+10-4
......@@ -909,14 +909,18 @@ pub const Inst = struct {
909909 /// Allocates comptime-mutable memory.
910910 /// Uses the `un_node` union field. The operand is the type of the allocated object.
911911 /// The node source location points to a var decl node.
912 alloc_comptime,
912 alloc_comptime_mut,
913913 /// Same as `alloc` except the type is inferred.
914914 /// Uses the `node` union field.
915915 alloc_inferred,
916916 /// Same as `alloc_inferred` except mutable.
917917 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.
919921 alloc_inferred_comptime,
922 /// Same as `alloc_comptime_mut` except the type is inferred.
923 alloc_inferred_comptime_mut,
920924 /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
921925 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
922926 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
......@@ -957,10 +961,11 @@ pub const Inst = struct {
957961 .add_sat,
958962 .alloc,
959963 .alloc_mut,
960 .alloc_comptime,
964 .alloc_comptime_mut,
961965 .alloc_inferred,
962966 .alloc_inferred_mut,
963967 .alloc_inferred_comptime,
968 .alloc_inferred_comptime_mut,
964969 .array_cat,
965970 .array_mul,
966971 .array_type,
......@@ -1446,10 +1451,11 @@ pub const Inst = struct {
14461451
14471452 .alloc = .un_node,
14481453 .alloc_mut = .un_node,
1449 .alloc_comptime = .un_node,
1454 .alloc_comptime_mut = .un_node,
14501455 .alloc_inferred = .node,
14511456 .alloc_inferred_mut = .node,
14521457 .alloc_inferred_comptime = .node,
1458 .alloc_inferred_comptime_mut = .node,
14531459 .resolve_inferred_alloc = .un_node,
14541460
14551461 .@"resume" = .un_node,
src/print_zir.zig+2-1
......@@ -155,7 +155,7 @@ const Writer = struct {
155155
156156 .alloc,
157157 .alloc_mut,
158 .alloc_comptime,
158 .alloc_comptime_mut,
159159 .indexable_ptr_len,
160160 .anyframe_type,
161161 .bit_not,
......@@ -401,6 +401,7 @@ const Writer = struct {
401401 .alloc_inferred,
402402 .alloc_inferred_mut,
403403 .alloc_inferred_comptime,
404 .alloc_inferred_comptime_mut,
404405 => try self.writeNode(stream, inst),
405406
406407 .error_value,
test/behavior.zig-2
......@@ -105,7 +105,6 @@ test {
105105 _ = @import("behavior/math.zig");
106106 _ = @import("behavior/maximum_minimum.zig");
107107 _ = @import("behavior/merge_error_sets.zig");
108 _ = @import("behavior/null_llvm.zig");
109108 _ = @import("behavior/popcount.zig");
110109 _ = @import("behavior/saturating_arithmetic.zig");
111110 _ = @import("behavior/sizeof_and_typeof.zig");
......@@ -156,7 +155,6 @@ test {
156155 _ = @import("behavior/ir_block_deps.zig");
157156 _ = @import("behavior/misc.zig");
158157 _ = @import("behavior/muladd.zig");
159 _ = @import("behavior/null_stage1.zig");
160158 _ = @import("behavior/optional_stage1.zig");
161159 _ = @import("behavior/popcount_stage1.zig");
162160 _ = @import("behavior/reflection.zig");
test/behavior/null.zig+48
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
34
......@@ -140,3 +141,50 @@ const Particle = struct {
140141 c: u64,
141142 d: u64,
142143};
144
145test "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
153const SillyStruct = struct {
154 context: ?i32,
155};
156
157const here_is_a_null_literal = SillyStruct{ .context = null };
158
159test "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}
175const StructWithOptional = struct {
176 field: ?i32,
177};
178
179var struct_with_optional: StructWithOptional = undefined;
180
181test "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
188const StructWithOptionalType = struct {
189 t: ?type,
190};
test/behavior/null_llvm.zig deleted-36
......@@ -1,36 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "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
12const SillyStruct = struct {
13 context: ?i32,
14};
15
16const here_is_a_null_literal = SillyStruct{ .context = null };
17
18const StructWithOptional = struct {
19 field: ?i32,
20};
21
22var struct_with_optional: StructWithOptional = undefined;
23
24test "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 @@
1const expect = @import("std").testing.expect;
2
3test "if var maybe pointer" {
4 try expect(shouldBeAPlus1(Particle{
5 .a = 14,
6 .b = 1,
7 .c = 1,
8 .d = 1,
9 }) == 15);
10}
11fn 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}
21const Particle = struct {
22 a: u64,
23 b: u64,
24 c: u64,
25 d: u64,
26};
27
28test "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
35const StructWithOptionalType = struct {
36 t: ?type,
37};