| ... | ... | @@ -1060,21 +1060,24 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void { |
| 1060 | 1060 | .unreferenced => false, |
| 1061 | 1061 | }; |
| 1062 | 1062 | |
| 1063 | | const type_changed = self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) { |
| 1064 | | error.OutOfMemory => return error.OutOfMemory, |
| 1065 | | error.AnalysisFail => return error.AnalysisFail, |
| 1066 | | else => { |
| 1067 | | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); |
| 1068 | | self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( |
| 1069 | | self.allocator, |
| 1070 | | decl.src(), |
| 1071 | | "unable to analyze: {}", |
| 1072 | | .{@errorName(err)}, |
| 1073 | | )); |
| 1074 | | decl.analysis = .sema_failure_retryable; |
| 1075 | | return error.AnalysisFail; |
| 1076 | | }, |
| 1077 | | }; |
| 1063 | const type_changed = if (self.root_scope.cast(Scope.ZIRModule)) |zir_module| |
| 1064 | try self.analyzeZirDecl(decl, zir_module.contents.module.decls[decl.src_index]) |
| 1065 | else |
| 1066 | self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) { |
| 1067 | error.OutOfMemory => return error.OutOfMemory, |
| 1068 | error.AnalysisFail => return error.AnalysisFail, |
| 1069 | else => { |
| 1070 | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); |
| 1071 | self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( |
| 1072 | self.allocator, |
| 1073 | decl.src(), |
| 1074 | "unable to analyze: {}", |
| 1075 | .{@errorName(err)}, |
| 1076 | )); |
| 1077 | decl.analysis = .sema_failure_retryable; |
| 1078 | return error.AnalysisFail; |
| 1079 | }, |
| 1080 | }; |
| 1078 | 1081 | |
| 1079 | 1082 | if (subsequent_analysis) { |
| 1080 | 1083 | // We may need to chase the dependants and re-analyze them. |
| ... | ... | @@ -1724,71 +1727,63 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1724 | 1727 | } |
| 1725 | 1728 | |
| 1726 | 1729 | fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 1727 | | switch (root_scope.status) { |
| 1728 | | .never_loaded => { |
| 1729 | | const src_module = try self.getSrcModule(root_scope); |
| 1730 | // We may be analyzing it for the first time, or this may be |
| 1731 | // an incremental update. This code handles both cases. |
| 1732 | const src_module = try self.getSrcModule(root_scope); |
| 1730 | 1733 | |
| 1731 | | // Here we ensure enough queue capacity to store all the decls, so that later we can use |
| 1732 | | // appendAssumeCapacity. |
| 1733 | | try self.work_queue.ensureUnusedCapacity(src_module.decls.len); |
| 1734 | try self.work_queue.ensureUnusedCapacity(src_module.decls.len); |
| 1735 | try root_scope.decls.ensureCapacity(self.allocator, src_module.decls.len); |
| 1734 | 1736 | |
| 1735 | | for (src_module.decls) |src_decl| { |
| 1736 | | if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| { |
| 1737 | | _ = try self.resolveDecl(&root_scope.base, src_decl); |
| 1738 | | } |
| 1739 | | } |
| 1740 | | }, |
| 1737 | var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.allocator); |
| 1738 | defer exports_to_resolve.deinit(); |
| 1741 | 1739 | |
| 1742 | | .unloaded_parse_failure, |
| 1743 | | .unloaded_sema_failure, |
| 1744 | | .unloaded_success, |
| 1745 | | .loaded_sema_failure, |
| 1746 | | .loaded_success, |
| 1747 | | => { |
| 1748 | | const src_module = try self.getSrcModule(root_scope); |
| 1749 | | |
| 1750 | | var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.allocator); |
| 1751 | | defer exports_to_resolve.deinit(); |
| 1752 | | |
| 1753 | | // Keep track of the decls that we expect to see in this file so that |
| 1754 | | // we know which ones have been deleted. |
| 1755 | | var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator); |
| 1756 | | defer deleted_decls.deinit(); |
| 1757 | | try deleted_decls.ensureCapacity(self.decl_table.size); |
| 1758 | | { |
| 1759 | | var it = self.decl_table.iterator(); |
| 1760 | | while (it.next()) |kv| { |
| 1761 | | deleted_decls.putAssumeCapacityNoClobber(kv.value, {}); |
| 1762 | | } |
| 1763 | | } |
| 1740 | // Keep track of the decls that we expect to see in this file so that |
| 1741 | // we know which ones have been deleted. |
| 1742 | var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator); |
| 1743 | defer deleted_decls.deinit(); |
| 1744 | try deleted_decls.ensureCapacity(self.decl_table.size); |
| 1745 | { |
| 1746 | var it = self.decl_table.iterator(); |
| 1747 | while (it.next()) |kv| { |
| 1748 | deleted_decls.putAssumeCapacityNoClobber(kv.value, {}); |
| 1749 | } |
| 1750 | } |
| 1764 | 1751 | |
| 1765 | | for (src_module.decls) |src_decl| { |
| 1766 | | const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name); |
| 1767 | | if (self.decl_table.get(name_hash)) |kv| { |
| 1768 | | const decl = kv.value; |
| 1769 | | deleted_decls.removeAssertDiscard(decl); |
| 1770 | | //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents }); |
| 1771 | | if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) { |
| 1772 | | try self.markOutdatedDecl(decl); |
| 1773 | | decl.contents_hash = src_decl.contents_hash; |
| 1774 | | } |
| 1775 | | } else if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| { |
| 1776 | | try exports_to_resolve.append(src_decl); |
| 1777 | | } |
| 1752 | for (src_module.decls) |src_decl, decl_i| { |
| 1753 | const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name); |
| 1754 | if (self.decl_table.get(name_hash)) |kv| { |
| 1755 | const decl = kv.value; |
| 1756 | deleted_decls.removeAssertDiscard(decl); |
| 1757 | //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents }); |
| 1758 | if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) { |
| 1759 | try self.markOutdatedDecl(decl); |
| 1760 | decl.contents_hash = src_decl.contents_hash; |
| 1778 | 1761 | } |
| 1779 | | { |
| 1780 | | // Handle explicitly deleted decls from the source code. Not to be confused |
| 1781 | | // with when we delete decls because they are no longer referenced. |
| 1782 | | var it = deleted_decls.iterator(); |
| 1783 | | while (it.next()) |kv| { |
| 1784 | | //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name}); |
| 1785 | | try self.deleteDecl(kv.key); |
| 1786 | | } |
| 1787 | | } |
| 1788 | | for (exports_to_resolve.items) |export_decl| { |
| 1789 | | _ = try self.resolveDecl(&root_scope.base, export_decl); |
| 1762 | } else { |
| 1763 | const new_decl = try self.createNewDecl( |
| 1764 | &root_scope.base, |
| 1765 | src_decl.name, |
| 1766 | decl_i, |
| 1767 | name_hash, |
| 1768 | src_decl.contents_hash, |
| 1769 | ); |
| 1770 | root_scope.decls.appendAssumeCapacity(new_decl); |
| 1771 | if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| { |
| 1772 | try exports_to_resolve.append(src_decl); |
| 1790 | 1773 | } |
| 1791 | | }, |
| 1774 | } |
| 1775 | } |
| 1776 | { |
| 1777 | // Handle explicitly deleted decls from the source code. Not to be confused |
| 1778 | // with when we delete decls because they are no longer referenced. |
| 1779 | var it = deleted_decls.iterator(); |
| 1780 | while (it.next()) |kv| { |
| 1781 | //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name}); |
| 1782 | try self.deleteDecl(kv.key); |
| 1783 | } |
| 1784 | } |
| 1785 | for (exports_to_resolve.items) |export_decl| { |
| 1786 | _ = try self.resolveZirDecl(&root_scope.base, export_decl); |
| 1792 | 1787 | } |
| 1793 | 1788 | } |
| 1794 | 1789 | |
| ... | ... | @@ -1933,73 +1928,67 @@ fn createNewDecl( |
| 1933 | 1928 | return new_decl; |
| 1934 | 1929 | } |
| 1935 | 1930 | |
| 1936 | | fn analyzeNewDecl(self: *Module, new_decl: *Decl, src_decl: *zir.Decl) InnerError!void { |
| 1931 | fn analyzeZirDecl(self: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool { |
| 1937 | 1932 | var decl_scope: Scope.DeclAnalysis = .{ |
| 1938 | | .decl = new_decl, |
| 1933 | .decl = decl, |
| 1939 | 1934 | .arena = std.heap.ArenaAllocator.init(self.allocator), |
| 1940 | 1935 | }; |
| 1941 | 1936 | errdefer decl_scope.arena.deinit(); |
| 1942 | 1937 | |
| 1943 | | new_decl.analysis = .in_progress; |
| 1938 | decl.analysis = .in_progress; |
| 1944 | 1939 | |
| 1945 | | const typed_value = self.analyzeConstInst(&decl_scope.base, src_decl.inst) catch |err| switch (err) { |
| 1946 | | error.OutOfMemory => return error.OutOfMemory, |
| 1947 | | error.AnalysisFail => { |
| 1948 | | switch (new_decl.analysis) { |
| 1949 | | .in_progress => new_decl.analysis = .dependency_failure, |
| 1950 | | else => {}, |
| 1951 | | } |
| 1952 | | new_decl.generation = self.generation; |
| 1953 | | return error.AnalysisFail; |
| 1954 | | }, |
| 1955 | | }; |
| 1940 | const typed_value = try self.analyzeConstInst(&decl_scope.base, src_decl.inst); |
| 1956 | 1941 | const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); |
| 1957 | 1942 | |
| 1958 | | arena_state.* = decl_scope.arena.state; |
| 1943 | var prev_type_has_bits = false; |
| 1944 | var type_changed = true; |
| 1959 | 1945 | |
| 1960 | | new_decl.typed_value = .{ |
| 1946 | if (decl.typedValueManaged()) |tvm| { |
| 1947 | prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits(); |
| 1948 | type_changed = !tvm.typed_value.ty.eql(typed_value.ty); |
| 1949 | |
| 1950 | tvm.deinit(self.allocator); |
| 1951 | } |
| 1952 | |
| 1953 | arena_state.* = decl_scope.arena.state; |
| 1954 | decl.typed_value = .{ |
| 1961 | 1955 | .most_recent = .{ |
| 1962 | 1956 | .typed_value = typed_value, |
| 1963 | 1957 | .arena = arena_state, |
| 1964 | 1958 | }, |
| 1965 | 1959 | }; |
| 1966 | | new_decl.analysis = .complete; |
| 1967 | | new_decl.generation = self.generation; |
| 1960 | decl.analysis = .complete; |
| 1961 | decl.generation = self.generation; |
| 1968 | 1962 | if (typed_value.ty.hasCodeGenBits()) { |
| 1969 | 1963 | // We don't fully codegen the decl until later, but we do need to reserve a global |
| 1970 | 1964 | // offset table index for it. This allows us to codegen decls out of dependency order, |
| 1971 | 1965 | // increasing how many computations can be done in parallel. |
| 1972 | | try self.bin_file.allocateDeclIndexes(new_decl); |
| 1973 | | try self.work_queue.writeItem(.{ .codegen_decl = new_decl }); |
| 1966 | try self.bin_file.allocateDeclIndexes(decl); |
| 1967 | try self.work_queue.writeItem(.{ .codegen_decl = decl }); |
| 1968 | } else if (prev_type_has_bits) { |
| 1969 | self.bin_file.freeDecl(decl); |
| 1974 | 1970 | } |
| 1971 | |
| 1972 | return type_changed; |
| 1975 | 1973 | } |
| 1976 | 1974 | |
| 1977 | | fn resolveDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl { |
| 1978 | | // If the name is empty, then we make this an anonymous Decl. |
| 1979 | | const scope_decl = scope.decl().?; |
| 1980 | | const new_decl = try self.allocateNewDecl(scope, scope_decl.src_index, src_decl.contents_hash); |
| 1981 | | try self.analyzeNewDecl(new_decl, src_decl); |
| 1982 | | return new_decl; |
| 1983 | | //const name_hash = Decl.hashSimpleName(src_decl.name); |
| 1984 | | //if (self.decl_table.get(name_hash)) |kv| { |
| 1985 | | // const decl = kv.value; |
| 1986 | | // decl.src = src_decl.src; |
| 1987 | | // try self.reAnalyzeDecl(decl, src_decl); |
| 1988 | | // return decl; |
| 1989 | | //} else if (src_decl.cast(zir.Inst.DeclVal)) |decl_val| { |
| 1990 | | // // This is just a named reference to another decl. |
| 1991 | | // return self.analyzeDeclVal(scope, decl_val); |
| 1992 | | //} else { |
| 1993 | | // const new_decl = try self.createNewDecl(scope, src_decl.name, src_decl.src, name_hash, src_decl.contents_hash); |
| 1994 | | // try self.analyzeNewDecl(new_decl, src_decl); |
| 1995 | | |
| 1996 | | // return new_decl; |
| 1997 | | //} |
| 1975 | fn resolveZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl { |
| 1976 | const zir_module = self.root_scope.cast(Scope.ZIRModule).?; |
| 1977 | const entry = zir_module.contents.module.findDecl(src_decl.name).?; |
| 1978 | return self.resolveZirDeclHavingIndex(scope, src_decl, entry.index); |
| 1979 | } |
| 1980 | |
| 1981 | fn resolveZirDeclHavingIndex(self: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl { |
| 1982 | const name_hash = scope.namespace().fullyQualifiedNameHash(src_decl.name); |
| 1983 | const decl = self.decl_table.getValue(name_hash).?; |
| 1984 | decl.src_index = src_index; |
| 1985 | try self.ensureDeclAnalyzed(decl); |
| 1986 | return decl; |
| 1998 | 1987 | } |
| 1999 | 1988 | |
| 2000 | 1989 | /// Declares a dependency on the decl. |
| 2001 | | fn resolveCompleteDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl { |
| 2002 | | const decl = try self.resolveDecl(scope, src_decl); |
| 1990 | fn resolveCompleteZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl { |
| 1991 | const decl = try self.resolveZirDecl(scope, src_decl); |
| 2003 | 1992 | switch (decl.analysis) { |
| 2004 | 1993 | .unreferenced => unreachable, |
| 2005 | 1994 | .in_progress => unreachable, |
| ... | ... | @@ -2014,15 +2003,32 @@ fn resolveCompleteDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerE |
| 2014 | 2003 | |
| 2015 | 2004 | .complete => {}, |
| 2016 | 2005 | } |
| 2017 | | if (scope.decl()) |scope_decl| { |
| 2018 | | try self.declareDeclDependency(scope_decl, decl); |
| 2019 | | } |
| 2020 | 2006 | return decl; |
| 2021 | 2007 | } |
| 2022 | 2008 | |
| 2023 | | /// TODO look into removing this function |
| 2009 | /// TODO Look into removing this function. The body is only needed for .zir files, not .zig files. |
| 2024 | 2010 | fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst { |
| 2025 | | return old_inst.analyzed_inst; |
| 2011 | if (old_inst.analyzed_inst) |inst| return inst; |
| 2012 | |
| 2013 | // If this assert trips, the instruction that was referenced did not get properly |
| 2014 | // analyzed before it was referenced. |
| 2015 | const zir_module = scope.namespace().cast(Scope.ZIRModule).?; |
| 2016 | const entry = if (old_inst.cast(zir.Inst.DeclVal)) |declval| blk: { |
| 2017 | const decl_name = declval.positionals.name; |
| 2018 | const entry = zir_module.contents.module.findDecl(decl_name) orelse |
| 2019 | return self.fail(scope, old_inst.src, "decl '{}' not found", .{decl_name}); |
| 2020 | break :blk entry; |
| 2021 | } else blk: { |
| 2022 | // If this assert trips, the instruction that was referenced did not get |
| 2023 | // properly analyzed by a previous instruction analysis before it was |
| 2024 | // referenced by the current one. |
| 2025 | break :blk zir_module.contents.module.findInstDecl(old_inst).?; |
| 2026 | }; |
| 2027 | const decl = try self.resolveCompleteZirDecl(scope, entry.decl); |
| 2028 | const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl); |
| 2029 | const result = try self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src); |
| 2030 | old_inst.analyzed_inst = result; |
| 2031 | return result; |
| 2026 | 2032 | } |
| 2027 | 2033 | |
| 2028 | 2034 | fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| ... | ... | @@ -2071,6 +2077,7 @@ fn resolveType(self: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { |
| 2071 | 2077 | } |
| 2072 | 2078 | |
| 2073 | 2079 | fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const u8, exported_decl: *Decl) !void { |
| 2080 | try self.ensureDeclAnalyzed(exported_decl); |
| 2074 | 2081 | const typed_value = exported_decl.typed_value.most_recent.typed_value; |
| 2075 | 2082 | switch (typed_value.ty.zigTypeTag()) { |
| 2076 | 2083 | .Fn => {}, |
| ... | ... | @@ -2439,7 +2446,7 @@ fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerEr |
| 2439 | 2446 | const src_decl = zir_module.contents.module.findDecl(decl_name) orelse |
| 2440 | 2447 | return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name}); |
| 2441 | 2448 | |
| 2442 | | const decl = try self.resolveCompleteDecl(scope, src_decl.decl); |
| 2449 | const decl = try self.resolveCompleteZirDecl(scope, src_decl.decl); |
| 2443 | 2450 | |
| 2444 | 2451 | return decl; |
| 2445 | 2452 | } |
| ... | ... | @@ -2555,19 +2562,31 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro |
| 2555 | 2562 | } |
| 2556 | 2563 | |
| 2557 | 2564 | fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { |
| 2558 | | return self.fail(scope, fn_inst.base.src, "TODO implement ZIR fn inst", .{}); |
| 2559 | | //const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type); |
| 2560 | | //const new_func = try scope.arena().create(Fn); |
| 2561 | | //new_func.* = .{ |
| 2562 | | // .analysis = .{ .queued = fn_inst }, |
| 2563 | | // .owner_decl = scope.decl().?, |
| 2564 | | //}; |
| 2565 | | //const fn_payload = try scope.arena().create(Value.Payload.Function); |
| 2566 | | //fn_payload.* = .{ .func = new_func }; |
| 2567 | | //return self.constInst(scope, fn_inst.base.src, .{ |
| 2568 | | // .ty = fn_type, |
| 2569 | | // .val = Value.initPayload(&fn_payload.base), |
| 2570 | | //}); |
| 2565 | const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type); |
| 2566 | const fn_zir = blk: { |
| 2567 | var fn_arena = std.heap.ArenaAllocator.init(self.allocator); |
| 2568 | errdefer fn_arena.deinit(); |
| 2569 | |
| 2570 | const fn_zir = try scope.arena().create(Fn.ZIR); |
| 2571 | fn_zir.* = .{ |
| 2572 | .body = .{ |
| 2573 | .instructions = fn_inst.positionals.body.instructions, |
| 2574 | }, |
| 2575 | .arena = fn_arena.state, |
| 2576 | }; |
| 2577 | break :blk fn_zir; |
| 2578 | }; |
| 2579 | const new_func = try scope.arena().create(Fn); |
| 2580 | new_func.* = .{ |
| 2581 | .analysis = .{ .queued = fn_zir }, |
| 2582 | .owner_decl = scope.decl().?, |
| 2583 | }; |
| 2584 | const fn_payload = try scope.arena().create(Value.Payload.Function); |
| 2585 | fn_payload.* = .{ .func = new_func }; |
| 2586 | return self.constInst(scope, fn_inst.base.src, .{ |
| 2587 | .ty = fn_type, |
| 2588 | .val = Value.initPayload(&fn_payload.base), |
| 2589 | }); |
| 2571 | 2590 | } |
| 2572 | 2591 | |
| 2573 | 2592 | fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| ... | ... | @@ -3277,6 +3296,7 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err |
| 3277 | 3296 | .decl => { |
| 3278 | 3297 | const decl = scope.cast(Scope.DeclAnalysis).?.decl; |
| 3279 | 3298 | decl.analysis = .sema_failure; |
| 3299 | decl.generation = self.generation; |
| 3280 | 3300 | self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg); |
| 3281 | 3301 | }, |
| 3282 | 3302 | .block => { |
| ... | ... | @@ -3285,12 +3305,14 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err |
| 3285 | 3305 | func.analysis = .sema_failure; |
| 3286 | 3306 | } else { |
| 3287 | 3307 | block.decl.analysis = .sema_failure; |
| 3308 | block.decl.generation = self.generation; |
| 3288 | 3309 | } |
| 3289 | 3310 | self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg); |
| 3290 | 3311 | }, |
| 3291 | 3312 | .gen_zir => { |
| 3292 | 3313 | const gen_zir = scope.cast(Scope.GenZIR).?; |
| 3293 | 3314 | gen_zir.decl.analysis = .sema_failure; |
| 3315 | gen_zir.decl.generation = self.generation; |
| 3294 | 3316 | self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg); |
| 3295 | 3317 | }, |
| 3296 | 3318 | .zir_module => { |