| author | |
| committer | |
| log | 302a69f127ae8542f49d9cd07c7cc49f3bbd6181 |
| tree | 063f062e7701e4679a0e97ad1a25021294663640 |
| parent | 0e2d858d69ee1595bb58d936f83f0e0248d54d68 |
| parent | 6d3858dc8a5e5d510a6c9cc972357dda551628b3 |
| signature |
Stage2: basic imports10 files changed, 301 insertions(+), 5 deletions(-)
src/Compilation.zig+17-1| ... | ... | @@ -8,6 +8,7 @@ const log = std.log.scoped(.compilation); |
| 8 | 8 | const Target = std.Target; |
| 9 | 9 | |
| 10 | 10 | const Value = @import("value.zig").Value; |
| 11 | const Type = @import("type.zig").Type; | |
| 11 | 12 | const target_util = @import("target.zig"); |
| 12 | 13 | const Package = @import("Package.zig"); |
| 13 | 14 | const link = @import("link.zig"); |
| ... | ... | @@ -640,15 +641,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 640 | 641 | |
| 641 | 642 | const root_scope = rs: { |
| 642 | 643 | if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) { |
| 644 | const struct_payload = try gpa.create(Type.Payload.EmptyStruct); | |
| 643 | 645 | const root_scope = try gpa.create(Module.Scope.File); |
| 646 | struct_payload.* = .{ .scope = &root_scope.root_container }; | |
| 644 | 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 | 650 | .source = .{ .unloaded = {} }, |
| 647 | 651 | .contents = .{ .not_available = {} }, |
| 648 | 652 | .status = .never_loaded, |
| 649 | 653 | .root_container = .{ |
| 650 | 654 | .file_scope = root_scope, |
| 651 | 655 | .decls = .{}, |
| 656 | .ty = Type.initPayload(&struct_payload.base), | |
| 652 | 657 | }, |
| 653 | 658 | }; |
| 654 | 659 | break :rs &root_scope.base; |
| ... | ... | @@ -1025,6 +1030,17 @@ pub fn update(self: *Compilation) !void { |
| 1025 | 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 | } |
| 1030 | 1046 |
src/Module.zig+52-4| ... | ... | @@ -70,6 +70,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{}, |
| 70 | 70 | /// Error tags and their values, tag names are duped with mod.gpa. |
| 71 | 71 | global_error_set: std.StringHashMapUnmanaged(u16) = .{}, |
| 72 | 72 | |
| 73 | /// Keys are fully qualified paths | |
| 74 | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, | |
| 75 | ||
| 73 | 76 | /// Incrementing integer used to compare against the corresponding Decl |
| 74 | 77 | /// field to determine whether a Decl's status applies to an ongoing update, or a |
| 75 | 78 | /// previous analysis. |
| ... | ... | @@ -208,7 +211,7 @@ pub const Decl = struct { |
| 208 | 211 | .container => { |
| 209 | 212 | const container = @fieldParentPtr(Scope.Container, "base", self.scope); |
| 210 | 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 | 215 | const decl_node = tree.root_node.decls()[self.src_index]; |
| 213 | 216 | return tree.token_locs[decl_node.firstToken()].start; |
| 214 | 217 | }, |
| ... | ... | @@ -532,12 +535,13 @@ pub const Scope = struct { |
| 532 | 535 | |
| 533 | 536 | /// Direct children of the file. |
| 534 | 537 | decls: std.AutoArrayHashMapUnmanaged(*Decl, void), |
| 535 | ||
| 536 | // TODO implement container types and put this in a status union | |
| 537 | // ty: Type | |
| 538 | ty: Type, | |
| 538 | 539 | |
| 539 | 540 | pub fn deinit(self: *Container, gpa: *Allocator) void { |
| 540 | 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 | 545 | self.* = undefined; |
| 542 | 546 | } |
| 543 | 547 | |
| ... | ... | @@ -854,6 +858,11 @@ pub fn deinit(self: *Module) void { |
| 854 | 858 | gpa.free(entry.key); |
| 855 | 859 | } |
| 856 | 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 | } |
| 858 | 867 | |
| 859 | 868 | fn freeExportList(gpa: *Allocator, export_list: []*Export) void { |
| ... | ... | @@ -2381,6 +2390,45 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, |
| 2381 | 2390 | return self.fail(scope, src, "TODO implement analysis of slice", .{}); |
| 2382 | 2391 | } |
| 2383 | 2392 | |
| 2393 | pub 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 | 2432 | /// Asserts that lhs and rhs types are both numeric. |
| 2385 | 2433 | pub fn cmpNumeric( |
| 2386 | 2434 | self: *Module, |
src/astgen.zig+11| ... | ... | @@ -1973,6 +1973,15 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa |
| 1973 | 1973 | } |
| 1974 | 1974 | } |
| 1975 | 1975 | |
| 1976 | fn 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 | ||
| 1976 | 1985 | fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| 1977 | 1986 | const tree = scope.tree(); |
| 1978 | 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 | 2004 | } else if (mem.eql(u8, builtin_name, "@breakpoint")) { |
| 1996 | 2005 | const src = tree.token_locs[call.builtin_token].start; |
| 1997 | 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 | 2009 | } else { |
| 1999 | 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 | 1454 | cleanup_root_dir = dir; |
| 1455 | 1455 | root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir }; |
| 1456 | 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 | 1462 | } else { |
| 1458 | 1463 | root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() }; |
| 1459 | 1464 | root_pkg_memory.root_src_path = src_path; |
src/test.zig+15| ... | ... | @@ -56,6 +56,12 @@ pub const TestContext = struct { |
| 56 | 56 | }, |
| 57 | 57 | }; |
| 58 | 58 | |
| 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 | 65 | pub const TestType = enum { |
| 60 | 66 | Zig, |
| 61 | 67 | ZIR, |
| ... | ... | @@ -78,6 +84,8 @@ pub const TestContext = struct { |
| 78 | 84 | extension: TestType, |
| 79 | 85 | cbe: bool = false, |
| 80 | 86 | |
| 87 | files: std.ArrayList(File), | |
| 88 | ||
| 81 | 89 | /// Adds a subcase in which the module is updated with `src`, and the |
| 82 | 90 | /// resulting ZIR is validated against `result`. |
| 83 | 91 | pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void { |
| ... | ... | @@ -156,6 +164,7 @@ pub const TestContext = struct { |
| 156 | 164 | .updates = std.ArrayList(Update).init(ctx.cases.allocator), |
| 157 | 165 | .output_mode = .Exe, |
| 158 | 166 | .extension = T, |
| 167 | .files = std.ArrayList(File).init(ctx.cases.allocator), | |
| 159 | 168 | }) catch unreachable; |
| 160 | 169 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| 161 | 170 | } |
| ... | ... | @@ -182,6 +191,7 @@ pub const TestContext = struct { |
| 182 | 191 | .updates = std.ArrayList(Update).init(ctx.cases.allocator), |
| 183 | 192 | .output_mode = .Obj, |
| 184 | 193 | .extension = T, |
| 194 | .files = std.ArrayList(File).init(ctx.cases.allocator), | |
| 185 | 195 | }) catch unreachable; |
| 186 | 196 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| 187 | 197 | } |
| ... | ... | @@ -204,6 +214,7 @@ pub const TestContext = struct { |
| 204 | 214 | .output_mode = .Obj, |
| 205 | 215 | .extension = T, |
| 206 | 216 | .cbe = true, |
| 217 | .files = std.ArrayList(File).init(ctx.cases.allocator), | |
| 207 | 218 | }) catch unreachable; |
| 208 | 219 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| 209 | 220 | } |
| ... | ... | @@ -505,6 +516,10 @@ pub const TestContext = struct { |
| 505 | 516 | }); |
| 506 | 517 | defer comp.destroy(); |
| 507 | 518 | |
| 519 | for (case.files.items) |file| { | |
| 520 | try tmp.dir.writeFile(file.path, file.src); | |
| 521 | } | |
| 522 | ||
| 508 | 523 | for (case.updates.items) |update, update_index| { |
| 509 | 524 | var update_node = root_node.start("update", 3); |
| 510 | 525 | update_node.activate(); |
src/type.zig+112| ... | ... | @@ -89,6 +89,8 @@ pub const Type = extern union { |
| 89 | 89 | .anyerror_void_error_union, .error_union => return .ErrorUnion, |
| 90 | 90 | |
| 91 | 91 | .anyframe_T, .@"anyframe" => return .AnyFrame, |
| 92 | ||
| 93 | .empty_struct => return .Struct, | |
| 92 | 94 | } |
| 93 | 95 | } |
| 94 | 96 | |
| ... | ... | @@ -439,6 +441,7 @@ pub const Type = extern union { |
| 439 | 441 | }, |
| 440 | 442 | .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), |
| 441 | 443 | .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle), |
| 444 | .empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct), | |
| 442 | 445 | } |
| 443 | 446 | } |
| 444 | 447 | |
| ... | ... | @@ -505,6 +508,8 @@ pub const Type = extern union { |
| 505 | 508 | .@"null" => return out_stream.writeAll("@Type(.Null)"), |
| 506 | 509 | .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"), |
| 507 | 510 | |
| 511 | // TODO this should print the structs name | |
| 512 | .empty_struct => return out_stream.writeAll("struct {}"), | |
| 508 | 513 | .@"anyframe" => return out_stream.writeAll("anyframe"), |
| 509 | 514 | .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"), |
| 510 | 515 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), |
| ... | ... | @@ -788,6 +793,7 @@ pub const Type = extern union { |
| 788 | 793 | .@"null", |
| 789 | 794 | .@"undefined", |
| 790 | 795 | .enum_literal, |
| 796 | .empty_struct, | |
| 791 | 797 | => false, |
| 792 | 798 | }; |
| 793 | 799 | } |
| ... | ... | @@ -910,6 +916,7 @@ pub const Type = extern union { |
| 910 | 916 | .@"null", |
| 911 | 917 | .@"undefined", |
| 912 | 918 | .enum_literal, |
| 919 | .empty_struct, | |
| 913 | 920 | => unreachable, |
| 914 | 921 | }; |
| 915 | 922 | } |
| ... | ... | @@ -932,6 +939,7 @@ pub const Type = extern union { |
| 932 | 939 | .@"undefined" => unreachable, |
| 933 | 940 | .enum_literal => unreachable, |
| 934 | 941 | .single_const_pointer_to_comptime_int => unreachable, |
| 942 | .empty_struct => unreachable, | |
| 935 | 943 | |
| 936 | 944 | .u8, |
| 937 | 945 | .i8, |
| ... | ... | @@ -1107,6 +1115,7 @@ pub const Type = extern union { |
| 1107 | 1115 | .anyerror_void_error_union, |
| 1108 | 1116 | .error_set, |
| 1109 | 1117 | .error_set_single, |
| 1118 | .empty_struct, | |
| 1110 | 1119 | => false, |
| 1111 | 1120 | |
| 1112 | 1121 | .single_const_pointer, |
| ... | ... | @@ -1181,6 +1190,7 @@ pub const Type = extern union { |
| 1181 | 1190 | .anyerror_void_error_union, |
| 1182 | 1191 | .error_set, |
| 1183 | 1192 | .error_set_single, |
| 1193 | .empty_struct, | |
| 1184 | 1194 | => false, |
| 1185 | 1195 | |
| 1186 | 1196 | .const_slice, |
| ... | ... | @@ -1252,6 +1262,7 @@ pub const Type = extern union { |
| 1252 | 1262 | .anyerror_void_error_union, |
| 1253 | 1263 | .error_set, |
| 1254 | 1264 | .error_set_single, |
| 1265 | .empty_struct, | |
| 1255 | 1266 | => false, |
| 1256 | 1267 | |
| 1257 | 1268 | .single_const_pointer, |
| ... | ... | @@ -1332,6 +1343,7 @@ pub const Type = extern union { |
| 1332 | 1343 | .anyerror_void_error_union, |
| 1333 | 1344 | .error_set, |
| 1334 | 1345 | .error_set_single, |
| 1346 | .empty_struct, | |
| 1335 | 1347 | => false, |
| 1336 | 1348 | |
| 1337 | 1349 | .pointer => { |
| ... | ... | @@ -1407,6 +1419,7 @@ pub const Type = extern union { |
| 1407 | 1419 | .anyerror_void_error_union, |
| 1408 | 1420 | .error_set, |
| 1409 | 1421 | .error_set_single, |
| 1422 | .empty_struct, | |
| 1410 | 1423 | => false, |
| 1411 | 1424 | |
| 1412 | 1425 | .pointer => { |
| ... | ... | @@ -1524,6 +1537,7 @@ pub const Type = extern union { |
| 1524 | 1537 | .anyerror_void_error_union, |
| 1525 | 1538 | .error_set, |
| 1526 | 1539 | .error_set_single, |
| 1540 | .empty_struct, | |
| 1527 | 1541 | => unreachable, |
| 1528 | 1542 | |
| 1529 | 1543 | .array => self.cast(Payload.Array).?.elem_type, |
| ... | ... | @@ -1651,6 +1665,7 @@ pub const Type = extern union { |
| 1651 | 1665 | .anyerror_void_error_union, |
| 1652 | 1666 | .error_set, |
| 1653 | 1667 | .error_set_single, |
| 1668 | .empty_struct, | |
| 1654 | 1669 | => unreachable, |
| 1655 | 1670 | |
| 1656 | 1671 | .array => self.cast(Payload.Array).?.len, |
| ... | ... | @@ -1716,6 +1731,7 @@ pub const Type = extern union { |
| 1716 | 1731 | .anyerror_void_error_union, |
| 1717 | 1732 | .error_set, |
| 1718 | 1733 | .error_set_single, |
| 1734 | .empty_struct, | |
| 1719 | 1735 | => unreachable, |
| 1720 | 1736 | |
| 1721 | 1737 | .single_const_pointer, |
| ... | ... | @@ -1798,6 +1814,7 @@ pub const Type = extern union { |
| 1798 | 1814 | .anyerror_void_error_union, |
| 1799 | 1815 | .error_set, |
| 1800 | 1816 | .error_set_single, |
| 1817 | .empty_struct, | |
| 1801 | 1818 | => false, |
| 1802 | 1819 | |
| 1803 | 1820 | .int_signed, |
| ... | ... | @@ -1872,6 +1889,7 @@ pub const Type = extern union { |
| 1872 | 1889 | .anyerror_void_error_union, |
| 1873 | 1890 | .error_set, |
| 1874 | 1891 | .error_set_single, |
| 1892 | .empty_struct, | |
| 1875 | 1893 | => false, |
| 1876 | 1894 | |
| 1877 | 1895 | .int_unsigned, |
| ... | ... | @@ -1936,6 +1954,7 @@ pub const Type = extern union { |
| 1936 | 1954 | .anyerror_void_error_union, |
| 1937 | 1955 | .error_set, |
| 1938 | 1956 | .error_set_single, |
| 1957 | .empty_struct, | |
| 1939 | 1958 | => unreachable, |
| 1940 | 1959 | |
| 1941 | 1960 | .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits }, |
| ... | ... | @@ -2018,6 +2037,7 @@ pub const Type = extern union { |
| 2018 | 2037 | .anyerror_void_error_union, |
| 2019 | 2038 | .error_set, |
| 2020 | 2039 | .error_set_single, |
| 2040 | .empty_struct, | |
| 2021 | 2041 | => false, |
| 2022 | 2042 | |
| 2023 | 2043 | .usize, |
| ... | ... | @@ -2129,6 +2149,7 @@ pub const Type = extern union { |
| 2129 | 2149 | .anyerror_void_error_union, |
| 2130 | 2150 | .error_set, |
| 2131 | 2151 | .error_set_single, |
| 2152 | .empty_struct, | |
| 2132 | 2153 | => unreachable, |
| 2133 | 2154 | }; |
| 2134 | 2155 | } |
| ... | ... | @@ -2206,6 +2227,7 @@ pub const Type = extern union { |
| 2206 | 2227 | .anyerror_void_error_union, |
| 2207 | 2228 | .error_set, |
| 2208 | 2229 | .error_set_single, |
| 2230 | .empty_struct, | |
| 2209 | 2231 | => unreachable, |
| 2210 | 2232 | } |
| 2211 | 2233 | } |
| ... | ... | @@ -2282,6 +2304,7 @@ pub const Type = extern union { |
| 2282 | 2304 | .anyerror_void_error_union, |
| 2283 | 2305 | .error_set, |
| 2284 | 2306 | .error_set_single, |
| 2307 | .empty_struct, | |
| 2285 | 2308 | => unreachable, |
| 2286 | 2309 | } |
| 2287 | 2310 | } |
| ... | ... | @@ -2358,6 +2381,7 @@ pub const Type = extern union { |
| 2358 | 2381 | .anyerror_void_error_union, |
| 2359 | 2382 | .error_set, |
| 2360 | 2383 | .error_set_single, |
| 2384 | .empty_struct, | |
| 2361 | 2385 | => unreachable, |
| 2362 | 2386 | }; |
| 2363 | 2387 | } |
| ... | ... | @@ -2431,6 +2455,7 @@ pub const Type = extern union { |
| 2431 | 2455 | .anyerror_void_error_union, |
| 2432 | 2456 | .error_set, |
| 2433 | 2457 | .error_set_single, |
| 2458 | .empty_struct, | |
| 2434 | 2459 | => unreachable, |
| 2435 | 2460 | }; |
| 2436 | 2461 | } |
| ... | ... | @@ -2504,6 +2529,7 @@ pub const Type = extern union { |
| 2504 | 2529 | .anyerror_void_error_union, |
| 2505 | 2530 | .error_set, |
| 2506 | 2531 | .error_set_single, |
| 2532 | .empty_struct, | |
| 2507 | 2533 | => unreachable, |
| 2508 | 2534 | }; |
| 2509 | 2535 | } |
| ... | ... | @@ -2577,6 +2603,7 @@ pub const Type = extern union { |
| 2577 | 2603 | .anyerror_void_error_union, |
| 2578 | 2604 | .error_set, |
| 2579 | 2605 | .error_set_single, |
| 2606 | .empty_struct, | |
| 2580 | 2607 | => false, |
| 2581 | 2608 | }; |
| 2582 | 2609 | } |
| ... | ... | @@ -2636,6 +2663,7 @@ pub const Type = extern union { |
| 2636 | 2663 | .error_set_single, |
| 2637 | 2664 | => return null, |
| 2638 | 2665 | |
| 2666 | .empty_struct => return Value.initTag(.empty_struct_value), | |
| 2639 | 2667 | .void => return Value.initTag(.void_value), |
| 2640 | 2668 | .noreturn => return Value.initTag(.unreachable_value), |
| 2641 | 2669 | .@"null" => return Value.initTag(.null_value), |
| ... | ... | @@ -2743,6 +2771,7 @@ pub const Type = extern union { |
| 2743 | 2771 | .anyerror_void_error_union, |
| 2744 | 2772 | .error_set, |
| 2745 | 2773 | .error_set_single, |
| 2774 | .empty_struct, | |
| 2746 | 2775 | => return false, |
| 2747 | 2776 | |
| 2748 | 2777 | .c_const_pointer, |
| ... | ... | @@ -2760,6 +2789,80 @@ pub const Type = extern union { |
| 2760 | 2789 | (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array); |
| 2761 | 2790 | } |
| 2762 | 2791 | |
| 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 | 2866 | /// This enum does not directly correspond to `std.builtin.TypeId` because |
| 2764 | 2867 | /// it has extra enum tags in it, as a way of using less memory. For example, |
| 2765 | 2868 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types |
| ... | ... | @@ -2835,6 +2938,7 @@ pub const Type = extern union { |
| 2835 | 2938 | anyframe_T, |
| 2836 | 2939 | error_set, |
| 2837 | 2940 | error_set_single, |
| 2941 | empty_struct, | |
| 2838 | 2942 | |
| 2839 | 2943 | pub const last_no_payload_tag = Tag.const_slice_u8; |
| 2840 | 2944 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| ... | ... | @@ -2942,6 +3046,14 @@ pub const Type = extern union { |
| 2942 | 3046 | /// memory is owned by `Module` |
| 2943 | 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 | }; |
| 2947 | 3059 |
src/value.zig+15| ... | ... | @@ -68,6 +68,7 @@ pub const Value = extern union { |
| 68 | 68 | one, |
| 69 | 69 | void_value, |
| 70 | 70 | unreachable_value, |
| 71 | empty_struct_value, | |
| 71 | 72 | empty_array, |
| 72 | 73 | null_value, |
| 73 | 74 | bool_true, |
| ... | ... | @@ -182,6 +183,7 @@ pub const Value = extern union { |
| 182 | 183 | .null_value, |
| 183 | 184 | .bool_true, |
| 184 | 185 | .bool_false, |
| 186 | .empty_struct_value, | |
| 185 | 187 | => unreachable, |
| 186 | 188 | |
| 187 | 189 | .ty => { |
| ... | ... | @@ -312,6 +314,8 @@ pub const Value = extern union { |
| 312 | 314 | .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"), |
| 313 | 315 | .anyframe_type => return out_stream.writeAll("anyframe"), |
| 314 | 316 | |
| 317 | // TODO this should print `NAME{}` | |
| 318 | .empty_struct_value => return out_stream.writeAll("struct {}{}"), | |
| 315 | 319 | .null_value => return out_stream.writeAll("null"), |
| 316 | 320 | .undef => return out_stream.writeAll("undefined"), |
| 317 | 321 | .zero => return out_stream.writeAll("0"), |
| ... | ... | @@ -475,6 +479,7 @@ pub const Value = extern union { |
| 475 | 479 | .float_128, |
| 476 | 480 | .enum_literal, |
| 477 | 481 | .@"error", |
| 482 | .empty_struct_value, | |
| 478 | 483 | => unreachable, |
| 479 | 484 | }; |
| 480 | 485 | } |
| ... | ... | @@ -543,6 +548,7 @@ pub const Value = extern union { |
| 543 | 548 | .enum_literal, |
| 544 | 549 | .error_set, |
| 545 | 550 | .@"error", |
| 551 | .empty_struct_value, | |
| 546 | 552 | => unreachable, |
| 547 | 553 | |
| 548 | 554 | .undef => unreachable, |
| ... | ... | @@ -626,6 +632,7 @@ pub const Value = extern union { |
| 626 | 632 | .enum_literal, |
| 627 | 633 | .error_set, |
| 628 | 634 | .@"error", |
| 635 | .empty_struct_value, | |
| 629 | 636 | => unreachable, |
| 630 | 637 | |
| 631 | 638 | .undef => unreachable, |
| ... | ... | @@ -709,6 +716,7 @@ pub const Value = extern union { |
| 709 | 716 | .enum_literal, |
| 710 | 717 | .error_set, |
| 711 | 718 | .@"error", |
| 719 | .empty_struct_value, | |
| 712 | 720 | => unreachable, |
| 713 | 721 | |
| 714 | 722 | .undef => unreachable, |
| ... | ... | @@ -820,6 +828,7 @@ pub const Value = extern union { |
| 820 | 828 | .enum_literal, |
| 821 | 829 | .error_set, |
| 822 | 830 | .@"error", |
| 831 | .empty_struct_value, | |
| 823 | 832 | => unreachable, |
| 824 | 833 | |
| 825 | 834 | .zero, |
| ... | ... | @@ -907,6 +916,7 @@ pub const Value = extern union { |
| 907 | 916 | .enum_literal, |
| 908 | 917 | .error_set, |
| 909 | 918 | .@"error", |
| 919 | .empty_struct_value, | |
| 910 | 920 | => unreachable, |
| 911 | 921 | |
| 912 | 922 | .zero, |
| ... | ... | @@ -1078,6 +1088,7 @@ pub const Value = extern union { |
| 1078 | 1088 | .enum_literal, |
| 1079 | 1089 | .error_set, |
| 1080 | 1090 | .@"error", |
| 1091 | .empty_struct_value, | |
| 1081 | 1092 | => unreachable, |
| 1082 | 1093 | |
| 1083 | 1094 | .zero, |
| ... | ... | @@ -1152,6 +1163,7 @@ pub const Value = extern union { |
| 1152 | 1163 | .enum_literal, |
| 1153 | 1164 | .error_set, |
| 1154 | 1165 | .@"error", |
| 1166 | .empty_struct_value, | |
| 1155 | 1167 | => unreachable, |
| 1156 | 1168 | |
| 1157 | 1169 | .zero, |
| ... | ... | @@ -1300,6 +1312,7 @@ pub const Value = extern union { |
| 1300 | 1312 | .enum_literal, |
| 1301 | 1313 | .error_set, |
| 1302 | 1314 | .@"error", |
| 1315 | .empty_struct_value, | |
| 1303 | 1316 | => unreachable, |
| 1304 | 1317 | |
| 1305 | 1318 | .ref_val => self.cast(Payload.RefVal).?.val, |
| ... | ... | @@ -1383,6 +1396,7 @@ pub const Value = extern union { |
| 1383 | 1396 | .enum_literal, |
| 1384 | 1397 | .error_set, |
| 1385 | 1398 | .@"error", |
| 1399 | .empty_struct_value, | |
| 1386 | 1400 | => unreachable, |
| 1387 | 1401 | |
| 1388 | 1402 | .empty_array => unreachable, // out of bounds array index |
| ... | ... | @@ -1483,6 +1497,7 @@ pub const Value = extern union { |
| 1483 | 1497 | .enum_literal, |
| 1484 | 1498 | .error_set, |
| 1485 | 1499 | .@"error", |
| 1500 | .empty_struct_value, | |
| 1486 | 1501 | => false, |
| 1487 | 1502 | |
| 1488 | 1503 | .undef => unreachable, |
src/zir.zig+4| ... | ... | @@ -161,6 +161,8 @@ pub const Inst = struct { |
| 161 | 161 | @"fn", |
| 162 | 162 | /// Returns a function type. |
| 163 | 163 | fntype, |
| 164 | /// @import(operand) | |
| 165 | import, | |
| 164 | 166 | /// Integer literal. |
| 165 | 167 | int, |
| 166 | 168 | /// Convert an integer value to another integer type, asserting that the destination type |
| ... | ... | @@ -315,6 +317,7 @@ pub const Inst = struct { |
| 315 | 317 | .ensure_err_payload_void, |
| 316 | 318 | .anyframe_type, |
| 317 | 319 | .bitnot, |
| 320 | .import, | |
| 318 | 321 | => UnOp, |
| 319 | 322 | |
| 320 | 323 | .add, |
| ... | ... | @@ -489,6 +492,7 @@ pub const Inst = struct { |
| 489 | 492 | .error_set, |
| 490 | 493 | .slice, |
| 491 | 494 | .slice_start, |
| 495 | .import, | |
| 492 | 496 | => false, |
| 493 | 497 | |
| 494 | 498 | .@"break", |
src/zir_sema.zig+32| ... | ... | @@ -134,6 +134,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 134 | 134 | .error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?), |
| 135 | 135 | .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?), |
| 136 | 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 | } |
| 139 | 140 | |
| ... | ... | @@ -1047,6 +1048,19 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr |
| 1047 | 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 | 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 | 1204 | return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null); |
| 1191 | 1205 | } |
| 1192 | 1206 | |
| 1207 | fn 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 | ||
| 1193 | 1225 | fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1194 | 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 | 909 | ); |
| 910 | 910 | } |
| 911 | 911 | |
| 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 | 951 | var case = ctx.exe("wasm function calls", wasi); |
| 914 | 952 |