authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 20:34:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 20:34:21-07:00
log8387307807434cf151d72a7dfb5b7da4863b2192
tree9795185b63245e1a820b1614858726f5ce494e56
parent7818586a2bc24252468977f8304d3c5b870a932a

AstGen: implement global variable decls


3 files changed, 154 insertions(+), 512 deletions(-)

BRANCH_TODO+52-496
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1 * get rid of failed_root_src_file1 * get rid of failed_root_src_file
2 * get rid of Scope.DeclRef
2 * handle decl collision with usingnamespace3 * handle decl collision with usingnamespace
3 * the decl doing the looking up needs to create a decl dependency4 * the decl doing the looking up needs to create a decl dependency
4 on each usingnamespace decl5 on each usingnamespace decl
...@@ -106,42 +107,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd...@@ -106,42 +107,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
106}107}
107108
108109
109 // Detect which source files changed.
110 for (module.import_table.items()) |entry| {
111 const file = entry.value;
112 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
113 defer f.close();
114
115 // TODO handle error here by populating a retryable compile error
116 const stat = try f.stat();
117 const unchanged_metadata =
118 stat.size == file.stat_size and
119 stat.mtime == file.stat_mtime and
120 stat.inode == file.stat_inode;
121
122 if (unchanged_metadata) {
123 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
124 continue;
125 }
126
127 log.debug("metadata changed: {s}", .{file.sub_file_path});
128 if (file.status == .unloaded_parse_failure) {
129 module.failed_files.swapRemove(file).?.value.destroy(module.gpa);
130 }
131
132 file.unload(module.gpa);
133 // TODO handle error here by populating a retryable compile error
134 try file.finishGettingSource(module.gpa, f, stat);
135
136 module.analyzeFile(file) catch |err| switch (err) {
137 error.OutOfMemory => return error.OutOfMemory,
138 error.AnalysisFail => continue,
139 else => |e| return e,
140 };
141 }
142
143
144
145 const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|110 const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|
146 pkg.namespace_hash111 pkg.namespace_hash
147 else112 else
...@@ -256,68 +221,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd...@@ -256,68 +221,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
256221
257222
258223
259pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
260 const tracy = trace(@src());
261 defer tracy.end();
262
263 if (file.tree_loaded) {
264 return &file.tree;
265 }
266
267 switch (file.status) {
268 .never_loaded, .success, .retryable_failure => {},
269 .parse_failure, .astgen_failure => return error.AnalysisFail,
270 }
271
272 switch (file.status) {
273 .never_loaded, .unloaded_success => {
274 const gpa = mod.gpa;
275
276 try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1);
277
278 const source = try file.getSource(gpa);
279
280 var keep_tree = false;
281 file.tree = try std.zig.parse(gpa, source);
282 defer if (!keep_tree) file.tree.deinit(gpa);
283
284 const tree = &file.tree;
285
286 if (tree.errors.len != 0) {
287 const parse_err = tree.errors[0];
288
289 var msg = std.ArrayList(u8).init(gpa);
290 defer msg.deinit();
291
292 const token_starts = tree.tokens.items(.start);
293
294 try tree.renderError(parse_err, msg.writer());
295 const err_msg = try gpa.create(ErrorMsg);
296 err_msg.* = .{
297 .src_loc = .{
298 .container = .{ .file_scope = file },
299 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
300 },
301 .msg = msg.toOwnedSlice(),
302 };
303
304 mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
305 file.status = .unloaded_parse_failure;
306 return error.AnalysisFail;
307 }
308
309 file.status = .success;
310 file.tree_loaded = true;
311 keep_tree = true;
312
313 return tree;
314 },
315
316 .unloaded_parse_failure => return error.AnalysisFail,
317
318 .success => return &file.tree,
319 }
320}
321224
322225
323226
...@@ -510,131 +413,6 @@ fn astgenAndSemaFn(...@@ -510,131 +413,6 @@ fn astgenAndSemaFn(
510 body_node: ast.Node.Index,413 body_node: ast.Node.Index,
511 fn_proto: ast.full.FnProto,414 fn_proto: ast.full.FnProto,
512) !bool {415) !bool {
513 var fn_type_sema: Sema = .{
514 .mod = mod,
515 .gpa = mod.gpa,
516 .arena = &decl_arena.allocator,
517 .code = fn_type_code,
518 .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len),
519 .owner_decl = decl,
520 .namespace = decl.namespace,
521 .func = null,
522 .owner_func = null,
523 .param_inst_list = &.{},
524 };
525 var block_scope: Scope.Block = .{
526 .parent = null,
527 .sema = &fn_type_sema,
528 .src_decl = decl,
529 .instructions = .{},
530 .inlining = null,
531 .is_comptime = true,
532 };
533 defer block_scope.instructions.deinit(mod.gpa);
534
535 const fn_type = try fn_type_sema.rootAsType(&block_scope);
536 if (body_node == 0) {
537 // Extern function.
538 var type_changed = true;
539 if (decl.typedValueManaged()) |tvm| {
540 type_changed = !tvm.typed_value.ty.eql(fn_type);
541
542 tvm.deinit(mod.gpa);
543 }
544 const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
545
546 decl_arena_state.* = decl_arena.state;
547 decl.typed_value = .{
548 .most_recent = .{
549 .typed_value = .{ .ty = fn_type, .val = fn_val },
550 .arena = decl_arena_state,
551 },
552 };
553 decl.analysis = .complete;
554 decl.generation = mod.generation;
555
556 try mod.comp.bin_file.allocateDeclIndexes(decl);
557 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
558
559 if (type_changed and mod.emit_h != null) {
560 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
561 }
562
563 return type_changed;
564 }
565
566 if (fn_type.fnIsVarArgs()) {
567 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
568 }
569
570 const new_func = try decl_arena.allocator.create(Fn);
571 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
572
573 const fn_zir: Zir = blk: {
574 // We put the ZIR inside the Decl arena.
575 var astgen = try AstGen.init(mod, decl, &decl_arena.allocator);
576 astgen.ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count);
577 defer astgen.deinit();
578
579 var gen_scope: Scope.GenZir = .{
580 .force_comptime = false,
581 .parent = &decl.namespace.base,
582 .astgen = &astgen,
583 };
584 defer gen_scope.instructions.deinit(mod.gpa);
585
586 // Iterate over the parameters. We put the param names as the first N
587 // items inside `extra` so that debug info later can refer to the parameter names
588 // even while the respective source code is unloaded.
589 try astgen.extra.ensureCapacity(mod.gpa, param_count);
590
591 var params_scope = &gen_scope.base;
592 var i: usize = 0;
593 var it = fn_proto.iterate(tree);
594 while (it.next()) |param| : (i += 1) {
595 const name_token = param.name_token.?;
596 const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);
597 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
598 sub_scope.* = .{
599 .parent = params_scope,
600 .gen_zir = &gen_scope,
601 .name = param_name,
602 // Implicit const list first, then implicit arg list.
603 .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
604 .src = decl.tokSrcLoc(name_token),
605 };
606 params_scope = &sub_scope.base;
607
608 // Additionally put the param name into `string_bytes` and reference it with
609 // `extra` so that we have access to the data in codegen, for debug info.
610 const str_index = @intCast(u32, astgen.string_bytes.items.len);
611 astgen.extra.appendAssumeCapacity(str_index);
612 const used_bytes = astgen.string_bytes.items.len;
613 try astgen.string_bytes.ensureCapacity(mod.gpa, used_bytes + param_name.len + 1);
614 astgen.string_bytes.appendSliceAssumeCapacity(param_name);
615 astgen.string_bytes.appendAssumeCapacity(0);
616 }
617
618 _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node);
619
620 if (gen_scope.instructions.items.len == 0 or
621 !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
622 .isNoReturn())
623 {
624 // astgen uses result location semantics to coerce return operands.
625 // Since we are adding the return instruction here, we must handle the coercion.
626 // We do this by using the `ret_coerce` instruction.
627 _ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
628 }
629
630 const code = try gen_scope.finish();
631 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
632 code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {};
633 }
634
635 break :blk code;
636 };
637
638 const is_inline = fn_type.fnCallingConvention() == .Inline;416 const is_inline = fn_type.fnCallingConvention() == .Inline;
639 const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;417 const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
640418
...@@ -716,264 +494,11 @@ fn astgenAndSemaVarDecl(...@@ -716,264 +494,11 @@ fn astgenAndSemaVarDecl(
716 tree: ast.Tree,494 tree: ast.Tree,
717 var_decl: ast.full.VarDecl,495 var_decl: ast.full.VarDecl,
718) !bool {496) !bool {
719 const tracy = trace(@src());
720 defer tracy.end();
721
722 decl.analysis = .in_progress;
723 decl.is_pub = var_decl.visib_token != null;
724
725 const token_tags = tree.tokens.items(.tag);497 const token_tags = tree.tokens.items(.tag);
726498
727 // We need the memory for the Type to go into the arena for the Decl
728 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
729 errdefer decl_arena.deinit();
730 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
731
732 // Used for simple error reporting.
733 var decl_scope: Scope.DeclRef = .{ .decl = decl };
734
735 const is_extern = blk: {
736 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
737 break :blk token_tags[maybe_extern_token] == .keyword_extern;
738 };
739
740 if (var_decl.lib_name) |lib_name| {
741 assert(is_extern);
742 return mod.failTok(&decl_scope.base, lib_name, "TODO implement function library name", .{});
743 }
744 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
745 const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: {
746 if (!is_mutable) {
747 return mod.failTok(&decl_scope.base, some, "threadlocal variable cannot be constant", .{});
748 }
749 break :blk true;
750 } else false;
751 assert(var_decl.comptime_token == null);
752 if (var_decl.ast.align_node != 0) {
753 return mod.failNode(
754 &decl_scope.base,
755 var_decl.ast.align_node,
756 "TODO implement function align expression",
757 .{},
758 );
759 }
760 if (var_decl.ast.section_node != 0) {
761 return mod.failNode(
762 &decl_scope.base,
763 var_decl.ast.section_node,
764 "TODO implement function section expression",
765 .{},
766 );
767 }
768
769 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
770 if (is_extern) {
771 return mod.failNode(
772 &decl_scope.base,
773 var_decl.ast.init_node,
774 "extern variables have no initializers",
775 .{},
776 );
777 }
778
779 var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
780 defer gen_scope_arena.deinit();
781
782 var astgen = try AstGen.init(mod, decl, &gen_scope_arena.allocator);
783 defer astgen.deinit();
784
785 var gen_scope: Scope.GenZir = .{
786 .force_comptime = true,
787 .parent = &decl.namespace.base,
788 .astgen = &astgen,
789 };
790 defer gen_scope.instructions.deinit(mod.gpa);
791
792 const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
793 .ty = try AstGen.expr(&gen_scope, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node),
794 } else .none;
795
796 const init_inst = try AstGen.comptimeExpr(
797 &gen_scope,
798 &gen_scope.base,
799 init_result_loc,
800 var_decl.ast.init_node,
801 );
802 _ = try gen_scope.addBreak(.break_inline, 0, init_inst);
803 var code = try gen_scope.finish();
804 defer code.deinit(mod.gpa);
805 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
806 code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
807 }
808
809 var sema: Sema = .{
810 .mod = mod,
811 .gpa = mod.gpa,
812 .arena = &gen_scope_arena.allocator,
813 .code = code,
814 .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
815 .owner_decl = decl,
816 .namespace = decl.namespace,
817 .func = null,
818 .owner_func = null,
819 .param_inst_list = &.{},
820 };
821 var block_scope: Scope.Block = .{
822 .parent = null,
823 .sema = &sema,
824 .src_decl = decl,
825 .instructions = .{},
826 .inlining = null,
827 .is_comptime = true,
828 };
829 defer block_scope.instructions.deinit(mod.gpa);
830
831 const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
832 // The result location guarantees the type coercion.
833 const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref);
834 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
835 const val = analyzed_init_inst.value().?;
836
837 break :vi .{
838 .ty = try analyzed_init_inst.ty.copy(&decl_arena.allocator),
839 .val = try val.copy(&decl_arena.allocator),
840 };
841 } else if (!is_extern) {
842 return mod.failTok(
843 &decl_scope.base,
844 var_decl.ast.mut_token,
845 "variables must be initialized",
846 .{},
847 );
848 } else if (var_decl.ast.type_node != 0) vi: {
849 var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
850 defer type_scope_arena.deinit();
851
852 var astgen = try AstGen.init(mod, decl, &type_scope_arena.allocator);
853 defer astgen.deinit();
854
855 var type_scope: Scope.GenZir = .{
856 .force_comptime = true,
857 .parent = &decl.namespace.base,
858 .astgen = &astgen,
859 };
860 defer type_scope.instructions.deinit(mod.gpa);
861
862 const var_type = try AstGen.typeExpr(&type_scope, &type_scope.base, var_decl.ast.type_node);
863 _ = try type_scope.addBreak(.break_inline, 0, var_type);
864
865 var code = try type_scope.finish();
866 defer code.deinit(mod.gpa);
867 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
868 code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
869 }
870
871 var sema: Sema = .{
872 .mod = mod,
873 .gpa = mod.gpa,
874 .arena = &type_scope_arena.allocator,
875 .code = code,
876 .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
877 .owner_decl = decl,
878 .namespace = decl.namespace,
879 .func = null,
880 .owner_func = null,
881 .param_inst_list = &.{},
882 };
883 var block_scope: Scope.Block = .{
884 .parent = null,
885 .sema = &sema,
886 .src_decl = decl,
887 .instructions = .{},
888 .inlining = null,
889 .is_comptime = true,
890 };
891 defer block_scope.instructions.deinit(mod.gpa);
892
893 const ty = try sema.rootAsType(&block_scope);
894
895 break :vi .{
896 .ty = try ty.copy(&decl_arena.allocator),
897 .val = null,
898 };
899 } else {
900 return mod.failTok(
901 &decl_scope.base,
902 var_decl.ast.mut_token,
903 "unable to infer variable type",
904 .{},
905 );
906 };
907
908 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
909 return mod.failTok(
910 &decl_scope.base,
911 var_decl.ast.mut_token,
912 "variable of type '{}' must be const",
913 .{var_info.ty},
914 );
915 }
916
917 var type_changed = true;
918 if (decl.typedValueManaged()) |tvm| {
919 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
920
921 tvm.deinit(mod.gpa);
922 }
923
924 const new_variable = try decl_arena.allocator.create(Var);
925 new_variable.* = .{
926 .owner_decl = decl,
927 .init = var_info.val orelse undefined,
928 .is_extern = is_extern,
929 .is_mutable = is_mutable,
930 .is_threadlocal = is_threadlocal,
931 };
932 const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
933
934 decl_arena_state.* = decl_arena.state;
935 decl.typed_value = .{
936 .most_recent = .{
937 .typed_value = .{
938 .ty = var_info.ty,
939 .val = var_val,
940 },
941 .arena = decl_arena_state,
942 },
943 };
944 decl.analysis = .complete;
945 decl.generation = mod.generation;
946
947 if (var_decl.extern_export_token) |maybe_export_token| {
948 if (token_tags[maybe_export_token] == .keyword_export) {
949 const export_src = decl.tokSrcLoc(maybe_export_token);
950 const name_token = var_decl.ast.mut_token + 1;
951 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
952 // The scope needs to have the decl in it.
953 try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
954 }
955 }
956 return type_changed;
957}499}
958500
959501
960/// Call `deinit` on the result.
961pub fn init(mod: *Module, decl: *Decl, arena: *Allocator) !AstGen {
962 var astgen: AstGen = .{
963 .mod = mod,
964 .decl = decl,
965 .arena = arena,
966 };
967 // Must be a block instruction at index 0 with the root body.
968 try astgen.instructions.append(mod.gpa, .{
969 .tag = .block,
970 .data = .{ .pl_node = .{
971 .src_node = 0,
972 .payload_index = undefined,
973 } },
974 });
975 return astgen;
976}
977 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.502 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
978 pub fn tree(scope: *Scope) *const ast.Tree {503 pub fn tree(scope: *Scope) *const ast.Tree {
979 switch (scope.tag) {504 switch (scope.tag) {
...@@ -1181,26 +706,6 @@ fn errorSetDecl(...@@ -1181,26 +706,6 @@ fn errorSetDecl(
1181}706}
1182707
1183708
1184/// The string is stored in `arena` regardless of whether it uses @"" syntax.
1185pub fn identifierTokenStringTreeArena(
1186 astgen: *AstGen,
1187 token: ast.TokenIndex,
1188 tree: *const ast.Tree,
1189 arena: *Allocator,
1190) InnerError![]u8 {
1191 const token_tags = tree.tokens.items(.tag);
1192 assert(token_tags[token] == .identifier);
1193 const ident_name = tree.tokenSlice(token);
1194 if (!mem.startsWith(u8, ident_name, "@")) {
1195 return arena.dupe(u8, ident_name);
1196 }
1197 var buf: ArrayListUnmanaged(u8) = .{};
1198 defer buf.deinit(astgen.gpa);
1199 try astgen.parseStrLit(token, &buf, ident_name, 1);
1200 return arena.dupe(u8, buf.items);
1201}
1202
1203
1204709
1205 if (mod.lookupIdentifier(scope, ident_name)) |decl| {710 if (mod.lookupIdentifier(scope, ident_name)) |decl| {
1206 const msg = msg: {711 const msg = msg: {
...@@ -1217,3 +722,54 @@ pub fn identifierTokenStringTreeArena(...@@ -1217,3 +722,54 @@ pub fn identifierTokenStringTreeArena(
1217 return mod.failWithOwnedErrorMsg(scope, msg);722 return mod.failWithOwnedErrorMsg(scope, msg);
1218 }723 }
1219724
725
726 var type_changed = true;
727 if (decl.typedValueManaged()) |tvm| {
728 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
729
730 tvm.deinit(mod.gpa);
731 }
732
733 const new_variable = try decl_arena.allocator.create(Var);
734 new_variable.* = .{
735 .owner_decl = decl,
736 .init = var_info.val orelse undefined,
737 .is_extern = is_extern,
738 .is_mutable = is_mutable,
739 .is_threadlocal = is_threadlocal,
740 };
741 const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
742
743 decl_arena_state.* = decl_arena.state;
744 decl.typed_value = .{
745 .most_recent = .{
746 .typed_value = .{
747 .ty = var_info.ty,
748 .val = var_val,
749 },
750 .arena = decl_arena_state,
751 },
752 };
753 decl.analysis = .complete;
754 decl.generation = mod.generation;
755
756
757
758 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
759 return mod.failTok(
760 &decl_scope.base,
761 var_decl.ast.mut_token,
762 "variable of type '{}' must be const",
763 .{var_info.ty},
764 );
765 }
766
767 if (var_decl.extern_export_token) |maybe_export_token| {
768 if (token_tags[maybe_export_token] == .keyword_export) {
769 const export_src = decl.tokSrcLoc(maybe_export_token);
770 const name_token = var_decl.ast.mut_token + 1;
771 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
772 // The scope needs to have the decl in it.
773 try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
774 }
775 }
src/AstGen.zig+96-15
...@@ -1491,7 +1491,7 @@ fn varDecl(...@@ -1491,7 +1491,7 @@ fn varDecl(
1491 }1491 }
14921492
1493 if (var_decl.ast.init_node == 0) {1493 if (var_decl.ast.init_node == 0) {
1494 return astgen.failTok(name_token, "variables must be initialized", .{});1494 return astgen.failNode(node, "variables must be initialized", .{});
1495 }1495 }
14961496
1497 switch (token_tags[var_decl.ast.mut_token]) {1497 switch (token_tags[var_decl.ast.mut_token]) {
...@@ -1851,10 +1851,12 @@ fn fnDecl(...@@ -1851,10 +1851,12 @@ fn fnDecl(
18511851
1852 const is_pub = fn_proto.visib_token != null;1852 const is_pub = fn_proto.visib_token != null;
1853 const is_export = blk: {1853 const is_export = blk: {
1854 if (fn_proto.extern_export_token) |maybe_export_token| {1854 const maybe_export_token = fn_proto.extern_export_token orelse break :blk false;
1855 break :blk token_tags[maybe_export_token] == .keyword_export;1855 break :blk token_tags[maybe_export_token] == .keyword_export;
1856 }1856 };
1857 break :blk false;1857 const is_extern = blk: {
1858 const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false;
1859 break :blk token_tags[maybe_extern_token] == .keyword_extern;
1858 };1860 };
1859 if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) {1861 if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) {
1860 try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);1862 try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
...@@ -1937,11 +1939,6 @@ fn fnDecl(...@@ -1937,11 +1939,6 @@ fn fnDecl(
1937 fn_proto.ast.return_type,1939 fn_proto.ast.return_type,
1938 );1940 );
19391941
1940 const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
1941 token_tags[maybe_export_token] == .keyword_extern
1942 else
1943 false;
1944
1945 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)1942 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
1946 // TODO instead of enum literal type, this needs to be the1943 // TODO instead of enum literal type, this needs to be the
1947 // std.builtin.CallingConvention enum. We need to implement importing other files1944 // std.builtin.CallingConvention enum. We need to implement importing other files
...@@ -2070,10 +2067,94 @@ fn fnDecl(...@@ -2070,10 +2067,94 @@ fn fnDecl(
2070fn globalVarDecl(2067fn globalVarDecl(
2071 astgen: *AstGen,2068 astgen: *AstGen,
2072 gz: *GenZir,2069 gz: *GenZir,
2070 scope: *Scope,
2073 wip_decls: *WipDecls,2071 wip_decls: *WipDecls,
2072 node: ast.Node.Index,
2074 var_decl: ast.full.VarDecl,2073 var_decl: ast.full.VarDecl,
2075) InnerError!void {2074) InnerError!void {
2076 @panic("TODO astgen globalVarDecl");2075 const gpa = astgen.gpa;
2076 const tree = &astgen.file.tree;
2077 const token_tags = tree.tokens.items(.tag);
2078
2079 const is_pub = var_decl.visib_token != null;
2080 const is_export = blk: {
2081 const maybe_export_token = var_decl.extern_export_token orelse break :blk false;
2082 break :blk token_tags[maybe_export_token] == .keyword_export;
2083 };
2084 const is_extern = blk: {
2085 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
2086 break :blk token_tags[maybe_extern_token] == .keyword_extern;
2087 };
2088 if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) {
2089 try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
2090 wip_decls.cur_bit_bag = 0;
2091 }
2092 wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> 2) |
2093 (@as(u32, @boolToInt(is_pub)) << 30) |
2094 (@as(u32, @boolToInt(is_export)) << 31);
2095 wip_decls.decl_index += 1;
2096
2097 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
2098 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
2099 if (!is_mutable) {
2100 return astgen.failTok(tok, "threadlocal variable cannot be constant", .{});
2101 }
2102 break :blk true;
2103 } else false;
2104
2105 const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: {
2106 const lib_name_str = try gz.strLitAsString(lib_name_token);
2107 break :blk lib_name_str.index;
2108 } else 0;
2109
2110 assert(var_decl.comptime_token == null); // handled by parser
2111 if (var_decl.ast.align_node != 0) {
2112 return astgen.failNode(var_decl.ast.align_node, "TODO implement alignment on globals", .{});
2113 }
2114 if (var_decl.ast.section_node != 0) {
2115 return astgen.failNode(var_decl.ast.section_node, "TODO linksection on globals", .{});
2116 }
2117
2118 const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: {
2119 if (is_extern) {
2120 return astgen.failNode(
2121 var_decl.ast.init_node,
2122 "extern variables have no initializers",
2123 .{},
2124 );
2125 }
2126
2127 const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
2128 .ty = try expr(gz, scope, .{ .ty = .type_type }, var_decl.ast.type_node),
2129 } else .none;
2130
2131 const init_inst = try expr(gz, scope, init_result_loc, var_decl.ast.init_node);
2132
2133 if (!is_mutable) {
2134 // const globals are just their instruction. mutable globals have
2135 // a special ZIR form.
2136 break :vi init_inst;
2137 }
2138
2139 @panic("TODO astgen global variable");
2140 } else if (!is_extern) {
2141 return astgen.failNode(node, "variables must be initialized", .{});
2142 } else if (var_decl.ast.type_node != 0) {
2143 // Extern variable which has an explicit type.
2144
2145 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
2146
2147 @panic("TODO AstGen extern global variable");
2148 } else {
2149 return astgen.failNode(node, "unable to infer variable type", .{});
2150 };
2151
2152 const name_token = var_decl.ast.mut_token + 1;
2153 const name_str_index = try gz.identAsString(name_token);
2154
2155 try wip_decls.name_and_value.ensureCapacity(gpa, wip_decls.name_and_value.items.len + 2);
2156 wip_decls.name_and_value.appendAssumeCapacity(name_str_index);
2157 wip_decls.name_and_value.appendAssumeCapacity(@enumToInt(var_inst));
2077}2158}
20782159
2079fn comptimeDecl(2160fn comptimeDecl(
...@@ -2191,19 +2272,19 @@ fn structDeclInner(...@@ -2191,19 +2272,19 @@ fn structDeclInner(
2191 },2272 },
21922273
2193 .global_var_decl => {2274 .global_var_decl => {
2194 try astgen.globalVarDecl(gz, &wip_decls, tree.globalVarDecl(member_node));2275 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node));
2195 continue;2276 continue;
2196 },2277 },
2197 .local_var_decl => {2278 .local_var_decl => {
2198 try astgen.globalVarDecl(gz, &wip_decls, tree.localVarDecl(member_node));2279 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node));
2199 continue;2280 continue;
2200 },2281 },
2201 .simple_var_decl => {2282 .simple_var_decl => {
2202 try astgen.globalVarDecl(gz, &wip_decls, tree.simpleVarDecl(member_node));2283 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node));
2203 continue;2284 continue;
2204 },2285 },
2205 .aligned_var_decl => {2286 .aligned_var_decl => {
2206 try astgen.globalVarDecl(gz, &wip_decls, tree.alignedVarDecl(member_node));2287 try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node));
2207 continue;2288 continue;
2208 },2289 },
22092290
src/Module.zig+6-1
...@@ -2457,6 +2457,9 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {...@@ -2457,6 +2457,9 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
2457}2457}
24582458
2459pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {2459pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {
2460 const tracy = trace(@src());
2461 defer tracy.end();
2462
2460 const comp = mod.comp;2463 const comp = mod.comp;
2461 const gpa = mod.gpa;2464 const gpa = mod.gpa;
24622465
...@@ -2468,7 +2471,9 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2468,7 +2471,9 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
24682471
2469 // Determine whether we need to reload the file from disk and redo parsing and AstGen.2472 // Determine whether we need to reload the file from disk and redo parsing and AstGen.
2470 switch (file.status) {2473 switch (file.status) {
2471 .never_loaded, .retryable_failure => {},2474 .never_loaded, .retryable_failure => {
2475 log.debug("first-time AstGen: {s}", .{file.sub_file_path});
2476 },
2472 .parse_failure, .astgen_failure, .success => {2477 .parse_failure, .astgen_failure, .success => {
2473 const unchanged_metadata =2478 const unchanged_metadata =
2474 stat.size == file.stat_size and2479 stat.size == file.stat_size and