authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-03 17:22:57-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-03 17:22:57-04:00
logf2bbd8a548c9a707aa121c58fe8c8a97666b84f2
tree82c2511159c52b9cd4e67daaed9c1e5948a3880e
parentdac1cd77505ef9fa493e069549c139d74e31081f
parent6f0126e9573a6bde9cbe5b113208e0a515b2eee7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6242 from Vexu/stage2

Stage2: slicing and split container scope from file scope

10 files changed, 394 insertions(+), 111 deletions(-)

lib/std/zig/tokenizer.zig+2-1
...@@ -1175,6 +1175,7 @@ pub const Tokenizer = struct {...@@ -1175,6 +1175,7 @@ pub const Tokenizer = struct {
1175 },1175 },
1176 .num_dot_dec => switch (c) {1176 .num_dot_dec => switch (c) {
1177 '.' => {1177 '.' => {
1178 result.id = .IntegerLiteral;
1178 self.index -= 1;1179 self.index -= 1;
1179 state = .start;1180 state = .start;
1180 break;1181 break;
...@@ -1183,7 +1184,6 @@ pub const Tokenizer = struct {...@@ -1183,7 +1184,6 @@ pub const Tokenizer = struct {
1183 state = .float_exponent_unsigned;1184 state = .float_exponent_unsigned;
1184 },1185 },
1185 '0'...'9' => {1186 '0'...'9' => {
1186 result.id = .FloatLiteral;
1187 state = .float_fraction_dec;1187 state = .float_fraction_dec;
1188 },1188 },
1189 else => {1189 else => {
...@@ -1769,6 +1769,7 @@ test "tokenizer - number literals decimal" {...@@ -1769,6 +1769,7 @@ test "tokenizer - number literals decimal" {
1769 testTokenize("7", &[_]Token.Id{.IntegerLiteral});1769 testTokenize("7", &[_]Token.Id{.IntegerLiteral});
1770 testTokenize("8", &[_]Token.Id{.IntegerLiteral});1770 testTokenize("8", &[_]Token.Id{.IntegerLiteral});
1771 testTokenize("9", &[_]Token.Id{.IntegerLiteral});1771 testTokenize("9", &[_]Token.Id{.IntegerLiteral});
1772 testTokenize("1..", &[_]Token.Id{ .IntegerLiteral, .Ellipsis2 });
1772 testTokenize("0a", &[_]Token.Id{ .Invalid, .Identifier });1773 testTokenize("0a", &[_]Token.Id{ .Invalid, .Identifier });
1773 testTokenize("9b", &[_]Token.Id{ .Invalid, .Identifier });1774 testTokenize("9b", &[_]Token.Id{ .Invalid, .Identifier });
1774 testTokenize("1z", &[_]Token.Id{ .Invalid, .Identifier });1775 testTokenize("1z", &[_]Token.Id{ .Invalid, .Identifier });
src-self-hosted/Module.zig+162-52
...@@ -125,7 +125,7 @@ pub const Decl = struct {...@@ -125,7 +125,7 @@ pub const Decl = struct {
125 /// mapping them to an address in the output file.125 /// mapping them to an address in the output file.
126 /// Memory owned by this decl, using Module's allocator.126 /// Memory owned by this decl, using Module's allocator.
127 name: [*:0]const u8,127 name: [*:0]const u8,
128 /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`.128 /// The direct parent container of the Decl. This is either a `Scope.Container` or `Scope.ZIRModule`.
129 /// Reference to externally owned memory.129 /// Reference to externally owned memory.
130 scope: *Scope,130 scope: *Scope,
131 /// The AST Node decl index or ZIR Inst index that contains this declaration.131 /// The AST Node decl index or ZIR Inst index that contains this declaration.
...@@ -217,9 +217,10 @@ pub const Decl = struct {...@@ -217,9 +217,10 @@ pub const Decl = struct {
217217
218 pub fn src(self: Decl) usize {218 pub fn src(self: Decl) usize {
219 switch (self.scope.tag) {219 switch (self.scope.tag) {
220 .file => {220 .container => {
221 const file = @fieldParentPtr(Scope.File, "base", self.scope);221 const container = @fieldParentPtr(Scope.Container, "base", self.scope);
222 const tree = file.contents.tree;222 const tree = container.file_scope.contents.tree;
223 // TODO Container should have it's own decls()
223 const decl_node = tree.root_node.decls()[self.src_index];224 const decl_node = tree.root_node.decls()[self.src_index];
224 return tree.token_locs[decl_node.firstToken()].start;225 return tree.token_locs[decl_node.firstToken()].start;
225 },226 },
...@@ -229,6 +230,7 @@ pub const Decl = struct {...@@ -229,6 +230,7 @@ pub const Decl = struct {
229 const src_decl = module.decls[self.src_index];230 const src_decl = module.decls[self.src_index];
230 return src_decl.inst.src;231 return src_decl.inst.src;
231 },232 },
233 .file,
232 .block => unreachable,234 .block => unreachable,
233 .gen_zir => unreachable,235 .gen_zir => unreachable,
234 .local_val => unreachable,236 .local_val => unreachable,
...@@ -359,6 +361,7 @@ pub const Scope = struct {...@@ -359,6 +361,7 @@ pub const Scope = struct {
359 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,361 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
360 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,362 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
361 .file => unreachable,363 .file => unreachable,
364 .container => unreachable,
362 }365 }
363 }366 }
364367
...@@ -368,15 +371,16 @@ pub const Scope = struct {...@@ -368,15 +371,16 @@ pub const Scope = struct {
368 return switch (self.tag) {371 return switch (self.tag) {
369 .block => self.cast(Block).?.decl,372 .block => self.cast(Block).?.decl,
370 .gen_zir => self.cast(GenZIR).?.decl,373 .gen_zir => self.cast(GenZIR).?.decl,
371 .local_val => return self.cast(LocalVal).?.gen_zir.decl,374 .local_val => self.cast(LocalVal).?.gen_zir.decl,
372 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl,375 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
373 .decl => self.cast(DeclAnalysis).?.decl,376 .decl => self.cast(DeclAnalysis).?.decl,
374 .zir_module => null,377 .zir_module => null,
375 .file => null,378 .file => null,
379 .container => null,
376 };380 };
377 }381 }
378382
379 /// Asserts the scope has a parent which is a ZIRModule or File and383 /// Asserts the scope has a parent which is a ZIRModule or Container and
380 /// returns it.384 /// returns it.
381 pub fn namespace(self: *Scope) *Scope {385 pub fn namespace(self: *Scope) *Scope {
382 switch (self.tag) {386 switch (self.tag) {
...@@ -385,7 +389,8 @@ pub const Scope = struct {...@@ -385,7 +389,8 @@ pub const Scope = struct {
385 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,389 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
386 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,390 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
387 .decl => return self.cast(DeclAnalysis).?.decl.scope,391 .decl => return self.cast(DeclAnalysis).?.decl.scope,
388 .zir_module, .file => return self,392 .file => return &self.cast(File).?.root_container.base,
393 .zir_module, .container => return self,
389 }394 }
390 }395 }
391396
...@@ -399,8 +404,9 @@ pub const Scope = struct {...@@ -399,8 +404,9 @@ pub const Scope = struct {
399 .local_val => unreachable,404 .local_val => unreachable,
400 .local_ptr => unreachable,405 .local_ptr => unreachable,
401 .decl => unreachable,406 .decl => unreachable,
407 .file => unreachable,
402 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),408 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
403 .file => return self.cast(File).?.fullyQualifiedNameHash(name),409 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
404 }410 }
405 }411 }
406412
...@@ -409,11 +415,12 @@ pub const Scope = struct {...@@ -409,11 +415,12 @@ pub const Scope = struct {
409 switch (self.tag) {415 switch (self.tag) {
410 .file => return self.cast(File).?.contents.tree,416 .file => return self.cast(File).?.contents.tree,
411 .zir_module => unreachable,417 .zir_module => unreachable,
412 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,418 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(Container).?.file_scope.contents.tree,
413 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,419 .block => return self.cast(Block).?.decl.scope.cast(Container).?.file_scope.contents.tree,
414 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,420 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(Container).?.file_scope.contents.tree,
415 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(File).?.contents.tree,421 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
416 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(File).?.contents.tree,422 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
423 .container => return self.cast(Container).?.file_scope.contents.tree,
417 }424 }
418 }425 }
419426
...@@ -427,13 +434,15 @@ pub const Scope = struct {...@@ -427,13 +434,15 @@ pub const Scope = struct {
427 .decl => unreachable,434 .decl => unreachable,
428 .zir_module => unreachable,435 .zir_module => unreachable,
429 .file => unreachable,436 .file => unreachable,
437 .container => unreachable,
430 };438 };
431 }439 }
432440
433 /// Asserts the scope has a parent which is a ZIRModule or File and441 /// Asserts the scope has a parent which is a ZIRModule, Contaienr or File and
434 /// returns the sub_file_path field.442 /// returns the sub_file_path field.
435 pub fn subFilePath(base: *Scope) []const u8 {443 pub fn subFilePath(base: *Scope) []const u8 {
436 switch (base.tag) {444 switch (base.tag) {
445 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
437 .file => return @fieldParentPtr(File, "base", base).sub_file_path,446 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
438 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,447 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
439 .block => unreachable,448 .block => unreachable,
...@@ -453,11 +462,13 @@ pub const Scope = struct {...@@ -453,11 +462,13 @@ pub const Scope = struct {
453 .local_val => unreachable,462 .local_val => unreachable,
454 .local_ptr => unreachable,463 .local_ptr => unreachable,
455 .decl => unreachable,464 .decl => unreachable,
465 .container => unreachable,
456 }466 }
457 }467 }
458468
459 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {469 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
460 switch (base.tag) {470 switch (base.tag) {
471 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
461 .file => return @fieldParentPtr(File, "base", base).getSource(module),472 .file => return @fieldParentPtr(File, "base", base).getSource(module),
462 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),473 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
463 .gen_zir => unreachable,474 .gen_zir => unreachable,
...@@ -471,8 +482,9 @@ pub const Scope = struct {...@@ -471,8 +482,9 @@ pub const Scope = struct {
471 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.482 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
472 pub fn removeDecl(base: *Scope, child: *Decl) void {483 pub fn removeDecl(base: *Scope, child: *Decl) void {
473 switch (base.tag) {484 switch (base.tag) {
474 .file => return @fieldParentPtr(File, "base", base).removeDecl(child),485 .container => return @fieldParentPtr(Container, "base", base).removeDecl(child),
475 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),486 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
487 .file => unreachable,
476 .block => unreachable,488 .block => unreachable,
477 .gen_zir => unreachable,489 .gen_zir => unreachable,
478 .local_val => unreachable,490 .local_val => unreachable,
...@@ -499,6 +511,7 @@ pub const Scope = struct {...@@ -499,6 +511,7 @@ pub const Scope = struct {
499 .local_val => unreachable,511 .local_val => unreachable,
500 .local_ptr => unreachable,512 .local_ptr => unreachable,
501 .decl => unreachable,513 .decl => unreachable,
514 .container => unreachable,
502 }515 }
503 }516 }
504517
...@@ -515,6 +528,8 @@ pub const Scope = struct {...@@ -515,6 +528,8 @@ pub const Scope = struct {
515 zir_module,528 zir_module,
516 /// .zig source code.529 /// .zig source code.
517 file,530 file,
531 /// struct, enum or union, every .file contains one of these.
532 container,
518 block,533 block,
519 decl,534 decl,
520 gen_zir,535 gen_zir,
...@@ -522,6 +537,38 @@ pub const Scope = struct {...@@ -522,6 +537,38 @@ pub const Scope = struct {
522 local_ptr,537 local_ptr,
523 };538 };
524539
540 pub const Container = struct {
541 pub const base_tag: Tag = .container;
542 base: Scope = Scope{ .tag = base_tag },
543
544 file_scope: *Scope.File,
545
546 /// Direct children of the file.
547 decls: ArrayListUnmanaged(*Decl),
548
549 // TODO implement container types and put this in a status union
550 // ty: Type
551
552 pub fn deinit(self: *Container, gpa: *Allocator) void {
553 self.decls.deinit(gpa);
554 self.* = undefined;
555 }
556
557 pub fn removeDecl(self: *Container, child: *Decl) void {
558 for (self.decls.items) |item, i| {
559 if (item == child) {
560 _ = self.decls.swapRemove(i);
561 return;
562 }
563 }
564 }
565
566 pub fn fullyQualifiedNameHash(self: *Container, name: []const u8) NameHash {
567 // TODO container scope qualified names.
568 return std.zig.hashSrc(name);
569 }
570 };
571
525 pub const File = struct {572 pub const File = struct {
526 pub const base_tag: Tag = .file;573 pub const base_tag: Tag = .file;
527 base: Scope = Scope{ .tag = base_tag },574 base: Scope = Scope{ .tag = base_tag },
...@@ -544,8 +591,7 @@ pub const Scope = struct {...@@ -544,8 +591,7 @@ pub const Scope = struct {
544 loaded_success,591 loaded_success,
545 },592 },
546593
547 /// Direct children of the file.594 root_container: Container,
548 decls: ArrayListUnmanaged(*Decl),
549595
550 pub fn unload(self: *File, gpa: *Allocator) void {596 pub fn unload(self: *File, gpa: *Allocator) void {
551 switch (self.status) {597 switch (self.status) {
...@@ -569,20 +615,11 @@ pub const Scope = struct {...@@ -569,20 +615,11 @@ pub const Scope = struct {
569 }615 }
570616
571 pub fn deinit(self: *File, gpa: *Allocator) void {617 pub fn deinit(self: *File, gpa: *Allocator) void {
572 self.decls.deinit(gpa);618 self.root_container.deinit(gpa);
573 self.unload(gpa);619 self.unload(gpa);
574 self.* = undefined;620 self.* = undefined;
575 }621 }
576622
577 pub fn removeDecl(self: *File, child: *Decl) void {
578 for (self.decls.items) |item, i| {
579 if (item == child) {
580 _ = self.decls.swapRemove(i);
581 return;
582 }
583 }
584 }
585
586 pub fn dumpSrc(self: *File, src: usize) void {623 pub fn dumpSrc(self: *File, src: usize) void {
587 const loc = std.zig.findLineColumn(self.source.bytes, src);624 const loc = std.zig.findLineColumn(self.source.bytes, src);
588 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });625 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
...@@ -604,11 +641,6 @@ pub const Scope = struct {...@@ -604,11 +641,6 @@ pub const Scope = struct {
604 .bytes => |bytes| return bytes,641 .bytes => |bytes| return bytes,
605 }642 }
606 }643 }
607
608 pub fn fullyQualifiedNameHash(self: *File, name: []const u8) NameHash {
609 // We don't have struct scopes yet so this is currently just a simple name hash.
610 return std.zig.hashSrc(name);
611 }
612 };644 };
613645
614 pub const ZIRModule = struct {646 pub const ZIRModule = struct {
...@@ -861,7 +893,10 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {...@@ -861,7 +893,10 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
861 .source = .{ .unloaded = {} },893 .source = .{ .unloaded = {} },
862 .contents = .{ .not_available = {} },894 .contents = .{ .not_available = {} },
863 .status = .never_loaded,895 .status = .never_loaded,
864 .decls = .{},896 .root_container = .{
897 .file_scope = root_scope,
898 .decls = .{},
899 },
865 };900 };
866 break :blk &root_scope.base;901 break :blk &root_scope.base;
867 } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) {902 } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) {
...@@ -969,7 +1004,7 @@ pub fn update(self: *Module) !void {...@@ -969,7 +1004,7 @@ pub fn update(self: *Module) !void {
969 // to force a refresh we unload now.1004 // to force a refresh we unload now.
970 if (self.root_scope.cast(Scope.File)) |zig_file| {1005 if (self.root_scope.cast(Scope.File)) |zig_file| {
971 zig_file.unload(self.gpa);1006 zig_file.unload(self.gpa);
972 self.analyzeRootSrcFile(zig_file) catch |err| switch (err) {1007 self.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
973 error.AnalysisFail => {1008 error.AnalysisFail => {
974 assert(self.totalErrorCount() != 0);1009 assert(self.totalErrorCount() != 0);
975 },1010 },
...@@ -1237,8 +1272,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1237,8 +1272,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1237 const tracy = trace(@src());1272 const tracy = trace(@src());
1238 defer tracy.end();1273 defer tracy.end();
12391274
1240 const file_scope = decl.scope.cast(Scope.File).?;1275 const container_scope = decl.scope.cast(Scope.Container).?;
1241 const tree = try self.getAstTree(file_scope);1276 const tree = try self.getAstTree(container_scope);
1242 const ast_node = tree.root_node.decls()[decl.src_index];1277 const ast_node = tree.root_node.decls()[decl.src_index];
1243 switch (ast_node.tag) {1278 switch (ast_node.tag) {
1244 .FnProto => {1279 .FnProto => {
...@@ -1698,10 +1733,12 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {...@@ -1698,10 +1733,12 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
1698 }1733 }
1699}1734}
17001735
1701fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {1736fn getAstTree(self: *Module, container_scope: *Scope.Container) !*ast.Tree {
1702 const tracy = trace(@src());1737 const tracy = trace(@src());
1703 defer tracy.end();1738 defer tracy.end();
17041739
1740 const root_scope = container_scope.file_scope;
1741
1705 switch (root_scope.status) {1742 switch (root_scope.status) {
1706 .never_loaded, .unloaded_success => {1743 .never_loaded, .unloaded_success => {
1707 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);1744 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
...@@ -1743,24 +1780,24 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {...@@ -1743,24 +1780,24 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1743 }1780 }
1744}1781}
17451782
1746fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {1783fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void {
1747 const tracy = trace(@src());1784 const tracy = trace(@src());
1748 defer tracy.end();1785 defer tracy.end();
17491786
1750 // We may be analyzing it for the first time, or this may be1787 // We may be analyzing it for the first time, or this may be
1751 // an incremental update. This code handles both cases.1788 // an incremental update. This code handles both cases.
1752 const tree = try self.getAstTree(root_scope);1789 const tree = try self.getAstTree(container_scope);
1753 const decls = tree.root_node.decls();1790 const decls = tree.root_node.decls();
17541791
1755 try self.work_queue.ensureUnusedCapacity(decls.len);1792 try self.work_queue.ensureUnusedCapacity(decls.len);
1756 try root_scope.decls.ensureCapacity(self.gpa, decls.len);1793 try container_scope.decls.ensureCapacity(self.gpa, decls.len);
17571794
1758 // Keep track of the decls that we expect to see in this file so that1795 // Keep track of the decls that we expect to see in this file so that
1759 // we know which ones have been deleted.1796 // we know which ones have been deleted.
1760 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);1797 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
1761 defer deleted_decls.deinit();1798 defer deleted_decls.deinit();
1762 try deleted_decls.ensureCapacity(root_scope.decls.items.len);1799 try deleted_decls.ensureCapacity(container_scope.decls.items.len);
1763 for (root_scope.decls.items) |file_decl| {1800 for (container_scope.decls.items) |file_decl| {
1764 deleted_decls.putAssumeCapacityNoClobber(file_decl, {});1801 deleted_decls.putAssumeCapacityNoClobber(file_decl, {});
1765 }1802 }
17661803
...@@ -1773,7 +1810,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1773,7 +1810,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
17731810
1774 const name_loc = tree.token_locs[name_tok];1811 const name_loc = tree.token_locs[name_tok];
1775 const name = tree.tokenSliceLoc(name_loc);1812 const name = tree.tokenSliceLoc(name_loc);
1776 const name_hash = root_scope.fullyQualifiedNameHash(name);1813 const name_hash = container_scope.fullyQualifiedNameHash(name);
1777 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));1814 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1778 if (self.decl_table.get(name_hash)) |decl| {1815 if (self.decl_table.get(name_hash)) |decl| {
1779 // Update the AST Node index of the decl, even if its contents are unchanged, it may1816 // Update the AST Node index of the decl, even if its contents are unchanged, it may
...@@ -1801,8 +1838,8 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1801,8 +1838,8 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1801 }1838 }
1802 }1839 }
1803 } else {1840 } else {
1804 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);1841 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1805 root_scope.decls.appendAssumeCapacity(new_decl);1842 container_scope.decls.appendAssumeCapacity(new_decl);
1806 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {1843 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
1807 if (tree.token_ids[maybe_export_token] == .Keyword_export) {1844 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1808 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });1845 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
...@@ -1812,7 +1849,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1812,7 +1849,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1812 } else if (src_decl.castTag(.VarDecl)) |var_decl| {1849 } else if (src_decl.castTag(.VarDecl)) |var_decl| {
1813 const name_loc = tree.token_locs[var_decl.name_token];1850 const name_loc = tree.token_locs[var_decl.name_token];
1814 const name = tree.tokenSliceLoc(name_loc);1851 const name = tree.tokenSliceLoc(name_loc);
1815 const name_hash = root_scope.fullyQualifiedNameHash(name);1852 const name_hash = container_scope.fullyQualifiedNameHash(name);
1816 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));1853 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1817 if (self.decl_table.get(name_hash)) |decl| {1854 if (self.decl_table.get(name_hash)) |decl| {
1818 // Update the AST Node index of the decl, even if its contents are unchanged, it may1855 // Update the AST Node index of the decl, even if its contents are unchanged, it may
...@@ -1828,8 +1865,8 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1828,8 +1865,8 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1828 decl.contents_hash = contents_hash;1865 decl.contents_hash = contents_hash;
1829 }1866 }
1830 } else {1867 } else {
1831 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);1868 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1832 root_scope.decls.appendAssumeCapacity(new_decl);1869 container_scope.decls.appendAssumeCapacity(new_decl);
1833 if (var_decl.getExternExportToken()) |maybe_export_token| {1870 if (var_decl.getExternExportToken()) |maybe_export_token| {
1834 if (tree.token_ids[maybe_export_token] == .Keyword_export) {1871 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1835 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });1872 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
...@@ -1841,11 +1878,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1841,11 +1878,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1841 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});1878 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
1842 defer self.gpa.free(name);1879 defer self.gpa.free(name);
18431880
1844 const name_hash = root_scope.fullyQualifiedNameHash(name);1881 const name_hash = container_scope.fullyQualifiedNameHash(name);
1845 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));1882 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
18461883
1847 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);1884 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1848 root_scope.decls.appendAssumeCapacity(new_decl);1885 container_scope.decls.appendAssumeCapacity(new_decl);
1849 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });1886 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1850 } else if (src_decl.castTag(.ContainerField)) |container_field| {1887 } else if (src_decl.castTag(.ContainerField)) |container_field| {
1851 log.err("TODO: analyze container field", .{});1888 log.err("TODO: analyze container field", .{});
...@@ -2591,6 +2628,72 @@ pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) In...@@ -2591,6 +2628,72 @@ pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) In
2591 return self.fail(scope, src, "TODO implement analysis of iserr", .{});2628 return self.fail(scope, src, "TODO implement analysis of iserr", .{});
2592}2629}
25932630
2631pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
2632 const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
2633 .Pointer => array_ptr.ty.elemType(),
2634 else => return self.fail(scope, src, "expected pointer, found '{}'", .{array_ptr.ty}),
2635 };
2636
2637 var array_type = ptr_child;
2638 const elem_type = switch (ptr_child.zigTypeTag()) {
2639 .Array => ptr_child.elemType(),
2640 .Pointer => blk: {
2641 if (ptr_child.isSinglePointer()) {
2642 if (ptr_child.elemType().zigTypeTag() == .Array) {
2643 array_type = ptr_child.elemType();
2644 break :blk ptr_child.elemType().elemType();
2645 }
2646
2647 return self.fail(scope, src, "slice of single-item pointer", .{});
2648 }
2649 break :blk ptr_child.elemType();
2650 },
2651 else => return self.fail(scope, src, "slice of non-array type '{}'", .{ptr_child}),
2652 };
2653
2654 const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
2655 const casted = try self.coerce(scope, elem_type, sentinel);
2656 break :blk try self.resolveConstValue(scope, casted);
2657 } else null;
2658
2659 var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
2660 var return_elem_type = elem_type;
2661 if (end_opt) |end| {
2662 if (end.value()) |end_val| {
2663 if (start.value()) |start_val| {
2664 const start_u64 = start_val.toUnsignedInt();
2665 const end_u64 = end_val.toUnsignedInt();
2666 if (start_u64 > end_u64) {
2667 return self.fail(scope, src, "out of bounds slice", .{});
2668 }
2669
2670 const len = end_u64 - start_u64;
2671 const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
2672 array_type.sentinel()
2673 else
2674 slice_sentinel;
2675 return_elem_type = try self.arrayType(scope, len, array_sentinel, elem_type);
2676 return_ptr_size = .One;
2677 }
2678 }
2679 }
2680 const return_type = try self.ptrType(
2681 scope,
2682 src,
2683 return_elem_type,
2684 if (end_opt == null) slice_sentinel else null,
2685 0, // TODO alignment
2686 0,
2687 0,
2688 !ptr_child.isConstPtr(),
2689 ptr_child.isAllowzeroPtr(),
2690 ptr_child.isVolatilePtr(),
2691 return_ptr_size,
2692 );
2693
2694 return self.fail(scope, src, "TODO implement analysis of slice", .{});
2695}
2696
2594/// Asserts that lhs and rhs types are both numeric.2697/// Asserts that lhs and rhs types are both numeric.
2595pub fn cmpNumeric(2698pub fn cmpNumeric(
2596 self: *Module,2699 self: *Module,
...@@ -2801,6 +2904,12 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty...@@ -2801,6 +2904,12 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
2801 prev_inst = next_inst;2904 prev_inst = next_inst;
2802 continue;2905 continue;
2803 }2906 }
2907 if (next_inst.ty.zigTypeTag() == .Undefined)
2908 continue;
2909 if (prev_inst.ty.zigTypeTag() == .Undefined) {
2910 prev_inst = next_inst;
2911 continue;
2912 }
2804 if (prev_inst.ty.isInt() and2913 if (prev_inst.ty.isInt() and
2805 next_inst.ty.isInt() and2914 next_inst.ty.isInt() and
2806 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())2915 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())
...@@ -3052,6 +3161,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err...@@ -3052,6 +3161,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
3052 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);3161 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
3053 },3162 },
3054 .file => unreachable,3163 .file => unreachable,
3164 .container => unreachable,
3055 }3165 }
3056 return error.AnalysisFail;3166 return error.AnalysisFail;
3057}3167}
src-self-hosted/astgen.zig+74-26
...@@ -275,16 +275,16 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -275,16 +275,16 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),
277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
278 .Slice => return rlWrap(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)),
278 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),279 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
279 .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),280 .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
281 .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?),
280282
281 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),283 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
282 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),284 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
283 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
284 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),285 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
285 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),286 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
286 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),287 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
287 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
288 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),288 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
289 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),289 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
290 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),290 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
...@@ -790,13 +790,31 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*...@@ -790,13 +790,31 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*
790}790}
791791
792fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst {792fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst {
793 return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .iserr, .unwrap_err_unsafe, node.rhs, node.payload);
794}
795
796fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
797 return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .isnull, .unwrap_optional_unsafe, node.rhs, null);
798}
799
800fn orelseCatchExpr(
801 mod: *Module,
802 scope: *Scope,
803 rl: ResultLoc,
804 lhs: *ast.Node,
805 op_token: ast.TokenIndex,
806 cond_op: zir.Inst.Tag,
807 unwrap_op: zir.Inst.Tag,
808 rhs: *ast.Node,
809 payload_node: ?*ast.Node,
810) InnerError!*zir.Inst {
793 const tree = scope.tree();811 const tree = scope.tree();
794 const src = tree.token_locs[node.op_token].start;812 const src = tree.token_locs[op_token].start;
795813
796 const err_union_ptr = try expr(mod, scope, .ref, node.lhs);814 const operand_ptr = try expr(mod, scope, .ref, lhs);
797 // TODO we could avoid an unnecessary copy if .iserr took a pointer815 // TODO we could avoid an unnecessary copy if .iserr, .isnull took a pointer
798 const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr);816 const err_union = try addZIRUnOp(mod, scope, src, .deref, operand_ptr);
799 const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union);817 const cond = try addZIRUnOp(mod, scope, src, cond_op, err_union);
800818
801 var block_scope: Scope.GenZIR = .{819 var block_scope: Scope.GenZIR = .{
802 .parent = scope,820 .parent = scope,
...@@ -825,55 +843,55 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch)...@@ -825,55 +843,55 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch)
825 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },843 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
826 };844 };
827845
828 var err_scope: Scope.GenZIR = .{846 var then_scope: Scope.GenZIR = .{
829 .parent = scope,847 .parent = scope,
830 .decl = block_scope.decl,848 .decl = block_scope.decl,
831 .arena = block_scope.arena,849 .arena = block_scope.arena,
832 .instructions = .{},850 .instructions = .{},
833 };851 };
834 defer err_scope.instructions.deinit(mod.gpa);852 defer then_scope.instructions.deinit(mod.gpa);
835853
836 var err_val_scope: Scope.LocalVal = undefined;854 var err_val_scope: Scope.LocalVal = undefined;
837 const err_sub_scope = blk: {855 const then_sub_scope = blk: {
838 const payload = node.payload orelse856 const payload = payload_node orelse
839 break :blk &err_scope.base;857 break :blk &then_scope.base;
840858
841 const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());859 const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());
842 if (mem.eql(u8, err_name, "_"))860 if (mem.eql(u8, err_name, "_"))
843 break :blk &err_scope.base;861 break :blk &then_scope.base;
844862
845 const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr);863 const unwrapped_err_ptr = try addZIRUnOp(mod, &then_scope.base, src, .unwrap_err_code, operand_ptr);
846 err_val_scope = .{864 err_val_scope = .{
847 .parent = &err_scope.base,865 .parent = &then_scope.base,
848 .gen_zir = &err_scope,866 .gen_zir = &then_scope,
849 .name = err_name,867 .name = err_name,
850 .inst = try addZIRUnOp(mod, &err_scope.base, src, .deref, unwrapped_err_ptr),868 .inst = try addZIRUnOp(mod, &then_scope.base, src, .deref, unwrapped_err_ptr),
851 };869 };
852 break :blk &err_val_scope.base;870 break :blk &err_val_scope.base;
853 };871 };
854872
855 _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{873 _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{
856 .block = block,874 .block = block,
857 .operand = try expr(mod, err_sub_scope, branch_rl, node.rhs),875 .operand = try expr(mod, then_sub_scope, branch_rl, rhs),
858 }, .{});876 }, .{});
859877
860 var not_err_scope: Scope.GenZIR = .{878 var else_scope: Scope.GenZIR = .{
861 .parent = scope,879 .parent = scope,
862 .decl = block_scope.decl,880 .decl = block_scope.decl,
863 .arena = block_scope.arena,881 .arena = block_scope.arena,
864 .instructions = .{},882 .instructions = .{},
865 };883 };
866 defer not_err_scope.instructions.deinit(mod.gpa);884 defer else_scope.instructions.deinit(mod.gpa);
867885
868 const unwrapped_payload = try addZIRUnOp(mod, &not_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr);886 const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand_ptr);
869 _ = try addZIRInst(mod, &not_err_scope.base, src, zir.Inst.Break, .{887 _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{
870 .block = block,888 .block = block,
871 .operand = unwrapped_payload,889 .operand = unwrapped_payload,
872 }, .{});890 }, .{});
873891
874 condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) };892 condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) };
875 condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) };893 condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) };
876 return rlWrap(mod, scope, rl, &block.base);894 return rlWrapPtr(mod, scope, rl, &block.base);
877}895}
878896
879/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.897/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.
...@@ -933,6 +951,36 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array...@@ -933,6 +951,36 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array
933 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{}));951 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{}));
934}952}
935953
954fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst {
955 const tree = scope.tree();
956 const src = tree.token_locs[node.rtoken].start;
957
958 const usize_type = try addZIRInstConst(mod, scope, src, .{
959 .ty = Type.initTag(.type),
960 .val = Value.initTag(.usize_type),
961 });
962
963 const array_ptr = try expr(mod, scope, .ref, node.lhs);
964 const start = try expr(mod, scope, .{ .ty = usize_type }, node.start);
965
966 if (node.end == null and node.sentinel == null) {
967 return try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start);
968 }
969
970 const end = if (node.end) |end| try expr(mod, scope, .{ .ty = usize_type }, end) else null;
971 // we could get the child type here, but it is easier to just do it in semantic analysis.
972 const sentinel = if (node.sentinel) |sentinel| try expr(mod, scope, .none, sentinel) else null;
973
974 return try addZIRInst(
975 mod,
976 scope,
977 src,
978 zir.Inst.Slice,
979 .{ .array_ptr = array_ptr, .start = start },
980 .{ .end = end, .sentinel = sentinel },
981 );
982}
983
936fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {984fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
937 const tree = scope.tree();985 const tree = scope.tree();
938 const src = tree.token_locs[node.rtoken].start;986 const src = tree.token_locs[node.rtoken].start;
src-self-hosted/codegen.zig+3-3
...@@ -132,7 +132,7 @@ pub fn generateSymbol(...@@ -132,7 +132,7 @@ pub fn generateSymbol(
132 .Array => {132 .Array => {
133 // TODO populate .debug_info for the array133 // TODO populate .debug_info for the array
134 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {134 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
135 if (typed_value.ty.arraySentinel()) |sentinel| {135 if (typed_value.ty.sentinel()) |sentinel| {
136 try code.ensureCapacity(code.items.len + payload.data.len + 1);136 try code.ensureCapacity(code.items.len + payload.data.len + 1);
137 code.appendSliceAssumeCapacity(payload.data);137 code.appendSliceAssumeCapacity(payload.data);
138 const prev_len = code.items.len;138 const prev_len = code.items.len;
...@@ -436,8 +436,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -436,8 +436,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
436 try branch_stack.append(.{});436 try branch_stack.append(.{});
437437
438 const src_data: struct {lbrace_src: usize, rbrace_src: usize, source: []const u8} = blk: {438 const src_data: struct {lbrace_src: usize, rbrace_src: usize, source: []const u8} = blk: {
439 if (module_fn.owner_decl.scope.cast(Module.Scope.File)) |scope_file| {439 if (module_fn.owner_decl.scope.cast(Module.Scope.Container)) |container_scope| {
440 const tree = scope_file.contents.tree;440 const tree = container_scope.file_scope.contents.tree;
441 const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;441 const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;
442 const block = fn_proto.getBodyNode().?.castTag(.Block).?;442 const block = fn_proto.getBodyNode().?.castTag(.Block).?;
443 const lbrace_src = tree.token_locs[block.lbrace].start;443 const lbrace_src = tree.token_locs[block.lbrace].start;
src-self-hosted/codegen/c.zig+1-1
...@@ -85,7 +85,7 @@ fn genArray(file: *C, decl: *Decl) !void {...@@ -85,7 +85,7 @@ fn genArray(file: *C, decl: *Decl) !void {
85 const name = try map(file.base.allocator, mem.span(decl.name));85 const name = try map(file.base.allocator, mem.span(decl.name));
86 defer file.base.allocator.free(name);86 defer file.base.allocator.free(name);
87 if (tv.val.cast(Value.Payload.Bytes)) |payload|87 if (tv.val.cast(Value.Payload.Bytes)) |payload|
88 if (tv.ty.arraySentinel()) |sentinel|88 if (tv.ty.sentinel()) |sentinel|
89 if (sentinel.toUnsignedInt() == 0)89 if (sentinel.toUnsignedInt() == 0)
90 try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data })90 try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data })
91 else91 else
src-self-hosted/link/Elf.zig+4-4
...@@ -1656,8 +1656,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -1656,8 +1656,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
1656 try dbg_line_buffer.ensureCapacity(26);1656 try dbg_line_buffer.ensureCapacity(26);
16571657
1658 const line_off: u28 = blk: {1658 const line_off: u28 = blk: {
1659 if (decl.scope.cast(Module.Scope.File)) |scope_file| {1659 if (decl.scope.cast(Module.Scope.Container)) |container_scope| {
1660 const tree = scope_file.contents.tree;1660 const tree = container_scope.file_scope.contents.tree;
1661 const file_ast_decls = tree.root_node.decls();1661 const file_ast_decls = tree.root_node.decls();
1662 // TODO Look into improving the performance here by adding a token-index-to-line1662 // TODO Look into improving the performance here by adding a token-index-to-line
1663 // lookup table. Currently this involves scanning over the source code for newlines.1663 // lookup table. Currently this involves scanning over the source code for newlines.
...@@ -2157,8 +2157,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2157,8 +2157,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
2157 const tracy = trace(@src());2157 const tracy = trace(@src());
2158 defer tracy.end();2158 defer tracy.end();
21592159
2160 const scope_file = decl.scope.cast(Module.Scope.File).?;2160 const container_scope = decl.scope.cast(Module.Scope.Container).?;
2161 const tree = scope_file.contents.tree;2161 const tree = container_scope.file_scope.contents.tree;
2162 const file_ast_decls = tree.root_node.decls();2162 const file_ast_decls = tree.root_node.decls();
2163 // TODO Look into improving the performance here by adding a token-index-to-line2163 // TODO Look into improving the performance here by adding a token-index-to-line
2164 // lookup table. Currently this involves scanning over the source code for newlines.2164 // lookup table. Currently this involves scanning over the source code for newlines.
src-self-hosted/type.zig+98-20
...@@ -163,7 +163,7 @@ pub const Type = extern union {...@@ -163,7 +163,7 @@ pub const Type = extern union {
163 // Hot path for common case:163 // Hot path for common case:
164 if (a.castPointer()) |a_payload| {164 if (a.castPointer()) |a_payload| {
165 if (b.castPointer()) |b_payload| {165 if (b.castPointer()) |b_payload| {
166 return eql(a_payload.pointee_type, b_payload.pointee_type);166 return a.tag() == b.tag() and eql(a_payload.pointee_type, b_payload.pointee_type);
167 }167 }
168 }168 }
169 const is_slice_a = isSlice(a);169 const is_slice_a = isSlice(a);
...@@ -189,10 +189,10 @@ pub const Type = extern union {...@@ -189,10 +189,10 @@ pub const Type = extern union {
189 .Array => {189 .Array => {
190 if (a.arrayLen() != b.arrayLen())190 if (a.arrayLen() != b.arrayLen())
191 return false;191 return false;
192 if (a.elemType().eql(b.elemType()))192 if (!a.elemType().eql(b.elemType()))
193 return false;193 return false;
194 const sentinel_a = a.arraySentinel();194 const sentinel_a = a.sentinel();
195 const sentinel_b = b.arraySentinel();195 const sentinel_b = b.sentinel();
196 if (sentinel_a) |sa| {196 if (sentinel_a) |sa| {
197 if (sentinel_b) |sb| {197 if (sentinel_b) |sb| {
198 return sa.eql(sb);198 return sa.eql(sb);
...@@ -501,9 +501,9 @@ pub const Type = extern union {...@@ -501,9 +501,9 @@ pub const Type = extern union {
501 .noreturn,501 .noreturn,
502 => return out_stream.writeAll(@tagName(t)),502 => return out_stream.writeAll(@tagName(t)),
503503
504 .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),504 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
505 .@"null" => return out_stream.writeAll("@TypeOf(null)"),505 .@"null" => return out_stream.writeAll("@Type(.Null)"),
506 .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),506 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
507507
508 .@"anyframe" => return out_stream.writeAll("anyframe"),508 .@"anyframe" => return out_stream.writeAll("anyframe"),
509 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),509 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
...@@ -630,8 +630,8 @@ pub const Type = extern union {...@@ -630,8 +630,8 @@ pub const Type = extern union {
630 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);630 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
631 if (payload.sentinel) |some| switch (payload.size) {631 if (payload.sentinel) |some| switch (payload.size) {
632 .One, .C => unreachable,632 .One, .C => unreachable,
633 .Many => try out_stream.writeAll("[*:{}]"),633 .Many => try out_stream.print("[*:{}]", .{some}),
634 .Slice => try out_stream.writeAll("[:{}]"),634 .Slice => try out_stream.print("[:{}]", .{some}),
635 } else switch (payload.size) {635 } else switch (payload.size) {
636 .One => try out_stream.writeAll("*"),636 .One => try out_stream.writeAll("*"),
637 .Many => try out_stream.writeAll("[*]"),637 .Many => try out_stream.writeAll("[*]"),
...@@ -1341,6 +1341,81 @@ pub const Type = extern union {...@@ -1341,6 +1341,81 @@ pub const Type = extern union {
1341 };1341 };
1342 }1342 }
13431343
1344 pub fn isAllowzeroPtr(self: Type) bool {
1345 return switch (self.tag()) {
1346 .u8,
1347 .i8,
1348 .u16,
1349 .i16,
1350 .u32,
1351 .i32,
1352 .u64,
1353 .i64,
1354 .usize,
1355 .isize,
1356 .c_short,
1357 .c_ushort,
1358 .c_int,
1359 .c_uint,
1360 .c_long,
1361 .c_ulong,
1362 .c_longlong,
1363 .c_ulonglong,
1364 .c_longdouble,
1365 .f16,
1366 .f32,
1367 .f64,
1368 .f128,
1369 .c_void,
1370 .bool,
1371 .void,
1372 .type,
1373 .anyerror,
1374 .comptime_int,
1375 .comptime_float,
1376 .noreturn,
1377 .@"null",
1378 .@"undefined",
1379 .array,
1380 .array_sentinel,
1381 .array_u8,
1382 .array_u8_sentinel_0,
1383 .fn_noreturn_no_args,
1384 .fn_void_no_args,
1385 .fn_naked_noreturn_no_args,
1386 .fn_ccc_void_no_args,
1387 .function,
1388 .int_unsigned,
1389 .int_signed,
1390 .single_mut_pointer,
1391 .single_const_pointer,
1392 .many_const_pointer,
1393 .many_mut_pointer,
1394 .c_const_pointer,
1395 .c_mut_pointer,
1396 .const_slice,
1397 .mut_slice,
1398 .single_const_pointer_to_comptime_int,
1399 .const_slice_u8,
1400 .optional,
1401 .optional_single_mut_pointer,
1402 .optional_single_const_pointer,
1403 .enum_literal,
1404 .error_union,
1405 .@"anyframe",
1406 .anyframe_T,
1407 .anyerror_void_error_union,
1408 .error_set,
1409 .error_set_single,
1410 => false,
1411
1412 .pointer => {
1413 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
1414 return payload.@"allowzero";
1415 },
1416 };
1417 }
1418
1344 /// Asserts that the type is an optional1419 /// Asserts that the type is an optional
1345 pub fn isPtrLikeOptional(self: Type) bool {1420 pub fn isPtrLikeOptional(self: Type) bool {
1346 switch (self.tag()) {1421 switch (self.tag()) {
...@@ -1585,8 +1660,8 @@ pub const Type = extern union {...@@ -1585,8 +1660,8 @@ pub const Type = extern union {
1585 };1660 };
1586 }1661 }
15871662
1588 /// Asserts the type is an array or vector.1663 /// Asserts the type is an array, pointer or vector.
1589 pub fn arraySentinel(self: Type) ?Value {1664 pub fn sentinel(self: Type) ?Value {
1590 return switch (self.tag()) {1665 return switch (self.tag()) {
1591 .u8,1666 .u8,
1592 .i8,1667 .i8,
...@@ -1626,16 +1701,8 @@ pub const Type = extern union {...@@ -1626,16 +1701,8 @@ pub const Type = extern union {
1626 .fn_naked_noreturn_no_args,1701 .fn_naked_noreturn_no_args,
1627 .fn_ccc_void_no_args,1702 .fn_ccc_void_no_args,
1628 .function,1703 .function,
1629 .pointer,
1630 .single_const_pointer,
1631 .single_mut_pointer,
1632 .many_const_pointer,
1633 .many_mut_pointer,
1634 .c_const_pointer,
1635 .c_mut_pointer,
1636 .const_slice,1704 .const_slice,
1637 .mut_slice,1705 .mut_slice,
1638 .single_const_pointer_to_comptime_int,
1639 .const_slice_u8,1706 .const_slice_u8,
1640 .int_unsigned,1707 .int_unsigned,
1641 .int_signed,1708 .int_signed,
...@@ -1651,7 +1718,18 @@ pub const Type = extern union {...@@ -1651,7 +1718,18 @@ pub const Type = extern union {
1651 .error_set_single,1718 .error_set_single,
1652 => unreachable,1719 => unreachable,
16531720
1654 .array, .array_u8 => return null,1721 .single_const_pointer,
1722 .single_mut_pointer,
1723 .many_const_pointer,
1724 .many_mut_pointer,
1725 .c_const_pointer,
1726 .c_mut_pointer,
1727 .single_const_pointer_to_comptime_int,
1728 .array,
1729 .array_u8,
1730 => return null,
1731
1732 .pointer => return self.cast(Payload.Pointer).?.sentinel,
1655 .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,1733 .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
1656 .array_u8_sentinel_0 => return Value.initTag(.zero),1734 .array_u8_sentinel_0 => return Value.initTag(.zero),
1657 };1735 };
src-self-hosted/value.zig+3-3
...@@ -301,15 +301,15 @@ pub const Value = extern union {...@@ -301,15 +301,15 @@ pub const Value = extern union {
301 .comptime_int_type => return out_stream.writeAll("comptime_int"),301 .comptime_int_type => return out_stream.writeAll("comptime_int"),
302 .comptime_float_type => return out_stream.writeAll("comptime_float"),302 .comptime_float_type => return out_stream.writeAll("comptime_float"),
303 .noreturn_type => return out_stream.writeAll("noreturn"),303 .noreturn_type => return out_stream.writeAll("noreturn"),
304 .null_type => return out_stream.writeAll("@TypeOf(null)"),304 .null_type => return out_stream.writeAll("@Type(.Null)"),
305 .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),305 .undefined_type => return out_stream.writeAll("@Type(.Undefined)"),
306 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),306 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
307 .fn_void_no_args_type => return out_stream.writeAll("fn() void"),307 .fn_void_no_args_type => return out_stream.writeAll("fn() void"),
308 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),308 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
309 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),309 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
310 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),310 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
311 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),311 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
312 .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),312 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
313 .anyframe_type => return out_stream.writeAll("anyframe"),313 .anyframe_type => return out_stream.writeAll("anyframe"),
314314
315 .null_value => return out_stream.writeAll("null"),315 .null_value => return out_stream.writeAll("null"),
src-self-hosted/zir.zig+23-1
...@@ -231,6 +231,10 @@ pub const Inst = struct {...@@ -231,6 +231,10 @@ pub const Inst = struct {
231 const_slice_type,231 const_slice_type,
232 /// Create a pointer type with attributes232 /// Create a pointer type with attributes
233 ptr_type,233 ptr_type,
234 /// Slice operation `array_ptr[start..end:sentinel]`
235 slice,
236 /// Slice operation with just start `lhs[rhs..]`
237 slice_start,
234 /// Write a value to a pointer. For loading, see `deref`.238 /// Write a value to a pointer. For loading, see `deref`.
235 store,239 store,
236 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.240 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
...@@ -343,6 +347,7 @@ pub const Inst = struct {...@@ -343,6 +347,7 @@ pub const Inst = struct {
343 .xor,347 .xor,
344 .error_union_type,348 .error_union_type,
345 .merge_error_sets,349 .merge_error_sets,
350 .slice_start,
346 => BinOp,351 => BinOp,
347352
348 .block,353 .block,
...@@ -380,6 +385,7 @@ pub const Inst = struct {...@@ -380,6 +385,7 @@ pub const Inst = struct {
380 .ptr_type => PtrType,385 .ptr_type => PtrType,
381 .enum_literal => EnumLiteral,386 .enum_literal => EnumLiteral,
382 .error_set => ErrorSet,387 .error_set => ErrorSet,
388 .slice => Slice,
383 };389 };
384 }390 }
385391
...@@ -481,6 +487,8 @@ pub const Inst = struct {...@@ -481,6 +487,8 @@ pub const Inst = struct {
481 .error_union_type,487 .error_union_type,
482 .bitnot,488 .bitnot,
483 .error_set,489 .error_set,
490 .slice,
491 .slice_start,
484 => false,492 => false,
485493
486 .@"break",494 .@"break",
...@@ -961,6 +969,20 @@ pub const Inst = struct {...@@ -961,6 +969,20 @@ pub const Inst = struct {
961 },969 },
962 kw_args: struct {},970 kw_args: struct {},
963 };971 };
972
973 pub const Slice = struct {
974 pub const base_tag = Tag.slice;
975 base: Inst,
976
977 positionals: struct {
978 array_ptr: *Inst,
979 start: *Inst,
980 },
981 kw_args: struct {
982 end: ?*Inst = null,
983 sentinel: ?*Inst = null,
984 },
985 };
964};986};
965987
966pub const ErrorMsg = struct {988pub const ErrorMsg = struct {
...@@ -2574,7 +2596,7 @@ const EmitZIR = struct {...@@ -2574,7 +2596,7 @@ const EmitZIR = struct {
2574 var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };2596 var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
2575 const len = Value.initPayload(&len_pl.base);2597 const len = Value.initPayload(&len_pl.base);
25762598
2577 const inst = if (ty.arraySentinel()) |sentinel| blk: {2599 const inst = if (ty.sentinel()) |sentinel| blk: {
2578 const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);2600 const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);
2579 inst.* = .{2601 inst.* = .{
2580 .base = .{2602 .base = .{
src-self-hosted/zir_sema.zig+24
...@@ -132,6 +132,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -132,6 +132,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
132 .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?),132 .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?),
133 .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?),133 .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?),
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).?),
136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
135 }137 }
136}138}
137139
...@@ -1172,6 +1174,22 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne...@@ -1172,6 +1174,22 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
1172 return mod.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});1174 return mod.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});
1173}1175}
11741176
1177fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst {
1178 const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
1179 const start = try resolveInst(mod, scope, inst.positionals.start);
1180 const end = if (inst.kw_args.end) |end| try resolveInst(mod, scope, end) else null;
1181 const sentinel = if (inst.kw_args.sentinel) |sentinel| try resolveInst(mod, scope, sentinel) else null;
1182
1183 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, end, sentinel);
1184}
1185
1186fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1187 const array_ptr = try resolveInst(mod, scope, inst.positionals.lhs);
1188 const start = try resolveInst(mod, scope, inst.positionals.rhs);
1189
1190 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
1191}
1192
1175fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {1193fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1176 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});1194 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});
1177}1195}
...@@ -1239,6 +1257,12 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn...@@ -1239,6 +1257,12 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn
12391257
1240 if (casted_lhs.value()) |lhs_val| {1258 if (casted_lhs.value()) |lhs_val| {
1241 if (casted_rhs.value()) |rhs_val| {1259 if (casted_rhs.value()) |rhs_val| {
1260 if (lhs_val.isUndef() or rhs_val.isUndef()) {
1261 return mod.constInst(scope, inst.base.src, .{
1262 .ty = resolved_type,
1263 .val = Value.initTag(.undef),
1264 });
1265 }
1242 return analyzeInstComptimeOp(mod, scope, scalar_type, inst, lhs_val, rhs_val);1266 return analyzeInstComptimeOp(mod, scope, scalar_type, inst, lhs_val, rhs_val);
1243 }1267 }
1244 }1268 }