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 {
11751175 },
11761176 .num_dot_dec => switch (c) {
11771177 '.' => {
1178 result.id = .IntegerLiteral;
11781179 self.index -= 1;
11791180 state = .start;
11801181 break;
......@@ -1183,7 +1184,6 @@ pub const Tokenizer = struct {
11831184 state = .float_exponent_unsigned;
11841185 },
11851186 '0'...'9' => {
1186 result.id = .FloatLiteral;
11871187 state = .float_fraction_dec;
11881188 },
11891189 else => {
......@@ -1769,6 +1769,7 @@ test "tokenizer - number literals decimal" {
17691769 testTokenize("7", &[_]Token.Id{.IntegerLiteral});
17701770 testTokenize("8", &[_]Token.Id{.IntegerLiteral});
17711771 testTokenize("9", &[_]Token.Id{.IntegerLiteral});
1772 testTokenize("1..", &[_]Token.Id{ .IntegerLiteral, .Ellipsis2 });
17721773 testTokenize("0a", &[_]Token.Id{ .Invalid, .Identifier });
17731774 testTokenize("9b", &[_]Token.Id{ .Invalid, .Identifier });
17741775 testTokenize("1z", &[_]Token.Id{ .Invalid, .Identifier });
src-self-hosted/Module.zig+162-52
......@@ -125,7 +125,7 @@ pub const Decl = struct {
125125 /// mapping them to an address in the output file.
126126 /// Memory owned by this decl, using Module's allocator.
127127 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`.
129129 /// Reference to externally owned memory.
130130 scope: *Scope,
131131 /// The AST Node decl index or ZIR Inst index that contains this declaration.
......@@ -217,9 +217,10 @@ pub const Decl = struct {
217217
218218 pub fn src(self: Decl) usize {
219219 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()
223224 const decl_node = tree.root_node.decls()[self.src_index];
224225 return tree.token_locs[decl_node.firstToken()].start;
225226 },
......@@ -229,6 +230,7 @@ pub const Decl = struct {
229230 const src_decl = module.decls[self.src_index];
230231 return src_decl.inst.src;
231232 },
233 .file,
232234 .block => unreachable,
233235 .gen_zir => unreachable,
234236 .local_val => unreachable,
......@@ -359,6 +361,7 @@ pub const Scope = struct {
359361 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
360362 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
361363 .file => unreachable,
364 .container => unreachable,
362365 }
363366 }
364367
......@@ -368,15 +371,16 @@ pub const Scope = struct {
368371 return switch (self.tag) {
369372 .block => self.cast(Block).?.decl,
370373 .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,
373376 .decl => self.cast(DeclAnalysis).?.decl,
374377 .zir_module => null,
375378 .file => null,
379 .container => null,
376380 };
377381 }
378382
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
380384 /// returns it.
381385 pub fn namespace(self: *Scope) *Scope {
382386 switch (self.tag) {
......@@ -385,7 +389,8 @@ pub const Scope = struct {
385389 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
386390 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
387391 .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,
389394 }
390395 }
391396
......@@ -399,8 +404,9 @@ pub const Scope = struct {
399404 .local_val => unreachable,
400405 .local_ptr => unreachable,
401406 .decl => unreachable,
407 .file => unreachable,
402408 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
403 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
409 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
404410 }
405411 }
406412
......@@ -409,11 +415,12 @@ pub const Scope = struct {
409415 switch (self.tag) {
410416 .file => return self.cast(File).?.contents.tree,
411417 .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,
417424 }
418425 }
419426
......@@ -427,13 +434,15 @@ pub const Scope = struct {
427434 .decl => unreachable,
428435 .zir_module => unreachable,
429436 .file => unreachable,
437 .container => unreachable,
430438 };
431439 }
432440
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
434442 /// returns the sub_file_path field.
435443 pub fn subFilePath(base: *Scope) []const u8 {
436444 switch (base.tag) {
445 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
437446 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
438447 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
439448 .block => unreachable,
......@@ -453,11 +462,13 @@ pub const Scope = struct {
453462 .local_val => unreachable,
454463 .local_ptr => unreachable,
455464 .decl => unreachable,
465 .container => unreachable,
456466 }
457467 }
458468
459469 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
460470 switch (base.tag) {
471 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
461472 .file => return @fieldParentPtr(File, "base", base).getSource(module),
462473 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
463474 .gen_zir => unreachable,
......@@ -471,8 +482,9 @@ pub const Scope = struct {
471482 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
472483 pub fn removeDecl(base: *Scope, child: *Decl) void {
473484 switch (base.tag) {
474 .file => return @fieldParentPtr(File, "base", base).removeDecl(child),
485 .container => return @fieldParentPtr(Container, "base", base).removeDecl(child),
475486 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
487 .file => unreachable,
476488 .block => unreachable,
477489 .gen_zir => unreachable,
478490 .local_val => unreachable,
......@@ -499,6 +511,7 @@ pub const Scope = struct {
499511 .local_val => unreachable,
500512 .local_ptr => unreachable,
501513 .decl => unreachable,
514 .container => unreachable,
502515 }
503516 }
504517
......@@ -515,6 +528,8 @@ pub const Scope = struct {
515528 zir_module,
516529 /// .zig source code.
517530 file,
531 /// struct, enum or union, every .file contains one of these.
532 container,
518533 block,
519534 decl,
520535 gen_zir,
......@@ -522,6 +537,38 @@ pub const Scope = struct {
522537 local_ptr,
523538 };
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
525572 pub const File = struct {
526573 pub const base_tag: Tag = .file;
527574 base: Scope = Scope{ .tag = base_tag },
......@@ -544,8 +591,7 @@ pub const Scope = struct {
544591 loaded_success,
545592 },
546593
547 /// Direct children of the file.
548 decls: ArrayListUnmanaged(*Decl),
594 root_container: Container,
549595
550596 pub fn unload(self: *File, gpa: *Allocator) void {
551597 switch (self.status) {
......@@ -569,20 +615,11 @@ pub const Scope = struct {
569615 }
570616
571617 pub fn deinit(self: *File, gpa: *Allocator) void {
572 self.decls.deinit(gpa);
618 self.root_container.deinit(gpa);
573619 self.unload(gpa);
574620 self.* = undefined;
575621 }
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
586623 pub fn dumpSrc(self: *File, src: usize) void {
587624 const loc = std.zig.findLineColumn(self.source.bytes, src);
588625 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
......@@ -604,11 +641,6 @@ pub const Scope = struct {
604641 .bytes => |bytes| return bytes,
605642 }
606643 }
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 }
612644 };
613645
614646 pub const ZIRModule = struct {
......@@ -861,7 +893,10 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
861893 .source = .{ .unloaded = {} },
862894 .contents = .{ .not_available = {} },
863895 .status = .never_loaded,
864 .decls = .{},
896 .root_container = .{
897 .file_scope = root_scope,
898 .decls = .{},
899 },
865900 };
866901 break :blk &root_scope.base;
867902 } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) {
......@@ -969,7 +1004,7 @@ pub fn update(self: *Module) !void {
9691004 // to force a refresh we unload now.
9701005 if (self.root_scope.cast(Scope.File)) |zig_file| {
9711006 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) {
9731008 error.AnalysisFail => {
9741009 assert(self.totalErrorCount() != 0);
9751010 },
......@@ -1237,8 +1272,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12371272 const tracy = trace(@src());
12381273 defer tracy.end();
12391274
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);
12421277 const ast_node = tree.root_node.decls()[decl.src_index];
12431278 switch (ast_node.tag) {
12441279 .FnProto => {
......@@ -1698,10 +1733,12 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
16981733 }
16991734}
17001735
1701fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1736fn getAstTree(self: *Module, container_scope: *Scope.Container) !*ast.Tree {
17021737 const tracy = trace(@src());
17031738 defer tracy.end();
17041739
1740 const root_scope = container_scope.file_scope;
1741
17051742 switch (root_scope.status) {
17061743 .never_loaded, .unloaded_success => {
17071744 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 {
17431780 }
17441781}
17451782
1746fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1783fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void {
17471784 const tracy = trace(@src());
17481785 defer tracy.end();
17491786
17501787 // We may be analyzing it for the first time, or this may be
17511788 // an incremental update. This code handles both cases.
1752 const tree = try self.getAstTree(root_scope);
1789 const tree = try self.getAstTree(container_scope);
17531790 const decls = tree.root_node.decls();
17541791
17551792 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
17581795 // Keep track of the decls that we expect to see in this file so that
17591796 // we know which ones have been deleted.
17601797 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
17611798 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| {
17641801 deleted_decls.putAssumeCapacityNoClobber(file_decl, {});
17651802 }
17661803
......@@ -1773,7 +1810,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
17731810
17741811 const name_loc = tree.token_locs[name_tok];
17751812 const name = tree.tokenSliceLoc(name_loc);
1776 const name_hash = root_scope.fullyQualifiedNameHash(name);
1813 const name_hash = container_scope.fullyQualifiedNameHash(name);
17771814 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
17781815 if (self.decl_table.get(name_hash)) |decl| {
17791816 // 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 {
18011838 }
18021839 }
18031840 } 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);
18061843 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
18071844 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
18081845 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
......@@ -1812,7 +1849,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
18121849 } else if (src_decl.castTag(.VarDecl)) |var_decl| {
18131850 const name_loc = tree.token_locs[var_decl.name_token];
18141851 const name = tree.tokenSliceLoc(name_loc);
1815 const name_hash = root_scope.fullyQualifiedNameHash(name);
1852 const name_hash = container_scope.fullyQualifiedNameHash(name);
18161853 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
18171854 if (self.decl_table.get(name_hash)) |decl| {
18181855 // 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 {
18281865 decl.contents_hash = contents_hash;
18291866 }
18301867 } 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);
18331870 if (var_decl.getExternExportToken()) |maybe_export_token| {
18341871 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
18351872 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
......@@ -1841,11 +1878,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
18411878 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
18421879 defer self.gpa.free(name);
18431880
1844 const name_hash = root_scope.fullyQualifiedNameHash(name);
1881 const name_hash = container_scope.fullyQualifiedNameHash(name);
18451882 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);
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);
18491886 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
18501887 } else if (src_decl.castTag(.ContainerField)) |container_field| {
18511888 log.err("TODO: analyze container field", .{});
......@@ -2591,6 +2628,72 @@ pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) In
25912628 return self.fail(scope, src, "TODO implement analysis of iserr", .{});
25922629}
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
25942697/// Asserts that lhs and rhs types are both numeric.
25952698pub fn cmpNumeric(
25962699 self: *Module,
......@@ -2801,6 +2904,12 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
28012904 prev_inst = next_inst;
28022905 continue;
28032906 }
2907 if (next_inst.ty.zigTypeTag() == .Undefined)
2908 continue;
2909 if (prev_inst.ty.zigTypeTag() == .Undefined) {
2910 prev_inst = next_inst;
2911 continue;
2912 }
28042913 if (prev_inst.ty.isInt() and
28052914 next_inst.ty.isInt() and
28062915 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())
......@@ -3052,6 +3161,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
30523161 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
30533162 },
30543163 .file => unreachable,
3164 .container => unreachable,
30553165 }
30563166 return error.AnalysisFail;
30573167}
src-self-hosted/astgen.zig+74-26
......@@ -275,16 +275,16 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
275275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
276276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),
277277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
278 .Slice => return rlWrap(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)),
278279 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
279280 .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
281 .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?),
280282
281283 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
282284 .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", .{}),
284285 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
285286 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
286287 .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", .{}),
288288 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
289289 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
290290 .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!*
790790}
791791
792792fn 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 {
793811 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);
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);
800818
801819 var block_scope: Scope.GenZIR = .{
802820 .parent = scope,
......@@ -825,55 +843,55 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch)
825843 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
826844 };
827845
828 var err_scope: Scope.GenZIR = .{
846 var then_scope: Scope.GenZIR = .{
829847 .parent = scope,
830848 .decl = block_scope.decl,
831849 .arena = block_scope.arena,
832850 .instructions = .{},
833851 };
834 defer err_scope.instructions.deinit(mod.gpa);
852 defer then_scope.instructions.deinit(mod.gpa);
835853
836854 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;
840858
841859 const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());
842860 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);
846864 err_val_scope = .{
847 .parent = &err_scope.base,
848 .gen_zir = &err_scope,
865 .parent = &then_scope.base,
866 .gen_zir = &then_scope,
849867 .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),
851869 };
852870 break :blk &err_val_scope.base;
853871 };
854872
855 _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{
873 _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{
856874 .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),
858876 }, .{});
859877
860 var not_err_scope: Scope.GenZIR = .{
878 var else_scope: Scope.GenZIR = .{
861879 .parent = scope,
862880 .decl = block_scope.decl,
863881 .arena = block_scope.arena,
864882 .instructions = .{},
865883 };
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);
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, .{
870888 .block = block,
871889 .operand = unwrapped_payload,
872890 }, .{});
873891
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);
877895}
878896
879897/// 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
933951 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{}));
934952}
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
936984fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
937985 const tree = scope.tree();
938986 const src = tree.token_locs[node.rtoken].start;
src-self-hosted/codegen.zig+3-3
......@@ -132,7 +132,7 @@ pub fn generateSymbol(
132132 .Array => {
133133 // TODO populate .debug_info for the array
134134 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
135 if (typed_value.ty.arraySentinel()) |sentinel| {
135 if (typed_value.ty.sentinel()) |sentinel| {
136136 try code.ensureCapacity(code.items.len + payload.data.len + 1);
137137 code.appendSliceAssumeCapacity(payload.data);
138138 const prev_len = code.items.len;
......@@ -436,8 +436,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
436436 try branch_stack.append(.{});
437437
438438 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;
441441 const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;
442442 const block = fn_proto.getBodyNode().?.castTag(.Block).?;
443443 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 {
8585 const name = try map(file.base.allocator, mem.span(decl.name));
8686 defer file.base.allocator.free(name);
8787 if (tv.val.cast(Value.Payload.Bytes)) |payload|
88 if (tv.ty.arraySentinel()) |sentinel|
88 if (tv.ty.sentinel()) |sentinel|
8989 if (sentinel.toUnsignedInt() == 0)
9090 try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data })
9191 else
src-self-hosted/link/Elf.zig+4-4
......@@ -1656,8 +1656,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
16561656 try dbg_line_buffer.ensureCapacity(26);
16571657
16581658 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;
16611661 const file_ast_decls = tree.root_node.decls();
16621662 // TODO Look into improving the performance here by adding a token-index-to-line
16631663 // 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
21572157 const tracy = trace(@src());
21582158 defer tracy.end();
21592159
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;
21622162 const file_ast_decls = tree.root_node.decls();
21632163 // TODO Look into improving the performance here by adding a token-index-to-line
21642164 // 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 {
163163 // Hot path for common case:
164164 if (a.castPointer()) |a_payload| {
165165 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);
167167 }
168168 }
169169 const is_slice_a = isSlice(a);
......@@ -189,10 +189,10 @@ pub const Type = extern union {
189189 .Array => {
190190 if (a.arrayLen() != b.arrayLen())
191191 return false;
192 if (a.elemType().eql(b.elemType()))
192 if (!a.elemType().eql(b.elemType()))
193193 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();
196196 if (sentinel_a) |sa| {
197197 if (sentinel_b) |sb| {
198198 return sa.eql(sb);
......@@ -501,9 +501,9 @@ pub const Type = extern union {
501501 .noreturn,
502502 => return out_stream.writeAll(@tagName(t)),
503503
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)"),
507507
508508 .@"anyframe" => return out_stream.writeAll("anyframe"),
509509 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
......@@ -630,8 +630,8 @@ pub const Type = extern union {
630630 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
631631 if (payload.sentinel) |some| switch (payload.size) {
632632 .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}),
635635 } else switch (payload.size) {
636636 .One => try out_stream.writeAll("*"),
637637 .Many => try out_stream.writeAll("[*]"),
......@@ -1341,6 +1341,81 @@ pub const Type = extern union {
13411341 };
13421342 }
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
13441419 /// Asserts that the type is an optional
13451420 pub fn isPtrLikeOptional(self: Type) bool {
13461421 switch (self.tag()) {
......@@ -1585,8 +1660,8 @@ pub const Type = extern union {
15851660 };
15861661 }
15871662
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 {
15901665 return switch (self.tag()) {
15911666 .u8,
15921667 .i8,
......@@ -1626,16 +1701,8 @@ pub const Type = extern union {
16261701 .fn_naked_noreturn_no_args,
16271702 .fn_ccc_void_no_args,
16281703 .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,
16361704 .const_slice,
16371705 .mut_slice,
1638 .single_const_pointer_to_comptime_int,
16391706 .const_slice_u8,
16401707 .int_unsigned,
16411708 .int_signed,
......@@ -1651,7 +1718,18 @@ pub const Type = extern union {
16511718 .error_set_single,
16521719 => 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,
16551733 .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
16561734 .array_u8_sentinel_0 => return Value.initTag(.zero),
16571735 };
src-self-hosted/value.zig+3-3
......@@ -301,15 +301,15 @@ pub const Value = extern union {
301301 .comptime_int_type => return out_stream.writeAll("comptime_int"),
302302 .comptime_float_type => return out_stream.writeAll("comptime_float"),
303303 .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)"),
306306 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
307307 .fn_void_no_args_type => return out_stream.writeAll("fn() void"),
308308 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
309309 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
310310 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
311311 .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)"),
313313 .anyframe_type => return out_stream.writeAll("anyframe"),
314314
315315 .null_value => return out_stream.writeAll("null"),
src-self-hosted/zir.zig+23-1
......@@ -231,6 +231,10 @@ pub const Inst = struct {
231231 const_slice_type,
232232 /// Create a pointer type with attributes
233233 ptr_type,
234 /// Slice operation `array_ptr[start..end:sentinel]`
235 slice,
236 /// Slice operation with just start `lhs[rhs..]`
237 slice_start,
234238 /// Write a value to a pointer. For loading, see `deref`.
235239 store,
236240 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
......@@ -343,6 +347,7 @@ pub const Inst = struct {
343347 .xor,
344348 .error_union_type,
345349 .merge_error_sets,
350 .slice_start,
346351 => BinOp,
347352
348353 .block,
......@@ -380,6 +385,7 @@ pub const Inst = struct {
380385 .ptr_type => PtrType,
381386 .enum_literal => EnumLiteral,
382387 .error_set => ErrorSet,
388 .slice => Slice,
383389 };
384390 }
385391
......@@ -481,6 +487,8 @@ pub const Inst = struct {
481487 .error_union_type,
482488 .bitnot,
483489 .error_set,
490 .slice,
491 .slice_start,
484492 => false,
485493
486494 .@"break",
......@@ -961,6 +969,20 @@ pub const Inst = struct {
961969 },
962970 kw_args: struct {},
963971 };
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 };
964986};
965987
966988pub const ErrorMsg = struct {
......@@ -2574,7 +2596,7 @@ const EmitZIR = struct {
25742596 var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
25752597 const len = Value.initPayload(&len_pl.base);
25762598
2577 const inst = if (ty.arraySentinel()) |sentinel| blk: {
2599 const inst = if (ty.sentinel()) |sentinel| blk: {
25782600 const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);
25792601 inst.* = .{
25802602 .base = .{
src-self-hosted/zir_sema.zig+24
......@@ -132,6 +132,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
132132 .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?),
133133 .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?),
134134 .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).?),
135137 }
136138}
137139
......@@ -1172,6 +1174,22 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
11721174 return mod.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});
11731175}
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
11751193fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
11761194 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});
11771195}
......@@ -1239,6 +1257,12 @@ fn analyzeInstArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn
12391257
12401258 if (casted_lhs.value()) |lhs_val| {
12411259 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 }
12421266 return analyzeInstComptimeOp(mod, scope, scalar_type, inst, lhs_val, rhs_val);
12431267 }
12441268 }