authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-08 11:29:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-08 11:29:31-07:00
logb9e508c410cd077d704a73418281f6d7839df241
tree1ec79de1aebed48460a5e87170a7cbbce99c0dcd
parenta483e38df62f73dc0cdadee6faf3e083094210d4

stage2: revert to only has_decl and export ZIR support

Reverting most of the code from the previous commits in this branch. Will pull in the code with modifications bit by bit.

7 files changed, 73 insertions(+), 158 deletions(-)

src/AstGen.zig+6-4
......@@ -4149,12 +4149,14 @@ fn builtinCall(
41494149 },
41504150
41514151 .@"export" => {
4152 const target_fn = try expr(gz, scope, .none, params[0]);
4153 // FIXME: When structs work in stage2, actually implement this correctly!
4154 // Currently the name is always signifies Strong linkage.
4152 // TODO: @export is supposed to be able to export things other than functions.
4153 // Instead of `comptimeExpr` here we need `decl_ref`.
4154 const fn_to_export = try comptimeExpr(gz, scope, .none, params[0]);
4155 // TODO: the second parameter here is supposed to be
4156 // `std.builtin.ExportOptions`, not a string.
41554157 const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
41564158 _ = try gz.addPlNode(.@"export", node, zir.Inst.Bin{
4157 .lhs = target_fn,
4159 .lhs = fn_to_export,
41584160 .rhs = export_name,
41594161 });
41604162 return rvalue(gz, scope, rl, .void_value, node);
src/Compilation.zig+35-75
......@@ -510,11 +510,11 @@ pub const InitOptions = struct {
510510fn addPackageTableToCacheHash(
511511 hash: *Cache.HashHelper,
512512 arena: *std.heap.ArenaAllocator,
513 package: *Package,
513 pkg_table: Package.Table,
514514 hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
515515) (error{OutOfMemory} || std.os.GetCwdError)!void {
516516 const allocator = &arena.allocator;
517 const pkg_table = package.table;
517
518518 const packages = try allocator.alloc(Package.Table.Entry, pkg_table.count());
519519 {
520520 // Copy over the hashmap entries to our slice
......@@ -547,8 +547,7 @@ fn addPackageTableToCacheHash(
547547 },
548548 }
549549 // Recurse to handle the package's dependencies
550 if (package != pkg.value)
551 try addPackageTableToCacheHash(hash, arena, pkg.value, hash_type);
550 try addPackageTableToCacheHash(hash, arena, pkg.value.table, hash_type);
552551 }
553552}
554553
......@@ -886,7 +885,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
886885 {
887886 var local_arena = std.heap.ArenaAllocator.init(gpa);
888887 defer local_arena.deinit();
889 try addPackageTableToCacheHash(&hash, &local_arena, root_pkg, .path_bytes);
888 try addPackageTableToCacheHash(&hash, &local_arena, root_pkg.table, .path_bytes);
890889 }
891890 hash.add(valgrind);
892891 hash.add(single_threaded);
......@@ -907,46 +906,38 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
907906 artifact_sub_dir,
908907 };
909908
910 const builtin_pkg = try Package.create(gpa, zig_cache_artifact_directory.path.?, "builtin2.zig");
911
912 const std_dir_path = try options.zig_lib_directory.join(gpa, &[_][]const u8{"std"});
913 defer gpa.free(std_dir_path);
914 const start_pkg = try Package.create(gpa, std_dir_path, "start2.zig");
915
916 try root_pkg.add(gpa, "builtin", builtin_pkg);
917 try root_pkg.add(gpa, "root", root_pkg);
918
919 try start_pkg.add(gpa, "builtin", builtin_pkg);
920 try start_pkg.add(gpa, "root", root_pkg);
921
922909 // TODO when we implement serialization and deserialization of incremental compilation metadata,
923910 // this is where we would load it. We have open a handle to the directory where
924911 // the output either already is, or will be.
925912 // However we currently do not have serialization of such metadata, so for now
926913 // we set up an empty Module that does the entire compilation fresh.
927914
928 if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) return error.ZirFilesUnsupported;
929
930 const start_scope = ss: {
931 const start_scope = try gpa.create(Module.Scope.File);
932 const struct_ty = try Type.Tag.empty_struct.create(
933 gpa,
934 &start_scope.root_container,
935 );
936 start_scope.* = .{
937 // TODO this is duped so it can be freed in Container.deinit
938 .sub_file_path = try gpa.dupe(u8, start_pkg.root_src_path),
939 .source = .{ .unloaded = {} },
940 .tree = undefined,
941 .status = .never_loaded,
942 .pkg = start_pkg,
943 .root_container = .{
944 .file_scope = start_scope,
945 .decls = .{},
946 .ty = struct_ty,
947 },
948 };
949 break :ss start_scope;
915 const root_scope = rs: {
916 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
917 const root_scope = try gpa.create(Module.Scope.File);
918 const struct_ty = try Type.Tag.empty_struct.create(
919 gpa,
920 &root_scope.root_container,
921 );
922 root_scope.* = .{
923 // TODO this is duped so it can be freed in Container.deinit
924 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
925 .source = .{ .unloaded = {} },
926 .tree = undefined,
927 .status = .never_loaded,
928 .pkg = root_pkg,
929 .root_container = .{
930 .file_scope = root_scope,
931 .decls = .{},
932 .ty = struct_ty,
933 },
934 };
935 break :rs root_scope;
936 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
937 return error.ZirFilesUnsupported;
938 } else {
939 unreachable;
940 }
950941 };
951942
952943 const module = try arena.create(Module);
......@@ -955,9 +946,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
955946 .gpa = gpa,
956947 .comp = comp,
957948 .root_pkg = root_pkg,
958 .root_scope = null,
959 .start_pkg = start_pkg,
960 .start_scope = start_scope,
949 .root_scope = root_scope,
961950 .zig_cache_artifact_directory = zig_cache_artifact_directory,
962951 .emit_h = options.emit_h,
963952 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),
......@@ -1359,9 +1348,9 @@ pub fn update(self: *Compilation) !void {
13591348 // TODO Detect which source files changed.
13601349 // Until then we simulate a full cache miss. Source files could have been loaded
13611350 // for any reason; to force a refresh we unload now.
1362 module.unloadFile(module.start_scope);
1351 module.unloadFile(module.root_scope);
13631352 module.failed_root_src_file = null;
1364 module.analyzeContainer(&module.start_scope.root_container) catch |err| switch (err) {
1353 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
13651354 error.AnalysisFail => {
13661355 assert(self.totalErrorCount() != 0);
13671356 },
......@@ -1422,7 +1411,7 @@ pub fn update(self: *Compilation) !void {
14221411 // to report error messages. Otherwise we unload all source files to save memory.
14231412 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
14241413 if (self.bin_file.options.module) |module| {
1425 module.start_scope.unload(self.gpa);
1414 module.root_scope.unload(self.gpa);
14261415 }
14271416 }
14281417}
......@@ -2833,11 +2822,6 @@ fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) !void {
28332822 const source = try comp.generateBuiltinZigSource(comp.gpa);
28342823 defer comp.gpa.free(source);
28352824 try mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source);
2836
2837 // FIXME: Remove builtin2.zig when stage2 can correctly generate code for builtin.zig!
2838 const source2 = try comp.generateBuiltin2ZigSource(comp.gpa);
2839 defer comp.gpa.free(source2);
2840 try mod.zig_cache_artifact_directory.handle.writeFile("builtin2.zig", source2);
28412825}
28422826
28432827pub fn dump_argv(argv: []const []const u8) void {
......@@ -2847,30 +2831,6 @@ pub fn dump_argv(argv: []const []const u8) void {
28472831 std.debug.print("{s}\n", .{argv[argv.len - 1]});
28482832}
28492833
2850fn generateBuiltin2ZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
2851 var buffer = std.ArrayList(u8).init(allocator);
2852 defer buffer.deinit();
2853
2854 const target = comp.getTarget();
2855
2856 try buffer.writer().print(
2857 \\pub const link_libc = {};
2858 \\pub const arch = {};
2859 \\pub const os = {};
2860 \\pub const output_mode = {};
2861 \\pub const object_format = {};
2862 \\
2863 , .{
2864 comp.bin_file.options.link_libc,
2865 @enumToInt(target.cpu.arch),
2866 @enumToInt(target.os.tag),
2867 @enumToInt(comp.bin_file.options.output_mode),
2868 @enumToInt(comp.bin_file.options.object_format),
2869 });
2870
2871 return buffer.toOwnedSlice();
2872}
2873
28742834pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
28752835 const tracy = trace(@src());
28762836 defer tracy.end();
......@@ -3215,7 +3175,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
32153175 {
32163176 var local_arena = std.heap.ArenaAllocator.init(comp.gpa);
32173177 defer local_arena.deinit();
3218 try addPackageTableToCacheHash(&man.hash, &local_arena, mod.root_pkg, .{ .files = &man });
3178 try addPackageTableToCacheHash(&man.hash, &local_arena, mod.root_pkg.table, .{ .files = &man });
32193179 }
32203180 man.hash.add(comp.bin_file.options.valgrind);
32213181 man.hash.add(comp.bin_file.options.single_threaded);
src/Module.zig+4-11
......@@ -35,11 +35,8 @@ comp: *Compilation,
3535zig_cache_artifact_directory: Compilation.Directory,
3636/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
3737root_pkg: *Package,
38/// This is populated when `@import("root")` is analysed.
39root_scope: ?*Scope.File,
40start_pkg: *Package,
4138/// Module owns this resource.
42start_scope: *Scope.File,
39root_scope: *Scope.File,
4340/// It's rare for a decl to be exported, so we save memory by having a sparse map of
4441/// Decl pointers to details about them being exported.
4542/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
......@@ -2344,9 +2341,7 @@ pub fn deinit(mod: *Module) void {
23442341 mod.export_owners.deinit(gpa);
23452342
23462343 mod.symbol_exports.deinit(gpa);
2347
2348 mod.start_scope.destroy(gpa);
2349 mod.start_pkg.destroy(gpa);
2344 mod.root_scope.destroy(gpa);
23502345
23512346 var it = mod.global_error_set.iterator();
23522347 while (it.next()) |entry| {
......@@ -2518,7 +2513,6 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
25182513
25192514 const block_expr = node_datas[decl_node].lhs;
25202515 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2521 _ = try gen_scope.addBreak(.break_inline, gen_scope.break_block, .void_value);
25222516
25232517 const code = try gen_scope.finish();
25242518 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
......@@ -2863,9 +2857,8 @@ fn astgenAndSemaFn(
28632857
28642858 _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node);
28652859
2866 const inst_tags = astgen.instructions.items(.tag);
2867 if (inst_tags.len == 0 or
2868 !inst_tags[inst_tags.len - 1]
2860 if (gen_scope.instructions.items.len == 0 or
2861 !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
28692862 .isNoReturn())
28702863 {
28712864 // astgen uses result location semantics to coerce return operands.
src/Package.zig+1-28
......@@ -15,9 +15,6 @@ root_src_path: []const u8,
1515table: Table = .{},
1616parent: ?*Package = null,
1717
18// Used when freeing packages
19seen: bool = false,
20
2118/// Allocate a Package. No references to the slices passed are kept.
2219pub fn create(
2320 gpa: *Allocator,
......@@ -58,20 +55,10 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void {
5855 pkg.root_src_directory.handle.close();
5956 }
6057
61 // First we recurse into all the packages and remove packages from the tables
62 // once we have seen it before. We do this to make sure that that
63 // a package can only be found once in the whole tree.
64 if (!pkg.seen) {
65 pkg.seen = true;
66 pkg.markSeen(gpa);
67 }
68
6958 {
7059 var it = pkg.table.iterator();
7160 while (it.next()) |kv| {
72 if (pkg != kv.value) {
73 kv.value.destroy(gpa);
74 }
61 kv.value.destroy(gpa);
7562 gpa.free(kv.key);
7663 }
7764 }
......@@ -80,20 +67,6 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void {
8067 gpa.destroy(pkg);
8168}
8269
83fn markSeen(pkg: *Package, gpa: *Allocator) void {
84 var it = pkg.table.iterator();
85 while (it.next()) |kv| {
86 if (pkg != kv.value) {
87 if (kv.value.seen) {
88 pkg.table.removeAssertDiscard(kv.key);
89 } else {
90 kv.value.seen = true;
91 kv.value.markSeen(gpa);
92 }
93 }
94 }
95}
96
9770pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void {
9871 try pkg.table.ensureCapacity(gpa, pkg.table.count() + 1);
9972 const name_dupe = try mem.dupe(gpa, u8, name);
src/Sema.zig+24-35
......@@ -1345,21 +1345,18 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!
13451345 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13461346 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
13471347 const src = inst_data.src();
1348 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1349 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
13481350
1349 const target_fn = try sema.resolveInst(extra.lhs);
1350 const target_fn_val = try sema.resolveConstValue(
1351 block,
1352 .{ .node_offset_builtin_call_arg0 = inst_data.src_node },
1353 target_fn,
1354 );
1355
1356 const export_name = try sema.resolveConstString(
1357 block,
1358 .{ .node_offset_builtin_call_arg1 = inst_data.src_node },
1359 extra.rhs,
1360 );
1351 // TODO (see corresponding TODO in AstGen) this is supposed to be a `decl_ref`
1352 // instruction, which could reference any decl, which is then supposed to get
1353 // exported, regardless of whether or not it is a function.
1354 const target_fn = try sema.resolveInstConst(block, lhs_src, extra.lhs);
1355 // TODO (see corresponding TODO in AstGen) this is supposed to be
1356 // `std.builtin.ExportOptions`, not a string.
1357 const export_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
13611358
1362 const actual_fn = target_fn_val.castTag(.function).?.data;
1359 const actual_fn = target_fn.val.castTag(.function).?.data;
13631360 try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl);
13641361}
13651362
......@@ -3636,26 +3633,21 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
36363633 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
36373634 const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
36383635 const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
3636 const mod = sema.mod;
3637 const arena = sema.arena;
36393638
3640 const maybe_scope = container_type.getContainerScope();
3641 if (maybe_scope == null) {
3642 return sema.mod.fail(
3643 &block.base,
3644 src,
3645 "expected container (struct, enum, or union), found '{}'",
3646 .{container_type},
3647 );
3639 const container_scope = container_type.getContainerScope() orelse return mod.fail(
3640 &block.base,
3641 lhs_src,
3642 "expected struct, enum, union, or opaque, found '{}'",
3643 .{container_type},
3644 );
3645 if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| {
3646 // TODO if !decl.is_pub and inDifferentFiles() return false
3647 return mod.constBool(arena, src, true);
3648 } else {
3649 return mod.constBool(arena, src, false);
36483650 }
3649
3650 const found = blk: {
3651 for (maybe_scope.?.decls.items()) |kv| {
3652 if (mem.eql(u8, mem.spanZ(kv.key.name), decl_name))
3653 break :blk true;
3654 }
3655 break :blk false;
3656 };
3657
3658 return sema.mod.constBool(sema.arena, src, found);
36593651}
36603652
36613653fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
......@@ -4699,7 +4691,7 @@ fn namedFieldPtr(
46994691 }
47004692
47014693 // TODO this will give false positives for structs inside the root file
4702 if (container_scope.file_scope == mod.root_scope.?) {
4694 if (container_scope.file_scope == mod.root_scope) {
47034695 return mod.fail(
47044696 &block.base,
47054697 src,
......@@ -5338,9 +5330,6 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
53385330 .ty = struct_ty,
53395331 },
53405332 };
5341 if (mem.eql(u8, target_string, "root")) {
5342 sema.mod.root_scope = file_scope;
5343 }
53445333 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
53455334 error.AnalysisFail => {
53465335 assert(sema.mod.comp.totalErrorCount() != 0);
src/main.zig+1-2
......@@ -1732,8 +1732,6 @@ fn buildOutputType(
17321732 },
17331733 }
17341734
1735 // This gets cleaned up, because root_pkg becomes part of the
1736 // package table of the start_pkg.
17371735 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
17381736 if (main_pkg_path) |p| {
17391737 const rel_src_path = try fs.path.relative(gpa, p, src_path);
......@@ -1743,6 +1741,7 @@ fn buildOutputType(
17431741 break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path));
17441742 }
17451743 } else null;
1744 defer if (root_pkg) |p| p.destroy(gpa);
17461745
17471746 // Transfer packages added with --pkg-begin/--pkg-end to the root package
17481747 if (root_pkg) |pkg| {
src/zir.zig+2-3
......@@ -328,8 +328,7 @@ pub const Inst = struct {
328328 error_union_type,
329329 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
330330 error_value,
331 /// Exports a function with a specified name. This can be used at comptime
332 /// to export a function conditionally.
331 /// Implements the `@export` builtin function.
333332 /// Uses the `pl_node` union field. Payload is `Bin`.
334333 @"export",
335334 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
......@@ -364,7 +363,7 @@ pub const Inst = struct {
364363 fn_type_cc,
365364 /// Same as `fn_type_cc` but the function is variadic.
366365 fn_type_cc_var_args,
367 /// Determines whether a container has a declaration matching name.
366 /// Implements the `@hasDecl` builtin.
368367 /// Uses the `pl_node` union field. Payload is `Bin`.
369368 has_decl,
370369 /// `@import(operand)`.