authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-04 18:00:21-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-10-04 18:00:21-04:00
log302a69f127ae8542f49d9cd07c7cc49f3bbd6181
tree063f062e7701e4679a0e97ad1a25021294663640
parent0e2d858d69ee1595bb58d936f83f0e0248d54d68
parent6d3858dc8a5e5d510a6c9cc972357dda551628b3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6295 from Vexu/stage2

Stage2: basic imports

10 files changed, 301 insertions(+), 5 deletions(-)

src/Compilation.zig+17-1
...@@ -8,6 +8,7 @@ const log = std.log.scoped(.compilation);...@@ -8,6 +8,7 @@ const log = std.log.scoped(.compilation);
8const Target = std.Target;8const Target = std.Target;
99
10const Value = @import("value.zig").Value;10const Value = @import("value.zig").Value;
11const Type = @import("type.zig").Type;
11const target_util = @import("target.zig");12const target_util = @import("target.zig");
12const Package = @import("Package.zig");13const Package = @import("Package.zig");
13const link = @import("link.zig");14const link = @import("link.zig");
...@@ -640,15 +641,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -640,15 +641,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
640641
641 const root_scope = rs: {642 const root_scope = rs: {
642 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {643 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
644 const struct_payload = try gpa.create(Type.Payload.EmptyStruct);
643 const root_scope = try gpa.create(Module.Scope.File);645 const root_scope = try gpa.create(Module.Scope.File);
646 struct_payload.* = .{ .scope = &root_scope.root_container };
644 root_scope.* = .{647 root_scope.* = .{
645 .sub_file_path = root_pkg.root_src_path,648 // TODO this is duped so it can be freed in Container.deinit
649 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
646 .source = .{ .unloaded = {} },650 .source = .{ .unloaded = {} },
647 .contents = .{ .not_available = {} },651 .contents = .{ .not_available = {} },
648 .status = .never_loaded,652 .status = .never_loaded,
649 .root_container = .{653 .root_container = .{
650 .file_scope = root_scope,654 .file_scope = root_scope,
651 .decls = .{},655 .decls = .{},
656 .ty = Type.initPayload(&struct_payload.base),
652 },657 },
653 };658 };
654 break :rs &root_scope.base;659 break :rs &root_scope.base;
...@@ -1025,6 +1030,17 @@ pub fn update(self: *Compilation) !void {...@@ -1025,6 +1030,17 @@ pub fn update(self: *Compilation) !void {
1025 else => |e| return e,1030 else => |e| return e,
1026 };1031 };
1027 }1032 }
1033
1034 // TODO only analyze imports if they are still referenced
1035 for (module.import_table.items()) |entry| {
1036 entry.value.unload(module.gpa);
1037 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
1038 error.AnalysisFail => {
1039 assert(self.totalErrorCount() != 0);
1040 },
1041 else => |e| return e,
1042 };
1043 }
1028 }1044 }
1029 }1045 }
10301046
src/Module.zig+52-4
...@@ -70,6 +70,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{},...@@ -70,6 +70,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{},
70/// Error tags and their values, tag names are duped with mod.gpa.70/// Error tags and their values, tag names are duped with mod.gpa.
71global_error_set: std.StringHashMapUnmanaged(u16) = .{},71global_error_set: std.StringHashMapUnmanaged(u16) = .{},
7272
73/// Keys are fully qualified paths
74import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
75
73/// Incrementing integer used to compare against the corresponding Decl76/// Incrementing integer used to compare against the corresponding Decl
74/// field to determine whether a Decl's status applies to an ongoing update, or a77/// field to determine whether a Decl's status applies to an ongoing update, or a
75/// previous analysis.78/// previous analysis.
...@@ -208,7 +211,7 @@ pub const Decl = struct {...@@ -208,7 +211,7 @@ pub const Decl = struct {
208 .container => {211 .container => {
209 const container = @fieldParentPtr(Scope.Container, "base", self.scope);212 const container = @fieldParentPtr(Scope.Container, "base", self.scope);
210 const tree = container.file_scope.contents.tree;213 const tree = container.file_scope.contents.tree;
211 // TODO Container should have it's own decls()214 // TODO Container should have its own decls()
212 const decl_node = tree.root_node.decls()[self.src_index];215 const decl_node = tree.root_node.decls()[self.src_index];
213 return tree.token_locs[decl_node.firstToken()].start;216 return tree.token_locs[decl_node.firstToken()].start;
214 },217 },
...@@ -532,12 +535,13 @@ pub const Scope = struct {...@@ -532,12 +535,13 @@ pub const Scope = struct {
532535
533 /// Direct children of the file.536 /// Direct children of the file.
534 decls: std.AutoArrayHashMapUnmanaged(*Decl, void),537 decls: std.AutoArrayHashMapUnmanaged(*Decl, void),
535538 ty: Type,
536 // TODO implement container types and put this in a status union
537 // ty: Type
538539
539 pub fn deinit(self: *Container, gpa: *Allocator) void {540 pub fn deinit(self: *Container, gpa: *Allocator) void {
540 self.decls.deinit(gpa);541 self.decls.deinit(gpa);
542 // TODO either Container of File should have an arena for sub_file_path and ty
543 gpa.destroy(self.ty.cast(Type.Payload.EmptyStruct).?);
544 gpa.free(self.file_scope.sub_file_path);
541 self.* = undefined;545 self.* = undefined;
542 }546 }
543547
...@@ -854,6 +858,11 @@ pub fn deinit(self: *Module) void {...@@ -854,6 +858,11 @@ pub fn deinit(self: *Module) void {
854 gpa.free(entry.key);858 gpa.free(entry.key);
855 }859 }
856 self.global_error_set.deinit(gpa);860 self.global_error_set.deinit(gpa);
861
862 for (self.import_table.items()) |entry| {
863 entry.value.base.destroy(gpa);
864 }
865 self.import_table.deinit(gpa);
857}866}
858867
859fn freeExportList(gpa: *Allocator, export_list: []*Export) void {868fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
...@@ -2381,6 +2390,45 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst,...@@ -2381,6 +2390,45 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst,
2381 return self.fail(scope, src, "TODO implement analysis of slice", .{});2390 return self.fail(scope, src, "TODO implement analysis of slice", .{});
2382}2391}
23832392
2393pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []const u8) !*Scope.File {
2394 // TODO if (package_table.get(target_string)) |pkg|
2395 if (self.import_table.get(target_string)) |some| {
2396 return some;
2397 }
2398
2399 // TODO check for imports outside of pkg path
2400 if (false) return error.ImportOutsidePkgPath;
2401
2402 // TODO Scope.Container arena for ty and sub_file_path
2403 const struct_payload = try self.gpa.create(Type.Payload.EmptyStruct);
2404 errdefer self.gpa.destroy(struct_payload);
2405 const file_scope = try self.gpa.create(Scope.File);
2406 errdefer self.gpa.destroy(file_scope);
2407 const file_path = try self.gpa.dupe(u8, target_string);
2408 errdefer self.gpa.free(file_path);
2409
2410 struct_payload.* = .{ .scope = &file_scope.root_container };
2411 file_scope.* = .{
2412 .sub_file_path = file_path,
2413 .source = .{ .unloaded = {} },
2414 .contents = .{ .not_available = {} },
2415 .status = .never_loaded,
2416 .root_container = .{
2417 .file_scope = file_scope,
2418 .decls = .{},
2419 .ty = Type.initPayload(&struct_payload.base),
2420 },
2421 };
2422 self.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
2423 error.AnalysisFail => {
2424 assert(self.comp.totalErrorCount() != 0);
2425 },
2426 else => |e| return e,
2427 };
2428 try self.import_table.put(self.gpa, file_scope.sub_file_path, file_scope);
2429 return file_scope;
2430}
2431
2384/// Asserts that lhs and rhs types are both numeric.2432/// Asserts that lhs and rhs types are both numeric.
2385pub fn cmpNumeric(2433pub fn cmpNumeric(
2386 self: *Module,2434 self: *Module,
src/astgen.zig+11
...@@ -1973,6 +1973,15 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa...@@ -1973,6 +1973,15 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
1973 }1973 }
1974}1974}
19751975
1976fn import(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
1977 try ensureBuiltinParamCount(mod, scope, call, 1);
1978 const tree = scope.tree();
1979 const src = tree.token_locs[call.builtin_token].start;
1980 const params = call.params();
1981 const target = try expr(mod, scope, .none, params[0]);
1982 return addZIRUnOp(mod, scope, src, .import, target);
1983}
1984
1976fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {1985fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
1977 const tree = scope.tree();1986 const tree = scope.tree();
1978 const builtin_name = tree.tokenSlice(call.builtin_token);1987 const builtin_name = tree.tokenSlice(call.builtin_token);
...@@ -1995,6 +2004,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built...@@ -1995,6 +2004,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built
1995 } else if (mem.eql(u8, builtin_name, "@breakpoint")) {2004 } else if (mem.eql(u8, builtin_name, "@breakpoint")) {
1996 const src = tree.token_locs[call.builtin_token].start;2005 const src = tree.token_locs[call.builtin_token].start;
1997 return rlWrap(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint));2006 return rlWrap(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint));
2007 } else if (mem.eql(u8, builtin_name, "@import")) {
2008 return rlWrap(mod, scope, rl, try import(mod, scope, call));
1998 } else {2009 } else {
1999 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});2010 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});
2000 }2011 }
src/main.zig+5
...@@ -1454,6 +1454,11 @@ fn buildOutputType(...@@ -1454,6 +1454,11 @@ fn buildOutputType(
1454 cleanup_root_dir = dir;1454 cleanup_root_dir = dir;
1455 root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };1455 root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
1456 root_pkg_memory.root_src_path = try fs.path.relative(arena, p, src_path);1456 root_pkg_memory.root_src_path = try fs.path.relative(arena, p, src_path);
1457 } else if (fs.path.dirname(src_path)) |p| {
1458 const dir = try fs.cwd().openDir(p, .{});
1459 cleanup_root_dir = dir;
1460 root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
1461 root_pkg_memory.root_src_path = fs.path.basename(src_path);
1457 } else {1462 } else {
1458 root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() };1463 root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() };
1459 root_pkg_memory.root_src_path = src_path;1464 root_pkg_memory.root_src_path = src_path;
src/test.zig+15
...@@ -56,6 +56,12 @@ pub const TestContext = struct {...@@ -56,6 +56,12 @@ pub const TestContext = struct {
56 },56 },
57 };57 };
5858
59 pub const File = struct {
60 /// Contents of the importable file. Doesn't yet support incremental updates.
61 src: [:0]const u8,
62 path: []const u8,
63 };
64
59 pub const TestType = enum {65 pub const TestType = enum {
60 Zig,66 Zig,
61 ZIR,67 ZIR,
...@@ -78,6 +84,8 @@ pub const TestContext = struct {...@@ -78,6 +84,8 @@ pub const TestContext = struct {
78 extension: TestType,84 extension: TestType,
79 cbe: bool = false,85 cbe: bool = false,
8086
87 files: std.ArrayList(File),
88
81 /// Adds a subcase in which the module is updated with `src`, and the89 /// Adds a subcase in which the module is updated with `src`, and the
82 /// resulting ZIR is validated against `result`.90 /// resulting ZIR is validated against `result`.
83 pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {91 pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
...@@ -156,6 +164,7 @@ pub const TestContext = struct {...@@ -156,6 +164,7 @@ pub const TestContext = struct {
156 .updates = std.ArrayList(Update).init(ctx.cases.allocator),164 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
157 .output_mode = .Exe,165 .output_mode = .Exe,
158 .extension = T,166 .extension = T,
167 .files = std.ArrayList(File).init(ctx.cases.allocator),
159 }) catch unreachable;168 }) catch unreachable;
160 return &ctx.cases.items[ctx.cases.items.len - 1];169 return &ctx.cases.items[ctx.cases.items.len - 1];
161 }170 }
...@@ -182,6 +191,7 @@ pub const TestContext = struct {...@@ -182,6 +191,7 @@ pub const TestContext = struct {
182 .updates = std.ArrayList(Update).init(ctx.cases.allocator),191 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
183 .output_mode = .Obj,192 .output_mode = .Obj,
184 .extension = T,193 .extension = T,
194 .files = std.ArrayList(File).init(ctx.cases.allocator),
185 }) catch unreachable;195 }) catch unreachable;
186 return &ctx.cases.items[ctx.cases.items.len - 1];196 return &ctx.cases.items[ctx.cases.items.len - 1];
187 }197 }
...@@ -204,6 +214,7 @@ pub const TestContext = struct {...@@ -204,6 +214,7 @@ pub const TestContext = struct {
204 .output_mode = .Obj,214 .output_mode = .Obj,
205 .extension = T,215 .extension = T,
206 .cbe = true,216 .cbe = true,
217 .files = std.ArrayList(File).init(ctx.cases.allocator),
207 }) catch unreachable;218 }) catch unreachable;
208 return &ctx.cases.items[ctx.cases.items.len - 1];219 return &ctx.cases.items[ctx.cases.items.len - 1];
209 }220 }
...@@ -505,6 +516,10 @@ pub const TestContext = struct {...@@ -505,6 +516,10 @@ pub const TestContext = struct {
505 });516 });
506 defer comp.destroy();517 defer comp.destroy();
507518
519 for (case.files.items) |file| {
520 try tmp.dir.writeFile(file.path, file.src);
521 }
522
508 for (case.updates.items) |update, update_index| {523 for (case.updates.items) |update, update_index| {
509 var update_node = root_node.start("update", 3);524 var update_node = root_node.start("update", 3);
510 update_node.activate();525 update_node.activate();
src/type.zig+112
...@@ -89,6 +89,8 @@ pub const Type = extern union {...@@ -89,6 +89,8 @@ pub const Type = extern union {
89 .anyerror_void_error_union, .error_union => return .ErrorUnion,89 .anyerror_void_error_union, .error_union => return .ErrorUnion,
9090
91 .anyframe_T, .@"anyframe" => return .AnyFrame,91 .anyframe_T, .@"anyframe" => return .AnyFrame,
92
93 .empty_struct => return .Struct,
92 }94 }
93 }95 }
9496
...@@ -439,6 +441,7 @@ pub const Type = extern union {...@@ -439,6 +441,7 @@ pub const Type = extern union {
439 },441 },
440 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),442 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
441 .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle),443 .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle),
444 .empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct),
442 }445 }
443 }446 }
444447
...@@ -505,6 +508,8 @@ pub const Type = extern union {...@@ -505,6 +508,8 @@ pub const Type = extern union {
505 .@"null" => return out_stream.writeAll("@Type(.Null)"),508 .@"null" => return out_stream.writeAll("@Type(.Null)"),
506 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),509 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
507510
511 // TODO this should print the structs name
512 .empty_struct => return out_stream.writeAll("struct {}"),
508 .@"anyframe" => return out_stream.writeAll("anyframe"),513 .@"anyframe" => return out_stream.writeAll("anyframe"),
509 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),514 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
510 .const_slice_u8 => return out_stream.writeAll("[]const u8"),515 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
...@@ -788,6 +793,7 @@ pub const Type = extern union {...@@ -788,6 +793,7 @@ pub const Type = extern union {
788 .@"null",793 .@"null",
789 .@"undefined",794 .@"undefined",
790 .enum_literal,795 .enum_literal,
796 .empty_struct,
791 => false,797 => false,
792 };798 };
793 }799 }
...@@ -910,6 +916,7 @@ pub const Type = extern union {...@@ -910,6 +916,7 @@ pub const Type = extern union {
910 .@"null",916 .@"null",
911 .@"undefined",917 .@"undefined",
912 .enum_literal,918 .enum_literal,
919 .empty_struct,
913 => unreachable,920 => unreachable,
914 };921 };
915 }922 }
...@@ -932,6 +939,7 @@ pub const Type = extern union {...@@ -932,6 +939,7 @@ pub const Type = extern union {
932 .@"undefined" => unreachable,939 .@"undefined" => unreachable,
933 .enum_literal => unreachable,940 .enum_literal => unreachable,
934 .single_const_pointer_to_comptime_int => unreachable,941 .single_const_pointer_to_comptime_int => unreachable,
942 .empty_struct => unreachable,
935943
936 .u8,944 .u8,
937 .i8,945 .i8,
...@@ -1107,6 +1115,7 @@ pub const Type = extern union {...@@ -1107,6 +1115,7 @@ pub const Type = extern union {
1107 .anyerror_void_error_union,1115 .anyerror_void_error_union,
1108 .error_set,1116 .error_set,
1109 .error_set_single,1117 .error_set_single,
1118 .empty_struct,
1110 => false,1119 => false,
11111120
1112 .single_const_pointer,1121 .single_const_pointer,
...@@ -1181,6 +1190,7 @@ pub const Type = extern union {...@@ -1181,6 +1190,7 @@ pub const Type = extern union {
1181 .anyerror_void_error_union,1190 .anyerror_void_error_union,
1182 .error_set,1191 .error_set,
1183 .error_set_single,1192 .error_set_single,
1193 .empty_struct,
1184 => false,1194 => false,
11851195
1186 .const_slice,1196 .const_slice,
...@@ -1252,6 +1262,7 @@ pub const Type = extern union {...@@ -1252,6 +1262,7 @@ pub const Type = extern union {
1252 .anyerror_void_error_union,1262 .anyerror_void_error_union,
1253 .error_set,1263 .error_set,
1254 .error_set_single,1264 .error_set_single,
1265 .empty_struct,
1255 => false,1266 => false,
12561267
1257 .single_const_pointer,1268 .single_const_pointer,
...@@ -1332,6 +1343,7 @@ pub const Type = extern union {...@@ -1332,6 +1343,7 @@ pub const Type = extern union {
1332 .anyerror_void_error_union,1343 .anyerror_void_error_union,
1333 .error_set,1344 .error_set,
1334 .error_set_single,1345 .error_set_single,
1346 .empty_struct,
1335 => false,1347 => false,
13361348
1337 .pointer => {1349 .pointer => {
...@@ -1407,6 +1419,7 @@ pub const Type = extern union {...@@ -1407,6 +1419,7 @@ pub const Type = extern union {
1407 .anyerror_void_error_union,1419 .anyerror_void_error_union,
1408 .error_set,1420 .error_set,
1409 .error_set_single,1421 .error_set_single,
1422 .empty_struct,
1410 => false,1423 => false,
14111424
1412 .pointer => {1425 .pointer => {
...@@ -1524,6 +1537,7 @@ pub const Type = extern union {...@@ -1524,6 +1537,7 @@ pub const Type = extern union {
1524 .anyerror_void_error_union,1537 .anyerror_void_error_union,
1525 .error_set,1538 .error_set,
1526 .error_set_single,1539 .error_set_single,
1540 .empty_struct,
1527 => unreachable,1541 => unreachable,
15281542
1529 .array => self.cast(Payload.Array).?.elem_type,1543 .array => self.cast(Payload.Array).?.elem_type,
...@@ -1651,6 +1665,7 @@ pub const Type = extern union {...@@ -1651,6 +1665,7 @@ pub const Type = extern union {
1651 .anyerror_void_error_union,1665 .anyerror_void_error_union,
1652 .error_set,1666 .error_set,
1653 .error_set_single,1667 .error_set_single,
1668 .empty_struct,
1654 => unreachable,1669 => unreachable,
16551670
1656 .array => self.cast(Payload.Array).?.len,1671 .array => self.cast(Payload.Array).?.len,
...@@ -1716,6 +1731,7 @@ pub const Type = extern union {...@@ -1716,6 +1731,7 @@ pub const Type = extern union {
1716 .anyerror_void_error_union,1731 .anyerror_void_error_union,
1717 .error_set,1732 .error_set,
1718 .error_set_single,1733 .error_set_single,
1734 .empty_struct,
1719 => unreachable,1735 => unreachable,
17201736
1721 .single_const_pointer,1737 .single_const_pointer,
...@@ -1798,6 +1814,7 @@ pub const Type = extern union {...@@ -1798,6 +1814,7 @@ pub const Type = extern union {
1798 .anyerror_void_error_union,1814 .anyerror_void_error_union,
1799 .error_set,1815 .error_set,
1800 .error_set_single,1816 .error_set_single,
1817 .empty_struct,
1801 => false,1818 => false,
18021819
1803 .int_signed,1820 .int_signed,
...@@ -1872,6 +1889,7 @@ pub const Type = extern union {...@@ -1872,6 +1889,7 @@ pub const Type = extern union {
1872 .anyerror_void_error_union,1889 .anyerror_void_error_union,
1873 .error_set,1890 .error_set,
1874 .error_set_single,1891 .error_set_single,
1892 .empty_struct,
1875 => false,1893 => false,
18761894
1877 .int_unsigned,1895 .int_unsigned,
...@@ -1936,6 +1954,7 @@ pub const Type = extern union {...@@ -1936,6 +1954,7 @@ pub const Type = extern union {
1936 .anyerror_void_error_union,1954 .anyerror_void_error_union,
1937 .error_set,1955 .error_set,
1938 .error_set_single,1956 .error_set_single,
1957 .empty_struct,
1939 => unreachable,1958 => unreachable,
19401959
1941 .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },1960 .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
...@@ -2018,6 +2037,7 @@ pub const Type = extern union {...@@ -2018,6 +2037,7 @@ pub const Type = extern union {
2018 .anyerror_void_error_union,2037 .anyerror_void_error_union,
2019 .error_set,2038 .error_set,
2020 .error_set_single,2039 .error_set_single,
2040 .empty_struct,
2021 => false,2041 => false,
20222042
2023 .usize,2043 .usize,
...@@ -2129,6 +2149,7 @@ pub const Type = extern union {...@@ -2129,6 +2149,7 @@ pub const Type = extern union {
2129 .anyerror_void_error_union,2149 .anyerror_void_error_union,
2130 .error_set,2150 .error_set,
2131 .error_set_single,2151 .error_set_single,
2152 .empty_struct,
2132 => unreachable,2153 => unreachable,
2133 };2154 };
2134 }2155 }
...@@ -2206,6 +2227,7 @@ pub const Type = extern union {...@@ -2206,6 +2227,7 @@ pub const Type = extern union {
2206 .anyerror_void_error_union,2227 .anyerror_void_error_union,
2207 .error_set,2228 .error_set,
2208 .error_set_single,2229 .error_set_single,
2230 .empty_struct,
2209 => unreachable,2231 => unreachable,
2210 }2232 }
2211 }2233 }
...@@ -2282,6 +2304,7 @@ pub const Type = extern union {...@@ -2282,6 +2304,7 @@ pub const Type = extern union {
2282 .anyerror_void_error_union,2304 .anyerror_void_error_union,
2283 .error_set,2305 .error_set,
2284 .error_set_single,2306 .error_set_single,
2307 .empty_struct,
2285 => unreachable,2308 => unreachable,
2286 }2309 }
2287 }2310 }
...@@ -2358,6 +2381,7 @@ pub const Type = extern union {...@@ -2358,6 +2381,7 @@ pub const Type = extern union {
2358 .anyerror_void_error_union,2381 .anyerror_void_error_union,
2359 .error_set,2382 .error_set,
2360 .error_set_single,2383 .error_set_single,
2384 .empty_struct,
2361 => unreachable,2385 => unreachable,
2362 };2386 };
2363 }2387 }
...@@ -2431,6 +2455,7 @@ pub const Type = extern union {...@@ -2431,6 +2455,7 @@ pub const Type = extern union {
2431 .anyerror_void_error_union,2455 .anyerror_void_error_union,
2432 .error_set,2456 .error_set,
2433 .error_set_single,2457 .error_set_single,
2458 .empty_struct,
2434 => unreachable,2459 => unreachable,
2435 };2460 };
2436 }2461 }
...@@ -2504,6 +2529,7 @@ pub const Type = extern union {...@@ -2504,6 +2529,7 @@ pub const Type = extern union {
2504 .anyerror_void_error_union,2529 .anyerror_void_error_union,
2505 .error_set,2530 .error_set,
2506 .error_set_single,2531 .error_set_single,
2532 .empty_struct,
2507 => unreachable,2533 => unreachable,
2508 };2534 };
2509 }2535 }
...@@ -2577,6 +2603,7 @@ pub const Type = extern union {...@@ -2577,6 +2603,7 @@ pub const Type = extern union {
2577 .anyerror_void_error_union,2603 .anyerror_void_error_union,
2578 .error_set,2604 .error_set,
2579 .error_set_single,2605 .error_set_single,
2606 .empty_struct,
2580 => false,2607 => false,
2581 };2608 };
2582 }2609 }
...@@ -2636,6 +2663,7 @@ pub const Type = extern union {...@@ -2636,6 +2663,7 @@ pub const Type = extern union {
2636 .error_set_single,2663 .error_set_single,
2637 => return null,2664 => return null,
26382665
2666 .empty_struct => return Value.initTag(.empty_struct_value),
2639 .void => return Value.initTag(.void_value),2667 .void => return Value.initTag(.void_value),
2640 .noreturn => return Value.initTag(.unreachable_value),2668 .noreturn => return Value.initTag(.unreachable_value),
2641 .@"null" => return Value.initTag(.null_value),2669 .@"null" => return Value.initTag(.null_value),
...@@ -2743,6 +2771,7 @@ pub const Type = extern union {...@@ -2743,6 +2771,7 @@ pub const Type = extern union {
2743 .anyerror_void_error_union,2771 .anyerror_void_error_union,
2744 .error_set,2772 .error_set,
2745 .error_set_single,2773 .error_set_single,
2774 .empty_struct,
2746 => return false,2775 => return false,
27472776
2748 .c_const_pointer,2777 .c_const_pointer,
...@@ -2760,6 +2789,80 @@ pub const Type = extern union {...@@ -2760,6 +2789,80 @@ pub const Type = extern union {
2760 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);2789 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
2761 }2790 }
27622791
2792 /// Asserts that the type is a container. (note: ErrorSet is not a container).
2793 pub fn getContainerScope(self: Type) *Module.Scope.Container {
2794 return switch (self.tag()) {
2795 .f16,
2796 .f32,
2797 .f64,
2798 .f128,
2799 .c_longdouble,
2800 .comptime_int,
2801 .comptime_float,
2802 .u8,
2803 .i8,
2804 .u16,
2805 .i16,
2806 .u32,
2807 .i32,
2808 .u64,
2809 .i64,
2810 .usize,
2811 .isize,
2812 .c_short,
2813 .c_ushort,
2814 .c_int,
2815 .c_uint,
2816 .c_long,
2817 .c_ulong,
2818 .c_longlong,
2819 .c_ulonglong,
2820 .bool,
2821 .type,
2822 .anyerror,
2823 .fn_noreturn_no_args,
2824 .fn_void_no_args,
2825 .fn_naked_noreturn_no_args,
2826 .fn_ccc_void_no_args,
2827 .function,
2828 .single_const_pointer_to_comptime_int,
2829 .const_slice_u8,
2830 .c_void,
2831 .void,
2832 .noreturn,
2833 .@"null",
2834 .@"undefined",
2835 .int_unsigned,
2836 .int_signed,
2837 .array,
2838 .array_sentinel,
2839 .array_u8,
2840 .array_u8_sentinel_0,
2841 .single_const_pointer,
2842 .single_mut_pointer,
2843 .many_const_pointer,
2844 .many_mut_pointer,
2845 .const_slice,
2846 .mut_slice,
2847 .optional,
2848 .optional_single_mut_pointer,
2849 .optional_single_const_pointer,
2850 .enum_literal,
2851 .error_union,
2852 .@"anyframe",
2853 .anyframe_T,
2854 .anyerror_void_error_union,
2855 .error_set,
2856 .error_set_single,
2857 .c_const_pointer,
2858 .c_mut_pointer,
2859 .pointer,
2860 => unreachable,
2861
2862 .empty_struct => self.cast(Type.Payload.EmptyStruct).?.scope,
2863 };
2864 }
2865
2763 /// This enum does not directly correspond to `std.builtin.TypeId` because2866 /// This enum does not directly correspond to `std.builtin.TypeId` because
2764 /// it has extra enum tags in it, as a way of using less memory. For example,2867 /// it has extra enum tags in it, as a way of using less memory. For example,
2765 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types2868 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
...@@ -2835,6 +2938,7 @@ pub const Type = extern union {...@@ -2835,6 +2938,7 @@ pub const Type = extern union {
2835 anyframe_T,2938 anyframe_T,
2836 error_set,2939 error_set,
2837 error_set_single,2940 error_set_single,
2941 empty_struct,
28382942
2839 pub const last_no_payload_tag = Tag.const_slice_u8;2943 pub const last_no_payload_tag = Tag.const_slice_u8;
2840 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;2944 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -2942,6 +3046,14 @@ pub const Type = extern union {...@@ -2942,6 +3046,14 @@ pub const Type = extern union {
2942 /// memory is owned by `Module`3046 /// memory is owned by `Module`
2943 name: []const u8,3047 name: []const u8,
2944 };3048 };
3049
3050 /// Mostly used for namespace like structs with zero fields.
3051 /// Most commonly used for files.
3052 pub const EmptyStruct = struct {
3053 base: Payload = .{ .tag = .empty_struct },
3054
3055 scope: *Module.Scope.Container,
3056 };
2945 };3057 };
2946};3058};
29473059
src/value.zig+15
...@@ -68,6 +68,7 @@ pub const Value = extern union {...@@ -68,6 +68,7 @@ pub const Value = extern union {
68 one,68 one,
69 void_value,69 void_value,
70 unreachable_value,70 unreachable_value,
71 empty_struct_value,
71 empty_array,72 empty_array,
72 null_value,73 null_value,
73 bool_true,74 bool_true,
...@@ -182,6 +183,7 @@ pub const Value = extern union {...@@ -182,6 +183,7 @@ pub const Value = extern union {
182 .null_value,183 .null_value,
183 .bool_true,184 .bool_true,
184 .bool_false,185 .bool_false,
186 .empty_struct_value,
185 => unreachable,187 => unreachable,
186188
187 .ty => {189 .ty => {
...@@ -312,6 +314,8 @@ pub const Value = extern union {...@@ -312,6 +314,8 @@ pub const Value = extern union {
312 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),314 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
313 .anyframe_type => return out_stream.writeAll("anyframe"),315 .anyframe_type => return out_stream.writeAll("anyframe"),
314316
317 // TODO this should print `NAME{}`
318 .empty_struct_value => return out_stream.writeAll("struct {}{}"),
315 .null_value => return out_stream.writeAll("null"),319 .null_value => return out_stream.writeAll("null"),
316 .undef => return out_stream.writeAll("undefined"),320 .undef => return out_stream.writeAll("undefined"),
317 .zero => return out_stream.writeAll("0"),321 .zero => return out_stream.writeAll("0"),
...@@ -475,6 +479,7 @@ pub const Value = extern union {...@@ -475,6 +479,7 @@ pub const Value = extern union {
475 .float_128,479 .float_128,
476 .enum_literal,480 .enum_literal,
477 .@"error",481 .@"error",
482 .empty_struct_value,
478 => unreachable,483 => unreachable,
479 };484 };
480 }485 }
...@@ -543,6 +548,7 @@ pub const Value = extern union {...@@ -543,6 +548,7 @@ pub const Value = extern union {
543 .enum_literal,548 .enum_literal,
544 .error_set,549 .error_set,
545 .@"error",550 .@"error",
551 .empty_struct_value,
546 => unreachable,552 => unreachable,
547553
548 .undef => unreachable,554 .undef => unreachable,
...@@ -626,6 +632,7 @@ pub const Value = extern union {...@@ -626,6 +632,7 @@ pub const Value = extern union {
626 .enum_literal,632 .enum_literal,
627 .error_set,633 .error_set,
628 .@"error",634 .@"error",
635 .empty_struct_value,
629 => unreachable,636 => unreachable,
630637
631 .undef => unreachable,638 .undef => unreachable,
...@@ -709,6 +716,7 @@ pub const Value = extern union {...@@ -709,6 +716,7 @@ pub const Value = extern union {
709 .enum_literal,716 .enum_literal,
710 .error_set,717 .error_set,
711 .@"error",718 .@"error",
719 .empty_struct_value,
712 => unreachable,720 => unreachable,
713721
714 .undef => unreachable,722 .undef => unreachable,
...@@ -820,6 +828,7 @@ pub const Value = extern union {...@@ -820,6 +828,7 @@ pub const Value = extern union {
820 .enum_literal,828 .enum_literal,
821 .error_set,829 .error_set,
822 .@"error",830 .@"error",
831 .empty_struct_value,
823 => unreachable,832 => unreachable,
824833
825 .zero,834 .zero,
...@@ -907,6 +916,7 @@ pub const Value = extern union {...@@ -907,6 +916,7 @@ pub const Value = extern union {
907 .enum_literal,916 .enum_literal,
908 .error_set,917 .error_set,
909 .@"error",918 .@"error",
919 .empty_struct_value,
910 => unreachable,920 => unreachable,
911921
912 .zero,922 .zero,
...@@ -1078,6 +1088,7 @@ pub const Value = extern union {...@@ -1078,6 +1088,7 @@ pub const Value = extern union {
1078 .enum_literal,1088 .enum_literal,
1079 .error_set,1089 .error_set,
1080 .@"error",1090 .@"error",
1091 .empty_struct_value,
1081 => unreachable,1092 => unreachable,
10821093
1083 .zero,1094 .zero,
...@@ -1152,6 +1163,7 @@ pub const Value = extern union {...@@ -1152,6 +1163,7 @@ pub const Value = extern union {
1152 .enum_literal,1163 .enum_literal,
1153 .error_set,1164 .error_set,
1154 .@"error",1165 .@"error",
1166 .empty_struct_value,
1155 => unreachable,1167 => unreachable,
11561168
1157 .zero,1169 .zero,
...@@ -1300,6 +1312,7 @@ pub const Value = extern union {...@@ -1300,6 +1312,7 @@ pub const Value = extern union {
1300 .enum_literal,1312 .enum_literal,
1301 .error_set,1313 .error_set,
1302 .@"error",1314 .@"error",
1315 .empty_struct_value,
1303 => unreachable,1316 => unreachable,
13041317
1305 .ref_val => self.cast(Payload.RefVal).?.val,1318 .ref_val => self.cast(Payload.RefVal).?.val,
...@@ -1383,6 +1396,7 @@ pub const Value = extern union {...@@ -1383,6 +1396,7 @@ pub const Value = extern union {
1383 .enum_literal,1396 .enum_literal,
1384 .error_set,1397 .error_set,
1385 .@"error",1398 .@"error",
1399 .empty_struct_value,
1386 => unreachable,1400 => unreachable,
13871401
1388 .empty_array => unreachable, // out of bounds array index1402 .empty_array => unreachable, // out of bounds array index
...@@ -1483,6 +1497,7 @@ pub const Value = extern union {...@@ -1483,6 +1497,7 @@ pub const Value = extern union {
1483 .enum_literal,1497 .enum_literal,
1484 .error_set,1498 .error_set,
1485 .@"error",1499 .@"error",
1500 .empty_struct_value,
1486 => false,1501 => false,
14871502
1488 .undef => unreachable,1503 .undef => unreachable,
src/zir.zig+4
...@@ -161,6 +161,8 @@ pub const Inst = struct {...@@ -161,6 +161,8 @@ pub const Inst = struct {
161 @"fn",161 @"fn",
162 /// Returns a function type.162 /// Returns a function type.
163 fntype,163 fntype,
164 /// @import(operand)
165 import,
164 /// Integer literal.166 /// Integer literal.
165 int,167 int,
166 /// Convert an integer value to another integer type, asserting that the destination type168 /// Convert an integer value to another integer type, asserting that the destination type
...@@ -315,6 +317,7 @@ pub const Inst = struct {...@@ -315,6 +317,7 @@ pub const Inst = struct {
315 .ensure_err_payload_void,317 .ensure_err_payload_void,
316 .anyframe_type,318 .anyframe_type,
317 .bitnot,319 .bitnot,
320 .import,
318 => UnOp,321 => UnOp,
319322
320 .add,323 .add,
...@@ -489,6 +492,7 @@ pub const Inst = struct {...@@ -489,6 +492,7 @@ pub const Inst = struct {
489 .error_set,492 .error_set,
490 .slice,493 .slice,
491 .slice_start,494 .slice_start,
495 .import,
492 => false,496 => false,
493497
494 .@"break",498 .@"break",
src/zir_sema.zig+32
...@@ -134,6 +134,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -134,6 +134,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
134 .error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?),134 .error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?),
135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
137 .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
137 }138 }
138}139}
139140
...@@ -1047,6 +1048,19 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr...@@ -1047,6 +1048,19 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
1047 .val = Value.initPayload(&ref_payload.base),1048 .val = Value.initPayload(&ref_payload.base),
1048 });1049 });
1049 },1050 },
1051 .Struct => {
1052 const container_scope = child_type.getContainerScope();
1053 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
1054 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
1055 return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);
1056 }
1057
1058 if (&container_scope.file_scope.base == mod.root_scope) {
1059 return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{}'", .{field_name});
1060 } else {
1061 return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{}'", .{ child_type, field_name });
1062 }
1063 },
1050 else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),1064 else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),
1051 }1065 }
1052 },1066 },
...@@ -1190,6 +1204,24 @@ fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn...@@ -1190,6 +1204,24 @@ fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn
1190 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);1204 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
1191}1205}
11921206
1207fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1208 const operand = try resolveConstString(mod, scope, inst.positionals.operand);
1209
1210 const file_scope = mod.analyzeImport(scope, inst.base.src, operand) catch |err| switch (err) {
1211 // error.ImportOutsidePkgPath => {
1212 // return mod.fail(scope, inst.base.src, "import of file outside package path: '{}'", .{operand});
1213 // },
1214 error.FileNotFound => {
1215 return mod.fail(scope, inst.base.src, "unable to find '{}'", .{operand});
1216 },
1217 else => {
1218 // TODO user friendly error to string
1219 return mod.fail(scope, inst.base.src, "unable to open '{}': {}", .{ operand, @errorName(err) });
1220 },
1221 };
1222 return mod.constType(scope, inst.base.src, file_scope.root_container.ty);
1223}
1224
1193fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {1225fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1194 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});1226 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});
1195}1227}
test/stage2/test.zig+38
...@@ -909,6 +909,44 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -909,6 +909,44 @@ pub fn addCases(ctx: *TestContext) !void {
909 );909 );
910 }910 }
911911
912 {
913 var case = ctx.exe("basic import", linux_x64);
914 case.addCompareOutput(
915 \\export fn _start() noreturn {
916 \\ @import("print.zig").print();
917 \\ exit();
918 \\}
919 \\
920 \\fn exit() noreturn {
921 \\ asm volatile ("syscall"
922 \\ :
923 \\ : [number] "{rax}" (231),
924 \\ [arg1] "{rdi}" (@as(usize, 0))
925 \\ : "rcx", "r11", "memory"
926 \\ );
927 \\ unreachable;
928 \\}
929 ,
930 "Hello, World!\n",
931 );
932 try case.files.append(.{
933 .src =
934 \\pub fn print() void {
935 \\ asm volatile ("syscall"
936 \\ :
937 \\ : [number] "{rax}" (@as(usize, 1)),
938 \\ [arg1] "{rdi}" (@as(usize, 1)),
939 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
940 \\ [arg3] "{rdx}" (@as(usize, 14))
941 \\ : "rcx", "r11", "memory"
942 \\ );
943 \\ return;
944 \\}
945 ,
946 .path = "print.zig",
947 });
948 }
949
912 {950 {
913 var case = ctx.exe("wasm function calls", wasi);951 var case = ctx.exe("wasm function calls", wasi);
914952