authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-28 22:43:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-28 22:43:26-07:00
log0c71d2fdc1cfa251b1c45a93724240a052c77a92
treef90f4d7e31b7e483aa1c826feb387c705e43abf5
parent3462193d30e54c17123cfe1e666d8e575d649426

stage2: implement semantic analysis for functions and global vars

* AstGen: add missing `break_inline` for comptime blocks. * Module: call getTree() in byteOffset(). This generates the AST when using cached ZIR and compile errors need to be reported. * Scope.File: distinguish between successful ZIR generation and AIR generation (when Decls in scope have been scanned). - `semaFile` correctly avoids doing work twice. * Implement first pass at `lookupInNamespace`. It has various TODOs left, such as `usingnamespace`, and setting up Decl dependencies.

7 files changed, 246 insertions(+), 304 deletions(-)

BRANCH_TODO+58-243
...@@ -1,3 +1,6 @@...@@ -1,3 +1,6 @@
1 * modify dbg_stmt ZIR instructions to have line/column rather than node indexes
2 * AstGen threadlocal
3 * extern "foo" for vars and for functions
1 * namespace decls table can't reference ZIR memory because it can get modified on updates4 * namespace decls table can't reference ZIR memory because it can get modified on updates
2 - change it for astgen worker to compare old and new ZIR, updating existing5 - change it for astgen worker to compare old and new ZIR, updating existing
3 namespaces & decls, and creating a changelist.6 namespaces & decls, and creating a changelist.
...@@ -65,49 +68,7 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd...@@ -65,49 +68,7 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
65/// Returns `true` if this is the first time analyzing the Decl.68/// Returns `true` if this is the first time analyzing the Decl.
66/// Returns `false` otherwise.69/// Returns `false` otherwise.
67fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {70fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
68 const tracy = trace(@src());
69 defer tracy.end();
70
71 const tree = try mod.getAstTree(decl.namespace.file_scope);
72 const node_tags = tree.nodes.items(.tag);
73 const node_datas = tree.nodes.items(.data);
74 const decl_node = decl.src_node;
75 switch (node_tags[decl_node]) {71 switch (node_tags[decl_node]) {
76 .fn_decl => {
77 const fn_proto = node_datas[decl_node].lhs;
78 const body = node_datas[decl_node].rhs;
79 switch (node_tags[fn_proto]) {
80 .fn_proto_simple => {
81 var params: [1]ast.Node.Index = undefined;
82 return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoSimple(&params, fn_proto));
83 },
84 .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoMulti(fn_proto)),
85 .fn_proto_one => {
86 var params: [1]ast.Node.Index = undefined;
87 return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoOne(&params, fn_proto));
88 },
89 .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProto(fn_proto)),
90 else => unreachable,
91 }
92 },
93 .fn_proto_simple => {
94 var params: [1]ast.Node.Index = undefined;
95 return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoSimple(&params, decl_node));
96 },
97 .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoMulti(decl_node)),
98 .fn_proto_one => {
99 var params: [1]ast.Node.Index = undefined;
100 return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoOne(&params, decl_node));
101 },
102 .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProto(decl_node)),
103
104 .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.globalVarDecl(decl_node)),
105 .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.localVarDecl(decl_node)),
106 .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.simpleVarDecl(decl_node)),
107 .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.alignedVarDecl(decl_node)),
108
109 .@"comptime" => {
110 },
111 .@"usingnamespace" => {72 .@"usingnamespace" => {
112 decl.analysis = .in_progress;73 decl.analysis = .in_progress;
11374
...@@ -135,128 +96,6 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -135,128 +96,6 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
135 }96 }
136}97}
13798
138fn astgenAndSemaFn(
139 mod: *Module,
140 decl: *Decl,
141 tree: ast.Tree,
142 body_node: ast.Node.Index,
143 fn_proto: ast.full.FnProto,
144) !bool {
145 const is_inline = fn_type.fnCallingConvention() == .Inline;
146 const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
147
148 new_func.* = .{
149 .state = anal_state,
150 .zir = fn_zir,
151 .body = undefined,
152 .owner_decl = decl,
153 };
154 fn_payload.* = .{
155 .base = .{ .tag = .function },
156 .data = new_func,
157 };
158
159 var prev_type_has_bits = false;
160 var prev_is_inline = false;
161 var type_changed = true;
162
163 if (decl.typedValueManaged()) |tvm| {
164 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
165 type_changed = !tvm.typed_value.ty.eql(fn_type);
166 if (tvm.typed_value.val.castTag(.function)) |payload| {
167 const prev_func = payload.data;
168 prev_is_inline = prev_func.state == .inline_only;
169 prev_func.deinit(mod.gpa);
170 }
171
172 tvm.deinit(mod.gpa);
173 }
174
175 decl_arena_state.* = decl_arena.state;
176 decl.typed_value = .{
177 .most_recent = .{
178 .typed_value = .{
179 .ty = fn_type,
180 .val = Value.initPayload(&fn_payload.base),
181 },
182 .arena = decl_arena_state,
183 },
184 };
185 decl.analysis = .complete;
186 decl.generation = mod.generation;
187
188 if (!is_inline and fn_type.hasCodeGenBits()) {
189 // We don't fully codegen the decl until later, but we do need to reserve a global
190 // offset table index for it. This allows us to codegen decls out of dependency order,
191 // increasing how many computations can be done in parallel.
192 try mod.comp.bin_file.allocateDeclIndexes(decl);
193 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
194 if (type_changed and mod.emit_h != null) {
195 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
196 }
197 } else if (!prev_is_inline and prev_type_has_bits) {
198 mod.comp.bin_file.freeDecl(decl);
199 }
200
201 if (fn_proto.extern_export_token) |maybe_export_token| {
202 if (token_tags[maybe_export_token] == .keyword_export) {
203 if (is_inline) {
204 return mod.failTok(
205 &block_scope.base,
206 maybe_export_token,
207 "export of inline function",
208 .{},
209 );
210 }
211 const export_src = decl.tokSrcLoc(maybe_export_token);
212 const name = tree.tokenSlice(fn_proto.name_token.?); // TODO identifierTokenString
213 // The scope needs to have the decl in it.
214 try mod.analyzeExport(&block_scope.base, export_src, name, decl);
215 }
216 }
217 return type_changed or is_inline != prev_is_inline;
218}
219 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
220 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
221 return mod.failTok(
222 &fn_type_scope.base,
223 lib_name_token,
224 "unable to add link lib '{s}': {s}",
225 .{ lib_name_str, @errorName(err) },
226 );
227 };
228 const target = mod.comp.getTarget();
229 if (target_util.is_libc_lib_name(target, lib_name_str)) {
230 if (!mod.comp.bin_file.options.link_libc) {
231 return mod.failTok(
232 &fn_type_scope.base,
233 lib_name_token,
234 "dependency on libc must be explicitly specified in the build command",
235 .{},
236 );
237 }
238 break :blk;
239 }
240 if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
241 if (!mod.comp.bin_file.options.link_libcpp) {
242 return mod.failTok(
243 &fn_type_scope.base,
244 lib_name_token,
245 "dependency on libc++ must be explicitly specified in the build command",
246 .{},
247 );
248 }
249 break :blk;
250 }
251 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
252 return mod.failTok(
253 &fn_type_scope.base,
254 lib_name_token,
255 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
256 .{ lib_name_str, lib_name_str },
257 );
258 }
259
260 if (mod.lookupIdentifier(scope, ident_name)) |decl| {99 if (mod.lookupIdentifier(scope, ident_name)) |decl| {
261 const msg = msg: {100 const msg = msg: {
262 const msg = try mod.errMsg(101 const msg = try mod.errMsg(
...@@ -273,58 +112,6 @@ fn astgenAndSemaFn(...@@ -273,58 +112,6 @@ fn astgenAndSemaFn(
273 }112 }
274113
275114
276 var type_changed = true;
277 if (decl.typedValueManaged()) |tvm| {
278 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
279
280 tvm.deinit(mod.gpa);
281 }
282
283 const new_variable = try decl_arena.allocator.create(Var);
284 new_variable.* = .{
285 .owner_decl = decl,
286 .init = var_info.val orelse undefined,
287 .is_extern = is_extern,
288 .is_mutable = is_mutable,
289 .is_threadlocal = is_threadlocal,
290 };
291 const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
292
293 decl_arena_state.* = decl_arena.state;
294 decl.typed_value = .{
295 .most_recent = .{
296 .typed_value = .{
297 .ty = var_info.ty,
298 .val = var_val,
299 },
300 .arena = decl_arena_state,
301 },
302 };
303 decl.analysis = .complete;
304 decl.generation = mod.generation;
305
306
307
308 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
309 return mod.failTok(
310 &decl_scope.base,
311 var_decl.ast.mut_token,
312 "variable of type '{}' must be const",
313 .{var_info.ty},
314 );
315 }
316
317 if (var_decl.extern_export_token) |maybe_export_token| {
318 if (token_tags[maybe_export_token] == .keyword_export) {
319 const export_src = decl.tokSrcLoc(maybe_export_token);
320 const name_token = var_decl.ast.mut_token + 1;
321 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
322 // The scope needs to have the decl in it.
323 try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
324 }
325 }
326
327
328 const error_set = try arena.create(Module.ErrorSet);115 const error_set = try arena.create(Module.ErrorSet);
329 error_set.* = .{116 error_set.* = .{
330 .owner_decl = astgen.decl,117 .owner_decl = astgen.decl,
...@@ -397,14 +184,6 @@ pub fn analyzeNamespace(...@@ -397,14 +184,6 @@ pub fn analyzeNamespace(
397 };184 };
398}185}
399186
400 if (align_inst != .none) {
401 return mod.fail(&namespace.base, .{ .node_abs = decl_node }, "TODO: implement decls with align()", .{});
402 }
403 if (section_inst != .none) {
404 return mod.fail(&namespace.base, .{ .node_abs = decl_node }, "TODO: implement decls with linksection()", .{});
405 }
406
407
408/// Trailing:187/// Trailing:
409/// 0. `EmitH` if `module.emit_h != null`.188/// 0. `EmitH` if `module.emit_h != null`.
410/// 1. A per-Decl link object. Represents the position of the code in the output file.189/// 1. A per-Decl link object. Represents the position of the code in the output file.
...@@ -442,25 +221,61 @@ pub fn analyzeNamespace(...@@ -442,25 +221,61 @@ pub fn analyzeNamespace(
442 /// This memory is managed with gpa, must be freed when the function is freed.221 /// This memory is managed with gpa, must be freed when the function is freed.
443 zir: Zir,222 zir: Zir,
444223
445pub fn root(sema: *Sema, root_block: *Scope.Block) !Zir.Inst.Index {
446 const inst_data = sema.code.instructions.items(.data)[0].pl_node;
447 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
448 const root_body = sema.code.extra[extra.end..][0..extra.data.body_len];
449 return sema.analyzeBody(root_block, root_body);
450}
451224
452pub fn rootAsRef(sema: *Sema, root_block: *Scope.Block) !Zir.Inst.Ref {225 if (fn_proto.lib_name) |lib_name_token| blk: {
453 const break_inst = try sema.root(root_block);226 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
454 return sema.code.instructions.items(.data)[break_inst].@"break".operand;227 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
455}228 return mod.failTok(
229 &fn_type_scope.base,
230 lib_name_token,
231 "unable to add link lib '{s}': {s}",
232 .{ lib_name_str, @errorName(err) },
233 );
234 };
235 const target = mod.comp.getTarget();
236 if (target_util.is_libc_lib_name(target, lib_name_str)) {
237 if (!mod.comp.bin_file.options.link_libc) {
238 return mod.failTok(
239 &fn_type_scope.base,
240 lib_name_token,
241 "dependency on libc must be explicitly specified in the build command",
242 .{},
243 );
244 }
245 break :blk;
246 }
247 if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
248 if (!mod.comp.bin_file.options.link_libcpp) {
249 return mod.failTok(
250 &fn_type_scope.base,
251 lib_name_token,
252 "dependency on libc++ must be explicitly specified in the build command",
253 .{},
254 );
255 }
256 break :blk;
257 }
258 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
259 return mod.failTok(
260 &fn_type_scope.base,
261 lib_name_token,
262 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
263 .{ lib_name_str, lib_name_str },
264 );
265 }
266 }
456267
457/// Assumes that `root_block` ends with `break_inline`.268 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
458pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {269 const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
459 assert(root_block.is_comptime);270
460 const zir_inst_ref = try sema.rootAsRef(root_block);271 new_func.* = .{
461 // Source location is unneeded because resolveConstValue must have already272 .state = anal_state,
462 // been successfully called when coercing the value to a type, from the273 .zir = fn_zir,
463 // result location.274 .body = undefined,
464 return sema.resolveType(root_block, .unneeded, zir_inst_ref);275 .owner_decl = decl,
465}276 };
277 fn_payload.* = .{
278 .base = .{ .tag = .function },
279 .data = new_func,
280 };
466281
src/AstGen.zig+4-1
...@@ -3035,7 +3035,10 @@ fn comptimeDecl(...@@ -3035,7 +3035,10 @@ fn comptimeDecl(
3035 };3035 };
3036 defer decl_block.instructions.deinit(gpa);3036 defer decl_block.instructions.deinit(gpa);
30373037
3038 _ = try expr(&decl_block, &decl_block.base, .none, body_node);3038 const block_result = try expr(&decl_block, &decl_block.base, .none, body_node);
3039 if (decl_block.instructions.items.len == 0 or !decl_block.refIsNoReturn(block_result)) {
3040 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
3041 }
3039 try decl_block.setBlockBody(block_inst);3042 try decl_block.setBlockBody(block_inst);
30403043
3041 try wip_decls.payload.ensureUnusedCapacity(gpa, 6);3044 try wip_decls.payload.ensureUnusedCapacity(gpa, 6);
src/Compilation.zig+2-2
...@@ -394,7 +394,7 @@ pub const AllErrors = struct {...@@ -394,7 +394,7 @@ pub const AllErrors = struct {
394 for (notes) |*note, i| {394 for (notes) |*note, i| {
395 const module_note = module_err_msg.notes[i];395 const module_note = module_err_msg.notes[i];
396 const source = try module_note.src_loc.file_scope.getSource(module.gpa);396 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
397 const byte_offset = try module_note.src_loc.byteOffset();397 const byte_offset = try module_note.src_loc.byteOffset(module.gpa);
398 const loc = std.zig.findLineColumn(source, byte_offset);398 const loc = std.zig.findLineColumn(source, byte_offset);
399 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;399 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;
400 note.* = .{400 note.* = .{
...@@ -417,7 +417,7 @@ pub const AllErrors = struct {...@@ -417,7 +417,7 @@ pub const AllErrors = struct {
417 return;417 return;
418 }418 }
419 const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);419 const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
420 const byte_offset = try module_err_msg.src_loc.byteOffset();420 const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa);
421 const loc = std.zig.findLineColumn(source, byte_offset);421 const loc = std.zig.findLineColumn(source, byte_offset);
422 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;422 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;
423 try errors.append(.{423 try errors.append(.{
src/Module.zig+169-53
...@@ -271,7 +271,7 @@ pub const Decl = struct {...@@ -271,7 +271,7 @@ pub const Decl = struct {
271 const func = payload.data;271 const func = payload.data;
272 func.deinit(gpa);272 func.deinit(gpa);
273 }273 }
274 if (decl.value_arena) |a| a.promote(gpa).deinit();274 decl.clearValues(gpa);
275 }275 }
276 decl.dependants.deinit(gpa);276 decl.dependants.deinit(gpa);
277 decl.dependencies.deinit(gpa);277 decl.dependencies.deinit(gpa);
...@@ -284,6 +284,14 @@ pub const Decl = struct {...@@ -284,6 +284,14 @@ pub const Decl = struct {
284 }284 }
285 }285 }
286286
287 pub fn clearValues(decl: *Decl, gpa: *Allocator) void {
288 if (decl.value_arena) |arena_state| {
289 arena_state.promote(gpa).deinit();
290 decl.value_arena = null;
291 decl.has_tv = false;
292 }
293 }
294
287 /// This name is relative to the containing namespace of the decl.295 /// This name is relative to the containing namespace of the decl.
288 /// The memory is owned by the containing File ZIR.296 /// The memory is owned by the containing File ZIR.
289 pub fn getName(decl: Decl) ?[:0]const u8 {297 pub fn getName(decl: Decl) ?[:0]const u8 {
...@@ -319,7 +327,7 @@ pub const Decl = struct {...@@ -319,7 +327,7 @@ pub const Decl = struct {
319 return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 6]);327 return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 6]);
320 }328 }
321329
322 pub fn zirLinkSectionRef(decl: Decl) Zir.Inst.Ref {330 pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref {
323 if (!decl.has_linksection) return .none;331 if (!decl.has_linksection) return .none;
324 const zir = decl.namespace.file_scope.zir;332 const zir = decl.namespace.file_scope.zir;
325 const extra_index = decl.zir_decl_index + 6 + @boolToInt(decl.has_align);333 const extra_index = decl.zir_decl_index + 6 + @boolToInt(decl.has_align);
...@@ -727,10 +735,11 @@ pub const Scope = struct {...@@ -727,10 +735,11 @@ pub const Scope = struct {
727 base: Scope = Scope{ .tag = base_tag },735 base: Scope = Scope{ .tag = base_tag },
728 status: enum {736 status: enum {
729 never_loaded,737 never_loaded,
738 retryable_failure,
730 parse_failure,739 parse_failure,
731 astgen_failure,740 astgen_failure,
732 retryable_failure,741 success_zir,
733 success,742 success_air,
734 },743 },
735 source_loaded: bool,744 source_loaded: bool,
736 tree_loaded: bool,745 tree_loaded: bool,
...@@ -2043,7 +2052,7 @@ pub const SrcLoc = struct {...@@ -2043,7 +2052,7 @@ pub const SrcLoc = struct {
2043 return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));2052 return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));
2044 }2053 }
20452054
2046 pub fn byteOffset(src_loc: SrcLoc) !u32 {2055 pub fn byteOffset(src_loc: SrcLoc, gpa: *Allocator) !u32 {
2047 switch (src_loc.lazy) {2056 switch (src_loc.lazy) {
2048 .unneeded => unreachable,2057 .unneeded => unreachable,
2049 .entire_file => return 0,2058 .entire_file => return 0,
...@@ -2051,30 +2060,31 @@ pub const SrcLoc = struct {...@@ -2051,30 +2060,31 @@ pub const SrcLoc = struct {
2051 .byte_abs => |byte_index| return byte_index,2060 .byte_abs => |byte_index| return byte_index,
20522061
2053 .token_abs => |tok_index| {2062 .token_abs => |tok_index| {
2054 const tree = src_loc.file_scope.tree;2063 const tree = try src_loc.file_scope.getTree(gpa);
2055 const token_starts = tree.tokens.items(.start);2064 const token_starts = tree.tokens.items(.start);
2056 return token_starts[tok_index];2065 return token_starts[tok_index];
2057 },2066 },
2058 .node_abs => |node| {2067 .node_abs => |node| {
2059 const tree = src_loc.file_scope.tree;2068 const tree = try src_loc.file_scope.getTree(gpa);
2060 const token_starts = tree.tokens.items(.start);2069 const token_starts = tree.tokens.items(.start);
2061 const tok_index = tree.firstToken(node);2070 const tok_index = tree.firstToken(node);
2062 return token_starts[tok_index];2071 return token_starts[tok_index];
2063 },2072 },
2064 .byte_offset => |byte_off| {2073 .byte_offset => |byte_off| {
2065 const tree = src_loc.file_scope.tree;2074 const tree = try src_loc.file_scope.getTree(gpa);
2066 const token_starts = tree.tokens.items(.start);2075 const token_starts = tree.tokens.items(.start);
2067 return token_starts[src_loc.declSrcToken()] + byte_off;2076 return token_starts[src_loc.declSrcToken()] + byte_off;
2068 },2077 },
2069 .token_offset => |tok_off| {2078 .token_offset => |tok_off| {
2070 const tok_index = src_loc.declSrcToken() + tok_off;2079 const tok_index = src_loc.declSrcToken() + tok_off;
2071 const tree = src_loc.file_scope.tree;2080 const tree = try src_loc.file_scope.getTree(gpa);
2072 const token_starts = tree.tokens.items(.start);2081 const token_starts = tree.tokens.items(.start);
2073 return token_starts[tok_index];2082 return token_starts[tok_index];
2074 },2083 },
2075 .node_offset, .node_offset_bin_op => |node_off| {2084 .node_offset, .node_offset_bin_op => |node_off| {
2076 const node = src_loc.declRelativeToNodeIndex(node_off);2085 const node = src_loc.declRelativeToNodeIndex(node_off);
2077 const tree = src_loc.file_scope.tree;2086 const tree = try src_loc.file_scope.getTree(gpa);
2087 assert(src_loc.file_scope.tree_loaded);
2078 const main_tokens = tree.nodes.items(.main_token);2088 const main_tokens = tree.nodes.items(.main_token);
2079 const tok_index = main_tokens[node];2089 const tok_index = main_tokens[node];
2080 const token_starts = tree.tokens.items(.start);2090 const token_starts = tree.tokens.items(.start);
...@@ -2082,14 +2092,14 @@ pub const SrcLoc = struct {...@@ -2082,14 +2092,14 @@ pub const SrcLoc = struct {
2082 },2092 },
2083 .node_offset_back2tok => |node_off| {2093 .node_offset_back2tok => |node_off| {
2084 const node = src_loc.declRelativeToNodeIndex(node_off);2094 const node = src_loc.declRelativeToNodeIndex(node_off);
2085 const tree = src_loc.file_scope.tree;2095 const tree = try src_loc.file_scope.getTree(gpa);
2086 const tok_index = tree.firstToken(node) - 2;2096 const tok_index = tree.firstToken(node) - 2;
2087 const token_starts = tree.tokens.items(.start);2097 const token_starts = tree.tokens.items(.start);
2088 return token_starts[tok_index];2098 return token_starts[tok_index];
2089 },2099 },
2090 .node_offset_var_decl_ty => |node_off| {2100 .node_offset_var_decl_ty => |node_off| {
2091 const node = src_loc.declRelativeToNodeIndex(node_off);2101 const node = src_loc.declRelativeToNodeIndex(node_off);
2092 const tree = src_loc.file_scope.tree;2102 const tree = try src_loc.file_scope.getTree(gpa);
2093 const node_tags = tree.nodes.items(.tag);2103 const node_tags = tree.nodes.items(.tag);
2094 const full = switch (node_tags[node]) {2104 const full = switch (node_tags[node]) {
2095 .global_var_decl => tree.globalVarDecl(node),2105 .global_var_decl => tree.globalVarDecl(node),
...@@ -2108,7 +2118,7 @@ pub const SrcLoc = struct {...@@ -2108,7 +2118,7 @@ pub const SrcLoc = struct {
2108 return token_starts[tok_index];2118 return token_starts[tok_index];
2109 },2119 },
2110 .node_offset_builtin_call_arg0 => |node_off| {2120 .node_offset_builtin_call_arg0 => |node_off| {
2111 const tree = src_loc.file_scope.tree;2121 const tree = try src_loc.file_scope.getTree(gpa);
2112 const node_datas = tree.nodes.items(.data);2122 const node_datas = tree.nodes.items(.data);
2113 const node_tags = tree.nodes.items(.tag);2123 const node_tags = tree.nodes.items(.tag);
2114 const node = src_loc.declRelativeToNodeIndex(node_off);2124 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2123,7 +2133,7 @@ pub const SrcLoc = struct {...@@ -2123,7 +2133,7 @@ pub const SrcLoc = struct {
2123 return token_starts[tok_index];2133 return token_starts[tok_index];
2124 },2134 },
2125 .node_offset_builtin_call_arg1 => |node_off| {2135 .node_offset_builtin_call_arg1 => |node_off| {
2126 const tree = src_loc.file_scope.tree;2136 const tree = try src_loc.file_scope.getTree(gpa);
2127 const node_datas = tree.nodes.items(.data);2137 const node_datas = tree.nodes.items(.data);
2128 const node_tags = tree.nodes.items(.tag);2138 const node_tags = tree.nodes.items(.tag);
2129 const node = src_loc.declRelativeToNodeIndex(node_off);2139 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2138,7 +2148,7 @@ pub const SrcLoc = struct {...@@ -2138,7 +2148,7 @@ pub const SrcLoc = struct {
2138 return token_starts[tok_index];2148 return token_starts[tok_index];
2139 },2149 },
2140 .node_offset_array_access_index => |node_off| {2150 .node_offset_array_access_index => |node_off| {
2141 const tree = src_loc.file_scope.tree;2151 const tree = try src_loc.file_scope.getTree(gpa);
2142 const node_datas = tree.nodes.items(.data);2152 const node_datas = tree.nodes.items(.data);
2143 const node_tags = tree.nodes.items(.tag);2153 const node_tags = tree.nodes.items(.tag);
2144 const node = src_loc.declRelativeToNodeIndex(node_off);2154 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2148,7 +2158,7 @@ pub const SrcLoc = struct {...@@ -2148,7 +2158,7 @@ pub const SrcLoc = struct {
2148 return token_starts[tok_index];2158 return token_starts[tok_index];
2149 },2159 },
2150 .node_offset_slice_sentinel => |node_off| {2160 .node_offset_slice_sentinel => |node_off| {
2151 const tree = src_loc.file_scope.tree;2161 const tree = try src_loc.file_scope.getTree(gpa);
2152 const node_datas = tree.nodes.items(.data);2162 const node_datas = tree.nodes.items(.data);
2153 const node_tags = tree.nodes.items(.tag);2163 const node_tags = tree.nodes.items(.tag);
2154 const node = src_loc.declRelativeToNodeIndex(node_off);2164 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2164,7 +2174,7 @@ pub const SrcLoc = struct {...@@ -2164,7 +2174,7 @@ pub const SrcLoc = struct {
2164 return token_starts[tok_index];2174 return token_starts[tok_index];
2165 },2175 },
2166 .node_offset_call_func => |node_off| {2176 .node_offset_call_func => |node_off| {
2167 const tree = src_loc.file_scope.tree;2177 const tree = try src_loc.file_scope.getTree(gpa);
2168 const node_datas = tree.nodes.items(.data);2178 const node_datas = tree.nodes.items(.data);
2169 const node_tags = tree.nodes.items(.tag);2179 const node_tags = tree.nodes.items(.tag);
2170 const node = src_loc.declRelativeToNodeIndex(node_off);2180 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2190,7 +2200,7 @@ pub const SrcLoc = struct {...@@ -2190,7 +2200,7 @@ pub const SrcLoc = struct {
2190 return token_starts[tok_index];2200 return token_starts[tok_index];
2191 },2201 },
2192 .node_offset_field_name => |node_off| {2202 .node_offset_field_name => |node_off| {
2193 const tree = src_loc.file_scope.tree;2203 const tree = try src_loc.file_scope.getTree(gpa);
2194 const node_datas = tree.nodes.items(.data);2204 const node_datas = tree.nodes.items(.data);
2195 const node_tags = tree.nodes.items(.tag);2205 const node_tags = tree.nodes.items(.tag);
2196 const node = src_loc.declRelativeToNodeIndex(node_off);2206 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2202,7 +2212,7 @@ pub const SrcLoc = struct {...@@ -2202,7 +2212,7 @@ pub const SrcLoc = struct {
2202 return token_starts[tok_index];2212 return token_starts[tok_index];
2203 },2213 },
2204 .node_offset_deref_ptr => |node_off| {2214 .node_offset_deref_ptr => |node_off| {
2205 const tree = src_loc.file_scope.tree;2215 const tree = try src_loc.file_scope.getTree(gpa);
2206 const node_datas = tree.nodes.items(.data);2216 const node_datas = tree.nodes.items(.data);
2207 const node_tags = tree.nodes.items(.tag);2217 const node_tags = tree.nodes.items(.tag);
2208 const node = src_loc.declRelativeToNodeIndex(node_off);2218 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2211,7 +2221,7 @@ pub const SrcLoc = struct {...@@ -2211,7 +2221,7 @@ pub const SrcLoc = struct {
2211 return token_starts[tok_index];2221 return token_starts[tok_index];
2212 },2222 },
2213 .node_offset_asm_source => |node_off| {2223 .node_offset_asm_source => |node_off| {
2214 const tree = src_loc.file_scope.tree;2224 const tree = try src_loc.file_scope.getTree(gpa);
2215 const node_datas = tree.nodes.items(.data);2225 const node_datas = tree.nodes.items(.data);
2216 const node_tags = tree.nodes.items(.tag);2226 const node_tags = tree.nodes.items(.tag);
2217 const node = src_loc.declRelativeToNodeIndex(node_off);2227 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2226,7 +2236,7 @@ pub const SrcLoc = struct {...@@ -2226,7 +2236,7 @@ pub const SrcLoc = struct {
2226 return token_starts[tok_index];2236 return token_starts[tok_index];
2227 },2237 },
2228 .node_offset_asm_ret_ty => |node_off| {2238 .node_offset_asm_ret_ty => |node_off| {
2229 const tree = src_loc.file_scope.tree;2239 const tree = try src_loc.file_scope.getTree(gpa);
2230 const node_datas = tree.nodes.items(.data);2240 const node_datas = tree.nodes.items(.data);
2231 const node_tags = tree.nodes.items(.tag);2241 const node_tags = tree.nodes.items(.tag);
2232 const node = src_loc.declRelativeToNodeIndex(node_off);2242 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2243,7 +2253,7 @@ pub const SrcLoc = struct {...@@ -2243,7 +2253,7 @@ pub const SrcLoc = struct {
22432253
2244 .node_offset_for_cond, .node_offset_if_cond => |node_off| {2254 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
2245 const node = src_loc.declRelativeToNodeIndex(node_off);2255 const node = src_loc.declRelativeToNodeIndex(node_off);
2246 const tree = src_loc.file_scope.tree;2256 const tree = try src_loc.file_scope.getTree(gpa);
2247 const node_tags = tree.nodes.items(.tag);2257 const node_tags = tree.nodes.items(.tag);
2248 const src_node = switch (node_tags[node]) {2258 const src_node = switch (node_tags[node]) {
2249 .if_simple => tree.ifSimple(node).ast.cond_expr,2259 .if_simple => tree.ifSimple(node).ast.cond_expr,
...@@ -2262,7 +2272,7 @@ pub const SrcLoc = struct {...@@ -2262,7 +2272,7 @@ pub const SrcLoc = struct {
2262 },2272 },
2263 .node_offset_bin_lhs => |node_off| {2273 .node_offset_bin_lhs => |node_off| {
2264 const node = src_loc.declRelativeToNodeIndex(node_off);2274 const node = src_loc.declRelativeToNodeIndex(node_off);
2265 const tree = src_loc.file_scope.tree;2275 const tree = try src_loc.file_scope.getTree(gpa);
2266 const node_datas = tree.nodes.items(.data);2276 const node_datas = tree.nodes.items(.data);
2267 const src_node = node_datas[node].lhs;2277 const src_node = node_datas[node].lhs;
2268 const main_tokens = tree.nodes.items(.main_token);2278 const main_tokens = tree.nodes.items(.main_token);
...@@ -2272,7 +2282,7 @@ pub const SrcLoc = struct {...@@ -2272,7 +2282,7 @@ pub const SrcLoc = struct {
2272 },2282 },
2273 .node_offset_bin_rhs => |node_off| {2283 .node_offset_bin_rhs => |node_off| {
2274 const node = src_loc.declRelativeToNodeIndex(node_off);2284 const node = src_loc.declRelativeToNodeIndex(node_off);
2275 const tree = src_loc.file_scope.tree;2285 const tree = try src_loc.file_scope.getTree(gpa);
2276 const node_datas = tree.nodes.items(.data);2286 const node_datas = tree.nodes.items(.data);
2277 const src_node = node_datas[node].rhs;2287 const src_node = node_datas[node].rhs;
2278 const main_tokens = tree.nodes.items(.main_token);2288 const main_tokens = tree.nodes.items(.main_token);
...@@ -2283,7 +2293,7 @@ pub const SrcLoc = struct {...@@ -2283,7 +2293,7 @@ pub const SrcLoc = struct {
22832293
2284 .node_offset_switch_operand => |node_off| {2294 .node_offset_switch_operand => |node_off| {
2285 const node = src_loc.declRelativeToNodeIndex(node_off);2295 const node = src_loc.declRelativeToNodeIndex(node_off);
2286 const tree = src_loc.file_scope.tree;2296 const tree = try src_loc.file_scope.getTree(gpa);
2287 const node_datas = tree.nodes.items(.data);2297 const node_datas = tree.nodes.items(.data);
2288 const src_node = node_datas[node].lhs;2298 const src_node = node_datas[node].lhs;
2289 const main_tokens = tree.nodes.items(.main_token);2299 const main_tokens = tree.nodes.items(.main_token);
...@@ -2294,7 +2304,7 @@ pub const SrcLoc = struct {...@@ -2294,7 +2304,7 @@ pub const SrcLoc = struct {
22942304
2295 .node_offset_switch_special_prong => |node_off| {2305 .node_offset_switch_special_prong => |node_off| {
2296 const switch_node = src_loc.declRelativeToNodeIndex(node_off);2306 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
2297 const tree = src_loc.file_scope.tree;2307 const tree = try src_loc.file_scope.getTree(gpa);
2298 const node_datas = tree.nodes.items(.data);2308 const node_datas = tree.nodes.items(.data);
2299 const node_tags = tree.nodes.items(.tag);2309 const node_tags = tree.nodes.items(.tag);
2300 const main_tokens = tree.nodes.items(.main_token);2310 const main_tokens = tree.nodes.items(.main_token);
...@@ -2320,7 +2330,7 @@ pub const SrcLoc = struct {...@@ -2320,7 +2330,7 @@ pub const SrcLoc = struct {
23202330
2321 .node_offset_switch_range => |node_off| {2331 .node_offset_switch_range => |node_off| {
2322 const switch_node = src_loc.declRelativeToNodeIndex(node_off);2332 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
2323 const tree = src_loc.file_scope.tree;2333 const tree = try src_loc.file_scope.getTree(gpa);
2324 const node_datas = tree.nodes.items(.data);2334 const node_datas = tree.nodes.items(.data);
2325 const node_tags = tree.nodes.items(.tag);2335 const node_tags = tree.nodes.items(.tag);
2326 const main_tokens = tree.nodes.items(.main_token);2336 const main_tokens = tree.nodes.items(.main_token);
...@@ -2349,7 +2359,7 @@ pub const SrcLoc = struct {...@@ -2349,7 +2359,7 @@ pub const SrcLoc = struct {
2349 },2359 },
23502360
2351 .node_offset_fn_type_cc => |node_off| {2361 .node_offset_fn_type_cc => |node_off| {
2352 const tree = src_loc.file_scope.tree;2362 const tree = try src_loc.file_scope.getTree(gpa);
2353 const node_datas = tree.nodes.items(.data);2363 const node_datas = tree.nodes.items(.data);
2354 const node_tags = tree.nodes.items(.tag);2364 const node_tags = tree.nodes.items(.tag);
2355 const node = src_loc.declRelativeToNodeIndex(node_off);2365 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2368,7 +2378,7 @@ pub const SrcLoc = struct {...@@ -2368,7 +2378,7 @@ pub const SrcLoc = struct {
2368 },2378 },
23692379
2370 .node_offset_fn_type_ret_ty => |node_off| {2380 .node_offset_fn_type_ret_ty => |node_off| {
2371 const tree = src_loc.file_scope.tree;2381 const tree = try src_loc.file_scope.getTree(gpa);
2372 const node_datas = tree.nodes.items(.data);2382 const node_datas = tree.nodes.items(.data);
2373 const node_tags = tree.nodes.items(.tag);2383 const node_tags = tree.nodes.items(.tag);
2374 const node = src_loc.declRelativeToNodeIndex(node_off);2384 const node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2387,7 +2397,7 @@ pub const SrcLoc = struct {...@@ -2387,7 +2397,7 @@ pub const SrcLoc = struct {
2387 },2397 },
23882398
2389 .node_offset_anyframe_type => |node_off| {2399 .node_offset_anyframe_type => |node_off| {
2390 const tree = src_loc.file_scope.tree;2400 const tree = try src_loc.file_scope.getTree(gpa);
2391 const node_datas = tree.nodes.items(.data);2401 const node_datas = tree.nodes.items(.data);
2392 const node_tags = tree.nodes.items(.tag);2402 const node_tags = tree.nodes.items(.tag);
2393 const parent_node = src_loc.declRelativeToNodeIndex(node_off);2403 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
...@@ -2912,7 +2922,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2912,7 +2922,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2912 file.stat_size = header.stat_size;2922 file.stat_size = header.stat_size;
2913 file.stat_inode = header.stat_inode;2923 file.stat_inode = header.stat_inode;
2914 file.stat_mtime = header.stat_mtime;2924 file.stat_mtime = header.stat_mtime;
2915 file.status = .success;2925 file.status = .success_zir;
2916 log.debug("AstGen cached success: {s}", .{file.sub_file_path});2926 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
29172927
2918 // TODO don't report compile errors until Sema @importFile2928 // TODO don't report compile errors until Sema @importFile
...@@ -2927,7 +2937,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2927,7 +2937,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2927 }2937 }
2928 return;2938 return;
2929 },2939 },
2930 .parse_failure, .astgen_failure, .success => {2940 .parse_failure, .astgen_failure, .success_zir, .success_air => {
2931 const unchanged_metadata =2941 const unchanged_metadata =
2932 stat.size == file.stat_size and2942 stat.size == file.stat_size and
2933 stat.mtime == file.stat_mtime and2943 stat.mtime == file.stat_mtime and
...@@ -3024,7 +3034,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -3024,7 +3034,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
30243034
3025 file.zir = try AstGen.generate(gpa, file);3035 file.zir = try AstGen.generate(gpa, file);
3026 file.zir_loaded = true;3036 file.zir_loaded = true;
3027 file.status = .success;3037 file.status = .success_zir;
3028 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});3038 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
30293039
3030 const safety_buffer = if (data_has_safety_tag)3040 const safety_buffer = if (data_has_safety_tag)
...@@ -3197,11 +3207,13 @@ pub fn semaPkg(mod: *Module, pkg: *Package) !void {...@@ -3197,11 +3207,13 @@ pub fn semaPkg(mod: *Module, pkg: *Package) !void {
3197}3207}
31983208
3199pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {3209pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {
3210 if (file.status == .success_air) return;
3211
3200 const tracy = trace(@src());3212 const tracy = trace(@src());
3201 defer tracy.end();3213 defer tracy.end();
32023214
3203 assert(file.zir_loaded);3215 assert(file.zir_loaded);
3204 assert(!file.zir.hasCompileErrors());3216 assert(file.status == .success_zir);
32053217
3206 const gpa = mod.gpa;3218 const gpa = mod.gpa;
3207 var decl_arena = std.heap.ArenaAllocator.init(gpa);3219 var decl_arena = std.heap.ArenaAllocator.init(gpa);
...@@ -3279,6 +3291,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {...@@ -3279,6 +3291,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {
3279 if (dep == struct_decl) continue;3291 if (dep == struct_decl) continue;
3280 _ = try mod.declareDeclDependency(struct_decl, dep);3292 _ = try mod.declareDeclDependency(struct_decl, dep);
3281 }3293 }
3294 file.status = .success_air;
3282}3295}
32833296
3284/// Returns `true` if the Decl type changed.3297/// Returns `true` if the Decl type changed.
...@@ -3319,26 +3332,128 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3319,26 +3332,128 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3319 };3332 };
3320 defer block_scope.instructions.deinit(gpa);3333 defer block_scope.instructions.deinit(gpa);
33213334
3335 const zir_datas = zir.instructions.items(.data);
3336 const zir_tags = zir.instructions.items(.tag);
3337
3322 const zir_block_index = decl.zirBlockIndex();3338 const zir_block_index = decl.zirBlockIndex();
3323 const inst_data = zir.instructions.items(.data)[zir_block_index].pl_node;3339 const inst_data = zir_datas[zir_block_index].pl_node;
3324 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);3340 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
3325 const body = zir.extra[extra.end..][0..extra.data.body_len];3341 const body = zir.extra[extra.end..][0..extra.data.body_len];
3326 const break_index = try sema.analyzeBody(&block_scope, body);3342 const break_index = try sema.analyzeBody(&block_scope, body);
3343 const result_ref = zir_datas[break_index].@"break".operand;
3344 const decl_tv = try sema.resolveInstConst(&block_scope, inst_data.src(), result_ref);
3345 const align_val = blk: {
3346 const align_ref = decl.zirAlignRef();
3347 if (align_ref == .none) break :blk Value.initTag(.null_value);
3348 break :blk (try sema.resolveInstConst(&block_scope, inst_data.src(), align_ref)).val;
3349 };
3350 const linksection_val = blk: {
3351 const linksection_ref = decl.zirLinksectionRef();
3352 if (linksection_ref == .none) break :blk Value.initTag(.null_value);
3353 break :blk (try sema.resolveInstConst(&block_scope, inst_data.src(), linksection_ref)).val;
3354 };
33273355
3328 if (decl.zirAlignRef() != .none) {3356 // We need the memory for the Type to go into the arena for the Decl
3329 @panic("TODO implement decl align");3357 var decl_arena = std.heap.ArenaAllocator.init(gpa);
3330 }3358 errdefer decl_arena.deinit();
3331 if (decl.zirLinkSectionRef() != .none) {3359 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
3332 @panic("TODO implement decl linksection");3360
3333 }3361 if (decl_tv.val.tag() == .function) {
3362 var prev_type_has_bits = false;
3363 var prev_is_inline = false;
3364 var type_changed = true;
3365
3366 if (decl.has_tv) {
3367 prev_type_has_bits = decl.ty.hasCodeGenBits();
3368 type_changed = !decl.ty.eql(decl_tv.ty);
3369 if (decl.val.castTag(.function)) |payload| {
3370 const prev_func = payload.data;
3371 prev_is_inline = prev_func.state == .inline_only;
3372 prev_func.deinit(gpa);
3373 }
3374 decl.clearValues(gpa);
3375 }
33343376
3335 decl.analysis = .complete;3377 decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
3336 decl.generation = mod.generation;3378 decl.val = try decl_tv.val.copy(&decl_arena.allocator);
3379 decl.align_val = try align_val.copy(&decl_arena.allocator);
3380 decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);
3381 decl.has_tv = true;
3382 decl_arena_state.* = decl_arena.state;
3383 decl.value_arena = decl_arena_state;
3384 decl.analysis = .complete;
3385 decl.generation = mod.generation;
3386
3387 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
3388 if (!is_inline and decl_tv.ty.hasCodeGenBits()) {
3389 // We don't fully codegen the decl until later, but we do need to reserve a global
3390 // offset table index for it. This allows us to codegen decls out of dependency order,
3391 // increasing how many computations can be done in parallel.
3392 try mod.comp.bin_file.allocateDeclIndexes(decl);
3393 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
3394 if (type_changed and mod.emit_h != null) {
3395 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
3396 }
3397 } else if (!prev_is_inline and prev_type_has_bits) {
3398 mod.comp.bin_file.freeDecl(decl);
3399 }
3400
3401 if (decl.is_exported) {
3402 const export_src = inst_data.src(); // TODO make this point at `export` token
3403 if (is_inline) {
3404 return mod.fail(&block_scope.base, export_src, "export of inline function", .{});
3405 }
3406 // The scope needs to have the decl in it.
3407 try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl);
3408 }
3409 return type_changed or is_inline != prev_is_inline;
3410 } else {
3411 const is_mutable = zir_tags[zir_block_index] == .block_inline_var;
33373412
3338 // TODO inspect the type and return a proper type_changed result3413 var is_threadlocal = false; // TODO implement threadlocal variables
3339 @breakpoint();3414 var is_extern = false; // TODO implement extern variables
33403415
3341 return true;3416 if (is_mutable and !decl_tv.ty.isValidVarType(is_extern)) {
3417 return mod.fail(
3418 &block_scope.base,
3419 inst_data.src(), // TODO point at the mut token
3420 "variable of type '{}' must be const",
3421 .{decl_tv.ty},
3422 );
3423 }
3424
3425 var type_changed = true;
3426 if (decl.has_tv) {
3427 type_changed = !decl.ty.eql(decl_tv.ty);
3428 decl.clearValues(gpa);
3429 }
3430
3431 const new_variable = try decl_arena.allocator.create(Var);
3432 new_variable.* = .{
3433 .owner_decl = decl,
3434 .init = try decl_tv.val.copy(&decl_arena.allocator),
3435 .is_extern = is_extern,
3436 .is_mutable = is_mutable,
3437 .is_threadlocal = is_threadlocal,
3438 };
3439
3440 decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
3441 decl.val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
3442 decl.align_val = try align_val.copy(&decl_arena.allocator);
3443 decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);
3444 decl.has_tv = true;
3445 decl_arena_state.* = decl_arena.state;
3446 decl.value_arena = decl_arena_state;
3447 decl.analysis = .complete;
3448 decl.generation = mod.generation;
3449
3450 if (decl.is_exported) {
3451 const export_src = inst_data.src(); // TODO point to the export token
3452 // The scope needs to have the decl in it.
3453 try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl);
3454 }
3455 return type_changed;
3456 }
3342}3457}
33433458
3344/// Returns the depender's index of the dependee.3459/// Returns the depender's index of the dependee.
...@@ -4160,6 +4275,7 @@ fn getNextAnonNameIndex(mod: *Module) usize {...@@ -4160,6 +4275,7 @@ fn getNextAnonNameIndex(mod: *Module) usize {
41604275
4161/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces4276/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces
4162/// in scope and check each one for the identifier.4277/// in scope and check each one for the identifier.
4278/// TODO emit a compile error if more than one decl would be matched.
4163pub fn lookupIdentifier(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {4279pub fn lookupIdentifier(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
4164 var namespace = scope.namespace();4280 var namespace = scope.namespace();
4165 while (true) {4281 while (true) {
...@@ -4179,13 +4295,14 @@ pub fn lookupInNamespace(...@@ -4179,13 +4295,14 @@ pub fn lookupInNamespace(
4179 ident_name: []const u8,4295 ident_name: []const u8,
4180 only_pub_usingnamespaces: bool,4296 only_pub_usingnamespaces: bool,
4181) ?*Decl {4297) ?*Decl {
4182 @panic("TODO lookupInNamespace");4298 // TODO the decl doing the looking up needs to create a decl dependency
4299 // TODO implement usingnamespace
4300 if (namespace.decls.get(ident_name)) |decl| {
4301 return decl;
4302 }
4303 return null;
4183 //// TODO handle decl collision with usingnamespace4304 //// TODO handle decl collision with usingnamespace
4184 //// TODO the decl doing the looking up needs to create a decl dependency
4185 //// on each usingnamespace decl here.4305 //// on each usingnamespace decl here.
4186 //if (mod.decl_table.get(name_hash)) |decl| {
4187 // return decl;
4188 //}
4189 //{4306 //{
4190 // var it = namespace.usingnamespace_set.iterator();4307 // var it = namespace.usingnamespace_set.iterator();
4191 // while (it.next()) |entry| {4308 // while (it.next()) |entry| {
...@@ -4198,7 +4315,6 @@ pub fn lookupInNamespace(...@@ -4198,7 +4315,6 @@ pub fn lookupInNamespace(
4198 // }4315 // }
4199 // }4316 // }
4200 //}4317 //}
4201 //return null;
4202}4318}
42034319
4204pub fn makeIntType(arena: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Type {4320pub fn makeIntType(arena: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Type {
...@@ -4659,7 +4775,7 @@ pub fn optimizeMode(mod: Module) std.builtin.Mode {...@@ -4659,7 +4775,7 @@ pub fn optimizeMode(mod: Module) std.builtin.Mode {
46594775
4660fn lockAndClearFileCompileError(mod: *Module, file: *Scope.File) void {4776fn lockAndClearFileCompileError(mod: *Module, file: *Scope.File) void {
4661 switch (file.status) {4777 switch (file.status) {
4662 .success, .retryable_failure => {},4778 .success_zir, .success_air, .retryable_failure => {},
4663 .never_loaded, .parse_failure, .astgen_failure => {4779 .never_loaded, .parse_failure, .astgen_failure => {
4664 const lock = mod.comp.mutex.acquire();4780 const lock = mod.comp.mutex.acquire();
4665 defer lock.release();4781 defer lock.release();
src/Sema.zig+9-2
...@@ -607,7 +607,7 @@ fn resolveInt(...@@ -607,7 +607,7 @@ fn resolveInt(
607 return val.toUnsignedInt();607 return val.toUnsignedInt();
608}608}
609609
610fn resolveInstConst(610pub fn resolveInstConst(
611 sema: *Sema,611 sema: *Sema,
612 block: *Scope.Block,612 block: *Scope.Block,
613 src: LazySrcLoc,613 src: LazySrcLoc,
...@@ -1850,7 +1850,9 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE...@@ -1850,7 +1850,9 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
1850 const src: LazySrcLoc = .{ .node_offset = src_node };1850 const src: LazySrcLoc = .{ .node_offset = src_node };
18511851
1852 const src_loc = src.toSrcLoc(&block.base);1852 const src_loc = src.toSrcLoc(&block.base);
1853 const abs_byte_off = try src_loc.byteOffset();1853 const abs_byte_off = src_loc.byteOffset(sema.gpa) catch |err| {
1854 return sema.mod.fail(&block.base, src, "TODO modify dbg_stmt ZIR instructions to have line/column rather than node indexes. {s}", .{@errorName(err)});
1855 };
1854 _ = try block.addDbgStmt(src, abs_byte_off);1856 _ = try block.addDbgStmt(src, abs_byte_off);
1855}1857}
18561858
...@@ -2738,6 +2740,10 @@ fn funcCommon(...@@ -2738,6 +2740,10 @@ fn funcCommon(
2738 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };2740 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
2739 const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);2741 const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);
27402742
2743 if (body.len == 0) {
2744 return sema.mod.fail(&block.base, src, "TODO: Sema: implement func with body", .{});
2745 }
2746
2741 // Hot path for some common function types.2747 // Hot path for some common function types.
2742 if (zir_param_types.len == 0 and !var_args) {2748 if (zir_param_types.len == 0 and !var_args) {
2743 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {2749 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
...@@ -4098,6 +4104,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -4098,6 +4104,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
4098 return mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });4104 return mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
4099 },4105 },
4100 };4106 };
4107 try mod.semaFile(result.file);
4101 return mod.constType(sema.arena, src, result.file.namespace.ty);4108 return mod.constType(sema.arena, src, result.file.namespace.ty);
4102}4109}
41034110
src/Zir.zig+3-2
...@@ -44,8 +44,8 @@ pub const Header = extern struct {...@@ -44,8 +44,8 @@ pub const Header = extern struct {
44 string_bytes_len: u32,44 string_bytes_len: u32,
45 extra_len: u32,45 extra_len: u32,
4646
47 stat_size: u64,
48 stat_inode: std.fs.File.INode,47 stat_inode: std.fs.File.INode,
48 stat_size: u64,
49 stat_mtime: i128,49 stat_mtime: i128,
50};50};
5151
...@@ -4121,7 +4121,8 @@ const Writer = struct {...@@ -4121,7 +4121,8 @@ const Writer = struct {
4121 .parent_decl_node = self.parent_decl_node,4121 .parent_decl_node = self.parent_decl_node,
4122 .lazy = src,4122 .lazy = src,
4123 };4123 };
4124 const abs_byte_off = try src_loc.byteOffset();4124 // Caller must ensure AST tree is loaded.
4125 const abs_byte_off = src_loc.byteOffset(self.gpa) catch unreachable;
4125 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);4126 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
4126 try stream.print("{s}:{d}:{d}", .{4127 try stream.print("{s}:{d}:{d}", .{
4127 @tagName(src), delta_line.line + 1, delta_line.column + 1,4128 @tagName(src), delta_line.line + 1, delta_line.column + 1,
src/codegen.zig+1-1
...@@ -2313,7 +2313,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2313,7 +2313,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2313 }2313 }
23142314
2315 fn genDbgStmt(self: *Self, inst: *ir.Inst.DbgStmt) !MCValue {2315 fn genDbgStmt(self: *Self, inst: *ir.Inst.DbgStmt) !MCValue {
2316 // TODO when reworking tzir memory layout, rework source locations here as2316 // TODO when reworking AIR memory layout, rework source locations here as
2317 // well to be more efficient, as well as support inlined function calls correctly.2317 // well to be more efficient, as well as support inlined function calls correctly.
2318 // For now we convert LazySrcLoc to absolute byte offset, to match what the2318 // For now we convert LazySrcLoc to absolute byte offset, to match what the
2319 // existing codegen code expects.2319 // existing codegen code expects.