| author | |
| committer | |
| log | f2bbd8a548c9a707aa121c58fe8c8a97666b84f2 |
| tree | 82c2511159c52b9cd4e67daaed9c1e5948a3880e |
| parent | dac1cd77505ef9fa493e069549c139d74e31081f |
| parent | 6f0126e9573a6bde9cbe5b113208e0a515b2eee7 |
| signature |
Stage2: slicing and split container scope from file scope10 files changed, 394 insertions(+), 111 deletions(-)
lib/std/zig/tokenizer.zig+2-1| ... | ... | @@ -1175,6 +1175,7 @@ pub const Tokenizer = struct { |
| 1175 | 1175 | }, |
| 1176 | 1176 | .num_dot_dec => switch (c) { |
| 1177 | 1177 | '.' => { |
| 1178 | result.id = .IntegerLiteral; | |
| 1178 | 1179 | self.index -= 1; |
| 1179 | 1180 | state = .start; |
| 1180 | 1181 | break; |
| ... | ... | @@ -1183,7 +1184,6 @@ pub const Tokenizer = struct { |
| 1183 | 1184 | state = .float_exponent_unsigned; |
| 1184 | 1185 | }, |
| 1185 | 1186 | '0'...'9' => { |
| 1186 | result.id = .FloatLiteral; | |
| 1187 | 1187 | state = .float_fraction_dec; |
| 1188 | 1188 | }, |
| 1189 | 1189 | else => { |
| ... | ... | @@ -1769,6 +1769,7 @@ test "tokenizer - number literals decimal" { |
| 1769 | 1769 | testTokenize("7", &[_]Token.Id{.IntegerLiteral}); |
| 1770 | 1770 | testTokenize("8", &[_]Token.Id{.IntegerLiteral}); |
| 1771 | 1771 | testTokenize("9", &[_]Token.Id{.IntegerLiteral}); |
| 1772 | testTokenize("1..", &[_]Token.Id{ .IntegerLiteral, .Ellipsis2 }); | |
| 1772 | 1773 | testTokenize("0a", &[_]Token.Id{ .Invalid, .Identifier }); |
| 1773 | 1774 | testTokenize("9b", &[_]Token.Id{ .Invalid, .Identifier }); |
| 1774 | 1775 | testTokenize("1z", &[_]Token.Id{ .Invalid, .Identifier }); |
src-self-hosted/Module.zig+162-52| ... | ... | @@ -125,7 +125,7 @@ pub const Decl = struct { |
| 125 | 125 | /// mapping them to an address in the output file. |
| 126 | 126 | /// Memory owned by this decl, using Module's allocator. |
| 127 | 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 | 129 | /// Reference to externally owned memory. |
| 130 | 130 | scope: *Scope, |
| 131 | 131 | /// The AST Node decl index or ZIR Inst index that contains this declaration. |
| ... | ... | @@ -217,9 +217,10 @@ pub const Decl = struct { |
| 217 | 217 | |
| 218 | 218 | pub fn src(self: Decl) usize { |
| 219 | 219 | switch (self.scope.tag) { |
| 220 | .file => { | |
| 221 | const file = @fieldParentPtr(Scope.File, "base", self.scope); | |
| 222 | const tree = file.contents.tree; | |
| 220 | .container => { | |
| 221 | const container = @fieldParentPtr(Scope.Container, "base", self.scope); | |
| 222 | const tree = container.file_scope.contents.tree; | |
| 223 | // TODO Container should have it's own decls() | |
| 223 | 224 | const decl_node = tree.root_node.decls()[self.src_index]; |
| 224 | 225 | return tree.token_locs[decl_node.firstToken()].start; |
| 225 | 226 | }, |
| ... | ... | @@ -229,6 +230,7 @@ pub const Decl = struct { |
| 229 | 230 | const src_decl = module.decls[self.src_index]; |
| 230 | 231 | return src_decl.inst.src; |
| 231 | 232 | }, |
| 233 | .file, | |
| 232 | 234 | .block => unreachable, |
| 233 | 235 | .gen_zir => unreachable, |
| 234 | 236 | .local_val => unreachable, |
| ... | ... | @@ -359,6 +361,7 @@ pub const Scope = struct { |
| 359 | 361 | .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena, |
| 360 | 362 | .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator, |
| 361 | 363 | .file => unreachable, |
| 364 | .container => unreachable, | |
| 362 | 365 | } |
| 363 | 366 | } |
| 364 | 367 | |
| ... | ... | @@ -368,15 +371,16 @@ pub const Scope = struct { |
| 368 | 371 | return switch (self.tag) { |
| 369 | 372 | .block => self.cast(Block).?.decl, |
| 370 | 373 | .gen_zir => self.cast(GenZIR).?.decl, |
| 371 | .local_val => return self.cast(LocalVal).?.gen_zir.decl, | |
| 372 | .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl, | |
| 374 | .local_val => self.cast(LocalVal).?.gen_zir.decl, | |
| 375 | .local_ptr => self.cast(LocalPtr).?.gen_zir.decl, | |
| 373 | 376 | .decl => self.cast(DeclAnalysis).?.decl, |
| 374 | 377 | .zir_module => null, |
| 375 | 378 | .file => null, |
| 379 | .container => null, | |
| 376 | 380 | }; |
| 377 | 381 | } |
| 378 | 382 | |
| 379 | /// Asserts the scope has a parent which is a ZIRModule or File and | |
| 383 | /// Asserts the scope has a parent which is a ZIRModule or Container and | |
| 380 | 384 | /// returns it. |
| 381 | 385 | pub fn namespace(self: *Scope) *Scope { |
| 382 | 386 | switch (self.tag) { |
| ... | ... | @@ -385,7 +389,8 @@ pub const Scope = struct { |
| 385 | 389 | .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope, |
| 386 | 390 | .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope, |
| 387 | 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 | } |
| 391 | 396 | |
| ... | ... | @@ -399,8 +404,9 @@ pub const Scope = struct { |
| 399 | 404 | .local_val => unreachable, |
| 400 | 405 | .local_ptr => unreachable, |
| 401 | 406 | .decl => unreachable, |
| 407 | .file => unreachable, | |
| 402 | 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 | } |
| 406 | 412 | |
| ... | ... | @@ -409,11 +415,12 @@ pub const Scope = struct { |
| 409 | 415 | switch (self.tag) { |
| 410 | 416 | .file => return self.cast(File).?.contents.tree, |
| 411 | 417 | .zir_module => unreachable, |
| 412 | .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree, | |
| 413 | .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree, | |
| 414 | .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree, | |
| 415 | .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(File).?.contents.tree, | |
| 416 | .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(File).?.contents.tree, | |
| 418 | .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(Container).?.file_scope.contents.tree, | |
| 419 | .block => return self.cast(Block).?.decl.scope.cast(Container).?.file_scope.contents.tree, | |
| 420 | .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(Container).?.file_scope.contents.tree, | |
| 421 | .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(Container).?.file_scope.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 | } |
| 419 | 426 | |
| ... | ... | @@ -427,13 +434,15 @@ pub const Scope = struct { |
| 427 | 434 | .decl => unreachable, |
| 428 | 435 | .zir_module => unreachable, |
| 429 | 436 | .file => unreachable, |
| 437 | .container => unreachable, | |
| 430 | 438 | }; |
| 431 | 439 | } |
| 432 | 440 | |
| 433 | /// Asserts the scope has a parent which is a ZIRModule or File and | |
| 441 | /// Asserts the scope has a parent which is a ZIRModule, Contaienr or File and | |
| 434 | 442 | /// returns the sub_file_path field. |
| 435 | 443 | pub fn subFilePath(base: *Scope) []const u8 { |
| 436 | 444 | switch (base.tag) { |
| 445 | .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path, | |
| 437 | 446 | .file => return @fieldParentPtr(File, "base", base).sub_file_path, |
| 438 | 447 | .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path, |
| 439 | 448 | .block => unreachable, |
| ... | ... | @@ -453,11 +462,13 @@ pub const Scope = struct { |
| 453 | 462 | .local_val => unreachable, |
| 454 | 463 | .local_ptr => unreachable, |
| 455 | 464 | .decl => unreachable, |
| 465 | .container => unreachable, | |
| 456 | 466 | } |
| 457 | 467 | } |
| 458 | 468 | |
| 459 | 469 | pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 { |
| 460 | 470 | switch (base.tag) { |
| 471 | .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module), | |
| 461 | 472 | .file => return @fieldParentPtr(File, "base", base).getSource(module), |
| 462 | 473 | .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module), |
| 463 | 474 | .gen_zir => unreachable, |
| ... | ... | @@ -471,8 +482,9 @@ pub const Scope = struct { |
| 471 | 482 | /// Asserts the scope is a namespace Scope and removes the Decl from the namespace. |
| 472 | 483 | pub fn removeDecl(base: *Scope, child: *Decl) void { |
| 473 | 484 | switch (base.tag) { |
| 474 | .file => return @fieldParentPtr(File, "base", base).removeDecl(child), | |
| 485 | .container => return @fieldParentPtr(Container, "base", base).removeDecl(child), | |
| 475 | 486 | .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child), |
| 487 | .file => unreachable, | |
| 476 | 488 | .block => unreachable, |
| 477 | 489 | .gen_zir => unreachable, |
| 478 | 490 | .local_val => unreachable, |
| ... | ... | @@ -499,6 +511,7 @@ pub const Scope = struct { |
| 499 | 511 | .local_val => unreachable, |
| 500 | 512 | .local_ptr => unreachable, |
| 501 | 513 | .decl => unreachable, |
| 514 | .container => unreachable, | |
| 502 | 515 | } |
| 503 | 516 | } |
| 504 | 517 | |
| ... | ... | @@ -515,6 +528,8 @@ pub const Scope = struct { |
| 515 | 528 | zir_module, |
| 516 | 529 | /// .zig source code. |
| 517 | 530 | file, |
| 531 | /// struct, enum or union, every .file contains one of these. | |
| 532 | container, | |
| 518 | 533 | block, |
| 519 | 534 | decl, |
| 520 | 535 | gen_zir, |
| ... | ... | @@ -522,6 +537,38 @@ pub const Scope = struct { |
| 522 | 537 | local_ptr, |
| 523 | 538 | }; |
| 524 | 539 | |
| 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 | 572 | pub const File = struct { |
| 526 | 573 | pub const base_tag: Tag = .file; |
| 527 | 574 | base: Scope = Scope{ .tag = base_tag }, |
| ... | ... | @@ -544,8 +591,7 @@ pub const Scope = struct { |
| 544 | 591 | loaded_success, |
| 545 | 592 | }, |
| 546 | 593 | |
| 547 | /// Direct children of the file. | |
| 548 | decls: ArrayListUnmanaged(*Decl), | |
| 594 | root_container: Container, | |
| 549 | 595 | |
| 550 | 596 | pub fn unload(self: *File, gpa: *Allocator) void { |
| 551 | 597 | switch (self.status) { |
| ... | ... | @@ -569,20 +615,11 @@ pub const Scope = struct { |
| 569 | 615 | } |
| 570 | 616 | |
| 571 | 617 | pub fn deinit(self: *File, gpa: *Allocator) void { |
| 572 | self.decls.deinit(gpa); | |
| 618 | self.root_container.deinit(gpa); | |
| 573 | 619 | self.unload(gpa); |
| 574 | 620 | self.* = undefined; |
| 575 | 621 | } |
| 576 | 622 | |
| 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 | 623 | pub fn dumpSrc(self: *File, src: usize) void { |
| 587 | 624 | const loc = std.zig.findLineColumn(self.source.bytes, src); |
| 588 | 625 | std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 }); |
| ... | ... | @@ -604,11 +641,6 @@ pub const Scope = struct { |
| 604 | 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 | }; |
| 613 | 645 | |
| 614 | 646 | pub const ZIRModule = struct { |
| ... | ... | @@ -861,7 +893,10 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module { |
| 861 | 893 | .source = .{ .unloaded = {} }, |
| 862 | 894 | .contents = .{ .not_available = {} }, |
| 863 | 895 | .status = .never_loaded, |
| 864 | .decls = .{}, | |
| 896 | .root_container = .{ | |
| 897 | .file_scope = root_scope, | |
| 898 | .decls = .{}, | |
| 899 | }, | |
| 865 | 900 | }; |
| 866 | 901 | break :blk &root_scope.base; |
| 867 | 902 | } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) { |
| ... | ... | @@ -969,7 +1004,7 @@ pub fn update(self: *Module) !void { |
| 969 | 1004 | // to force a refresh we unload now. |
| 970 | 1005 | if (self.root_scope.cast(Scope.File)) |zig_file| { |
| 971 | 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 | 1008 | error.AnalysisFail => { |
| 974 | 1009 | assert(self.totalErrorCount() != 0); |
| 975 | 1010 | }, |
| ... | ... | @@ -1237,8 +1272,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1237 | 1272 | const tracy = trace(@src()); |
| 1238 | 1273 | defer tracy.end(); |
| 1239 | 1274 | |
| 1240 | const file_scope = decl.scope.cast(Scope.File).?; | |
| 1241 | const tree = try self.getAstTree(file_scope); | |
| 1275 | const container_scope = decl.scope.cast(Scope.Container).?; | |
| 1276 | const tree = try self.getAstTree(container_scope); | |
| 1242 | 1277 | const ast_node = tree.root_node.decls()[decl.src_index]; |
| 1243 | 1278 | switch (ast_node.tag) { |
| 1244 | 1279 | .FnProto => { |
| ... | ... | @@ -1698,10 +1733,12 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module { |
| 1698 | 1733 | } |
| 1699 | 1734 | } |
| 1700 | 1735 | |
| 1701 | fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree { | |
| 1736 | fn getAstTree(self: *Module, container_scope: *Scope.Container) !*ast.Tree { | |
| 1702 | 1737 | const tracy = trace(@src()); |
| 1703 | 1738 | defer tracy.end(); |
| 1704 | 1739 | |
| 1740 | const root_scope = container_scope.file_scope; | |
| 1741 | ||
| 1705 | 1742 | switch (root_scope.status) { |
| 1706 | 1743 | .never_loaded, .unloaded_success => { |
| 1707 | 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 | 1780 | } |
| 1744 | 1781 | } |
| 1745 | 1782 | |
| 1746 | fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { | |
| 1783 | fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void { | |
| 1747 | 1784 | const tracy = trace(@src()); |
| 1748 | 1785 | defer tracy.end(); |
| 1749 | 1786 | |
| 1750 | 1787 | // We may be analyzing it for the first time, or this may be |
| 1751 | 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 | 1790 | const decls = tree.root_node.decls(); |
| 1754 | 1791 | |
| 1755 | 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); | |
| 1757 | 1794 | |
| 1758 | 1795 | // Keep track of the decls that we expect to see in this file so that |
| 1759 | 1796 | // we know which ones have been deleted. |
| 1760 | 1797 | var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa); |
| 1761 | 1798 | defer deleted_decls.deinit(); |
| 1762 | try deleted_decls.ensureCapacity(root_scope.decls.items.len); | |
| 1763 | for (root_scope.decls.items) |file_decl| { | |
| 1799 | try deleted_decls.ensureCapacity(container_scope.decls.items.len); | |
| 1800 | for (container_scope.decls.items) |file_decl| { | |
| 1764 | 1801 | deleted_decls.putAssumeCapacityNoClobber(file_decl, {}); |
| 1765 | 1802 | } |
| 1766 | 1803 | |
| ... | ... | @@ -1773,7 +1810,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1773 | 1810 | |
| 1774 | 1811 | const name_loc = tree.token_locs[name_tok]; |
| 1775 | 1812 | const name = tree.tokenSliceLoc(name_loc); |
| 1776 | const name_hash = root_scope.fullyQualifiedNameHash(name); | |
| 1813 | const name_hash = container_scope.fullyQualifiedNameHash(name); | |
| 1777 | 1814 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); |
| 1778 | 1815 | if (self.decl_table.get(name_hash)) |decl| { |
| 1779 | 1816 | // 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 | 1838 | } |
| 1802 | 1839 | } |
| 1803 | 1840 | } else { |
| 1804 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1805 | root_scope.decls.appendAssumeCapacity(new_decl); | |
| 1841 | const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1842 | container_scope.decls.appendAssumeCapacity(new_decl); | |
| 1806 | 1843 | if (fn_proto.getExternExportInlineToken()) |maybe_export_token| { |
| 1807 | 1844 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { |
| 1808 | 1845 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); |
| ... | ... | @@ -1812,7 +1849,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1812 | 1849 | } else if (src_decl.castTag(.VarDecl)) |var_decl| { |
| 1813 | 1850 | const name_loc = tree.token_locs[var_decl.name_token]; |
| 1814 | 1851 | const name = tree.tokenSliceLoc(name_loc); |
| 1815 | const name_hash = root_scope.fullyQualifiedNameHash(name); | |
| 1852 | const name_hash = container_scope.fullyQualifiedNameHash(name); | |
| 1816 | 1853 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); |
| 1817 | 1854 | if (self.decl_table.get(name_hash)) |decl| { |
| 1818 | 1855 | // 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 | 1865 | decl.contents_hash = contents_hash; |
| 1829 | 1866 | } |
| 1830 | 1867 | } else { |
| 1831 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1832 | root_scope.decls.appendAssumeCapacity(new_decl); | |
| 1868 | const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1869 | container_scope.decls.appendAssumeCapacity(new_decl); | |
| 1833 | 1870 | if (var_decl.getExternExportToken()) |maybe_export_token| { |
| 1834 | 1871 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { |
| 1835 | 1872 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); |
| ... | ... | @@ -1841,11 +1878,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1841 | 1878 | const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index}); |
| 1842 | 1879 | defer self.gpa.free(name); |
| 1843 | 1880 | |
| 1844 | const name_hash = root_scope.fullyQualifiedNameHash(name); | |
| 1881 | const name_hash = container_scope.fullyQualifiedNameHash(name); | |
| 1845 | 1882 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); |
| 1846 | 1883 | |
| 1847 | const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1848 | root_scope.decls.appendAssumeCapacity(new_decl); | |
| 1884 | const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash); | |
| 1885 | container_scope.decls.appendAssumeCapacity(new_decl); | |
| 1849 | 1886 | self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); |
| 1850 | 1887 | } else if (src_decl.castTag(.ContainerField)) |container_field| { |
| 1851 | 1888 | log.err("TODO: analyze container field", .{}); |
| ... | ... | @@ -2591,6 +2628,72 @@ pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) In |
| 2591 | 2628 | return self.fail(scope, src, "TODO implement analysis of iserr", .{}); |
| 2592 | 2629 | } |
| 2593 | 2630 | |
| 2631 | pub 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 | 2697 | /// Asserts that lhs and rhs types are both numeric. |
| 2595 | 2698 | pub fn cmpNumeric( |
| 2596 | 2699 | self: *Module, |
| ... | ... | @@ -2801,6 +2904,12 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty |
| 2801 | 2904 | prev_inst = next_inst; |
| 2802 | 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 | 2913 | if (prev_inst.ty.isInt() and |
| 2805 | 2914 | next_inst.ty.isInt() and |
| 2806 | 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 | 3161 | self.failed_files.putAssumeCapacityNoClobber(scope, err_msg); |
| 3053 | 3162 | }, |
| 3054 | 3163 | .file => unreachable, |
| 3164 | .container => unreachable, | |
| 3055 | 3165 | } |
| 3056 | 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 | 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 276 | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 277 | 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 | 279 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), |
| 279 | 280 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), |
| 281 | .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), | |
| 280 | 282 | |
| 281 | 283 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 282 | 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 | 285 | .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}), |
| 285 | 286 | .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), |
| 286 | 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 | 288 | .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), |
| 289 | 289 | .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}), |
| 290 | 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 | 790 | } |
| 791 | 791 | |
| 792 | 792 | fn 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 | ||
| 796 | fn 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 | ||
| 800 | fn 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 | 811 | const tree = scope.tree(); |
| 794 | const src = tree.token_locs[node.op_token].start; | |
| 812 | const src = tree.token_locs[op_token].start; | |
| 795 | 813 | |
| 796 | const err_union_ptr = try expr(mod, scope, .ref, node.lhs); | |
| 797 | // TODO we could avoid an unnecessary copy if .iserr took a pointer | |
| 798 | const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr); | |
| 799 | const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union); | |
| 814 | const operand_ptr = try expr(mod, scope, .ref, lhs); | |
| 815 | // TODO we could avoid an unnecessary copy if .iserr, .isnull took a pointer | |
| 816 | const err_union = try addZIRUnOp(mod, scope, src, .deref, operand_ptr); | |
| 817 | const cond = try addZIRUnOp(mod, scope, src, cond_op, err_union); | |
| 800 | 818 | |
| 801 | 819 | var block_scope: Scope.GenZIR = .{ |
| 802 | 820 | .parent = scope, |
| ... | ... | @@ -825,55 +843,55 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) |
| 825 | 843 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 826 | 844 | }; |
| 827 | 845 | |
| 828 | var err_scope: Scope.GenZIR = .{ | |
| 846 | var then_scope: Scope.GenZIR = .{ | |
| 829 | 847 | .parent = scope, |
| 830 | 848 | .decl = block_scope.decl, |
| 831 | 849 | .arena = block_scope.arena, |
| 832 | 850 | .instructions = .{}, |
| 833 | 851 | }; |
| 834 | defer err_scope.instructions.deinit(mod.gpa); | |
| 852 | defer then_scope.instructions.deinit(mod.gpa); | |
| 835 | 853 | |
| 836 | 854 | var err_val_scope: Scope.LocalVal = undefined; |
| 837 | const err_sub_scope = blk: { | |
| 838 | const payload = node.payload orelse | |
| 839 | break :blk &err_scope.base; | |
| 855 | const then_sub_scope = blk: { | |
| 856 | const payload = payload_node orelse | |
| 857 | break :blk &then_scope.base; | |
| 840 | 858 | |
| 841 | 859 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 842 | 860 | if (mem.eql(u8, err_name, "_")) |
| 843 | break :blk &err_scope.base; | |
| 861 | break :blk &then_scope.base; | |
| 844 | 862 | |
| 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 | 864 | err_val_scope = .{ |
| 847 | .parent = &err_scope.base, | |
| 848 | .gen_zir = &err_scope, | |
| 865 | .parent = &then_scope.base, | |
| 866 | .gen_zir = &then_scope, | |
| 849 | 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 | 870 | break :blk &err_val_scope.base; |
| 853 | 871 | }; |
| 854 | 872 | |
| 855 | _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{ | |
| 873 | _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ | |
| 856 | 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 | }, .{}); |
| 859 | 877 | |
| 860 | var not_err_scope: Scope.GenZIR = .{ | |
| 878 | var else_scope: Scope.GenZIR = .{ | |
| 861 | 879 | .parent = scope, |
| 862 | 880 | .decl = block_scope.decl, |
| 863 | 881 | .arena = block_scope.arena, |
| 864 | 882 | .instructions = .{}, |
| 865 | 883 | }; |
| 866 | defer not_err_scope.instructions.deinit(mod.gpa); | |
| 884 | defer else_scope.instructions.deinit(mod.gpa); | |
| 867 | 885 | |
| 868 | const unwrapped_payload = try addZIRUnOp(mod, &not_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr); | |
| 869 | _ = try addZIRInst(mod, &not_err_scope.base, src, zir.Inst.Break, .{ | |
| 886 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand_ptr); | |
| 887 | _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ | |
| 870 | 888 | .block = block, |
| 871 | 889 | .operand = unwrapped_payload, |
| 872 | 890 | }, .{}); |
| 873 | 891 | |
| 874 | condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) }; | |
| 875 | condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) }; | |
| 876 | return rlWrap(mod, scope, rl, &block.base); | |
| 892 | condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; | |
| 893 | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; | |
| 894 | return rlWrapPtr(mod, scope, rl, &block.base); | |
| 877 | 895 | } |
| 878 | 896 | |
| 879 | 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 | 951 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{})); |
| 934 | 952 | } |
| 935 | 953 | |
| 954 | fn 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 | ||
| 936 | 984 | fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { |
| 937 | 985 | const tree = scope.tree(); |
| 938 | 986 | const src = tree.token_locs[node.rtoken].start; |
src-self-hosted/codegen.zig+3-3| ... | ... | @@ -132,7 +132,7 @@ pub fn generateSymbol( |
| 132 | 132 | .Array => { |
| 133 | 133 | // TODO populate .debug_info for the array |
| 134 | 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 | 136 | try code.ensureCapacity(code.items.len + payload.data.len + 1); |
| 137 | 137 | code.appendSliceAssumeCapacity(payload.data); |
| 138 | 138 | const prev_len = code.items.len; |
| ... | ... | @@ -436,8 +436,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 436 | 436 | try branch_stack.append(.{}); |
| 437 | 437 | |
| 438 | 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| { | |
| 440 | const tree = scope_file.contents.tree; | |
| 439 | if (module_fn.owner_decl.scope.cast(Module.Scope.Container)) |container_scope| { | |
| 440 | const tree = container_scope.file_scope.contents.tree; | |
| 441 | 441 | const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?; |
| 442 | 442 | const block = fn_proto.getBodyNode().?.castTag(.Block).?; |
| 443 | 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 | 85 | const name = try map(file.base.allocator, mem.span(decl.name)); |
| 86 | 86 | defer file.base.allocator.free(name); |
| 87 | 87 | if (tv.val.cast(Value.Payload.Bytes)) |payload| |
| 88 | if (tv.ty.arraySentinel()) |sentinel| | |
| 88 | if (tv.ty.sentinel()) |sentinel| | |
| 89 | 89 | if (sentinel.toUnsignedInt() == 0) |
| 90 | 90 | try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data }) |
| 91 | 91 | 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 | 1656 | try dbg_line_buffer.ensureCapacity(26); |
| 1657 | 1657 | |
| 1658 | 1658 | const line_off: u28 = blk: { |
| 1659 | if (decl.scope.cast(Module.Scope.File)) |scope_file| { | |
| 1660 | const tree = scope_file.contents.tree; | |
| 1659 | if (decl.scope.cast(Module.Scope.Container)) |container_scope| { | |
| 1660 | const tree = container_scope.file_scope.contents.tree; | |
| 1661 | 1661 | const file_ast_decls = tree.root_node.decls(); |
| 1662 | 1662 | // TODO Look into improving the performance here by adding a token-index-to-line |
| 1663 | 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 | 2157 | const tracy = trace(@src()); |
| 2158 | 2158 | defer tracy.end(); |
| 2159 | 2159 | |
| 2160 | const scope_file = decl.scope.cast(Module.Scope.File).?; | |
| 2161 | const tree = scope_file.contents.tree; | |
| 2160 | const container_scope = decl.scope.cast(Module.Scope.Container).?; | |
| 2161 | const tree = container_scope.file_scope.contents.tree; | |
| 2162 | 2162 | const file_ast_decls = tree.root_node.decls(); |
| 2163 | 2163 | // TODO Look into improving the performance here by adding a token-index-to-line |
| 2164 | 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 | 163 | // Hot path for common case: |
| 164 | 164 | if (a.castPointer()) |a_payload| { |
| 165 | 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 | 169 | const is_slice_a = isSlice(a); |
| ... | ... | @@ -189,10 +189,10 @@ pub const Type = extern union { |
| 189 | 189 | .Array => { |
| 190 | 190 | if (a.arrayLen() != b.arrayLen()) |
| 191 | 191 | return false; |
| 192 | if (a.elemType().eql(b.elemType())) | |
| 192 | if (!a.elemType().eql(b.elemType())) | |
| 193 | 193 | return false; |
| 194 | const sentinel_a = a.arraySentinel(); | |
| 195 | const sentinel_b = b.arraySentinel(); | |
| 194 | const sentinel_a = a.sentinel(); | |
| 195 | const sentinel_b = b.sentinel(); | |
| 196 | 196 | if (sentinel_a) |sa| { |
| 197 | 197 | if (sentinel_b) |sb| { |
| 198 | 198 | return sa.eql(sb); |
| ... | ... | @@ -501,9 +501,9 @@ pub const Type = extern union { |
| 501 | 501 | .noreturn, |
| 502 | 502 | => return out_stream.writeAll(@tagName(t)), |
| 503 | 503 | |
| 504 | .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"), | |
| 505 | .@"null" => return out_stream.writeAll("@TypeOf(null)"), | |
| 506 | .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"), | |
| 504 | .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"), | |
| 505 | .@"null" => return out_stream.writeAll("@Type(.Null)"), | |
| 506 | .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"), | |
| 507 | 507 | |
| 508 | 508 | .@"anyframe" => return out_stream.writeAll("anyframe"), |
| 509 | 509 | .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"), |
| ... | ... | @@ -630,8 +630,8 @@ pub const Type = extern union { |
| 630 | 630 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); |
| 631 | 631 | if (payload.sentinel) |some| switch (payload.size) { |
| 632 | 632 | .One, .C => unreachable, |
| 633 | .Many => try out_stream.writeAll("[*:{}]"), | |
| 634 | .Slice => try out_stream.writeAll("[:{}]"), | |
| 633 | .Many => try out_stream.print("[*:{}]", .{some}), | |
| 634 | .Slice => try out_stream.print("[:{}]", .{some}), | |
| 635 | 635 | } else switch (payload.size) { |
| 636 | 636 | .One => try out_stream.writeAll("*"), |
| 637 | 637 | .Many => try out_stream.writeAll("[*]"), |
| ... | ... | @@ -1341,6 +1341,81 @@ pub const Type = extern union { |
| 1341 | 1341 | }; |
| 1342 | 1342 | } |
| 1343 | 1343 | |
| 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 | 1419 | /// Asserts that the type is an optional |
| 1345 | 1420 | pub fn isPtrLikeOptional(self: Type) bool { |
| 1346 | 1421 | switch (self.tag()) { |
| ... | ... | @@ -1585,8 +1660,8 @@ pub const Type = extern union { |
| 1585 | 1660 | }; |
| 1586 | 1661 | } |
| 1587 | 1662 | |
| 1588 | /// Asserts the type is an array or vector. | |
| 1589 | pub fn arraySentinel(self: Type) ?Value { | |
| 1663 | /// Asserts the type is an array, pointer or vector. | |
| 1664 | pub fn sentinel(self: Type) ?Value { | |
| 1590 | 1665 | return switch (self.tag()) { |
| 1591 | 1666 | .u8, |
| 1592 | 1667 | .i8, |
| ... | ... | @@ -1626,16 +1701,8 @@ pub const Type = extern union { |
| 1626 | 1701 | .fn_naked_noreturn_no_args, |
| 1627 | 1702 | .fn_ccc_void_no_args, |
| 1628 | 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 | 1704 | .const_slice, |
| 1637 | 1705 | .mut_slice, |
| 1638 | .single_const_pointer_to_comptime_int, | |
| 1639 | 1706 | .const_slice_u8, |
| 1640 | 1707 | .int_unsigned, |
| 1641 | 1708 | .int_signed, |
| ... | ... | @@ -1651,7 +1718,18 @@ pub const Type = extern union { |
| 1651 | 1718 | .error_set_single, |
| 1652 | 1719 | => unreachable, |
| 1653 | 1720 | |
| 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 | 1733 | .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel, |
| 1656 | 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 | 301 | .comptime_int_type => return out_stream.writeAll("comptime_int"), |
| 302 | 302 | .comptime_float_type => return out_stream.writeAll("comptime_float"), |
| 303 | 303 | .noreturn_type => return out_stream.writeAll("noreturn"), |
| 304 | .null_type => return out_stream.writeAll("@TypeOf(null)"), | |
| 305 | .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"), | |
| 304 | .null_type => return out_stream.writeAll("@Type(.Null)"), | |
| 305 | .undefined_type => return out_stream.writeAll("@Type(.Undefined)"), | |
| 306 | 306 | .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), |
| 307 | 307 | .fn_void_no_args_type => return out_stream.writeAll("fn() void"), |
| 308 | 308 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), |
| 309 | 309 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), |
| 310 | 310 | .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), |
| 311 | 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 | 313 | .anyframe_type => return out_stream.writeAll("anyframe"), |
| 314 | 314 | |
| 315 | 315 | .null_value => return out_stream.writeAll("null"), |
src-self-hosted/zir.zig+23-1| ... | ... | @@ -231,6 +231,10 @@ pub const Inst = struct { |
| 231 | 231 | const_slice_type, |
| 232 | 232 | /// Create a pointer type with attributes |
| 233 | 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 | 238 | /// Write a value to a pointer. For loading, see `deref`. |
| 235 | 239 | store, |
| 236 | 240 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. |
| ... | ... | @@ -343,6 +347,7 @@ pub const Inst = struct { |
| 343 | 347 | .xor, |
| 344 | 348 | .error_union_type, |
| 345 | 349 | .merge_error_sets, |
| 350 | .slice_start, | |
| 346 | 351 | => BinOp, |
| 347 | 352 | |
| 348 | 353 | .block, |
| ... | ... | @@ -380,6 +385,7 @@ pub const Inst = struct { |
| 380 | 385 | .ptr_type => PtrType, |
| 381 | 386 | .enum_literal => EnumLiteral, |
| 382 | 387 | .error_set => ErrorSet, |
| 388 | .slice => Slice, | |
| 383 | 389 | }; |
| 384 | 390 | } |
| 385 | 391 | |
| ... | ... | @@ -481,6 +487,8 @@ pub const Inst = struct { |
| 481 | 487 | .error_union_type, |
| 482 | 488 | .bitnot, |
| 483 | 489 | .error_set, |
| 490 | .slice, | |
| 491 | .slice_start, | |
| 484 | 492 | => false, |
| 485 | 493 | |
| 486 | 494 | .@"break", |
| ... | ... | @@ -961,6 +969,20 @@ pub const Inst = struct { |
| 961 | 969 | }, |
| 962 | 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 | }; |
| 965 | 987 | |
| 966 | 988 | pub const ErrorMsg = struct { |
| ... | ... | @@ -2574,7 +2596,7 @@ const EmitZIR = struct { |
| 2574 | 2596 | var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() }; |
| 2575 | 2597 | const len = Value.initPayload(&len_pl.base); |
| 2576 | 2598 | |
| 2577 | const inst = if (ty.arraySentinel()) |sentinel| blk: { | |
| 2599 | const inst = if (ty.sentinel()) |sentinel| blk: { | |
| 2578 | 2600 | const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel); |
| 2579 | 2601 | inst.* = .{ |
| 2580 | 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 | 132 | .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?), |
| 133 | 133 | .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?), |
| 134 | 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 | } |
| 137 | 139 | |
| ... | ... | @@ -1172,6 +1174,22 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 1172 | 1174 | return mod.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{}); |
| 1173 | 1175 | } |
| 1174 | 1176 | |
| 1177 | fn 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 | ||
| 1186 | fn 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 | ||
| 1175 | 1193 | fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 1176 | 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 | 1257 | |
| 1240 | 1258 | if (casted_lhs.value()) |lhs_val| { |
| 1241 | 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 | 1266 | return analyzeInstComptimeOp(mod, scope, scalar_type, inst, lhs_val, rhs_val); |
| 1243 | 1267 | } |
| 1244 | 1268 | } |