authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-14 11:26:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 19:06:39-07:00
log3114115348e789ae4bab8844c7ebd0067185f1c4
tree3d7fb3bd000ee263054bc4ddc9c98c0359b04a1f
parent9088d40e838b62c8f8ea0e6e68616b72e7704b27

stage2: preliminary reworking for whole-file-AstGen

See #8516. * AstGen is now done on whole files at once rather than per Decl. * Introduce a new wait group for AstGen tasks. `performAllTheWork` waits for all AstGen tasks to be complete before doing Sema, single-threaded. - The C object compilation tasks are moved to be spawned after AstGen, since they only need to complete by the end of the function. With this commit, the codebase compiles, but much more reworking is needed to get things back into a useful state.

6 files changed, 2757 insertions(+), 1946 deletions(-)

BRANCH_TODO+1118
......@@ -4,6 +4,13 @@
44 on each usingnamespace decl
55 * handle usingnamespace cycles
66
7 * have failed_trees and just put the file in there
8 - this way we can emit all the parse errors not just the first one
9 - but maybe we want just the first one?
10
11 * need a var decl zir instruction which includes the name because we need to do the
12 compile error for a local shadowing a decl with Sema looking up the decl name.
13 - this means LocalVal and LocalPtr should use the string table
714
815 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
916 pkg.namespace_hash
......@@ -99,3 +106,1114 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
99106}
100107
101108
109 // Detect which source files changed.
110 for (module.import_table.items()) |entry| {
111 const file = entry.value;
112 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
113 defer f.close();
114
115 // TODO handle error here by populating a retryable compile error
116 const stat = try f.stat();
117 const unchanged_metadata =
118 stat.size == file.stat_size and
119 stat.mtime == file.stat_mtime and
120 stat.inode == file.stat_inode;
121
122 if (unchanged_metadata) {
123 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
124 continue;
125 }
126
127 log.debug("metadata changed: {s}", .{file.sub_file_path});
128 if (file.status == .unloaded_parse_failure) {
129 module.failed_files.swapRemove(file).?.value.destroy(module.gpa);
130 }
131
132 file.unload(module.gpa);
133 // TODO handle error here by populating a retryable compile error
134 try file.finishGettingSource(module.gpa, f, stat);
135
136 module.analyzeFile(file) catch |err| switch (err) {
137 error.OutOfMemory => return error.OutOfMemory,
138 error.AnalysisFail => continue,
139 else => |e| return e,
140 };
141 }
142
143
144
145 const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|
146 pkg.namespace_hash
147 else
148 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
149
150 // We need a Decl to pass to AstGen and collect dependencies. But ultimately we
151 // want to pass them on to the Decl for the struct that represents the file.
152 var tmp_namespace: Scope.Namespace = .{
153 .parent = null,
154 .file_scope = new_file,
155 .parent_name_hash = parent_name_hash,
156 .ty = Type.initTag(.type),
157 };
158
159 const tree = try mod.getAstTree(new_file);
160
161
162 const top_decl = try mod.createNewDecl(
163 &tmp_namespace,
164 resolved_path,
165 0,
166 parent_name_hash,
167 std.zig.hashSrc(tree.source),
168 );
169 defer {
170 mod.decl_table.removeAssertDiscard(parent_name_hash);
171 top_decl.destroy(mod);
172 }
173
174 var gen_scope_arena = std.heap.ArenaAllocator.init(gpa);
175 defer gen_scope_arena.deinit();
176
177 var astgen = try AstGen.init(mod, top_decl, &gen_scope_arena.allocator);
178 defer astgen.deinit();
179
180 var gen_scope: Scope.GenZir = .{
181 .force_comptime = true,
182 .parent = &new_file.base,
183 .astgen = &astgen,
184 };
185 defer gen_scope.instructions.deinit(gpa);
186
187 const container_decl: ast.full.ContainerDecl = .{
188 .layout_token = null,
189 .ast = .{
190 .main_token = undefined,
191 .enum_token = null,
192 .members = tree.rootDecls(),
193 .arg = 0,
194 },
195 };
196
197 const struct_decl_ref = try AstGen.structDeclInner(
198 &gen_scope,
199 &gen_scope.base,
200 0,
201 container_decl,
202 .struct_decl,
203 );
204 _ = try gen_scope.addBreak(.break_inline, 0, struct_decl_ref);
205
206 var code = try gen_scope.finish();
207 defer code.deinit(gpa);
208 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
209 code.dump(gpa, "import", &gen_scope.base, 0) catch {};
210 }
211
212 var sema: Sema = .{
213 .mod = mod,
214 .gpa = gpa,
215 .arena = &gen_scope_arena.allocator,
216 .code = code,
217 .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
218 .owner_decl = top_decl,
219 .namespace = top_decl.namespace,
220 .func = null,
221 .owner_func = null,
222 .param_inst_list = &.{},
223 };
224 var block_scope: Scope.Block = .{
225 .parent = null,
226 .sema = &sema,
227 .src_decl = top_decl,
228 .instructions = .{},
229 .inlining = null,
230 .is_comptime = true,
231 };
232 defer block_scope.instructions.deinit(gpa);
233
234 const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
235 const analyzed_struct_inst = try sema.resolveInst(init_inst_zir_ref);
236 assert(analyzed_struct_inst.ty.zigTypeTag() == .Type);
237 const val = analyzed_struct_inst.value().?;
238 const struct_ty = try val.toType(&gen_scope_arena.allocator);
239 const struct_decl = struct_ty.getOwnerDecl();
240
241 struct_decl.contents_hash = top_decl.contents_hash;
242 new_file.namespace = struct_ty.getNamespace().?;
243 new_file.namespace.parent = null;
244 //new_file.namespace.parent_name_hash = tmp_namespace.parent_name_hash;
245
246 // Transfer the dependencies to `owner_decl`.
247 assert(top_decl.dependants.count() == 0);
248 for (top_decl.dependencies.items()) |entry| {
249 const dep = entry.key;
250 dep.removeDependant(top_decl);
251 if (dep == struct_decl) continue;
252 _ = try mod.declareDeclDependency(struct_decl, dep);
253 }
254
255 return new_file;
256
257
258
259pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
260 const tracy = trace(@src());
261 defer tracy.end();
262
263 if (file.tree_loaded) {
264 return &file.tree;
265 }
266
267 switch (file.status) {
268 .never_loaded, .success, .retryable_failure => {},
269 .parse_failure, .astgen_failure => return error.AnalysisFail,
270 }
271
272 switch (file.status) {
273 .never_loaded, .unloaded_success => {
274 const gpa = mod.gpa;
275
276 try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1);
277
278 const source = try file.getSource(gpa);
279
280 var keep_tree = false;
281 file.tree = try std.zig.parse(gpa, source);
282 defer if (!keep_tree) file.tree.deinit(gpa);
283
284 const tree = &file.tree;
285
286 if (tree.errors.len != 0) {
287 const parse_err = tree.errors[0];
288
289 var msg = std.ArrayList(u8).init(gpa);
290 defer msg.deinit();
291
292 const token_starts = tree.tokens.items(.start);
293
294 try tree.renderError(parse_err, msg.writer());
295 const err_msg = try gpa.create(ErrorMsg);
296 err_msg.* = .{
297 .src_loc = .{
298 .container = .{ .file_scope = file },
299 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
300 },
301 .msg = msg.toOwnedSlice(),
302 };
303
304 mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
305 file.status = .unloaded_parse_failure;
306 return error.AnalysisFail;
307 }
308
309 file.status = .success;
310 file.tree_loaded = true;
311 keep_tree = true;
312
313 return tree;
314 },
315
316 .unloaded_parse_failure => return error.AnalysisFail,
317
318 .success => return &file.tree,
319 }
320}
321
322
323
324pub fn analyzeFile(mod: *Module, file: *Scope.File) !void {
325 // We call `getAstTree` here so that `analyzeFile` has the error set that includes
326 // file system operations, but `analyzeNamespace` does not.
327 const tree = try mod.getAstTree(file.namespace.file_scope);
328 const decls = tree.rootDecls();
329 return mod.analyzeNamespace(file.namespace, decls);
330}
331
332/// Returns `true` if the Decl type changed.
333/// Returns `true` if this is the first time analyzing the Decl.
334/// Returns `false` otherwise.
335fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
336 const tracy = trace(@src());
337 defer tracy.end();
338
339 const tree = try mod.getAstTree(decl.namespace.file_scope);
340 const node_tags = tree.nodes.items(.tag);
341 const node_datas = tree.nodes.items(.data);
342 const decl_node = decl.src_node;
343 switch (node_tags[decl_node]) {
344 .fn_decl => {
345 const fn_proto = node_datas[decl_node].lhs;
346 const body = node_datas[decl_node].rhs;
347 switch (node_tags[fn_proto]) {
348 .fn_proto_simple => {
349 var params: [1]ast.Node.Index = undefined;
350 return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoSimple(&params, fn_proto));
351 },
352 .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoMulti(fn_proto)),
353 .fn_proto_one => {
354 var params: [1]ast.Node.Index = undefined;
355 return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoOne(&params, fn_proto));
356 },
357 .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProto(fn_proto)),
358 else => unreachable,
359 }
360 },
361 .fn_proto_simple => {
362 var params: [1]ast.Node.Index = undefined;
363 return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoSimple(&params, decl_node));
364 },
365 .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoMulti(decl_node)),
366 .fn_proto_one => {
367 var params: [1]ast.Node.Index = undefined;
368 return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoOne(&params, decl_node));
369 },
370 .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProto(decl_node)),
371
372 .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.globalVarDecl(decl_node)),
373 .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.localVarDecl(decl_node)),
374 .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.simpleVarDecl(decl_node)),
375 .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.alignedVarDecl(decl_node)),
376
377 .@"comptime" => {
378 decl.analysis = .in_progress;
379
380 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
381 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
382 defer analysis_arena.deinit();
383
384 var code: Zir = blk: {
385 var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator);
386 defer astgen.deinit();
387
388 var gen_scope: Scope.GenZir = .{
389 .force_comptime = true,
390 .parent = &decl.namespace.base,
391 .astgen = &astgen,
392 };
393 defer gen_scope.instructions.deinit(mod.gpa);
394
395 const block_expr = node_datas[decl_node].lhs;
396 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
397 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
398
399 const code = try gen_scope.finish();
400 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
401 code.dump(mod.gpa, "comptime_block", &gen_scope.base, 0) catch {};
402 }
403 break :blk code;
404 };
405 defer code.deinit(mod.gpa);
406
407 var sema: Sema = .{
408 .mod = mod,
409 .gpa = mod.gpa,
410 .arena = &analysis_arena.allocator,
411 .code = code,
412 .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len),
413 .owner_decl = decl,
414 .namespace = decl.namespace,
415 .func = null,
416 .owner_func = null,
417 .param_inst_list = &.{},
418 };
419 var block_scope: Scope.Block = .{
420 .parent = null,
421 .sema = &sema,
422 .src_decl = decl,
423 .instructions = .{},
424 .inlining = null,
425 .is_comptime = true,
426 };
427 defer block_scope.instructions.deinit(mod.gpa);
428
429 _ = try sema.root(&block_scope);
430
431 decl.analysis = .complete;
432 decl.generation = mod.generation;
433 return true;
434 },
435 .@"usingnamespace" => {
436 decl.analysis = .in_progress;
437
438 const type_expr = node_datas[decl_node].lhs;
439 const is_pub = blk: {
440 const main_tokens = tree.nodes.items(.main_token);
441 const token_tags = tree.tokens.items(.tag);
442 const main_token = main_tokens[decl_node];
443 break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub);
444 };
445
446 // A usingnamespace decl does not store any value so we can
447 // deinit this arena after analysis is done.
448 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
449 defer analysis_arena.deinit();
450
451 var code: Zir = blk: {
452 var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator);
453 defer astgen.deinit();
454
455 var gen_scope: Scope.GenZir = .{
456 .force_comptime = true,
457 .parent = &decl.namespace.base,
458 .astgen = &astgen,
459 };
460 defer gen_scope.instructions.deinit(mod.gpa);
461
462 const ns_type = try AstGen.typeExpr(&gen_scope, &gen_scope.base, type_expr);
463 _ = try gen_scope.addBreak(.break_inline, 0, ns_type);
464
465 const code = try gen_scope.finish();
466 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
467 code.dump(mod.gpa, "usingnamespace_type", &gen_scope.base, 0) catch {};
468 }
469 break :blk code;
470 };
471 defer code.deinit(mod.gpa);
472
473 var sema: Sema = .{
474 .mod = mod,
475 .gpa = mod.gpa,
476 .arena = &analysis_arena.allocator,
477 .code = code,
478 .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len),
479 .owner_decl = decl,
480 .namespace = decl.namespace,
481 .func = null,
482 .owner_func = null,
483 .param_inst_list = &.{},
484 };
485 var block_scope: Scope.Block = .{
486 .parent = null,
487 .sema = &sema,
488 .src_decl = decl,
489 .instructions = .{},
490 .inlining = null,
491 .is_comptime = true,
492 };
493 defer block_scope.instructions.deinit(mod.gpa);
494
495 const ty = try sema.rootAsType(&block_scope);
496 try decl.namespace.usingnamespace_set.put(mod.gpa, ty.getNamespace().?, is_pub);
497
498 decl.analysis = .complete;
499 decl.generation = mod.generation;
500 return true;
501 },
502 else => unreachable,
503 }
504}
505
506fn astgenAndSemaFn(
507 mod: *Module,
508 decl: *Decl,
509 tree: ast.Tree,
510 body_node: ast.Node.Index,
511 fn_proto: ast.full.FnProto,
512) !bool {
513 var fn_type_sema: Sema = .{
514 .mod = mod,
515 .gpa = mod.gpa,
516 .arena = &decl_arena.allocator,
517 .code = fn_type_code,
518 .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len),
519 .owner_decl = decl,
520 .namespace = decl.namespace,
521 .func = null,
522 .owner_func = null,
523 .param_inst_list = &.{},
524 };
525 var block_scope: Scope.Block = .{
526 .parent = null,
527 .sema = &fn_type_sema,
528 .src_decl = decl,
529 .instructions = .{},
530 .inlining = null,
531 .is_comptime = true,
532 };
533 defer block_scope.instructions.deinit(mod.gpa);
534
535 const fn_type = try fn_type_sema.rootAsType(&block_scope);
536 if (body_node == 0) {
537 // Extern function.
538 var type_changed = true;
539 if (decl.typedValueManaged()) |tvm| {
540 type_changed = !tvm.typed_value.ty.eql(fn_type);
541
542 tvm.deinit(mod.gpa);
543 }
544 const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
545
546 decl_arena_state.* = decl_arena.state;
547 decl.typed_value = .{
548 .most_recent = .{
549 .typed_value = .{ .ty = fn_type, .val = fn_val },
550 .arena = decl_arena_state,
551 },
552 };
553 decl.analysis = .complete;
554 decl.generation = mod.generation;
555
556 try mod.comp.bin_file.allocateDeclIndexes(decl);
557 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
558
559 if (type_changed and mod.emit_h != null) {
560 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
561 }
562
563 return type_changed;
564 }
565
566 if (fn_type.fnIsVarArgs()) {
567 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
568 }
569
570 const new_func = try decl_arena.allocator.create(Fn);
571 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
572
573 const fn_zir: Zir = blk: {
574 // We put the ZIR inside the Decl arena.
575 var astgen = try AstGen.init(mod, decl, &decl_arena.allocator);
576 astgen.ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count);
577 defer astgen.deinit();
578
579 var gen_scope: Scope.GenZir = .{
580 .force_comptime = false,
581 .parent = &decl.namespace.base,
582 .astgen = &astgen,
583 };
584 defer gen_scope.instructions.deinit(mod.gpa);
585
586 // Iterate over the parameters. We put the param names as the first N
587 // items inside `extra` so that debug info later can refer to the parameter names
588 // even while the respective source code is unloaded.
589 try astgen.extra.ensureCapacity(mod.gpa, param_count);
590
591 var params_scope = &gen_scope.base;
592 var i: usize = 0;
593 var it = fn_proto.iterate(tree);
594 while (it.next()) |param| : (i += 1) {
595 const name_token = param.name_token.?;
596 const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);
597 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
598 sub_scope.* = .{
599 .parent = params_scope,
600 .gen_zir = &gen_scope,
601 .name = param_name,
602 // Implicit const list first, then implicit arg list.
603 .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
604 .src = decl.tokSrcLoc(name_token),
605 };
606 params_scope = &sub_scope.base;
607
608 // Additionally put the param name into `string_bytes` and reference it with
609 // `extra` so that we have access to the data in codegen, for debug info.
610 const str_index = @intCast(u32, astgen.string_bytes.items.len);
611 astgen.extra.appendAssumeCapacity(str_index);
612 const used_bytes = astgen.string_bytes.items.len;
613 try astgen.string_bytes.ensureCapacity(mod.gpa, used_bytes + param_name.len + 1);
614 astgen.string_bytes.appendSliceAssumeCapacity(param_name);
615 astgen.string_bytes.appendAssumeCapacity(0);
616 }
617
618 _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node);
619
620 if (gen_scope.instructions.items.len == 0 or
621 !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
622 .isNoReturn())
623 {
624 // astgen uses result location semantics to coerce return operands.
625 // Since we are adding the return instruction here, we must handle the coercion.
626 // We do this by using the `ret_coerce` instruction.
627 _ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
628 }
629
630 const code = try gen_scope.finish();
631 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
632 code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {};
633 }
634
635 break :blk code;
636 };
637
638 const is_inline = fn_type.fnCallingConvention() == .Inline;
639 const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
640
641 new_func.* = .{
642 .state = anal_state,
643 .zir = fn_zir,
644 .body = undefined,
645 .owner_decl = decl,
646 };
647 fn_payload.* = .{
648 .base = .{ .tag = .function },
649 .data = new_func,
650 };
651
652 var prev_type_has_bits = false;
653 var prev_is_inline = false;
654 var type_changed = true;
655
656 if (decl.typedValueManaged()) |tvm| {
657 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
658 type_changed = !tvm.typed_value.ty.eql(fn_type);
659 if (tvm.typed_value.val.castTag(.function)) |payload| {
660 const prev_func = payload.data;
661 prev_is_inline = prev_func.state == .inline_only;
662 prev_func.deinit(mod.gpa);
663 }
664
665 tvm.deinit(mod.gpa);
666 }
667
668 decl_arena_state.* = decl_arena.state;
669 decl.typed_value = .{
670 .most_recent = .{
671 .typed_value = .{
672 .ty = fn_type,
673 .val = Value.initPayload(&fn_payload.base),
674 },
675 .arena = decl_arena_state,
676 },
677 };
678 decl.analysis = .complete;
679 decl.generation = mod.generation;
680
681 if (!is_inline and fn_type.hasCodeGenBits()) {
682 // We don't fully codegen the decl until later, but we do need to reserve a global
683 // offset table index for it. This allows us to codegen decls out of dependency order,
684 // increasing how many computations can be done in parallel.
685 try mod.comp.bin_file.allocateDeclIndexes(decl);
686 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
687 if (type_changed and mod.emit_h != null) {
688 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
689 }
690 } else if (!prev_is_inline and prev_type_has_bits) {
691 mod.comp.bin_file.freeDecl(decl);
692 }
693
694 if (fn_proto.extern_export_token) |maybe_export_token| {
695 if (token_tags[maybe_export_token] == .keyword_export) {
696 if (is_inline) {
697 return mod.failTok(
698 &block_scope.base,
699 maybe_export_token,
700 "export of inline function",
701 .{},
702 );
703 }
704 const export_src = decl.tokSrcLoc(maybe_export_token);
705 const name = tree.tokenSlice(fn_proto.name_token.?); // TODO identifierTokenString
706 // The scope needs to have the decl in it.
707 try mod.analyzeExport(&block_scope.base, export_src, name, decl);
708 }
709 }
710 return type_changed or is_inline != prev_is_inline;
711}
712
713fn astgenAndSemaVarDecl(
714 mod: *Module,
715 decl: *Decl,
716 tree: ast.Tree,
717 var_decl: ast.full.VarDecl,
718) !bool {
719 const tracy = trace(@src());
720 defer tracy.end();
721
722 decl.analysis = .in_progress;
723 decl.is_pub = var_decl.visib_token != null;
724
725 const token_tags = tree.tokens.items(.tag);
726
727 // We need the memory for the Type to go into the arena for the Decl
728 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
729 errdefer decl_arena.deinit();
730 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
731
732 // Used for simple error reporting.
733 var decl_scope: Scope.DeclRef = .{ .decl = decl };
734
735 const is_extern = blk: {
736 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
737 break :blk token_tags[maybe_extern_token] == .keyword_extern;
738 };
739
740 if (var_decl.lib_name) |lib_name| {
741 assert(is_extern);
742 return mod.failTok(&decl_scope.base, lib_name, "TODO implement function library name", .{});
743 }
744 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
745 const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: {
746 if (!is_mutable) {
747 return mod.failTok(&decl_scope.base, some, "threadlocal variable cannot be constant", .{});
748 }
749 break :blk true;
750 } else false;
751 assert(var_decl.comptime_token == null);
752 if (var_decl.ast.align_node != 0) {
753 return mod.failNode(
754 &decl_scope.base,
755 var_decl.ast.align_node,
756 "TODO implement function align expression",
757 .{},
758 );
759 }
760 if (var_decl.ast.section_node != 0) {
761 return mod.failNode(
762 &decl_scope.base,
763 var_decl.ast.section_node,
764 "TODO implement function section expression",
765 .{},
766 );
767 }
768
769 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
770 if (is_extern) {
771 return mod.failNode(
772 &decl_scope.base,
773 var_decl.ast.init_node,
774 "extern variables have no initializers",
775 .{},
776 );
777 }
778
779 var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
780 defer gen_scope_arena.deinit();
781
782 var astgen = try AstGen.init(mod, decl, &gen_scope_arena.allocator);
783 defer astgen.deinit();
784
785 var gen_scope: Scope.GenZir = .{
786 .force_comptime = true,
787 .parent = &decl.namespace.base,
788 .astgen = &astgen,
789 };
790 defer gen_scope.instructions.deinit(mod.gpa);
791
792 const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
793 .ty = try AstGen.expr(&gen_scope, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node),
794 } else .none;
795
796 const init_inst = try AstGen.comptimeExpr(
797 &gen_scope,
798 &gen_scope.base,
799 init_result_loc,
800 var_decl.ast.init_node,
801 );
802 _ = try gen_scope.addBreak(.break_inline, 0, init_inst);
803 var code = try gen_scope.finish();
804 defer code.deinit(mod.gpa);
805 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
806 code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
807 }
808
809 var sema: Sema = .{
810 .mod = mod,
811 .gpa = mod.gpa,
812 .arena = &gen_scope_arena.allocator,
813 .code = code,
814 .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
815 .owner_decl = decl,
816 .namespace = decl.namespace,
817 .func = null,
818 .owner_func = null,
819 .param_inst_list = &.{},
820 };
821 var block_scope: Scope.Block = .{
822 .parent = null,
823 .sema = &sema,
824 .src_decl = decl,
825 .instructions = .{},
826 .inlining = null,
827 .is_comptime = true,
828 };
829 defer block_scope.instructions.deinit(mod.gpa);
830
831 const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
832 // The result location guarantees the type coercion.
833 const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref);
834 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
835 const val = analyzed_init_inst.value().?;
836
837 break :vi .{
838 .ty = try analyzed_init_inst.ty.copy(&decl_arena.allocator),
839 .val = try val.copy(&decl_arena.allocator),
840 };
841 } else if (!is_extern) {
842 return mod.failTok(
843 &decl_scope.base,
844 var_decl.ast.mut_token,
845 "variables must be initialized",
846 .{},
847 );
848 } else if (var_decl.ast.type_node != 0) vi: {
849 var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
850 defer type_scope_arena.deinit();
851
852 var astgen = try AstGen.init(mod, decl, &type_scope_arena.allocator);
853 defer astgen.deinit();
854
855 var type_scope: Scope.GenZir = .{
856 .force_comptime = true,
857 .parent = &decl.namespace.base,
858 .astgen = &astgen,
859 };
860 defer type_scope.instructions.deinit(mod.gpa);
861
862 const var_type = try AstGen.typeExpr(&type_scope, &type_scope.base, var_decl.ast.type_node);
863 _ = try type_scope.addBreak(.break_inline, 0, var_type);
864
865 var code = try type_scope.finish();
866 defer code.deinit(mod.gpa);
867 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
868 code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
869 }
870
871 var sema: Sema = .{
872 .mod = mod,
873 .gpa = mod.gpa,
874 .arena = &type_scope_arena.allocator,
875 .code = code,
876 .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
877 .owner_decl = decl,
878 .namespace = decl.namespace,
879 .func = null,
880 .owner_func = null,
881 .param_inst_list = &.{},
882 };
883 var block_scope: Scope.Block = .{
884 .parent = null,
885 .sema = &sema,
886 .src_decl = decl,
887 .instructions = .{},
888 .inlining = null,
889 .is_comptime = true,
890 };
891 defer block_scope.instructions.deinit(mod.gpa);
892
893 const ty = try sema.rootAsType(&block_scope);
894
895 break :vi .{
896 .ty = try ty.copy(&decl_arena.allocator),
897 .val = null,
898 };
899 } else {
900 return mod.failTok(
901 &decl_scope.base,
902 var_decl.ast.mut_token,
903 "unable to infer variable type",
904 .{},
905 );
906 };
907
908 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
909 return mod.failTok(
910 &decl_scope.base,
911 var_decl.ast.mut_token,
912 "variable of type '{}' must be const",
913 .{var_info.ty},
914 );
915 }
916
917 var type_changed = true;
918 if (decl.typedValueManaged()) |tvm| {
919 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
920
921 tvm.deinit(mod.gpa);
922 }
923
924 const new_variable = try decl_arena.allocator.create(Var);
925 new_variable.* = .{
926 .owner_decl = decl,
927 .init = var_info.val orelse undefined,
928 .is_extern = is_extern,
929 .is_mutable = is_mutable,
930 .is_threadlocal = is_threadlocal,
931 };
932 const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
933
934 decl_arena_state.* = decl_arena.state;
935 decl.typed_value = .{
936 .most_recent = .{
937 .typed_value = .{
938 .ty = var_info.ty,
939 .val = var_val,
940 },
941 .arena = decl_arena_state,
942 },
943 };
944 decl.analysis = .complete;
945 decl.generation = mod.generation;
946
947 if (var_decl.extern_export_token) |maybe_export_token| {
948 if (token_tags[maybe_export_token] == .keyword_export) {
949 const export_src = decl.tokSrcLoc(maybe_export_token);
950 const name_token = var_decl.ast.mut_token + 1;
951 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
952 // The scope needs to have the decl in it.
953 try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
954 }
955 }
956 return type_changed;
957}
958
959
960/// Call `deinit` on the result.
961pub fn init(mod: *Module, decl: *Decl, arena: *Allocator) !AstGen {
962 var astgen: AstGen = .{
963 .mod = mod,
964 .decl = decl,
965 .arena = arena,
966 };
967 // Must be a block instruction at index 0 with the root body.
968 try astgen.instructions.append(mod.gpa, .{
969 .tag = .block,
970 .data = .{ .pl_node = .{
971 .src_node = 0,
972 .payload_index = undefined,
973 } },
974 });
975 return astgen;
976}
977 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
978 pub fn tree(scope: *Scope) *const ast.Tree {
979 switch (scope.tag) {
980 .file => return &scope.cast(File).?.tree,
981 .block => return &scope.cast(Block).?.src_decl.namespace.file_scope.tree,
982 .gen_zir => return scope.cast(GenZir).?.tree(),
983 .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace.file_scope.tree,
984 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace.file_scope.tree,
985 .namespace => return &scope.cast(Namespace).?.file_scope.tree,
986 .decl_ref => return &scope.cast(DeclRef).?.decl.namespace.file_scope.tree,
987 }
988 }
989
990
991 error.FileNotFound => {
992 return mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
993 },
994
995
996
997 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
998 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
999 return mod.failTok(
1000 &fn_type_scope.base,
1001 lib_name_token,
1002 "unable to add link lib '{s}': {s}",
1003 .{ lib_name_str, @errorName(err) },
1004 );
1005 };
1006 const target = mod.comp.getTarget();
1007 if (target_util.is_libc_lib_name(target, lib_name_str)) {
1008 if (!mod.comp.bin_file.options.link_libc) {
1009 return mod.failTok(
1010 &fn_type_scope.base,
1011 lib_name_token,
1012 "dependency on libc must be explicitly specified in the build command",
1013 .{},
1014 );
1015 }
1016 break :blk;
1017 }
1018 if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
1019 if (!mod.comp.bin_file.options.link_libcpp) {
1020 return mod.failTok(
1021 &fn_type_scope.base,
1022 lib_name_token,
1023 "dependency on libc++ must be explicitly specified in the build command",
1024 .{},
1025 );
1026 }
1027 break :blk;
1028 }
1029 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
1030 return mod.failTok(
1031 &fn_type_scope.base,
1032 lib_name_token,
1033 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
1034 .{ lib_name_str, lib_name_str },
1035 );
1036 }
1037
1038 if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
1039 // No explicitly provided tag values and no top level declarations! In this case,
1040 // we can construct the enum type in AstGen and it will be correctly shared by all
1041 // generic function instantiations and comptime function calls.
1042 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
1043 errdefer new_decl_arena.deinit();
1044 const arena = &new_decl_arena.allocator;
1045
1046 var fields_map: std.StringArrayHashMapUnmanaged(void) = .{};
1047 try fields_map.ensureCapacity(arena, counts.total_fields);
1048 for (container_decl.ast.members) |member_node| {
1049 if (member_node == counts.nonexhaustive_node)
1050 continue;
1051 const member = switch (node_tags[member_node]) {
1052 .container_field_init => tree.containerFieldInit(member_node),
1053 .container_field_align => tree.containerFieldAlign(member_node),
1054 .container_field => tree.containerField(member_node),
1055 else => unreachable, // We checked earlier.
1056 };
1057 const name_token = member.ast.name_token;
1058 const tag_name = try mod.identifierTokenStringTreeArena(
1059 scope,
1060 name_token,
1061 tree,
1062 arena,
1063 );
1064 const gop = fields_map.getOrPutAssumeCapacity(tag_name);
1065 if (gop.found_existing) {
1066 const msg = msg: {
1067 const msg = try mod.errMsg(
1068 scope,
1069 gz.tokSrcLoc(name_token),
1070 "duplicate enum tag",
1071 .{},
1072 );
1073 errdefer msg.destroy(gpa);
1074 // Iterate to find the other tag. We don't eagerly store it in a hash
1075 // map because in the hot path there will be no compile error and we
1076 // don't need to waste time with a hash map.
1077 const bad_node = for (container_decl.ast.members) |other_member_node| {
1078 const other_member = switch (node_tags[other_member_node]) {
1079 .container_field_init => tree.containerFieldInit(other_member_node),
1080 .container_field_align => tree.containerFieldAlign(other_member_node),
1081 .container_field => tree.containerField(other_member_node),
1082 else => unreachable, // We checked earlier.
1083 };
1084 const other_tag_name = try mod.identifierTokenStringTreeArena(
1085 scope,
1086 other_member.ast.name_token,
1087 tree,
1088 arena,
1089 );
1090 if (mem.eql(u8, tag_name, other_tag_name))
1091 break other_member_node;
1092 } else unreachable;
1093 const other_src = gz.nodeSrcLoc(bad_node);
1094 try mod.errNote(scope, other_src, msg, "other tag here", .{});
1095 break :msg msg;
1096 };
1097 return mod.failWithOwnedErrorMsg(scope, msg);
1098 }
1099 }
1100 const enum_simple = try arena.create(Module.EnumSimple);
1101 enum_simple.* = .{
1102 .owner_decl = astgen.decl,
1103 .node_offset = astgen.decl.nodeIndexToRelative(node),
1104 .fields = fields_map,
1105 };
1106 const enum_ty = try Type.Tag.enum_simple.create(arena, enum_simple);
1107 const enum_val = try Value.Tag.ty.create(arena, enum_ty);
1108 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1109 .ty = Type.initTag(.type),
1110 .val = enum_val,
1111 });
1112 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
1113 const result = try gz.addDecl(.decl_val, decl_index, node);
1114 return rvalue(gz, scope, rl, result, node);
1115 }
1116
1117
1118fn errorSetDecl(
1119 gz: *GenZir,
1120 scope: *Scope,
1121 rl: ResultLoc,
1122 node: ast.Node.Index,
1123) InnerError!Zir.Inst.Ref {
1124 const astgen = gz.astgen;
1125 const tree = &astgen.file.tree;
1126 const main_tokens = tree.nodes.items(.main_token);
1127 const token_tags = tree.tokens.items(.tag);
1128
1129 // Count how many fields there are.
1130 const error_token = main_tokens[node];
1131 const count: usize = count: {
1132 var tok_i = error_token + 2;
1133 var count: usize = 0;
1134 while (true) : (tok_i += 1) {
1135 switch (token_tags[tok_i]) {
1136 .doc_comment, .comma => {},
1137 .identifier => count += 1,
1138 .r_brace => break :count count,
1139 else => unreachable,
1140 }
1141 } else unreachable; // TODO should not need else unreachable here
1142 };
1143
1144 const gpa = astgen.gpa;
1145 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
1146 errdefer new_decl_arena.deinit();
1147 const arena = &new_decl_arena.allocator;
1148
1149 const fields = try arena.alloc([]const u8, count);
1150 {
1151 var tok_i = error_token + 2;
1152 var field_i: usize = 0;
1153 while (true) : (tok_i += 1) {
1154 switch (token_tags[tok_i]) {
1155 .doc_comment, .comma => {},
1156 .identifier => {
1157 fields[field_i] = try astgen.identifierTokenStringTreeArena(tok_i, tree, arena);
1158 field_i += 1;
1159 },
1160 .r_brace => break,
1161 else => unreachable,
1162 }
1163 }
1164 }
1165 const error_set = try arena.create(Module.ErrorSet);
1166 error_set.* = .{
1167 .owner_decl = astgen.decl,
1168 .node_offset = astgen.decl.nodeIndexToRelative(node),
1169 .names_ptr = fields.ptr,
1170 .names_len = @intCast(u32, fields.len),
1171 };
1172 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
1173 const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
1174 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1175 .ty = Type.initTag(.type),
1176 .val = error_set_val,
1177 });
1178 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
1179 const result = try gz.addDecl(.decl_val, decl_index, node);
1180 return rvalue(gz, scope, rl, result, node);
1181}
1182
1183
1184/// The string is stored in `arena` regardless of whether it uses @"" syntax.
1185pub fn identifierTokenStringTreeArena(
1186 astgen: *AstGen,
1187 token: ast.TokenIndex,
1188 tree: *const ast.Tree,
1189 arena: *Allocator,
1190) InnerError![]u8 {
1191 const token_tags = tree.tokens.items(.tag);
1192 assert(token_tags[token] == .identifier);
1193 const ident_name = tree.tokenSlice(token);
1194 if (!mem.startsWith(u8, ident_name, "@")) {
1195 return arena.dupe(u8, ident_name);
1196 }
1197 var buf: ArrayListUnmanaged(u8) = .{};
1198 defer buf.deinit(astgen.gpa);
1199 try astgen.parseStrLit(token, &buf, ident_name, 1);
1200 return arena.dupe(u8, buf.items);
1201}
1202
1203
1204
1205 if (mod.lookupIdentifier(scope, ident_name)) |decl| {
1206 const msg = msg: {
1207 const msg = try mod.errMsg(
1208 scope,
1209 name_src,
1210 "redeclaration of '{s}'",
1211 .{ident_name},
1212 );
1213 errdefer msg.destroy(gpa);
1214 try mod.errNoteNonLazy(decl.srcLoc(), msg, "previously declared here", .{});
1215 break :msg msg;
1216 };
1217 return mod.failWithOwnedErrorMsg(scope, msg);
1218 }
1219
src/AstGen.zig+1097-568
......@@ -25,37 +25,20 @@ const Decl = Module.Decl;
2525const LazySrcLoc = Module.LazySrcLoc;
2626const BuiltinFn = @import("BuiltinFn.zig");
2727
28gpa: *Allocator,
29file: *Scope.File,
2830instructions: std.MultiArrayList(Zir.Inst) = .{},
29string_bytes: ArrayListUnmanaged(u8) = .{},
3031extra: ArrayListUnmanaged(u32) = .{},
31/// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert
32/// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters.
33ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len,
34mod: *Module,
35decl: *Decl,
32string_bytes: ArrayListUnmanaged(u8) = .{},
33/// Used for temporary allocations; freed after AstGen is complete.
34/// The resulting ZIR code has no references to anything in this arena.
3635arena: *Allocator,
37
38/// Call `deinit` on the result.
39pub fn init(mod: *Module, decl: *Decl, arena: *Allocator) !AstGen {
40 var astgen: AstGen = .{
41 .mod = mod,
42 .decl = decl,
43 .arena = arena,
44 };
45 // Must be a block instruction at index 0 with the root body.
46 try astgen.instructions.append(mod.gpa, .{
47 .tag = .block,
48 .data = .{ .pl_node = .{
49 .src_node = 0,
50 .payload_index = undefined,
51 } },
52 });
53 return astgen;
54}
36string_table: std.StringHashMapUnmanaged(u32) = .{},
37compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
5538
5639pub fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {
5740 const fields = std.meta.fields(@TypeOf(extra));
58 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len + fields.len);
41 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + fields.len);
5942 return addExtraAssumeCapacity(astgen, extra);
6043}
6144
......@@ -74,7 +57,7 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
7457
7558pub fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void {
7659 const coerced = @bitCast([]const u32, refs);
77 return astgen.extra.appendSlice(astgen.mod.gpa, coerced);
60 return astgen.extra.appendSlice(astgen.gpa, coerced);
7861}
7962
8063pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void {
......@@ -82,32 +65,75 @@ pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) voi
8265 astgen.extra.appendSliceAssumeCapacity(coerced);
8366}
8467
85pub fn refIsNoReturn(astgen: AstGen, inst_ref: Zir.Inst.Ref) bool {
86 if (inst_ref == .unreachable_value) return true;
87 if (astgen.refToIndex(inst_ref)) |inst_index| {
88 return astgen.instructions.items(.tag)[inst_index].isNoReturn();
89 }
90 return false;
91}
68pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir {
69 var arena = std.heap.ArenaAllocator.init(gpa);
70 defer arena.deinit();
9271
93pub fn indexToRef(astgen: AstGen, inst: Zir.Inst.Index) Zir.Inst.Ref {
94 return @intToEnum(Zir.Inst.Ref, astgen.ref_start_index + inst);
95}
72 var astgen: AstGen = .{
73 .gpa = gpa,
74 .arena = &arena.allocator,
75 .file = file,
76 };
77 defer astgen.deinit(gpa);
78
79 // Indexes 0,1 of extra are reserved and set at the end.
80 try astgen.extra.resize(gpa, 2);
81
82 var gen_scope: Scope.GenZir = .{
83 .force_comptime = true,
84 .parent = &file.base,
85 .decl_node_index = 0,
86 .astgen = &astgen,
87 };
88 defer gen_scope.instructions.deinit(gpa);
89
90 const container_decl: ast.full.ContainerDecl = .{
91 .layout_token = null,
92 .ast = .{
93 .main_token = undefined,
94 .enum_token = null,
95 .members = file.tree.rootDecls(),
96 .arg = 0,
97 },
98 };
99 const struct_decl_ref = try AstGen.structDeclInner(
100 &gen_scope,
101 &gen_scope.base,
102 0,
103 container_decl,
104 .struct_decl,
105 );
106 astgen.extra.items[0] = @enumToInt(struct_decl_ref);
96107
97pub fn refToIndex(astgen: AstGen, inst: Zir.Inst.Ref) ?Zir.Inst.Index {
98 const ref_int = @enumToInt(inst);
99 if (ref_int >= astgen.ref_start_index) {
100 return ref_int - astgen.ref_start_index;
108 if (astgen.compile_errors.items.len == 0) {
109 astgen.extra.items[1] = 0;
101110 } else {
102 return null;
111 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
112 1 + astgen.compile_errors.items.len *
113 @typeInfo(Zir.Inst.CompileErrors.Item).Struct.fields.len);
114
115 astgen.extra.items[1] = astgen.addExtraAssumeCapacity(Zir.Inst.CompileErrors{
116 .items_len = @intCast(u32, astgen.compile_errors.items.len),
117 });
118
119 for (astgen.compile_errors.items) |item| {
120 _ = astgen.addExtraAssumeCapacity(item);
121 }
103122 }
123
124 return Zir{
125 .instructions = astgen.instructions.toOwnedSlice(),
126 .string_bytes = astgen.string_bytes.toOwnedSlice(gpa),
127 .extra = astgen.extra.toOwnedSlice(gpa),
128 };
104129}
105130
106pub fn deinit(astgen: *AstGen) void {
107 const gpa = astgen.mod.gpa;
131pub fn deinit(astgen: *AstGen, gpa: *Allocator) void {
108132 astgen.instructions.deinit(gpa);
109133 astgen.extra.deinit(gpa);
134 astgen.string_table.deinit(gpa);
110135 astgen.string_bytes.deinit(gpa);
136 astgen.compile_errors.deinit(gpa);
111137}
112138
113139pub const ResultLoc = union(enum) {
......@@ -193,7 +219,8 @@ pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerErro
193219}
194220
195221fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
196 const tree = gz.tree();
222 const astgen = gz.astgen;
223 const tree = &astgen.file.tree;
197224 const node_tags = tree.nodes.items(.tag);
198225 const main_tokens = tree.nodes.items(.main_token);
199226 switch (node_tags[node]) {
......@@ -351,7 +378,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins
351378 .@"comptime",
352379 .@"nosuspend",
353380 .error_value,
354 => return gz.astgen.mod.failNode(scope, node, "invalid left-hand side to assignment", .{}),
381 => return astgen.failNode(node, "invalid left-hand side to assignment", .{}),
355382
356383 .builtin_call,
357384 .builtin_call_comma,
......@@ -364,7 +391,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins
364391 // let it pass, and the error will be "invalid builtin function" later.
365392 if (BuiltinFn.list.get(builtin_name)) |info| {
366393 if (!info.allows_lvalue) {
367 return gz.astgen.mod.failNode(scope, node, "invalid left-hand side to assignment", .{});
394 return astgen.failNode(node, "invalid left-hand side to assignment", .{});
368395 }
369396 }
370397 },
......@@ -387,8 +414,8 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins
387414/// result instruction can be used to inspect whether it is isNoReturn() but that is it,
388415/// it must otherwise not be used.
389416pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
390 const mod = gz.astgen.mod;
391 const tree = gz.tree();
417 const astgen = gz.astgen;
418 const tree = &astgen.file.tree;
392419 const main_tokens = tree.nodes.items(.main_token);
393420 const token_tags = tree.tokens.items(.tag);
394421 const node_datas = tree.nodes.items(.data);
......@@ -548,7 +575,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
548575 .tag = .@"unreachable",
549576 .data = .{ .@"unreachable" = .{
550577 .safety = true,
551 .src_node = gz.astgen.decl.nodeIndexToRelative(node),
578 .src_node = gz.nodeIndexToRelative(node),
552579 } },
553580 });
554581 return Zir.Inst.Ref.unreachable_value;
......@@ -654,8 +681,8 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
654681 },
655682 .enum_literal => return simpleStrTok(gz, scope, rl, main_tokens[node], node, .enum_literal),
656683 .error_value => return simpleStrTok(gz, scope, rl, node_datas[node].rhs, node, .error_value),
657 .anyframe_literal => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
658 .anyframe_type => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
684 .anyframe_literal => return astgen.failNode(node, "async and related features are not yet supported", .{}),
685 .anyframe_type => return astgen.failNode(node, "async and related features are not yet supported", .{}),
659686 .@"catch" => {
660687 const catch_token = main_tokens[node];
661688 const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
......@@ -754,14 +781,14 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
754781 .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),
755782 .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),
756783
757 .@"nosuspend" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
758 .@"suspend" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
759 .@"await" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
760 .@"resume" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
784 .@"nosuspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
785 .@"suspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
786 .@"await" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
787 .@"resume" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
761788
762 .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
763 .@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}),
764 .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
789 .@"defer" => return astgen.failNode(node, "TODO implement astgen.expr for .defer", .{}),
790 .@"errdefer" => return astgen.failNode(node, "TODO implement astgen.expr for .errdefer", .{}),
791 .@"try" => return astgen.failNode(node, "TODO implement astgen.expr for .Try", .{}),
765792
766793 .array_init_one,
767794 .array_init_one_comma,
......@@ -771,7 +798,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
771798 .array_init_dot_comma,
772799 .array_init,
773800 .array_init_comma,
774 => return mod.failNode(scope, node, "TODO implement astgen.expr for array literals", .{}),
801 => return astgen.failNode(node, "TODO implement astgen.expr for array literals", .{}),
775802
776803 .struct_init_one, .struct_init_one_comma => {
777804 var fields: [1]ast.Node.Index = undefined;
......@@ -788,12 +815,12 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
788815 .struct_init_comma,
789816 => return structInitExpr(gz, scope, rl, node, tree.structInit(node)),
790817
791 .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
818 .@"anytype" => return astgen.failNode(node, "TODO implement astgen.expr for .anytype", .{}),
792819 .fn_proto_simple,
793820 .fn_proto_multi,
794821 .fn_proto_one,
795822 .fn_proto,
796 => return mod.failNode(scope, node, "TODO implement astgen.expr for function prototypes", .{}),
823 => return astgen.failNode(node, "TODO implement astgen.expr for function prototypes", .{}),
797824 }
798825}
799826
......@@ -804,10 +831,9 @@ pub fn structInitExpr(
804831 node: ast.Node.Index,
805832 struct_init: ast.full.StructInit,
806833) InnerError!Zir.Inst.Ref {
807 const tree = gz.tree();
808834 const astgen = gz.astgen;
809 const mod = astgen.mod;
810 const gpa = mod.gpa;
835 const tree = &astgen.file.tree;
836 const gpa = astgen.gpa;
811837
812838 if (struct_init.ast.fields.len == 0) {
813839 if (struct_init.ast.type_expr == 0) {
......@@ -819,8 +845,8 @@ pub fn structInitExpr(
819845 }
820846 }
821847 switch (rl) {
822 .discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),
823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
848 .discard => return astgen.failNode(node, "TODO implement structInitExpr discard", .{}),
849 .none, .none_or_ref => return astgen.failNode(node, "TODO implement structInitExpr none", .{}),
824850 .ref => unreachable, // struct literal not valid as l-value
825851 .ty => |ty_inst| {
826852 const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len);
......@@ -835,7 +861,7 @@ pub fn structInitExpr(
835861 .name_start = str_index,
836862 });
837863 fields_list[i] = .{
838 .field_type = astgen.refToIndex(field_ty_inst).?,
864 .field_type = gz.refToIndex(field_ty_inst).?,
839865 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
840866 };
841867 }
......@@ -860,7 +886,7 @@ pub fn structInitExpr(
860886 .lhs = ptr_inst,
861887 .field_name_start = str_index,
862888 });
863 field_ptr_list[i] = astgen.refToIndex(field_ptr).?;
889 field_ptr_list[i] = gz.refToIndex(field_ptr).?;
864890 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
865891 }
866892 const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
......@@ -870,10 +896,10 @@ pub fn structInitExpr(
870896 return validate_inst;
871897 },
872898 .inferred_ptr => |ptr_inst| {
873 return mod.failNode(scope, node, "TODO implement structInitExpr inferred_ptr", .{});
899 return astgen.failNode(node, "TODO implement structInitExpr inferred_ptr", .{});
874900 },
875901 .block_ptr => |block_gz| {
876 return mod.failNode(scope, node, "TODO implement structInitExpr block", .{});
902 return astgen.failNode(node, "TODO implement structInitExpr block", .{});
877903 },
878904 }
879905}
......@@ -892,8 +918,8 @@ pub fn comptimeExpr(
892918}
893919
894920fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
895 const mod = parent_gz.astgen.mod;
896 const tree = parent_gz.tree();
921 const astgen = parent_gz.astgen;
922 const tree = &astgen.file.tree;
897923 const node_datas = tree.nodes.items(.data);
898924 const break_label = node_datas[node].lhs;
899925 const rhs = node_datas[node].rhs;
......@@ -908,7 +934,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
908934 const block_inst = blk: {
909935 if (break_label != 0) {
910936 if (block_gz.label) |*label| {
911 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
937 if (try astgen.tokenIdentEql(label.token, break_label)) {
912938 label.used = true;
913939 break :blk label.block_inst;
914940 }
......@@ -932,7 +958,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
932958 const br = try parent_gz.addBreak(.@"break", block_inst, operand);
933959
934960 if (block_gz.break_result_loc == .block_ptr) {
935 try block_gz.labeled_breaks.append(mod.gpa, br);
961 try block_gz.labeled_breaks.append(astgen.gpa, br);
936962
937963 if (have_store_to_block) {
938964 const zir_tags = parent_gz.astgen.instructions.items(.tag);
......@@ -940,7 +966,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
940966 const store_inst = @intCast(u32, zir_tags.len - 2);
941967 assert(zir_tags[store_inst] == .store_to_block_ptr);
942968 assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr);
943 try block_gz.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
969 try block_gz.labeled_store_to_block_ptr_list.append(astgen.gpa, store_inst);
944970 }
945971 }
946972 return Zir.Inst.Ref.unreachable_value;
......@@ -948,18 +974,18 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
948974 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
949975 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
950976 else => if (break_label != 0) {
951 const label_name = try mod.identifierTokenString(parent_scope, break_label);
952 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
977 const label_name = try astgen.identifierTokenString(break_label);
978 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
953979 } else {
954 return mod.failNode(parent_scope, node, "break expression outside loop", .{});
980 return astgen.failNode(node, "break expression outside loop", .{});
955981 },
956982 }
957983 }
958984}
959985
960986fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
961 const mod = parent_gz.astgen.mod;
962 const tree = parent_gz.tree();
987 const astgen = parent_gz.astgen;
988 const tree = &astgen.file.tree;
963989 const node_datas = tree.nodes.items(.data);
964990 const break_label = node_datas[node].lhs;
965991
......@@ -976,7 +1002,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
9761002 }
9771003 if (break_label != 0) blk: {
9781004 if (gen_zir.label) |*label| {
979 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
1005 if (try astgen.tokenIdentEql(label.token, break_label)) {
9801006 label.used = true;
9811007 break :blk;
9821008 }
......@@ -993,10 +1019,10 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
9931019 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
9941020 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
9951021 else => if (break_label != 0) {
996 const label_name = try mod.identifierTokenString(parent_scope, break_label);
997 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
1022 const label_name = try astgen.identifierTokenString(break_label);
1023 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
9981024 } else {
999 return mod.failNode(parent_scope, node, "continue expression outside loop", .{});
1025 return astgen.failNode(node, "continue expression outside loop", .{});
10001026 },
10011027 }
10021028 }
......@@ -1012,7 +1038,8 @@ pub fn blockExpr(
10121038 const tracy = trace(@src());
10131039 defer tracy.end();
10141040
1015 const tree = gz.tree();
1041 const astgen = gz.astgen;
1042 const tree = &astgen.file.tree;
10161043 const main_tokens = tree.nodes.items(.main_token);
10171044 const token_tags = tree.tokens.items(.tag);
10181045
......@@ -1027,7 +1054,7 @@ pub fn blockExpr(
10271054 return rvalue(gz, scope, rl, .void_value, block_node);
10281055}
10291056
1030fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIndex) !void {
1057fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.TokenIndex) !void {
10311058 // Look for the label in the scope.
10321059 var scope = parent_scope;
10331060 while (true) {
......@@ -1035,29 +1062,20 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
10351062 .gen_zir => {
10361063 const gen_zir = scope.cast(GenZir).?;
10371064 if (gen_zir.label) |prev_label| {
1038 if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) {
1039 const tree = parent_scope.tree();
1065 if (try astgen.tokenIdentEql(label, prev_label.token)) {
1066 const tree = &astgen.file.tree;
10401067 const main_tokens = tree.nodes.items(.main_token);
10411068
1042 const label_name = try mod.identifierTokenString(parent_scope, label);
1043 const msg = msg: {
1044 const msg = try mod.errMsg(
1045 parent_scope,
1046 gen_zir.tokSrcLoc(label),
1047 "redefinition of label '{s}'",
1048 .{label_name},
1049 );
1050 errdefer msg.destroy(mod.gpa);
1051 try mod.errNote(
1052 parent_scope,
1053 gen_zir.tokSrcLoc(prev_label.token),
1054 msg,
1069 const label_name = try astgen.identifierTokenString(label);
1070 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{
1071 label_name,
1072 }, &[_]u32{
1073 try astgen.errNoteTok(
1074 prev_label.token,
10551075 "previous definition is here",
10561076 .{},
1057 );
1058 break :msg msg;
1059 };
1060 return mod.failWithOwnedErrorMsg(parent_scope, msg);
1077 ),
1078 });
10611079 }
10621080 }
10631081 scope = gen_zir.parent;
......@@ -1082,8 +1100,8 @@ fn labeledBlockExpr(
10821100
10831101 assert(zir_tag == .block);
10841102
1085 const mod = gz.astgen.mod;
1086 const tree = gz.tree();
1103 const astgen = gz.astgen;
1104 const tree = &astgen.file.tree;
10871105 const main_tokens = tree.nodes.items(.main_token);
10881106 const token_tags = tree.tokens.items(.tag);
10891107
......@@ -1091,15 +1109,16 @@ fn labeledBlockExpr(
10911109 const label_token = lbrace - 2;
10921110 assert(token_tags[label_token] == .identifier);
10931111
1094 try checkLabelRedefinition(mod, parent_scope, label_token);
1112 try astgen.checkLabelRedefinition(parent_scope, label_token);
10951113
10961114 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
10971115 // so that break statements can reference it.
10981116 const block_inst = try gz.addBlock(zir_tag, block_node);
1099 try gz.instructions.append(mod.gpa, block_inst);
1117 try gz.instructions.append(astgen.gpa, block_inst);
11001118
11011119 var block_scope: GenZir = .{
11021120 .parent = parent_scope,
1121 .decl_node_index = gz.decl_node_index,
11031122 .astgen = gz.astgen,
11041123 .force_comptime = gz.force_comptime,
11051124 .instructions = .{},
......@@ -1110,14 +1129,14 @@ fn labeledBlockExpr(
11101129 }),
11111130 };
11121131 block_scope.setBreakResultLoc(rl);
1113 defer block_scope.instructions.deinit(mod.gpa);
1114 defer block_scope.labeled_breaks.deinit(mod.gpa);
1115 defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa);
1132 defer block_scope.instructions.deinit(astgen.gpa);
1133 defer block_scope.labeled_breaks.deinit(astgen.gpa);
1134 defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
11161135
11171136 try blockExprStmts(&block_scope, &block_scope.base, block_node, statements);
11181137
11191138 if (!block_scope.label.?.used) {
1120 return mod.failTok(parent_scope, label_token, "unused block label", .{});
1139 return astgen.failTok(label_token, "unused block label", .{});
11211140 }
11221141
11231142 const zir_tags = gz.astgen.instructions.items(.tag);
......@@ -1133,7 +1152,7 @@ fn labeledBlockExpr(
11331152 }
11341153 try block_scope.setBlockBody(block_inst);
11351154
1136 return gz.astgen.indexToRef(block_inst);
1155 return gz.indexToRef(block_inst);
11371156 },
11381157 .break_operand => {
11391158 // All break operands are values that did not use the result location pointer.
......@@ -1146,7 +1165,7 @@ fn labeledBlockExpr(
11461165 // would be better still to elide the ones that are in this list.
11471166 }
11481167 try block_scope.setBlockBody(block_inst);
1149 const block_ref = gz.astgen.indexToRef(block_inst);
1168 const block_ref = gz.indexToRef(block_inst);
11501169 switch (rl) {
11511170 .ref => return block_ref,
11521171 else => return rvalue(gz, parent_scope, rl, block_ref, block_node),
......@@ -1161,11 +1180,12 @@ fn blockExprStmts(
11611180 node: ast.Node.Index,
11621181 statements: []const ast.Node.Index,
11631182) !void {
1164 const tree = gz.tree();
1183 const astgen = gz.astgen;
1184 const tree = &astgen.file.tree;
11651185 const main_tokens = tree.nodes.items(.main_token);
11661186 const node_tags = tree.nodes.items(.tag);
11671187
1168 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.mod.gpa);
1188 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa);
11691189 defer block_arena.deinit();
11701190
11711191 var scope = parent_scope;
......@@ -1198,7 +1218,7 @@ fn blockExprStmts(
11981218 // We need to emit an error if the result is not `noreturn` or `void`, but
11991219 // we want to avoid adding the ZIR instruction if possible for performance.
12001220 const maybe_unused_result = try expr(gz, scope, .none, statement);
1201 const elide_check = if (gz.astgen.refToIndex(maybe_unused_result)) |inst| b: {
1221 const elide_check = if (gz.refToIndex(maybe_unused_result)) |inst| b: {
12021222 // Note that this array becomes invalid after appending more items to it
12031223 // in the above while loop.
12041224 const zir_tags = gz.astgen.instructions.items(.tag);
......@@ -1267,10 +1287,10 @@ fn blockExprStmts(
12671287 .field_val,
12681288 .field_ptr_named,
12691289 .field_val_named,
1270 .fn_type,
1271 .fn_type_var_args,
1272 .fn_type_cc,
1273 .fn_type_cc_var_args,
1290 .func,
1291 .func_var_args,
1292 .func_extra,
1293 .func_extra_var_args,
12741294 .has_decl,
12751295 .int,
12761296 .float,
......@@ -1416,21 +1436,19 @@ fn varDecl(
14161436 block_arena: *Allocator,
14171437 var_decl: ast.full.VarDecl,
14181438) InnerError!*Scope {
1419 const mod = gz.astgen.mod;
1439 const astgen = gz.astgen;
14201440 if (var_decl.comptime_token) |comptime_token| {
1421 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
1441 return astgen.failTok(comptime_token, "TODO implement comptime locals", .{});
14221442 }
14231443 if (var_decl.ast.align_node != 0) {
1424 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});
1444 return astgen.failNode(var_decl.ast.align_node, "TODO implement alignment on locals", .{});
14251445 }
1426 const astgen = gz.astgen;
1427 const gpa = mod.gpa;
1428 const tree = gz.tree();
1446 const gpa = astgen.gpa;
1447 const tree = &astgen.file.tree;
14291448 const token_tags = tree.tokens.items(.tag);
14301449
14311450 const name_token = var_decl.ast.mut_token + 1;
1432 const name_src = gz.tokSrcLoc(name_token);
1433 const ident_name = try mod.identifierTokenString(scope, name_token);
1451 const ident_name = try astgen.identifierTokenString(name_token);
14341452
14351453 // Local variables shadowing detection, including function parameters.
14361454 {
......@@ -1439,55 +1457,41 @@ fn varDecl(
14391457 .local_val => {
14401458 const local_val = s.cast(Scope.LocalVal).?;
14411459 if (mem.eql(u8, local_val.name, ident_name)) {
1442 const msg = msg: {
1443 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{
1444 ident_name,
1445 });
1446 errdefer msg.destroy(gpa);
1447 try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{});
1448 break :msg msg;
1449 };
1450 return mod.failWithOwnedErrorMsg(scope, msg);
1460 return astgen.failTokNotes(name_token, "redefinition of '{s}'", .{
1461 ident_name,
1462 }, &[_]u32{
1463 try astgen.errNoteTok(
1464 local_val.token_src,
1465 "previous definition is here",
1466 .{},
1467 ),
1468 });
14511469 }
14521470 s = local_val.parent;
14531471 },
14541472 .local_ptr => {
14551473 const local_ptr = s.cast(Scope.LocalPtr).?;
14561474 if (mem.eql(u8, local_ptr.name, ident_name)) {
1457 const msg = msg: {
1458 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{
1459 ident_name,
1460 });
1461 errdefer msg.destroy(gpa);
1462 try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{});
1463 break :msg msg;
1464 };
1465 return mod.failWithOwnedErrorMsg(scope, msg);
1475 return astgen.failTokNotes(name_token, "redefinition of '{s}'", .{
1476 ident_name,
1477 }, &[_]u32{
1478 try astgen.errNoteTok(
1479 local_ptr.token_src,
1480 "previous definition is here",
1481 .{},
1482 ),
1483 });
14661484 }
14671485 s = local_ptr.parent;
14681486 },
14691487 .gen_zir => s = s.cast(GenZir).?.parent,
1470 else => break,
1488 .file => break,
1489 else => unreachable,
14711490 };
14721491 }
14731492
1474 // Namespace vars shadowing detection
1475 if (mod.lookupIdentifier(scope, ident_name)) |decl| {
1476 const msg = msg: {
1477 const msg = try mod.errMsg(
1478 scope,
1479 name_src,
1480 "redeclaration of '{s}'",
1481 .{ident_name},
1482 );
1483 errdefer msg.destroy(gpa);
1484 try mod.errNoteNonLazy(decl.srcLoc(), msg, "previously declared here", .{});
1485 break :msg msg;
1486 };
1487 return mod.failWithOwnedErrorMsg(scope, msg);
1488 }
14891493 if (var_decl.ast.init_node == 0) {
1490 return mod.fail(scope, name_src, "variables must be initialized", .{});
1494 return astgen.failTok(name_token, "variables must be initialized", .{});
14911495 }
14921496
14931497 switch (token_tags[var_decl.ast.mut_token]) {
......@@ -1506,7 +1510,7 @@ fn varDecl(
15061510 .gen_zir = gz,
15071511 .name = ident_name,
15081512 .inst = init_inst,
1509 .src = name_src,
1513 .token_src = name_token,
15101514 };
15111515 return &sub_scope.base;
15121516 }
......@@ -1515,6 +1519,7 @@ fn varDecl(
15151519 // result location pointer.
15161520 var init_scope: GenZir = .{
15171521 .parent = scope,
1522 .decl_node_index = gz.decl_node_index,
15181523 .force_comptime = gz.force_comptime,
15191524 .astgen = astgen,
15201525 };
......@@ -1546,7 +1551,7 @@ fn varDecl(
15461551 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;
15471552 try parent_zir.ensureCapacity(gpa, expected_len);
15481553 for (init_scope.instructions.items) |src_inst| {
1549 if (astgen.indexToRef(src_inst) == init_scope.rl_ptr) continue;
1554 if (gz.indexToRef(src_inst) == init_scope.rl_ptr) continue;
15501555 if (zir_tags[src_inst] == .store_to_block_ptr) {
15511556 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
15521557 }
......@@ -1560,7 +1565,7 @@ fn varDecl(
15601565 .gen_zir = gz,
15611566 .name = ident_name,
15621567 .inst = init_inst,
1563 .src = name_src,
1568 .token_src = name_token,
15641569 };
15651570 return &sub_scope.base;
15661571 }
......@@ -1588,7 +1593,7 @@ fn varDecl(
15881593 .gen_zir = gz,
15891594 .name = ident_name,
15901595 .ptr = init_scope.rl_ptr,
1591 .src = name_src,
1596 .token_src = name_token,
15921597 };
15931598 return &sub_scope.base;
15941599 },
......@@ -1617,7 +1622,7 @@ fn varDecl(
16171622 .gen_zir = gz,
16181623 .name = ident_name,
16191624 .ptr = var_data.alloc,
1620 .src = name_src,
1625 .token_src = name_token,
16211626 };
16221627 return &sub_scope.base;
16231628 },
......@@ -1626,7 +1631,8 @@ fn varDecl(
16261631}
16271632
16281633fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void {
1629 const tree = gz.tree();
1634 const astgen = gz.astgen;
1635 const tree = &astgen.file.tree;
16301636 const node_datas = tree.nodes.items(.data);
16311637 const main_tokens = tree.nodes.items(.main_token);
16321638 const node_tags = tree.nodes.items(.tag);
......@@ -1651,7 +1657,8 @@ fn assignOp(
16511657 infix_node: ast.Node.Index,
16521658 op_inst_tag: Zir.Inst.Tag,
16531659) InnerError!void {
1654 const tree = gz.tree();
1660 const astgen = gz.astgen;
1661 const tree = &astgen.file.tree;
16551662 const node_datas = tree.nodes.items(.data);
16561663
16571664 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
......@@ -1667,7 +1674,8 @@ fn assignOp(
16671674}
16681675
16691676fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
1670 const tree = gz.tree();
1677 const astgen = gz.astgen;
1678 const tree = &astgen.file.tree;
16711679 const node_datas = tree.nodes.items(.data);
16721680
16731681 const operand = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs);
......@@ -1676,7 +1684,8 @@ fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inne
16761684}
16771685
16781686fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
1679 const tree = gz.tree();
1687 const astgen = gz.astgen;
1688 const tree = &astgen.file.tree;
16801689 const node_datas = tree.nodes.items(.data);
16811690
16821691 const operand = try expr(gz, scope, .none, node_datas[node].lhs);
......@@ -1691,7 +1700,8 @@ fn negation(
16911700 node: ast.Node.Index,
16921701 tag: Zir.Inst.Tag,
16931702) InnerError!Zir.Inst.Ref {
1694 const tree = gz.tree();
1703 const astgen = gz.astgen;
1704 const tree = &astgen.file.tree;
16951705 const node_datas = tree.nodes.items(.data);
16961706
16971707 const operand = try expr(gz, scope, .none, node_datas[node].lhs);
......@@ -1706,7 +1716,8 @@ fn ptrType(
17061716 node: ast.Node.Index,
17071717 ptr_info: ast.full.PtrType,
17081718) InnerError!Zir.Inst.Ref {
1709 const tree = gz.tree();
1719 const astgen = gz.astgen;
1720 const tree = &astgen.file.tree;
17101721
17111722 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
17121723
......@@ -1748,7 +1759,7 @@ fn ptrType(
17481759 trailing_count += 2;
17491760 }
17501761
1751 const gpa = gz.astgen.mod.gpa;
1762 const gpa = gz.astgen.gpa;
17521763 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
17531764 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
17541765 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
......@@ -1767,7 +1778,7 @@ fn ptrType(
17671778 }
17681779
17691780 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1770 const result = gz.astgen.indexToRef(new_index);
1781 const result = gz.indexToRef(new_index);
17711782 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{
17721783 .ptr_type = .{
17731784 .flags = .{
......@@ -1788,7 +1799,8 @@ fn ptrType(
17881799}
17891800
17901801fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
1791 const tree = gz.tree();
1802 const astgen = gz.astgen;
1803 const tree = &astgen.file.tree;
17921804 const node_datas = tree.nodes.items(.data);
17931805
17941806 // TODO check for [_]T
......@@ -1800,7 +1812,8 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Z
18001812}
18011813
18021814fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
1803 const tree = gz.tree();
1815 const astgen = gz.astgen;
1816 const tree = &astgen.file.tree;
18041817 const node_datas = tree.nodes.items(.data);
18051818 const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
18061819
......@@ -1813,7 +1826,275 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.I
18131826 return rvalue(gz, scope, rl, result, node);
18141827}
18151828
1816pub fn structDeclInner(
1829const WipDecls = struct {
1830 decl_index: usize = 0,
1831 cur_bit_bag: u32 = 0,
1832 bit_bag: ArrayListUnmanaged(u32) = .{},
1833 name_and_value: ArrayListUnmanaged(u32) = .{},
1834
1835 fn deinit(wip_decls: *WipDecls, gpa: *Allocator) void {
1836 wip_decls.bit_bag.deinit(gpa);
1837 wip_decls.name_and_value.deinit(gpa);
1838 }
1839};
1840
1841fn fnDecl(
1842 astgen: *AstGen,
1843 gz: *GenZir,
1844 wip_decls: *WipDecls,
1845 body_node: ast.Node.Index,
1846 fn_proto: ast.full.FnProto,
1847) InnerError!void {
1848 const gpa = astgen.gpa;
1849 const tree = &astgen.file.tree;
1850 const token_tags = tree.tokens.items(.tag);
1851
1852 const is_pub = fn_proto.visib_token != null;
1853 const is_export = blk: {
1854 if (fn_proto.extern_export_token) |maybe_export_token| {
1855 break :blk token_tags[maybe_export_token] == .keyword_export;
1856 }
1857 break :blk false;
1858 };
1859 if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) {
1860 try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
1861 wip_decls.cur_bit_bag = 0;
1862 }
1863 wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> 2) |
1864 (@as(u32, @boolToInt(is_pub)) << 30) |
1865 (@as(u32, @boolToInt(is_export)) << 31);
1866 wip_decls.decl_index += 1;
1867
1868 // The AST params array does not contain anytype and ... parameters.
1869 // We must iterate to count how many param types to allocate.
1870 const param_count = blk: {
1871 var count: usize = 0;
1872 var it = fn_proto.iterate(tree.*);
1873 while (it.next()) |param| {
1874 if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
1875 count += 1;
1876 }
1877 break :blk count;
1878 };
1879 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
1880 defer gpa.free(param_types);
1881
1882 var is_var_args = false;
1883 {
1884 var param_type_i: usize = 0;
1885 var it = fn_proto.iterate(tree.*);
1886 while (it.next()) |param| : (param_type_i += 1) {
1887 if (param.anytype_ellipsis3) |token| {
1888 switch (token_tags[token]) {
1889 .keyword_anytype => return astgen.failTok(
1890 token,
1891 "TODO implement anytype parameter",
1892 .{},
1893 ),
1894 .ellipsis3 => {
1895 is_var_args = true;
1896 break;
1897 },
1898 else => unreachable,
1899 }
1900 }
1901 const param_type_node = param.type_expr;
1902 assert(param_type_node != 0);
1903 param_types[param_type_i] =
1904 try expr(gz, &gz.base, .{ .ty = .type_type }, param_type_node);
1905 }
1906 assert(param_type_i == param_count);
1907 }
1908
1909 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
1910 const lib_name_str = try gz.strLitAsString(lib_name_token);
1911 break :blk lib_name_str.index;
1912 } else 0;
1913
1914 if (fn_proto.ast.align_expr != 0) {
1915 return astgen.failNode(
1916 fn_proto.ast.align_expr,
1917 "TODO implement function align expression",
1918 .{},
1919 );
1920 }
1921 if (fn_proto.ast.section_expr != 0) {
1922 return astgen.failNode(
1923 fn_proto.ast.section_expr,
1924 "TODO implement function section expression",
1925 .{},
1926 );
1927 }
1928
1929 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
1930 if (token_tags[maybe_bang] == .bang) {
1931 return astgen.failTok(maybe_bang, "TODO implement inferred error sets", .{});
1932 }
1933 const return_type_inst = try AstGen.expr(
1934 gz,
1935 &gz.base,
1936 .{ .ty = .type_type },
1937 fn_proto.ast.return_type,
1938 );
1939
1940 const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
1941 token_tags[maybe_export_token] == .keyword_extern
1942 else
1943 false;
1944
1945 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
1946 // TODO instead of enum literal type, this needs to be the
1947 // std.builtin.CallingConvention enum. We need to implement importing other files
1948 // and enums in order to fix this.
1949 try AstGen.comptimeExpr(
1950 gz,
1951 &gz.base,
1952 .{ .ty = .enum_literal_type },
1953 fn_proto.ast.callconv_expr,
1954 )
1955 else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
1956 try gz.addSmallStr(.enum_literal_small, "C")
1957 else
1958 .none;
1959
1960 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
1961 if (is_extern) {
1962 return astgen.failNode(fn_proto.ast.fn_token, "non-extern function has no body", .{});
1963 }
1964
1965 if (cc != .none or lib_name != 0) {
1966 const tag: Zir.Inst.Tag = if (is_var_args) .func_extra_var_args else .func_extra;
1967 break :func try gz.addFuncExtra(tag, .{
1968 .src_node = fn_proto.ast.proto_node,
1969 .ret_ty = return_type_inst,
1970 .param_types = param_types,
1971 .cc = cc,
1972 .lib_name = lib_name,
1973 .body = &[0]Zir.Inst.Index{},
1974 });
1975 }
1976
1977 const tag: Zir.Inst.Tag = if (is_var_args) .func_var_args else .func;
1978 break :func try gz.addFunc(tag, .{
1979 .src_node = fn_proto.ast.proto_node,
1980 .ret_ty = return_type_inst,
1981 .param_types = param_types,
1982 .body = &[0]Zir.Inst.Index{},
1983 });
1984 } else func: {
1985 if (is_var_args) {
1986 return astgen.failNode(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
1987 }
1988
1989 var fn_gz: Scope.GenZir = .{
1990 .force_comptime = false,
1991 .decl_node_index = fn_proto.ast.proto_node,
1992 .parent = &gz.base,
1993 .astgen = astgen,
1994 .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count),
1995 };
1996 defer fn_gz.instructions.deinit(gpa);
1997
1998 // Iterate over the parameters. We put the param names as the first N
1999 // items inside `extra` so that debug info later can refer to the parameter names
2000 // even while the respective source code is unloaded.
2001 try astgen.extra.ensureCapacity(gpa, param_count);
2002
2003 {
2004 var params_scope = &fn_gz.base;
2005 var i: usize = 0;
2006 var it = fn_proto.iterate(tree.*);
2007 while (it.next()) |param| : (i += 1) {
2008 const name_token = param.name_token.?;
2009 const param_name = try astgen.identifierTokenString(name_token);
2010 const sub_scope = try astgen.arena.create(Scope.LocalVal);
2011 sub_scope.* = .{
2012 .parent = params_scope,
2013 .gen_zir = &fn_gz,
2014 .name = param_name,
2015 // Implicit const list first, then implicit arg list.
2016 .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
2017 .token_src = name_token,
2018 };
2019 params_scope = &sub_scope.base;
2020
2021 // Additionally put the param name into `string_bytes` and reference it with
2022 // `extra` so that we have access to the data in codegen, for debug info.
2023 const str_index = try fn_gz.identAsString(name_token);
2024 astgen.extra.appendAssumeCapacity(str_index);
2025 }
2026
2027 _ = try expr(&fn_gz, params_scope, .none, body_node);
2028 }
2029
2030 if (fn_gz.instructions.items.len == 0 or
2031 !astgen.instructions.items(.tag)[fn_gz.instructions.items.len - 1].isNoReturn())
2032 {
2033 // astgen uses result location semantics to coerce return operands.
2034 // Since we are adding the return instruction here, we must handle the coercion.
2035 // We do this by using the `ret_coerce` instruction.
2036 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
2037 }
2038
2039 if (cc != .none or lib_name != 0) {
2040 const tag: Zir.Inst.Tag = if (is_var_args) .func_extra_var_args else .func_extra;
2041 break :func try fn_gz.addFuncExtra(tag, .{
2042 .src_node = fn_proto.ast.proto_node,
2043 .ret_ty = return_type_inst,
2044 .param_types = param_types,
2045 .cc = cc,
2046 .lib_name = lib_name,
2047 .body = fn_gz.instructions.items,
2048 });
2049 }
2050
2051 const tag: Zir.Inst.Tag = if (is_var_args) .func_var_args else .func;
2052 break :func try fn_gz.addFunc(tag, .{
2053 .src_node = fn_proto.ast.proto_node,
2054 .ret_ty = return_type_inst,
2055 .param_types = param_types,
2056 .body = fn_gz.instructions.items,
2057 });
2058 };
2059
2060 const fn_name_token = fn_proto.name_token orelse {
2061 @panic("TODO handle missing function names in the parser");
2062 };
2063 const fn_name_str_index = try gz.identAsString(fn_name_token);
2064
2065 try wip_decls.name_and_value.ensureCapacity(gpa, wip_decls.name_and_value.items.len + 2);
2066 wip_decls.name_and_value.appendAssumeCapacity(fn_name_str_index);
2067 wip_decls.name_and_value.appendAssumeCapacity(@enumToInt(func_inst));
2068}
2069
2070fn globalVarDecl(
2071 astgen: *AstGen,
2072 gz: *GenZir,
2073 wip_decls: *WipDecls,
2074 var_decl: ast.full.VarDecl,
2075) InnerError!void {
2076 @panic("TODO astgen globalVarDecl");
2077}
2078
2079fn comptimeDecl(
2080 astgen: *AstGen,
2081 gz: *GenZir,
2082 wip_decls: *WipDecls,
2083 node: ast.Node.Index,
2084) InnerError!void {
2085 @panic("TODO astgen comptimeDecl");
2086}
2087
2088fn usingnamespaceDecl(
2089 astgen: *AstGen,
2090 gz: *GenZir,
2091 wip_decls: *WipDecls,
2092 node: ast.Node.Index,
2093) InnerError!void {
2094 @panic("TODO astgen usingnamespaceDecl");
2095}
2096
2097fn structDeclInner(
18172098 gz: *GenZir,
18182099 scope: *Scope,
18192100 node: ast.Node.Index,
......@@ -1821,25 +2102,33 @@ pub fn structDeclInner(
18212102 tag: Zir.Inst.Tag,
18222103) InnerError!Zir.Inst.Ref {
18232104 if (container_decl.ast.members.len == 0) {
1824 return gz.addPlNode(tag, node, Zir.Inst.StructDecl{ .fields_len = 0, .body_len = 0 });
2105 return gz.addPlNode(tag, node, Zir.Inst.StructDecl{
2106 .fields_len = 0,
2107 .body_len = 0,
2108 .decls_len = 0,
2109 });
18252110 }
18262111
18272112 const astgen = gz.astgen;
1828 const mod = astgen.mod;
1829 const gpa = mod.gpa;
1830 const tree = gz.tree();
2113 const gpa = astgen.gpa;
2114 const tree = &astgen.file.tree;
18312115 const node_tags = tree.nodes.items(.tag);
2116 const node_datas = tree.nodes.items(.data);
18322117
18332118 // The struct_decl instruction introduces a scope in which the decls of the struct
18342119 // are in scope, so that field types, alignments, and default value expressions
18352120 // can refer to decls within the struct itself.
18362121 var block_scope: GenZir = .{
18372122 .parent = scope,
2123 .decl_node_index = node,
18382124 .astgen = astgen,
18392125 .force_comptime = true,
18402126 };
18412127 defer block_scope.instructions.deinit(gpa);
18422128
2129 var wip_decls: WipDecls = .{};
2130 defer wip_decls.deinit(gpa);
2131
18432132 // We don't know which members are fields until we iterate, so cannot do
18442133 // an accurate ensureCapacity yet.
18452134 var fields_data = ArrayListUnmanaged(u32){};
......@@ -1856,14 +2145,84 @@ pub fn structDeclInner(
18562145 .container_field_init => tree.containerFieldInit(member_node),
18572146 .container_field_align => tree.containerFieldAlign(member_node),
18582147 .container_field => tree.containerField(member_node),
1859 else => continue,
2148
2149 .fn_decl => {
2150 const fn_proto = node_datas[member_node].lhs;
2151 const body = node_datas[member_node].rhs;
2152 switch (node_tags[fn_proto]) {
2153 .fn_proto_simple => {
2154 var params: [1]ast.Node.Index = undefined;
2155 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoSimple(&params, fn_proto));
2156 continue;
2157 },
2158 .fn_proto_multi => {
2159 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoMulti(fn_proto));
2160 continue;
2161 },
2162 .fn_proto_one => {
2163 var params: [1]ast.Node.Index = undefined;
2164 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoOne(&params, fn_proto));
2165 continue;
2166 },
2167 .fn_proto => {
2168 try astgen.fnDecl(gz, &wip_decls, body, tree.fnProto(fn_proto));
2169 continue;
2170 },
2171 else => unreachable,
2172 }
2173 },
2174 .fn_proto_simple => {
2175 var params: [1]ast.Node.Index = undefined;
2176 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoSimple(&params, member_node));
2177 continue;
2178 },
2179 .fn_proto_multi => {
2180 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoMulti(member_node));
2181 continue;
2182 },
2183 .fn_proto_one => {
2184 var params: [1]ast.Node.Index = undefined;
2185 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoOne(&params, member_node));
2186 continue;
2187 },
2188 .fn_proto => {
2189 try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProto(member_node));
2190 continue;
2191 },
2192
2193 .global_var_decl => {
2194 try astgen.globalVarDecl(gz, &wip_decls, tree.globalVarDecl(member_node));
2195 continue;
2196 },
2197 .local_var_decl => {
2198 try astgen.globalVarDecl(gz, &wip_decls, tree.localVarDecl(member_node));
2199 continue;
2200 },
2201 .simple_var_decl => {
2202 try astgen.globalVarDecl(gz, &wip_decls, tree.simpleVarDecl(member_node));
2203 continue;
2204 },
2205 .aligned_var_decl => {
2206 try astgen.globalVarDecl(gz, &wip_decls, tree.alignedVarDecl(member_node));
2207 continue;
2208 },
2209
2210 .@"comptime" => {
2211 try astgen.comptimeDecl(gz, &wip_decls, member_node);
2212 continue;
2213 },
2214 .@"usingnamespace" => {
2215 try astgen.usingnamespaceDecl(gz, &wip_decls, member_node);
2216 continue;
2217 },
2218 else => unreachable,
18602219 };
18612220 if (field_index % 16 == 0 and field_index != 0) {
18622221 try bit_bag.append(gpa, cur_bit_bag);
18632222 cur_bit_bag = 0;
18642223 }
18652224 if (member.comptime_token) |comptime_token| {
1866 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
2225 return astgen.failTok(comptime_token, "TODO implement comptime struct fields", .{});
18672226 }
18682227 try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);
18692228
......@@ -1890,11 +2249,14 @@ pub fn structDeclInner(
18902249
18912250 field_index += 1;
18922251 }
1893 if (field_index == 0) {
1894 return gz.addPlNode(tag, node, Zir.Inst.StructDecl{ .fields_len = 0, .body_len = 0 });
2252 if (field_index != 0) {
2253 const empty_slot_count = 16 - (field_index % 16);
2254 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
2255 }
2256 if (wip_decls.decl_index != 0) {
2257 const empty_slot_count = 16 - (wip_decls.decl_index % 16);
2258 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18952259 }
1896 const empty_slot_count = 16 - (field_index % 16);
1897 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18982260
18992261 const decl_inst = try gz.addBlock(tag, node);
19002262 try gz.instructions.append(gpa, decl_inst);
......@@ -1903,17 +2265,25 @@ pub fn structDeclInner(
19032265 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
19042266 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
19052267 bit_bag.items.len + 1 + fields_data.items.len +
1906 block_scope.instructions.items.len);
2268 block_scope.instructions.items.len +
2269 wip_decls.bit_bag.items.len + 1 + wip_decls.name_and_value.items.len);
19072270 const zir_datas = astgen.instructions.items(.data);
19082271 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
19092272 .body_len = @intCast(u32, block_scope.instructions.items.len),
19102273 .fields_len = @intCast(u32, field_index),
2274 .decls_len = @intCast(u32, wip_decls.decl_index),
19112275 });
19122276 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
2277
19132278 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
19142279 astgen.extra.appendAssumeCapacity(cur_bit_bag);
19152280 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
1916 return astgen.indexToRef(decl_inst);
2281
2282 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
2283 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
2284 astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);
2285
2286 return gz.indexToRef(decl_inst);
19172287}
19182288
19192289fn containerDecl(
......@@ -1924,9 +2294,8 @@ fn containerDecl(
19242294 container_decl: ast.full.ContainerDecl,
19252295) InnerError!Zir.Inst.Ref {
19262296 const astgen = gz.astgen;
1927 const mod = astgen.mod;
1928 const gpa = mod.gpa;
1929 const tree = gz.tree();
2297 const gpa = astgen.gpa;
2298 const tree = &astgen.file.tree;
19302299 const token_tags = tree.tokens.items(.tag);
19312300 const node_tags = tree.nodes.items(.tag);
19322301
......@@ -1952,11 +2321,11 @@ fn containerDecl(
19522321 return rvalue(gz, scope, rl, result, node);
19532322 },
19542323 .keyword_union => {
1955 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
2324 return astgen.failTok(container_decl.ast.main_token, "TODO AstGen for union decl", .{});
19562325 },
19572326 .keyword_enum => {
19582327 if (container_decl.layout_token) |t| {
1959 return mod.failTok(scope, t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
2328 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
19602329 }
19612330 // Count total fields as well as how many have explicitly provided tag values.
19622331 const counts = blk: {
......@@ -1975,10 +2344,10 @@ fn containerDecl(
19752344 },
19762345 };
19772346 if (member.comptime_token) |comptime_token| {
1978 return mod.failTok(scope, comptime_token, "enum fields cannot be marked comptime", .{});
2347 return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{});
19792348 }
19802349 if (member.ast.type_expr != 0) {
1981 return mod.failNode(scope, member.ast.type_expr, "enum fields do not have types", .{});
2350 return astgen.failNode(member.ast.type_expr, "enum fields do not have types", .{});
19822351 }
19832352 // Alignment expressions in enums are caught by the parser.
19842353 assert(member.ast.align_expr == 0);
......@@ -1986,30 +2355,29 @@ fn containerDecl(
19862355 const name_token = member.ast.name_token;
19872356 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
19882357 if (nonexhaustive_node != 0) {
1989 const msg = msg: {
1990 const msg = try mod.errMsg(
1991 scope,
1992 gz.nodeSrcLoc(member_node),
1993 "redundant non-exhaustive enum mark",
1994 .{},
1995 );
1996 errdefer msg.destroy(gpa);
1997 const other_src = gz.nodeSrcLoc(nonexhaustive_node);
1998 try mod.errNote(scope, other_src, msg, "other mark here", .{});
1999 break :msg msg;
2000 };
2001 return mod.failWithOwnedErrorMsg(scope, msg);
2358 return astgen.failNodeNotes(
2359 member_node,
2360 "redundant non-exhaustive enum mark",
2361 .{},
2362 &[_]u32{
2363 try astgen.errNoteNode(
2364 nonexhaustive_node,
2365 "other mark here",
2366 .{},
2367 ),
2368 },
2369 );
20022370 }
20032371 nonexhaustive_node = member_node;
20042372 if (member.ast.value_expr != 0) {
2005 return mod.failNode(scope, member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
2373 return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
20062374 }
20072375 continue;
20082376 }
20092377 total_fields += 1;
20102378 if (member.ast.value_expr != 0) {
20112379 if (arg_inst == .none) {
2012 return mod.failNode(scope, member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{});
2380 return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{});
20132381 }
20142382 values += 1;
20152383 }
......@@ -2025,104 +2393,27 @@ fn containerDecl(
20252393 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
20262394 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
20272395 // must be at least one tag.
2028 return mod.failNode(scope, node, "enum declarations must have at least one tag", .{});
2396 return astgen.failNode(node, "enum declarations must have at least one tag", .{});
20292397 }
20302398 if (counts.nonexhaustive_node != 0 and arg_inst == .none) {
2031 const msg = msg: {
2032 const msg = try mod.errMsg(
2033 scope,
2034 gz.nodeSrcLoc(node),
2035 "non-exhaustive enum missing integer tag type",
2036 .{},
2037 );
2038 errdefer msg.destroy(gpa);
2039 const other_src = gz.nodeSrcLoc(counts.nonexhaustive_node);
2040 try mod.errNote(scope, other_src, msg, "marked non-exhaustive here", .{});
2041 break :msg msg;
2042 };
2043 return mod.failWithOwnedErrorMsg(scope, msg);
2399 return astgen.failNodeNotes(
2400 node,
2401 "non-exhaustive enum missing integer tag type",
2402 .{},
2403 &[_]u32{
2404 try astgen.errNoteNode(
2405 counts.nonexhaustive_node,
2406 "marked non-exhaustive here",
2407 .{},
2408 ),
2409 },
2410 );
20442411 }
20452412 if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
2046 // No explicitly provided tag values and no top level declarations! In this case,
2047 // we can construct the enum type in AstGen and it will be correctly shared by all
2048 // generic function instantiations and comptime function calls.
2049 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
2050 errdefer new_decl_arena.deinit();
2051 const arena = &new_decl_arena.allocator;
2052
2053 var fields_map: std.StringArrayHashMapUnmanaged(void) = .{};
2054 try fields_map.ensureCapacity(arena, counts.total_fields);
2055 for (container_decl.ast.members) |member_node| {
2056 if (member_node == counts.nonexhaustive_node)
2057 continue;
2058 const member = switch (node_tags[member_node]) {
2059 .container_field_init => tree.containerFieldInit(member_node),
2060 .container_field_align => tree.containerFieldAlign(member_node),
2061 .container_field => tree.containerField(member_node),
2062 else => unreachable, // We checked earlier.
2063 };
2064 const name_token = member.ast.name_token;
2065 const tag_name = try mod.identifierTokenStringTreeArena(
2066 scope,
2067 name_token,
2068 tree,
2069 arena,
2070 );
2071 const gop = fields_map.getOrPutAssumeCapacity(tag_name);
2072 if (gop.found_existing) {
2073 const msg = msg: {
2074 const msg = try mod.errMsg(
2075 scope,
2076 gz.tokSrcLoc(name_token),
2077 "duplicate enum tag",
2078 .{},
2079 );
2080 errdefer msg.destroy(gpa);
2081 // Iterate to find the other tag. We don't eagerly store it in a hash
2082 // map because in the hot path there will be no compile error and we
2083 // don't need to waste time with a hash map.
2084 const bad_node = for (container_decl.ast.members) |other_member_node| {
2085 const other_member = switch (node_tags[other_member_node]) {
2086 .container_field_init => tree.containerFieldInit(other_member_node),
2087 .container_field_align => tree.containerFieldAlign(other_member_node),
2088 .container_field => tree.containerField(other_member_node),
2089 else => unreachable, // We checked earlier.
2090 };
2091 const other_tag_name = try mod.identifierTokenStringTreeArena(
2092 scope,
2093 other_member.ast.name_token,
2094 tree,
2095 arena,
2096 );
2097 if (mem.eql(u8, tag_name, other_tag_name))
2098 break other_member_node;
2099 } else unreachable;
2100 const other_src = gz.nodeSrcLoc(bad_node);
2101 try mod.errNote(scope, other_src, msg, "other tag here", .{});
2102 break :msg msg;
2103 };
2104 return mod.failWithOwnedErrorMsg(scope, msg);
2105 }
2106 }
2107 const enum_simple = try arena.create(Module.EnumSimple);
2108 enum_simple.* = .{
2109 .owner_decl = astgen.decl,
2110 .node_offset = astgen.decl.nodeIndexToRelative(node),
2111 .fields = fields_map,
2112 };
2113 const enum_ty = try Type.Tag.enum_simple.create(arena, enum_simple);
2114 const enum_val = try Value.Tag.ty.create(arena, enum_ty);
2115 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
2116 .ty = Type.initTag(.type),
2117 .val = enum_val,
2118 });
2119 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2120 const result = try gz.addDecl(.decl_val, decl_index, node);
2121 return rvalue(gz, scope, rl, result, node);
2413 @panic("AstGen simple enum");
21222414 }
21232415 // In this case we must generate ZIR code for the tag values, similar to
2124 // how structs are handled above. The new anonymous Decl will be created in
2125 // Sema, not AstGen.
2416 // how structs are handled above.
21262417 const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)
21272418 .enum_decl
21282419 else
......@@ -2139,6 +2430,7 @@ fn containerDecl(
21392430 // are in scope, so that tag values can refer to decls within the enum itself.
21402431 var block_scope: GenZir = .{
21412432 .parent = scope,
2433 .decl_node_index = node,
21422434 .astgen = astgen,
21432435 .force_comptime = true,
21442436 };
......@@ -2207,7 +2499,7 @@ fn containerDecl(
22072499 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
22082500 astgen.extra.appendAssumeCapacity(cur_bit_bag);
22092501 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
2210 return rvalue(gz, scope, rl, astgen.indexToRef(decl_inst), node);
2502 return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node);
22112503 },
22122504 .keyword_opaque => {
22132505 const result = try gz.addNode(.opaque_decl, node);
......@@ -2224,63 +2516,11 @@ fn errorSetDecl(
22242516 node: ast.Node.Index,
22252517) InnerError!Zir.Inst.Ref {
22262518 const astgen = gz.astgen;
2227 const mod = astgen.mod;
2228 const tree = gz.tree();
2519 const tree = &astgen.file.tree;
22292520 const main_tokens = tree.nodes.items(.main_token);
22302521 const token_tags = tree.tokens.items(.tag);
22312522
2232 // Count how many fields there are.
2233 const error_token = main_tokens[node];
2234 const count: usize = count: {
2235 var tok_i = error_token + 2;
2236 var count: usize = 0;
2237 while (true) : (tok_i += 1) {
2238 switch (token_tags[tok_i]) {
2239 .doc_comment, .comma => {},
2240 .identifier => count += 1,
2241 .r_brace => break :count count,
2242 else => unreachable,
2243 }
2244 } else unreachable; // TODO should not need else unreachable here
2245 };
2246
2247 const gpa = mod.gpa;
2248 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
2249 errdefer new_decl_arena.deinit();
2250 const arena = &new_decl_arena.allocator;
2251
2252 const fields = try arena.alloc([]const u8, count);
2253 {
2254 var tok_i = error_token + 2;
2255 var field_i: usize = 0;
2256 while (true) : (tok_i += 1) {
2257 switch (token_tags[tok_i]) {
2258 .doc_comment, .comma => {},
2259 .identifier => {
2260 fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena);
2261 field_i += 1;
2262 },
2263 .r_brace => break,
2264 else => unreachable,
2265 }
2266 }
2267 }
2268 const error_set = try arena.create(Module.ErrorSet);
2269 error_set.* = .{
2270 .owner_decl = astgen.decl,
2271 .node_offset = astgen.decl.nodeIndexToRelative(node),
2272 .names_ptr = fields.ptr,
2273 .names_len = @intCast(u32, fields.len),
2274 };
2275 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
2276 const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
2277 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
2278 .ty = Type.initTag(.type),
2279 .val = error_set_val,
2280 });
2281 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2282 const result = try gz.addDecl(.decl_val, decl_index, node);
2283 return rvalue(gz, scope, rl, result, node);
2523 @panic("TODO AstGen errorSetDecl");
22842524}
22852525
22862526fn orelseCatchExpr(
......@@ -2295,17 +2535,18 @@ fn orelseCatchExpr(
22952535 rhs: ast.Node.Index,
22962536 payload_token: ?ast.TokenIndex,
22972537) InnerError!Zir.Inst.Ref {
2298 const mod = parent_gz.astgen.mod;
2299 const tree = parent_gz.tree();
2538 const astgen = parent_gz.astgen;
2539 const tree = &astgen.file.tree;
23002540
23012541 var block_scope: GenZir = .{
23022542 .parent = scope,
2543 .decl_node_index = parent_gz.decl_node_index,
23032544 .astgen = parent_gz.astgen,
23042545 .force_comptime = parent_gz.force_comptime,
23052546 .instructions = .{},
23062547 };
23072548 block_scope.setBreakResultLoc(rl);
2308 defer block_scope.instructions.deinit(mod.gpa);
2549 defer block_scope.instructions.deinit(astgen.gpa);
23092550
23102551 // This could be a pointer or value depending on the `operand_rl` parameter.
23112552 // We cannot use `block_scope.break_result_loc` because that has the bare
......@@ -2331,30 +2572,31 @@ fn orelseCatchExpr(
23312572 const condbr = try block_scope.addCondBr(.condbr, node);
23322573
23332574 const block = try parent_gz.addBlock(.block, node);
2334 try parent_gz.instructions.append(mod.gpa, block);
2575 try parent_gz.instructions.append(astgen.gpa, block);
23352576 try block_scope.setBlockBody(block);
23362577
23372578 var then_scope: GenZir = .{
23382579 .parent = scope,
2580 .decl_node_index = parent_gz.decl_node_index,
23392581 .astgen = parent_gz.astgen,
23402582 .force_comptime = block_scope.force_comptime,
23412583 .instructions = .{},
23422584 };
2343 defer then_scope.instructions.deinit(mod.gpa);
2585 defer then_scope.instructions.deinit(astgen.gpa);
23442586
23452587 var err_val_scope: Scope.LocalVal = undefined;
23462588 const then_sub_scope = blk: {
23472589 const payload = payload_token orelse break :blk &then_scope.base;
23482590 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {
2349 return mod.failTok(&then_scope.base, payload, "discard of error capture; omit it instead", .{});
2591 return astgen.failTok(payload, "discard of error capture; omit it instead", .{});
23502592 }
2351 const err_name = try mod.identifierTokenString(scope, payload);
2593 const err_name = try astgen.identifierTokenString(payload);
23522594 err_val_scope = .{
23532595 .parent = &then_scope.base,
23542596 .gen_zir = &then_scope,
23552597 .name = err_name,
23562598 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),
2357 .src = parent_gz.tokSrcLoc(payload),
2599 .token_src = payload,
23582600 };
23592601 break :blk &err_val_scope.base;
23602602 };
......@@ -2367,11 +2609,12 @@ fn orelseCatchExpr(
23672609
23682610 var else_scope: GenZir = .{
23692611 .parent = scope,
2612 .decl_node_index = parent_gz.decl_node_index,
23702613 .astgen = parent_gz.astgen,
23712614 .force_comptime = block_scope.force_comptime,
23722615 .instructions = .{},
23732616 };
2374 defer else_scope.instructions.deinit(mod.gpa);
2617 defer else_scope.instructions.deinit(astgen.gpa);
23752618
23762619 // This could be a pointer or value depending on `unwrap_op`.
23772620 const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node);
......@@ -2424,23 +2667,23 @@ fn finishThenElseBlock(
24242667 const astgen = block_scope.astgen;
24252668 switch (strat.tag) {
24262669 .break_void => {
2427 if (!astgen.refIsNoReturn(then_result)) {
2670 if (!parent_gz.refIsNoReturn(then_result)) {
24282671 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value);
24292672 }
2430 const elide_else = if (else_result != .none) astgen.refIsNoReturn(else_result) else false;
2673 const elide_else = if (else_result != .none) parent_gz.refIsNoReturn(else_result) else false;
24312674 if (!elide_else) {
24322675 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
24332676 }
24342677 assert(!strat.elide_store_to_block_ptr_instructions);
24352678 try setCondBrPayload(condbr, cond, then_scope, else_scope);
2436 return astgen.indexToRef(main_block);
2679 return parent_gz.indexToRef(main_block);
24372680 },
24382681 .break_operand => {
2439 if (!astgen.refIsNoReturn(then_result)) {
2682 if (!parent_gz.refIsNoReturn(then_result)) {
24402683 _ = try then_scope.addBreak(break_tag, then_break_block, then_result);
24412684 }
24422685 if (else_result != .none) {
2443 if (!astgen.refIsNoReturn(else_result)) {
2686 if (!parent_gz.refIsNoReturn(else_result)) {
24442687 _ = try else_scope.addBreak(break_tag, main_block, else_result);
24452688 }
24462689 } else {
......@@ -2451,7 +2694,7 @@ fn finishThenElseBlock(
24512694 } else {
24522695 try setCondBrPayload(condbr, cond, then_scope, else_scope);
24532696 }
2454 const block_ref = astgen.indexToRef(main_block);
2697 const block_ref = parent_gz.indexToRef(main_block);
24552698 switch (rl) {
24562699 .ref => return block_ref,
24572700 else => return rvalue(parent_gz, parent_scope, rl, block_ref, node),
......@@ -2464,9 +2707,9 @@ fn finishThenElseBlock(
24642707/// tokens without allocating.
24652708/// OK in theory it could do it without allocating. This implementation
24662709/// allocates when the @"" form is used.
2467fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
2468 const ident_name_1 = try mod.identifierTokenString(scope, token1);
2469 const ident_name_2 = try mod.identifierTokenString(scope, token2);
2710fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
2711 const ident_name_1 = try astgen.identifierTokenString(token1);
2712 const ident_name_2 = try astgen.identifierTokenString(token2);
24702713 return mem.eql(u8, ident_name_1, ident_name_2);
24712714}
24722715
......@@ -2477,8 +2720,7 @@ pub fn fieldAccess(
24772720 node: ast.Node.Index,
24782721) InnerError!Zir.Inst.Ref {
24792722 const astgen = gz.astgen;
2480 const mod = astgen.mod;
2481 const tree = gz.tree();
2723 const tree = &astgen.file.tree;
24822724 const main_tokens = tree.nodes.items(.main_token);
24832725 const node_datas = tree.nodes.items(.data);
24842726
......@@ -2504,7 +2746,8 @@ fn arrayAccess(
25042746 rl: ResultLoc,
25052747 node: ast.Node.Index,
25062748) InnerError!Zir.Inst.Ref {
2507 const tree = gz.tree();
2749 const astgen = gz.astgen;
2750 const tree = &astgen.file.tree;
25082751 const main_tokens = tree.nodes.items(.main_token);
25092752 const node_datas = tree.nodes.items(.data);
25102753 switch (rl) {
......@@ -2528,7 +2771,8 @@ fn simpleBinOp(
25282771 node: ast.Node.Index,
25292772 op_inst_tag: Zir.Inst.Tag,
25302773) InnerError!Zir.Inst.Ref {
2531 const tree = gz.tree();
2774 const astgen = gz.astgen;
2775 const tree = &astgen.file.tree;
25322776 const node_datas = tree.nodes.items(.data);
25332777
25342778 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{
......@@ -2565,15 +2809,16 @@ fn boolBinOp(
25652809
25662810 var rhs_scope: GenZir = .{
25672811 .parent = scope,
2812 .decl_node_index = gz.decl_node_index,
25682813 .astgen = gz.astgen,
25692814 .force_comptime = gz.force_comptime,
25702815 };
2571 defer rhs_scope.instructions.deinit(gz.astgen.mod.gpa);
2816 defer rhs_scope.instructions.deinit(gz.astgen.gpa);
25722817 const rhs = try expr(&rhs_scope, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs);
25732818 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
25742819 try rhs_scope.setBoolBrBody(bool_br);
25752820
2576 const block_ref = gz.astgen.indexToRef(bool_br);
2821 const block_ref = gz.indexToRef(bool_br);
25772822 return rvalue(gz, scope, rl, block_ref, node);
25782823}
25792824
......@@ -2584,23 +2829,23 @@ fn ifExpr(
25842829 node: ast.Node.Index,
25852830 if_full: ast.full.If,
25862831) InnerError!Zir.Inst.Ref {
2587 const mod = parent_gz.astgen.mod;
2588
2832 const astgen = parent_gz.astgen;
25892833 var block_scope: GenZir = .{
25902834 .parent = scope,
2591 .astgen = parent_gz.astgen,
2835 .decl_node_index = parent_gz.decl_node_index,
2836 .astgen = astgen,
25922837 .force_comptime = parent_gz.force_comptime,
25932838 .instructions = .{},
25942839 };
25952840 block_scope.setBreakResultLoc(rl);
2596 defer block_scope.instructions.deinit(mod.gpa);
2841 defer block_scope.instructions.deinit(astgen.gpa);
25972842
25982843 const cond = c: {
25992844 // TODO https://github.com/ziglang/zig/issues/7929
26002845 if (if_full.error_token) |error_token| {
2601 return mod.failTok(scope, error_token, "TODO implement if error union", .{});
2846 return astgen.failTok(error_token, "TODO implement if error union", .{});
26022847 } else if (if_full.payload_token) |payload_token| {
2603 return mod.failTok(scope, payload_token, "TODO implement if optional", .{});
2848 return astgen.failTok(payload_token, "TODO implement if optional", .{});
26042849 } else {
26052850 break :c try expr(&block_scope, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr);
26062851 }
......@@ -2609,16 +2854,17 @@ fn ifExpr(
26092854 const condbr = try block_scope.addCondBr(.condbr, node);
26102855
26112856 const block = try parent_gz.addBlock(.block, node);
2612 try parent_gz.instructions.append(mod.gpa, block);
2857 try parent_gz.instructions.append(astgen.gpa, block);
26132858 try block_scope.setBlockBody(block);
26142859
26152860 var then_scope: GenZir = .{
26162861 .parent = scope,
2617 .astgen = parent_gz.astgen,
2862 .decl_node_index = parent_gz.decl_node_index,
2863 .astgen = astgen,
26182864 .force_comptime = block_scope.force_comptime,
26192865 .instructions = .{},
26202866 };
2621 defer then_scope.instructions.deinit(mod.gpa);
2867 defer then_scope.instructions.deinit(astgen.gpa);
26222868
26232869 // declare payload to the then_scope
26242870 const then_sub_scope = &then_scope.base;
......@@ -2631,11 +2877,12 @@ fn ifExpr(
26312877
26322878 var else_scope: GenZir = .{
26332879 .parent = scope,
2634 .astgen = parent_gz.astgen,
2880 .decl_node_index = parent_gz.decl_node_index,
2881 .astgen = astgen,
26352882 .force_comptime = block_scope.force_comptime,
26362883 .instructions = .{},
26372884 };
2638 defer else_scope.instructions.deinit(mod.gpa);
2885 defer else_scope.instructions.deinit(astgen.gpa);
26392886
26402887 const else_node = if_full.ast.else_expr;
26412888 const else_info: struct {
......@@ -2681,7 +2928,7 @@ fn setCondBrPayload(
26812928) !void {
26822929 const astgen = then_scope.astgen;
26832930
2684 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len +
2931 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len +
26852932 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
26862933 then_scope.instructions.items.len + else_scope.instructions.items.len);
26872934
......@@ -2704,7 +2951,7 @@ fn setCondBrPayloadElideBlockStorePtr(
27042951) !void {
27052952 const astgen = then_scope.astgen;
27062953
2707 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len +
2954 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len +
27082955 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
27092956 then_scope.instructions.items.len + else_scope.instructions.items.len - 2);
27102957
......@@ -2732,39 +2979,42 @@ fn whileExpr(
27322979 node: ast.Node.Index,
27332980 while_full: ast.full.While,
27342981) InnerError!Zir.Inst.Ref {
2735 const mod = parent_gz.astgen.mod;
2982 const astgen = parent_gz.astgen;
2983
27362984 if (while_full.label_token) |label_token| {
2737 try checkLabelRedefinition(mod, scope, label_token);
2985 try astgen.checkLabelRedefinition(scope, label_token);
27382986 }
27392987
27402988 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
27412989 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
27422990 const loop_block = try parent_gz.addBlock(loop_tag, node);
2743 try parent_gz.instructions.append(mod.gpa, loop_block);
2991 try parent_gz.instructions.append(astgen.gpa, loop_block);
27442992
27452993 var loop_scope: GenZir = .{
27462994 .parent = scope,
2747 .astgen = parent_gz.astgen,
2995 .decl_node_index = parent_gz.decl_node_index,
2996 .astgen = astgen,
27482997 .force_comptime = parent_gz.force_comptime,
27492998 .instructions = .{},
27502999 };
27513000 loop_scope.setBreakResultLoc(rl);
2752 defer loop_scope.instructions.deinit(mod.gpa);
3001 defer loop_scope.instructions.deinit(astgen.gpa);
27533002
27543003 var continue_scope: GenZir = .{
27553004 .parent = &loop_scope.base,
2756 .astgen = parent_gz.astgen,
3005 .decl_node_index = parent_gz.decl_node_index,
3006 .astgen = astgen,
27573007 .force_comptime = loop_scope.force_comptime,
27583008 .instructions = .{},
27593009 };
2760 defer continue_scope.instructions.deinit(mod.gpa);
3010 defer continue_scope.instructions.deinit(astgen.gpa);
27613011
27623012 const cond = c: {
27633013 // TODO https://github.com/ziglang/zig/issues/7929
27643014 if (while_full.error_token) |error_token| {
2765 return mod.failTok(scope, error_token, "TODO implement while error union", .{});
3015 return astgen.failTok(error_token, "TODO implement while error union", .{});
27663016 } else if (while_full.payload_token) |payload_token| {
2767 return mod.failTok(scope, payload_token, "TODO implement while optional", .{});
3017 return astgen.failTok(payload_token, "TODO implement while optional", .{});
27683018 } else {
27693019 const bool_type_rl: ResultLoc = .{ .ty = .bool_type };
27703020 break :c try expr(&continue_scope, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr);
......@@ -2775,7 +3025,7 @@ fn whileExpr(
27753025 const condbr = try continue_scope.addCondBr(condbr_tag, node);
27763026 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
27773027 const cond_block = try loop_scope.addBlock(block_tag, node);
2778 try loop_scope.instructions.append(mod.gpa, cond_block);
3028 try loop_scope.instructions.append(astgen.gpa, cond_block);
27793029 try continue_scope.setBlockBody(cond_block);
27803030
27813031 // TODO avoid emitting the continue expr when there
......@@ -2799,11 +3049,12 @@ fn whileExpr(
27993049
28003050 var then_scope: GenZir = .{
28013051 .parent = &continue_scope.base,
2802 .astgen = parent_gz.astgen,
3052 .decl_node_index = parent_gz.decl_node_index,
3053 .astgen = astgen,
28033054 .force_comptime = continue_scope.force_comptime,
28043055 .instructions = .{},
28053056 };
2806 defer then_scope.instructions.deinit(mod.gpa);
3057 defer then_scope.instructions.deinit(astgen.gpa);
28073058
28083059 const then_sub_scope = &then_scope.base;
28093060
......@@ -2812,11 +3063,12 @@ fn whileExpr(
28123063
28133064 var else_scope: GenZir = .{
28143065 .parent = &continue_scope.base,
2815 .astgen = parent_gz.astgen,
3066 .decl_node_index = parent_gz.decl_node_index,
3067 .astgen = astgen,
28163068 .force_comptime = continue_scope.force_comptime,
28173069 .instructions = .{},
28183070 };
2819 defer else_scope.instructions.deinit(mod.gpa);
3071 defer else_scope.instructions.deinit(astgen.gpa);
28203072
28213073 const else_node = while_full.ast.else_expr;
28223074 const else_info: struct {
......@@ -2836,7 +3088,7 @@ fn whileExpr(
28363088
28373089 if (loop_scope.label) |some| {
28383090 if (!some.used) {
2839 return mod.failTok(scope, some.token, "unused while loop label", .{});
3091 return astgen.failTok(some.token, "unused while loop label", .{});
28403092 }
28413093 }
28423094 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
......@@ -2867,13 +3119,14 @@ fn forExpr(
28673119 node: ast.Node.Index,
28683120 for_full: ast.full.While,
28693121) InnerError!Zir.Inst.Ref {
2870 const mod = parent_gz.astgen.mod;
3122 const astgen = parent_gz.astgen;
3123
28713124 if (for_full.label_token) |label_token| {
2872 try checkLabelRedefinition(mod, scope, label_token);
3125 try astgen.checkLabelRedefinition(scope, label_token);
28733126 }
28743127 // Set up variables and constants.
28753128 const is_inline = parent_gz.force_comptime or for_full.inline_token != null;
2876 const tree = parent_gz.tree();
3129 const tree = &astgen.file.tree;
28773130 const token_tags = tree.tokens.items(.tag);
28783131
28793132 const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr);
......@@ -2888,24 +3141,26 @@ fn forExpr(
28883141
28893142 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
28903143 const loop_block = try parent_gz.addBlock(loop_tag, node);
2891 try parent_gz.instructions.append(mod.gpa, loop_block);
3144 try parent_gz.instructions.append(astgen.gpa, loop_block);
28923145
28933146 var loop_scope: GenZir = .{
28943147 .parent = scope,
2895 .astgen = parent_gz.astgen,
3148 .decl_node_index = parent_gz.decl_node_index,
3149 .astgen = astgen,
28963150 .force_comptime = parent_gz.force_comptime,
28973151 .instructions = .{},
28983152 };
28993153 loop_scope.setBreakResultLoc(rl);
2900 defer loop_scope.instructions.deinit(mod.gpa);
3154 defer loop_scope.instructions.deinit(astgen.gpa);
29013155
29023156 var cond_scope: GenZir = .{
29033157 .parent = &loop_scope.base,
2904 .astgen = parent_gz.astgen,
3158 .decl_node_index = parent_gz.decl_node_index,
3159 .astgen = astgen,
29053160 .force_comptime = loop_scope.force_comptime,
29063161 .instructions = .{},
29073162 };
2908 defer cond_scope.instructions.deinit(mod.gpa);
3163 defer cond_scope.instructions.deinit(astgen.gpa);
29093164
29103165 // check condition i < array_expr.len
29113166 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
......@@ -2918,7 +3173,7 @@ fn forExpr(
29183173 const condbr = try cond_scope.addCondBr(condbr_tag, node);
29193174 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
29203175 const cond_block = try loop_scope.addBlock(block_tag, node);
2921 try loop_scope.instructions.append(mod.gpa, cond_block);
3176 try loop_scope.instructions.append(astgen.gpa, cond_block);
29223177 try cond_scope.setBlockBody(cond_block);
29233178
29243179 // Increment the index variable.
......@@ -2943,11 +3198,12 @@ fn forExpr(
29433198
29443199 var then_scope: GenZir = .{
29453200 .parent = &cond_scope.base,
2946 .astgen = parent_gz.astgen,
3201 .decl_node_index = parent_gz.decl_node_index,
3202 .astgen = astgen,
29473203 .force_comptime = cond_scope.force_comptime,
29483204 .instructions = .{},
29493205 };
2950 defer then_scope.instructions.deinit(mod.gpa);
3206 defer then_scope.instructions.deinit(astgen.gpa);
29513207
29523208 var index_scope: Scope.LocalPtr = undefined;
29533209 const then_sub_scope = blk: {
......@@ -2959,9 +3215,9 @@ fn forExpr(
29593215 const is_ptr = ident != payload_token;
29603216 const value_name = tree.tokenSlice(ident);
29613217 if (!mem.eql(u8, value_name, "_")) {
2962 return mod.failNode(&then_scope.base, ident, "TODO implement for loop value payload", .{});
3218 return astgen.failNode(ident, "TODO implement for loop value payload", .{});
29633219 } else if (is_ptr) {
2964 return mod.failTok(&then_scope.base, payload_token, "pointer modifier invalid on discard", .{});
3220 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
29653221 }
29663222
29673223 const index_token = if (token_tags[ident + 1] == .comma)
......@@ -2969,15 +3225,15 @@ fn forExpr(
29693225 else
29703226 break :blk &then_scope.base;
29713227 if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {
2972 return mod.failTok(&then_scope.base, index_token, "discard of index capture; omit it instead", .{});
3228 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
29733229 }
2974 const index_name = try mod.identifierTokenString(&then_scope.base, index_token);
3230 const index_name = try astgen.identifierTokenString(index_token);
29753231 index_scope = .{
29763232 .parent = &then_scope.base,
29773233 .gen_zir = &then_scope,
29783234 .name = index_name,
29793235 .ptr = index_ptr,
2980 .src = parent_gz.tokSrcLoc(index_token),
3236 .token_src = index_token,
29813237 };
29823238 break :blk &index_scope.base;
29833239 };
......@@ -2987,11 +3243,12 @@ fn forExpr(
29873243
29883244 var else_scope: GenZir = .{
29893245 .parent = &cond_scope.base,
2990 .astgen = parent_gz.astgen,
3246 .decl_node_index = parent_gz.decl_node_index,
3247 .astgen = astgen,
29913248 .force_comptime = cond_scope.force_comptime,
29923249 .instructions = .{},
29933250 };
2994 defer else_scope.instructions.deinit(mod.gpa);
3251 defer else_scope.instructions.deinit(astgen.gpa);
29953252
29963253 const else_node = for_full.ast.else_expr;
29973254 const else_info: struct {
......@@ -3011,7 +3268,7 @@ fn forExpr(
30113268
30123269 if (loop_scope.label) |some| {
30133270 if (!some.used) {
3014 return mod.failTok(scope, some.token, "unused for loop label", .{});
3271 return astgen.failTok(some.token, "unused for loop label", .{});
30153272 }
30163273 }
30173274 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
......@@ -3069,7 +3326,7 @@ pub const SwitchProngSrc = union(enum) {
30693326 ) LazySrcLoc {
30703327 @setCold(true);
30713328 const switch_node = decl.relativeToNodeIndex(switch_node_offset);
3072 const tree = decl.namespace.file_scope.base.tree();
3329 const tree = decl.namespace.file_scope.tree;
30733330 const main_tokens = tree.nodes.items(.main_token);
30743331 const node_datas = tree.nodes.items(.data);
30753332 const node_tags = tree.nodes.items(.tag);
......@@ -3147,9 +3404,8 @@ fn switchExpr(
31473404 switch_node: ast.Node.Index,
31483405) InnerError!Zir.Inst.Ref {
31493406 const astgen = parent_gz.astgen;
3150 const mod = astgen.mod;
3151 const gpa = mod.gpa;
3152 const tree = parent_gz.tree();
3407 const gpa = astgen.gpa;
3408 const tree = &astgen.file.tree;
31533409 const node_datas = tree.nodes.items(.data);
31543410 const node_tags = tree.nodes.items(.tag);
31553411 const main_tokens = tree.nodes.items(.main_token);
......@@ -3166,8 +3422,8 @@ fn switchExpr(
31663422 var multi_cases_len: u32 = 0;
31673423 var special_prong: Zir.SpecialProng = .none;
31683424 var special_node: ast.Node.Index = 0;
3169 var else_src: ?LazySrcLoc = null;
3170 var underscore_src: ?LazySrcLoc = null;
3425 var else_src: ?ast.TokenIndex = null;
3426 var underscore_src: ?ast.TokenIndex = null;
31713427 for (case_nodes) |case_node| {
31723428 const case = switch (node_tags[case_node]) {
31733429 .switch_case_one => tree.switchCaseOne(case_node),
......@@ -3181,34 +3437,38 @@ fn switchExpr(
31813437 }
31823438 // Check for else/`_` prong.
31833439 if (case.ast.values.len == 0) {
3184 const case_src = parent_gz.tokSrcLoc(case.ast.arrow_token - 1);
3440 const case_src = case.ast.arrow_token - 1;
31853441 if (else_src) |src| {
3186 const msg = msg: {
3187 const msg = try mod.errMsg(
3188 scope,
3189 case_src,
3190 "multiple else prongs in switch expression",
3191 .{},
3192 );
3193 errdefer msg.destroy(gpa);
3194 try mod.errNote(scope, src, msg, "previous else prong is here", .{});
3195 break :msg msg;
3196 };
3197 return mod.failWithOwnedErrorMsg(scope, msg);
3442 return astgen.failTokNotes(
3443 case_src,
3444 "multiple else prongs in switch expression",
3445 .{},
3446 &[_]u32{
3447 try astgen.errNoteTok(
3448 src,
3449 "previous else prong is here",
3450 .{},
3451 ),
3452 },
3453 );
31983454 } else if (underscore_src) |some_underscore| {
3199 const msg = msg: {
3200 const msg = try mod.errMsg(
3201 scope,
3202 parent_gz.nodeSrcLoc(switch_node),
3203 "else and '_' prong in switch expression",
3204 .{},
3205 );
3206 errdefer msg.destroy(gpa);
3207 try mod.errNote(scope, case_src, msg, "else prong is here", .{});
3208 try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{});
3209 break :msg msg;
3210 };
3211 return mod.failWithOwnedErrorMsg(scope, msg);
3455 return astgen.failNodeNotes(
3456 switch_node,
3457 "else and '_' prong in switch expression",
3458 .{},
3459 &[_]u32{
3460 try astgen.errNoteTok(
3461 case_src,
3462 "else prong is here",
3463 .{},
3464 ),
3465 try astgen.errNoteTok(
3466 some_underscore,
3467 "'_' prong is here",
3468 .{},
3469 ),
3470 },
3471 );
32123472 }
32133473 special_node = case_node;
32143474 special_prong = .@"else";
......@@ -3218,34 +3478,38 @@ fn switchExpr(
32183478 node_tags[case.ast.values[0]] == .identifier and
32193479 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
32203480 {
3221 const case_src = parent_gz.tokSrcLoc(case.ast.arrow_token - 1);
3481 const case_src = case.ast.arrow_token - 1;
32223482 if (underscore_src) |src| {
3223 const msg = msg: {
3224 const msg = try mod.errMsg(
3225 scope,
3226 case_src,
3227 "multiple '_' prongs in switch expression",
3228 .{},
3229 );
3230 errdefer msg.destroy(gpa);
3231 try mod.errNote(scope, src, msg, "previous '_' prong is here", .{});
3232 break :msg msg;
3233 };
3234 return mod.failWithOwnedErrorMsg(scope, msg);
3483 return astgen.failTokNotes(
3484 case_src,
3485 "multiple '_' prongs in switch expression",
3486 .{},
3487 &[_]u32{
3488 try astgen.errNoteTok(
3489 src,
3490 "previous '_' prong is here",
3491 .{},
3492 ),
3493 },
3494 );
32353495 } else if (else_src) |some_else| {
3236 const msg = msg: {
3237 const msg = try mod.errMsg(
3238 scope,
3239 parent_gz.nodeSrcLoc(switch_node),
3240 "else and '_' prong in switch expression",
3241 .{},
3242 );
3243 errdefer msg.destroy(gpa);
3244 try mod.errNote(scope, some_else, msg, "else prong is here", .{});
3245 try mod.errNote(scope, case_src, msg, "'_' prong is here", .{});
3246 break :msg msg;
3247 };
3248 return mod.failWithOwnedErrorMsg(scope, msg);
3496 return astgen.failNodeNotes(
3497 switch_node,
3498 "else and '_' prong in switch expression",
3499 .{},
3500 &[_]u32{
3501 try astgen.errNoteTok(
3502 some_else,
3503 "else prong is here",
3504 .{},
3505 ),
3506 try astgen.errNoteTok(
3507 case_src,
3508 "'_' prong is here",
3509 .{},
3510 ),
3511 },
3512 );
32493513 }
32503514 special_node = case_node;
32513515 special_prong = .under;
......@@ -3281,6 +3545,7 @@ fn switchExpr(
32813545
32823546 var block_scope: GenZir = .{
32833547 .parent = scope,
3548 .decl_node_index = parent_gz.decl_node_index,
32843549 .astgen = astgen,
32853550 .force_comptime = parent_gz.force_comptime,
32863551 .instructions = .{},
......@@ -3294,6 +3559,7 @@ fn switchExpr(
32943559 // We re-use this same scope for all cases, including the special prong, if any.
32953560 var case_scope: GenZir = .{
32963561 .parent = &block_scope.base,
3562 .decl_node_index = parent_gz.decl_node_index,
32973563 .astgen = astgen,
32983564 .force_comptime = parent_gz.force_comptime,
32993565 .instructions = .{},
......@@ -3317,7 +3583,7 @@ fn switchExpr(
33173583 const is_ptr = ident != payload_token;
33183584 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
33193585 if (is_ptr) {
3320 return mod.failTok(&case_scope.base, payload_token, "pointer modifier invalid on discard", .{});
3586 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
33213587 }
33223588 break :blk &case_scope.base;
33233589 }
......@@ -3332,18 +3598,18 @@ fn switchExpr(
33323598 .prong_index = undefined,
33333599 } },
33343600 });
3335 const capture_name = try mod.identifierTokenString(&parent_gz.base, payload_token);
3601 const capture_name = try astgen.identifierTokenString(payload_token);
33363602 capture_val_scope = .{
33373603 .parent = &case_scope.base,
33383604 .gen_zir = &case_scope,
33393605 .name = capture_name,
33403606 .inst = capture,
3341 .src = parent_gz.tokSrcLoc(payload_token),
3607 .token_src = payload_token,
33423608 };
33433609 break :blk &capture_val_scope.base;
33443610 };
33453611 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
3346 if (!astgen.refIsNoReturn(case_result)) {
3612 if (!parent_gz.refIsNoReturn(case_result)) {
33473613 block_scope.break_count += 1;
33483614 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
33493615 }
......@@ -3398,7 +3664,7 @@ fn switchExpr(
33983664 const is_ptr = ident != payload_token;
33993665 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
34003666 if (is_ptr) {
3401 return mod.failTok(&case_scope.base, payload_token, "pointer modifier invalid on discard", .{});
3667 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
34023668 }
34033669 break :blk &case_scope.base;
34043670 }
......@@ -3424,13 +3690,13 @@ fn switchExpr(
34243690 .prong_index = capture_index,
34253691 } },
34263692 });
3427 const capture_name = try mod.identifierTokenString(&parent_gz.base, payload_token);
3693 const capture_name = try astgen.identifierTokenString(payload_token);
34283694 capture_val_scope = .{
34293695 .parent = &case_scope.base,
34303696 .gen_zir = &case_scope,
34313697 .name = capture_name,
34323698 .inst = capture,
3433 .src = parent_gz.tokSrcLoc(payload_token),
3699 .token_src = payload_token,
34343700 };
34353701 break :blk &capture_val_scope.base;
34363702 };
......@@ -3464,7 +3730,7 @@ fn switchExpr(
34643730 }
34653731
34663732 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
3467 if (!astgen.refIsNoReturn(case_result)) {
3733 if (!parent_gz.refIsNoReturn(case_result)) {
34683734 block_scope.break_count += 1;
34693735 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
34703736 }
......@@ -3477,7 +3743,7 @@ fn switchExpr(
34773743 const item_node = case.ast.values[0];
34783744 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
34793745 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
3480 if (!astgen.refIsNoReturn(case_result)) {
3746 if (!parent_gz.refIsNoReturn(case_result)) {
34813747 block_scope.break_count += 1;
34823748 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
34833749 }
......@@ -3529,7 +3795,7 @@ fn switchExpr(
35293795 if (!strat.elide_store_to_block_ptr_instructions) {
35303796 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
35313797 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
3532 return astgen.indexToRef(switch_block);
3798 return parent_gz.indexToRef(switch_block);
35333799 }
35343800
35353801 // There will necessarily be a store_to_block_ptr for
......@@ -3571,7 +3837,7 @@ fn switchExpr(
35713837 .lhs = block_scope.rl_ty_inst,
35723838 .rhs = zir_datas[break_inst].@"break".operand,
35733839 };
3574 zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst);
3840 zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst);
35753841 } else {
35763842 scalar_cases_payload.items[body_len_index] -= 1;
35773843 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
......@@ -3611,7 +3877,7 @@ fn switchExpr(
36113877 .lhs = block_scope.rl_ty_inst,
36123878 .rhs = zir_datas[break_inst].@"break".operand,
36133879 };
3614 zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst);
3880 zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst);
36153881 } else {
36163882 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
36173883 scalar_cases_payload.items[body_len_index] -= 1;
......@@ -3656,7 +3922,7 @@ fn switchExpr(
36563922 .lhs = block_scope.rl_ty_inst,
36573923 .rhs = zir_datas[break_inst].@"break".operand,
36583924 };
3659 zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst);
3925 zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst);
36603926 } else {
36613927 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
36623928 multi_cases_payload.items[body_len_index] -= 1;
......@@ -3667,7 +3933,7 @@ fn switchExpr(
36673933 }
36683934 }
36693935
3670 const block_ref = astgen.indexToRef(switch_block);
3936 const block_ref = parent_gz.indexToRef(switch_block);
36713937 switch (rl) {
36723938 .ref => return block_ref,
36733939 else => return rvalue(parent_gz, scope, rl, block_ref, switch_node),
......@@ -3727,13 +3993,14 @@ fn switchExpr(
37273993 }
37283994 }
37293995
3730 return astgen.indexToRef(switch_block);
3996 return parent_gz.indexToRef(switch_block);
37313997 },
37323998 }
37333999}
37344000
37354001fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
3736 const tree = gz.tree();
4002 const astgen = gz.astgen;
4003 const tree = &astgen.file.tree;
37374004 const node_datas = tree.nodes.items(.data);
37384005 const main_tokens = tree.nodes.items(.main_token);
37394006
......@@ -3760,14 +4027,13 @@ fn identifier(
37604027 defer tracy.end();
37614028
37624029 const astgen = gz.astgen;
3763 const mod = astgen.mod;
3764 const tree = gz.tree();
4030 const tree = &astgen.file.tree;
37654031 const main_tokens = tree.nodes.items(.main_token);
37664032
37674033 const ident_token = main_tokens[ident];
3768 const ident_name = try mod.identifierTokenString(scope, ident_token);
4034 const ident_name = try astgen.identifierTokenString(ident_token);
37694035 if (mem.eql(u8, ident_name, "_")) {
3770 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
4036 return astgen.failNode(ident, "TODO implement '_' identifier", .{});
37714037 }
37724038
37734039 if (simple_types.get(ident_name)) |zir_const_ref| {
......@@ -3782,8 +4048,7 @@ fn identifier(
37824048 false => .unsigned,
37834049 };
37844050 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
3785 error.Overflow => return mod.failNode(
3786 scope,
4051 error.Overflow => return astgen.failNode(
37874052 ident,
37884053 "primitive integer type '{s}' exceeds maximum bit width of 65535",
37894054 .{ident_name},
......@@ -3793,7 +4058,7 @@ fn identifier(
37934058 const result = try gz.add(.{
37944059 .tag = .int_type,
37954060 .data = .{ .int_type = .{
3796 .src_node = astgen.decl.nodeIndexToRelative(ident),
4061 .src_node = gz.nodeIndexToRelative(ident),
37974062 .signedness = signedness,
37984063 .bit_count = bit_count,
37994064 } },
......@@ -3850,19 +4115,15 @@ fn stringLiteral(
38504115 rl: ResultLoc,
38514116 node: ast.Node.Index,
38524117) InnerError!Zir.Inst.Ref {
3853 const tree = gz.tree();
4118 const tree = gz.astgen.file.tree;
38544119 const main_tokens = tree.nodes.items(.main_token);
3855 const string_bytes = &gz.astgen.string_bytes;
3856 const str_index = string_bytes.items.len;
38574120 const str_lit_token = main_tokens[node];
3858 const token_bytes = tree.tokenSlice(str_lit_token);
3859 try gz.astgen.mod.parseStrLit(scope, str_lit_token, string_bytes, token_bytes, 0);
3860 const str_len = string_bytes.items.len - str_index;
4121 const str = try gz.strLitAsString(str_lit_token);
38614122 const result = try gz.add(.{
38624123 .tag = .str,
38634124 .data = .{ .str = .{
3864 .start = @intCast(u32, str_index),
3865 .len = @intCast(u32, str_len),
4125 .start = str.index,
4126 .len = str.len,
38664127 } },
38674128 });
38684129 return rvalue(gz, scope, rl, result, node);
......@@ -3874,14 +4135,15 @@ fn multilineStringLiteral(
38744135 rl: ResultLoc,
38754136 node: ast.Node.Index,
38764137) InnerError!Zir.Inst.Ref {
3877 const tree = gz.tree();
4138 const astgen = gz.astgen;
4139 const tree = &astgen.file.tree;
38784140 const node_datas = tree.nodes.items(.data);
38794141 const main_tokens = tree.nodes.items(.main_token);
38804142
38814143 const start = node_datas[node].lhs;
38824144 const end = node_datas[node].rhs;
38834145
3884 const gpa = gz.astgen.mod.gpa;
4146 const gpa = gz.astgen.gpa;
38854147 const string_bytes = &gz.astgen.string_bytes;
38864148 const str_index = string_bytes.items.len;
38874149
......@@ -3912,8 +4174,8 @@ fn multilineStringLiteral(
39124174}
39134175
39144176fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
3915 const mod = gz.astgen.mod;
3916 const tree = gz.tree();
4177 const astgen = gz.astgen;
4178 const tree = &astgen.file.tree;
39174179 const main_tokens = tree.nodes.items(.main_token);
39184180 const main_token = main_tokens[node];
39194181 const slice = tree.tokenSlice(main_token);
......@@ -3923,8 +4185,12 @@ fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index)
39234185 error.InvalidCharacter => {
39244186 const bad_byte = slice[bad_index];
39254187 const token_starts = tree.tokens.items(.start);
3926 const src_off = @intCast(u32, token_starts[main_token] + bad_index);
3927 return mod.failOff(scope, src_off, "invalid character: '{c}'\n", .{bad_byte});
4188 return astgen.failOff(
4189 main_token,
4190 @intCast(u32, bad_index),
4191 "invalid character: '{c}'\n",
4192 .{bad_byte},
4193 );
39284194 },
39294195 };
39304196 const result = try gz.addInt(value);
......@@ -3937,7 +4203,8 @@ fn integerLiteral(
39374203 rl: ResultLoc,
39384204 node: ast.Node.Index,
39394205) InnerError!Zir.Inst.Ref {
3940 const tree = gz.tree();
4206 const astgen = gz.astgen;
4207 const tree = &astgen.file.tree;
39414208 const main_tokens = tree.nodes.items(.main_token);
39424209 const int_token = main_tokens[node];
39434210 const prefixed_bytes = tree.tokenSlice(int_token);
......@@ -3949,7 +4216,7 @@ fn integerLiteral(
39494216 };
39504217 return rvalue(gz, scope, rl, result, node);
39514218 } else |err| {
3952 return gz.astgen.mod.failNode(scope, node, "TODO implement int literals that don't fit in a u64", .{});
4219 return gz.astgen.failNode(node, "TODO implement int literals that don't fit in a u64", .{});
39534220 }
39544221}
39554222
......@@ -3959,15 +4226,16 @@ fn floatLiteral(
39594226 rl: ResultLoc,
39604227 node: ast.Node.Index,
39614228) InnerError!Zir.Inst.Ref {
3962 const arena = gz.astgen.arena;
3963 const tree = gz.tree();
4229 const astgen = gz.astgen;
4230 const arena = astgen.arena;
4231 const tree = &astgen.file.tree;
39644232 const main_tokens = tree.nodes.items(.main_token);
39654233
39664234 const main_token = main_tokens[node];
39674235 const bytes = tree.tokenSlice(main_token);
39684236 if (bytes.len > 2 and bytes[1] == 'x') {
39694237 assert(bytes[0] == '0'); // validated by tokenizer
3970 return gz.astgen.mod.failTok(scope, main_token, "TODO implement hex floats", .{});
4238 return astgen.failTok(main_token, "TODO implement hex floats", .{});
39714239 }
39724240 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
39734241 error.InvalidCharacter => unreachable, // validated by tokenizer
......@@ -3999,9 +4267,9 @@ fn asmExpr(
39994267 node: ast.Node.Index,
40004268 full: ast.full.Asm,
40014269) InnerError!Zir.Inst.Ref {
4002 const mod = gz.astgen.mod;
4003 const arena = gz.astgen.arena;
4004 const tree = gz.tree();
4270 const astgen = gz.astgen;
4271 const arena = astgen.arena;
4272 const tree = &astgen.file.tree;
40054273 const main_tokens = tree.nodes.items(.main_token);
40064274 const node_datas = tree.nodes.items(.data);
40074275
......@@ -4010,7 +4278,7 @@ fn asmExpr(
40104278 if (full.outputs.len != 0) {
40114279 // when implementing this be sure to add test coverage for the asm return type
40124280 // not resolving into a type (the node_offset_asm_ret_ty field of LazySrcLoc)
4013 return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});
4281 return astgen.failTok(full.ast.asm_token, "TODO implement asm with an output", .{});
40144282 }
40154283
40164284 const constraints = try arena.alloc(u32, full.inputs.len);
......@@ -4018,11 +4286,11 @@ fn asmExpr(
40184286
40194287 for (full.inputs) |input, i| {
40204288 const constraint_token = main_tokens[input] + 2;
4021 const string_bytes = &gz.astgen.string_bytes;
4289 const string_bytes = &astgen.string_bytes;
40224290 constraints[i] = @intCast(u32, string_bytes.items.len);
40234291 const token_bytes = tree.tokenSlice(constraint_token);
4024 try mod.parseStrLit(scope, constraint_token, string_bytes, token_bytes, 0);
4025 try string_bytes.append(mod.gpa, 0);
4292 try astgen.parseStrLit(constraint_token, string_bytes, token_bytes, 0);
4293 try string_bytes.append(astgen.gpa, 0);
40264294
40274295 args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs);
40284296 }
......@@ -4036,10 +4304,10 @@ fn asmExpr(
40364304 .clobbers_len = 0, // TODO implement asm clobbers
40374305 });
40384306
4039 try gz.astgen.extra.ensureCapacity(mod.gpa, gz.astgen.extra.items.len +
4307 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len +
40404308 args.len + constraints.len);
4041 gz.astgen.appendRefsAssumeCapacity(args);
4042 gz.astgen.extra.appendSliceAssumeCapacity(constraints);
4309 astgen.appendRefsAssumeCapacity(args);
4310 astgen.extra.appendSliceAssumeCapacity(constraints);
40434311
40444312 return rvalue(gz, scope, rl, result, node);
40454313}
......@@ -4068,7 +4336,7 @@ fn as(
40684336
40694337 .inferred_ptr => |result_alloc| {
40704338 // TODO here we should be able to resolve the inference; we now have a type for the result.
4071 return gz.astgen.mod.failNode(scope, node, "TODO implement @as with inferred-type result location pointer", .{});
4339 return gz.astgen.failNode(node, "TODO implement @as with inferred-type result location pointer", .{});
40724340 },
40734341 }
40744342}
......@@ -4088,11 +4356,12 @@ fn asRlPtr(
40884356
40894357 var as_scope: GenZir = .{
40904358 .parent = scope,
4359 .decl_node_index = parent_gz.decl_node_index,
40914360 .astgen = astgen,
40924361 .force_comptime = parent_gz.force_comptime,
40934362 .instructions = .{},
40944363 };
4095 defer as_scope.instructions.deinit(astgen.mod.gpa);
4364 defer as_scope.instructions.deinit(astgen.gpa);
40964365
40974366 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
40984367 const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);
......@@ -4102,9 +4371,9 @@ fn asRlPtr(
41024371 const zir_tags = astgen.instructions.items(.tag);
41034372 const zir_datas = astgen.instructions.items(.data);
41044373 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
4105 try parent_zir.ensureCapacity(astgen.mod.gpa, expected_len);
4374 try parent_zir.ensureCapacity(astgen.gpa, expected_len);
41064375 for (as_scope.instructions.items) |src_inst| {
4107 if (astgen.indexToRef(src_inst) == as_scope.rl_ptr) continue;
4376 if (parent_gz.indexToRef(src_inst) == as_scope.rl_ptr) continue;
41084377 if (zir_tags[src_inst] == .store_to_block_ptr) {
41094378 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
41104379 }
......@@ -4114,7 +4383,7 @@ fn asRlPtr(
41144383 const casted_result = try parent_gz.addBin(.as, dest_type, result);
41154384 return rvalue(parent_gz, scope, rl, casted_result, operand_node);
41164385 } else {
4117 try parent_zir.appendSlice(astgen.mod.gpa, as_scope.instructions.items);
4386 try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
41184387 return result;
41194388 }
41204389}
......@@ -4127,7 +4396,7 @@ fn bitCast(
41274396 lhs: ast.Node.Index,
41284397 rhs: ast.Node.Index,
41294398) InnerError!Zir.Inst.Ref {
4130 const mod = gz.astgen.mod;
4399 const astgen = gz.astgen;
41314400 const dest_type = try typeExpr(gz, scope, lhs);
41324401 switch (rl) {
41334402 .none, .discard, .ty => {
......@@ -4144,11 +4413,11 @@ fn bitCast(
41444413 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);
41454414 },
41464415 .block_ptr => |block_ptr| {
4147 return mod.failNode(scope, node, "TODO implement @bitCast with result location inferred peer types", .{});
4416 return astgen.failNode(node, "TODO implement @bitCast with result location inferred peer types", .{});
41484417 },
41494418 .inferred_ptr => |result_alloc| {
41504419 // TODO here we should be able to resolve the inference; we now have a type for the result.
4151 return mod.failNode(scope, node, "TODO implement @bitCast with inferred-type result location pointer", .{});
4420 return astgen.failNode(node, "TODO implement @bitCast with inferred-type result location pointer", .{});
41524421 },
41534422 }
41544423}
......@@ -4161,7 +4430,7 @@ fn typeOf(
41614430 params: []const ast.Node.Index,
41624431) InnerError!Zir.Inst.Ref {
41634432 if (params.len < 1) {
4164 return gz.astgen.mod.failNode(scope, node, "expected at least 1 argument, found 0", .{});
4433 return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{});
41654434 }
41664435 if (params.len == 1) {
41674436 const result = try gz.addUnNode(.typeof, try expr(gz, scope, .none, params[0]), node);
......@@ -4188,8 +4457,8 @@ fn builtinCall(
41884457 node: ast.Node.Index,
41894458 params: []const ast.Node.Index,
41904459) InnerError!Zir.Inst.Ref {
4191 const mod = gz.astgen.mod;
4192 const tree = gz.tree();
4460 const astgen = gz.astgen;
4461 const tree = &astgen.file.tree;
41934462 const main_tokens = tree.nodes.items(.main_token);
41944463
41954464 const builtin_token = main_tokens[node];
......@@ -4201,14 +4470,14 @@ fn builtinCall(
42014470 // Also, some builtins have a variable number of parameters.
42024471
42034472 const info = BuiltinFn.list.get(builtin_name) orelse {
4204 return mod.failNode(scope, node, "invalid builtin function: '{s}'", .{
4473 return astgen.failNode(node, "invalid builtin function: '{s}'", .{
42054474 builtin_name,
42064475 });
42074476 };
42084477 if (info.param_count) |expected| {
42094478 if (expected != params.len) {
42104479 const s = if (expected == 1) "" else "s";
4211 return mod.failNode(scope, node, "expected {d} parameter{s}, found {d}", .{
4480 return astgen.failNode(node, "expected {d} parameter{s}, found {d}", .{
42124481 expected, s, params.len,
42134482 });
42144483 }
......@@ -4241,7 +4510,7 @@ fn builtinCall(
42414510 .breakpoint => {
42424511 _ = try gz.add(.{
42434512 .tag = .breakpoint,
4244 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(node) },
4513 .data = .{ .node = gz.nodeIndexToRelative(node) },
42454514 });
42464515 return rvalue(gz, scope, rl, .void_value, node);
42474516 },
......@@ -4271,8 +4540,8 @@ fn builtinCall(
42714540 return rvalue(gz, scope, rl, result, node);
42724541 },
42734542 .compile_log => {
4274 const arg_refs = try mod.gpa.alloc(Zir.Inst.Ref, params.len);
4275 defer mod.gpa.free(arg_refs);
4543 const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len);
4544 defer astgen.gpa.free(arg_refs);
42764545
42774546 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);
42784547
......@@ -4432,7 +4701,7 @@ fn builtinCall(
44324701 .Type,
44334702 .type_name,
44344703 .union_init,
4435 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{
4704 => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
44364705 builtin_name,
44374706 }),
44384707
......@@ -4441,7 +4710,7 @@ fn builtinCall(
44414710 .Frame,
44424711 .frame_address,
44434712 .frame_size,
4444 => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
4713 => return astgen.failNode(node, "async and related features are not yet supported", .{}),
44454714 }
44464715}
44474716
......@@ -4452,14 +4721,14 @@ fn callExpr(
44524721 node: ast.Node.Index,
44534722 call: ast.full.Call,
44544723) InnerError!Zir.Inst.Ref {
4455 const mod = gz.astgen.mod;
4724 const astgen = gz.astgen;
44564725 if (call.async_token) |async_token| {
4457 return mod.failTok(scope, async_token, "async and related features are not yet supported", .{});
4726 return astgen.failTok(async_token, "async and related features are not yet supported", .{});
44584727 }
44594728 const lhs = try expr(gz, scope, .none, call.ast.fn_expr);
44604729
4461 const args = try mod.gpa.alloc(Zir.Inst.Ref, call.ast.params.len);
4462 defer mod.gpa.free(args);
4730 const args = try astgen.gpa.alloc(Zir.Inst.Ref, call.ast.params.len);
4731 defer astgen.gpa.free(args);
44634732
44644733 for (call.ast.params) |param_node, i| {
44654734 const param_type = try gz.add(.{
......@@ -4482,10 +4751,10 @@ fn callExpr(
44824751 true => break :res try gz.addUnNode(.call_none, lhs, node),
44834752 false => .call,
44844753 },
4485 .async_kw => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
4754 .async_kw => return astgen.failNode(node, "async and related features are not yet supported", .{}),
44864755 .never_tail => unreachable,
44874756 .never_inline => unreachable,
4488 .no_async => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),
4757 .no_async => return astgen.failNode(node, "async and related features are not yet supported", .{}),
44894758 .always_tail => unreachable,
44904759 .always_inline => unreachable,
44914760 .compile_time => .call_compile_time,
......@@ -4768,7 +5037,7 @@ fn rvalue(
47685037 },
47695038 .ref => {
47705039 // We need a pointer but we have a value.
4771 const tree = gz.tree();
5040 const tree = &gz.astgen.file.tree;
47725041 const src_token = tree.firstToken(src_node);
47735042 return gz.addUnTok(.ref, result, src_token);
47745043 },
......@@ -4854,3 +5123,263 @@ fn rvalue(
48545123 },
48555124 }
48565125}
5126
5127/// Given an identifier token, obtain the string for it.
5128/// If the token uses @"" syntax, parses as a string, reports errors if applicable,
5129/// and allocates the result within `scope.arena()`.
5130/// Otherwise, returns a reference to the source code bytes directly.
5131/// See also `appendIdentStr` and `parseStrLit`.
5132pub fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 {
5133 const tree = &astgen.file.tree;
5134 const token_tags = tree.tokens.items(.tag);
5135 assert(token_tags[token] == .identifier);
5136 const ident_name = tree.tokenSlice(token);
5137 if (!mem.startsWith(u8, ident_name, "@")) {
5138 return ident_name;
5139 }
5140 var buf: ArrayListUnmanaged(u8) = .{};
5141 defer buf.deinit(astgen.gpa);
5142 try astgen.parseStrLit(token, &buf, ident_name, 1);
5143 const duped = try astgen.arena.dupe(u8, buf.items);
5144 return duped;
5145}
5146
5147/// Given an identifier token, obtain the string for it (possibly parsing as a string
5148/// literal if it is @"" syntax), and append the string to `buf`.
5149/// See also `identifierTokenString` and `parseStrLit`.
5150pub fn appendIdentStr(
5151 astgen: *AstGen,
5152 token: ast.TokenIndex,
5153 buf: *ArrayListUnmanaged(u8),
5154) InnerError!void {
5155 const tree = &astgen.file.tree;
5156 const token_tags = tree.tokens.items(.tag);
5157 assert(token_tags[token] == .identifier);
5158 const ident_name = tree.tokenSlice(token);
5159 if (!mem.startsWith(u8, ident_name, "@")) {
5160 return buf.appendSlice(astgen.gpa, ident_name);
5161 } else {
5162 return astgen.parseStrLit(token, buf, ident_name, 1);
5163 }
5164}
5165
5166/// Appends the result to `buf`.
5167pub fn parseStrLit(
5168 astgen: *AstGen,
5169 token: ast.TokenIndex,
5170 buf: *ArrayListUnmanaged(u8),
5171 bytes: []const u8,
5172 offset: u32,
5173) InnerError!void {
5174 const tree = &astgen.file.tree;
5175 const raw_string = bytes[offset..];
5176 var buf_managed = buf.toManaged(astgen.gpa);
5177 const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string);
5178 buf.* = buf_managed.toUnmanaged();
5179 switch (try result) {
5180 .success => return,
5181 .invalid_character => |bad_index| {
5182 return astgen.failOff(
5183 token,
5184 offset + @intCast(u32, bad_index),
5185 "invalid string literal character: '{c}'",
5186 .{raw_string[bad_index]},
5187 );
5188 },
5189 .expected_hex_digits => |bad_index| {
5190 return astgen.failOff(
5191 token,
5192 offset + @intCast(u32, bad_index),
5193 "expected hex digits after '\\x'",
5194 .{},
5195 );
5196 },
5197 .invalid_hex_escape => |bad_index| {
5198 return astgen.failOff(
5199 token,
5200 offset + @intCast(u32, bad_index),
5201 "invalid hex digit: '{c}'",
5202 .{raw_string[bad_index]},
5203 );
5204 },
5205 .invalid_unicode_escape => |bad_index| {
5206 return astgen.failOff(
5207 token,
5208 offset + @intCast(u32, bad_index),
5209 "invalid unicode digit: '{c}'",
5210 .{raw_string[bad_index]},
5211 );
5212 },
5213 .missing_matching_rbrace => |bad_index| {
5214 return astgen.failOff(
5215 token,
5216 offset + @intCast(u32, bad_index),
5217 "missing matching '}}' character",
5218 .{},
5219 );
5220 },
5221 .expected_unicode_digits => |bad_index| {
5222 return astgen.failOff(
5223 token,
5224 offset + @intCast(u32, bad_index),
5225 "expected unicode digits after '\\u'",
5226 .{},
5227 );
5228 },
5229 }
5230}
5231
5232pub fn failNode(
5233 astgen: *AstGen,
5234 node: ast.Node.Index,
5235 comptime format: []const u8,
5236 args: anytype,
5237) InnerError {
5238 return astgen.failNodeNotes(node, format, args, &[0]u32{});
5239}
5240
5241pub fn failNodeNotes(
5242 astgen: *AstGen,
5243 node: ast.Node.Index,
5244 comptime format: []const u8,
5245 args: anytype,
5246 notes: []const u32,
5247) InnerError {
5248 @setCold(true);
5249 const string_bytes = &astgen.string_bytes;
5250 const msg = @intCast(u32, string_bytes.items.len);
5251 {
5252 var managed = string_bytes.toManaged(astgen.gpa);
5253 defer string_bytes.* = managed.toUnmanaged();
5254 try managed.writer().print(format, args);
5255 }
5256 const notes_index: u32 = if (notes.len != 0) blk: {
5257 const notes_start = astgen.extra.items.len;
5258 try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len);
5259 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
5260 astgen.extra.appendSliceAssumeCapacity(notes);
5261 break :blk @intCast(u32, notes_start);
5262 } else 0;
5263 try astgen.compile_errors.append(astgen.gpa, .{
5264 .msg = msg,
5265 .node = node,
5266 .token = 0,
5267 .byte_offset = 0,
5268 .notes = notes_index,
5269 });
5270 return error.AnalysisFail;
5271}
5272
5273pub fn failTok(
5274 astgen: *AstGen,
5275 token: ast.TokenIndex,
5276 comptime format: []const u8,
5277 args: anytype,
5278) InnerError {
5279 return astgen.failTokNotes(token, format, args, &[0]u32{});
5280}
5281
5282pub fn failTokNotes(
5283 astgen: *AstGen,
5284 token: ast.TokenIndex,
5285 comptime format: []const u8,
5286 args: anytype,
5287 notes: []const u32,
5288) InnerError {
5289 @setCold(true);
5290 const string_bytes = &astgen.string_bytes;
5291 const msg = @intCast(u32, string_bytes.items.len);
5292 {
5293 var managed = string_bytes.toManaged(astgen.gpa);
5294 defer string_bytes.* = managed.toUnmanaged();
5295 try managed.writer().print(format, args);
5296 }
5297 const notes_index: u32 = if (notes.len != 0) blk: {
5298 const notes_start = astgen.extra.items.len;
5299 try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len);
5300 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
5301 astgen.extra.appendSliceAssumeCapacity(notes);
5302 break :blk @intCast(u32, notes_start);
5303 } else 0;
5304 try astgen.compile_errors.append(astgen.gpa, .{
5305 .msg = msg,
5306 .node = 0,
5307 .token = token,
5308 .byte_offset = 0,
5309 .notes = notes_index,
5310 });
5311 return error.AnalysisFail;
5312}
5313
5314/// Same as `fail`, except given an absolute byte offset, and the function sets up the `LazySrcLoc`
5315/// for pointing at it relatively by subtracting from the containing `Decl`.
5316pub fn failOff(
5317 astgen: *AstGen,
5318 token: ast.TokenIndex,
5319 byte_offset: u32,
5320 comptime format: []const u8,
5321 args: anytype,
5322) InnerError {
5323 @setCold(true);
5324 const string_bytes = &astgen.string_bytes;
5325 const msg = @intCast(u32, string_bytes.items.len);
5326 {
5327 var managed = string_bytes.toManaged(astgen.gpa);
5328 defer string_bytes.* = managed.toUnmanaged();
5329 try managed.writer().print(format, args);
5330 }
5331 try astgen.compile_errors.append(astgen.gpa, .{
5332 .msg = msg,
5333 .node = 0,
5334 .token = token,
5335 .byte_offset = byte_offset,
5336 .notes = 0,
5337 });
5338 return error.AnalysisFail;
5339}
5340
5341pub fn errNoteTok(
5342 astgen: *AstGen,
5343 token: ast.TokenIndex,
5344 comptime format: []const u8,
5345 args: anytype,
5346) Allocator.Error!u32 {
5347 @setCold(true);
5348 const string_bytes = &astgen.string_bytes;
5349 const msg = @intCast(u32, string_bytes.items.len);
5350 {
5351 var managed = string_bytes.toManaged(astgen.gpa);
5352 defer string_bytes.* = managed.toUnmanaged();
5353 try managed.writer().print(format, args);
5354 }
5355 return astgen.addExtra(Zir.Inst.CompileErrors.Item{
5356 .msg = msg,
5357 .node = 0,
5358 .token = token,
5359 .byte_offset = 0,
5360 .notes = 0,
5361 });
5362}
5363
5364pub fn errNoteNode(
5365 astgen: *AstGen,
5366 node: ast.Node.Index,
5367 comptime format: []const u8,
5368 args: anytype,
5369) Allocator.Error!u32 {
5370 @setCold(true);
5371 const string_bytes = &astgen.string_bytes;
5372 const msg = @intCast(u32, string_bytes.items.len);
5373 {
5374 var managed = string_bytes.toManaged(astgen.gpa);
5375 defer string_bytes.* = managed.toUnmanaged();
5376 try managed.writer().print(format, args);
5377 }
5378 return astgen.addExtra(Zir.Inst.CompileErrors.Item{
5379 .msg = msg,
5380 .node = node,
5381 .token = 0,
5382 .byte_offset = 0,
5383 .notes = 0,
5384 });
5385}
src/Compilation.zig+103-48
......@@ -49,6 +49,11 @@ work_queue: std.fifo.LinearFifo(Job, .Dynamic),
4949/// gets linked with the Compilation.
5050c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
5151
52/// These jobs are to tokenize, parse, and astgen files, which may be outdated
53/// since the last compilation, as well as scan for `@import` and queue up
54/// additional jobs corresponding to those new files.
55astgen_work_queue: std.fifo.LinearFifo(*Module.Scope.File, .Dynamic),
56
5257/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
5358/// This data is accessed by multiple threads and is protected by `mutex`.
5459failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
......@@ -141,6 +146,7 @@ emit_analysis: ?EmitLoc,
141146emit_docs: ?EmitLoc,
142147
143148work_queue_wait_group: WaitGroup,
149astgen_wait_group: WaitGroup,
144150
145151pub const InnerError = Module.InnerError;
146152
......@@ -1210,6 +1216,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12101216 .emit_docs = options.emit_docs,
12111217 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
12121218 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
1219 .astgen_work_queue = std.fifo.LinearFifo(*Module.Scope.File, .Dynamic).init(gpa),
12131220 .keep_source_files_loaded = options.keep_source_files_loaded,
12141221 .use_clang = use_clang,
12151222 .clang_argv = options.clang_argv,
......@@ -1238,6 +1245,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12381245 .test_evented_io = options.test_evented_io,
12391246 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
12401247 .work_queue_wait_group = undefined,
1248 .astgen_wait_group = undefined,
12411249 };
12421250 break :comp comp;
12431251 };
......@@ -1246,6 +1254,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12461254 try comp.work_queue_wait_group.init();
12471255 errdefer comp.work_queue_wait_group.deinit();
12481256
1257 try comp.astgen_wait_group.init();
1258 errdefer comp.astgen_wait_group.deinit();
1259
12491260 if (comp.bin_file.options.module) |mod| {
12501261 try comp.work_queue.writeItem(.{ .generate_builtin_zig = {} });
12511262 }
......@@ -1381,6 +1392,7 @@ pub fn destroy(self: *Compilation) void {
13811392 const gpa = self.gpa;
13821393 self.work_queue.deinit();
13831394 self.c_object_work_queue.deinit();
1395 self.astgen_work_queue.deinit();
13841396
13851397 {
13861398 var it = self.crt_files.iterator();
......@@ -1431,6 +1443,7 @@ pub fn destroy(self: *Compilation) void {
14311443 if (self.owned_link_dir) |*dir| dir.close();
14321444
14331445 self.work_queue_wait_group.deinit();
1446 self.astgen_wait_group.deinit();
14341447
14351448 // This destroys `self`.
14361449 self.arena_state.promote(gpa).deinit();
......@@ -1470,42 +1483,17 @@ pub fn update(self: *Compilation) !void {
14701483 module.compile_log_text.shrinkAndFree(module.gpa, 0);
14711484 module.generation += 1;
14721485
1473 // Detect which source files changed.
1474 for (module.import_table.items()) |entry| {
1475 const file = entry.value;
1476 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
1477 defer f.close();
1478
1479 // TODO handle error here by populating a retryable compile error
1480 const stat = try f.stat();
1481 const unchanged_metadata =
1482 stat.size == file.stat_size and
1483 stat.mtime == file.stat_mtime and
1484 stat.inode == file.stat_inode;
1485
1486 if (unchanged_metadata) {
1487 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
1488 continue;
1489 }
1490
1491 log.debug("metadata changed: {s}", .{file.sub_file_path});
1492 if (file.status == .unloaded_parse_failure) {
1493 module.failed_files.swapRemove(file).?.value.destroy(module.gpa);
1494 }
1495
1496 file.unload(module.gpa);
1497 // TODO handle error here by populating a retryable compile error
1498 try file.finishGettingSource(module.gpa, f, stat);
1486 // Make sure std.zig is inside the import_table. We unconditionally need
1487 // it for start.zig.
1488 _ = try module.importFile(module.root_pkg, "std");
14991489
1500 module.analyzeFile(file) catch |err| switch (err) {
1501 error.OutOfMemory => return error.OutOfMemory,
1502 error.AnalysisFail => continue,
1503 else => |e| return e,
1504 };
1490 // Put a work item in for every known source file to detect if
1491 // it changed, and, if so, re-compute ZIR and then queue the job
1492 // to update it.
1493 try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count());
1494 for (module.import_table.items()) |entry| {
1495 self.astgen_work_queue.writeItemAssumeCapacity(entry.value);
15051496 }
1506
1507 // Simulate `_ = @import("std");` which in turn imports start.zig.
1508 _ = try module.importFile(module.root_pkg, "std");
15091497 }
15101498 }
15111499
......@@ -1578,13 +1566,13 @@ pub fn totalErrorCount(self: *Compilation) usize {
15781566 // the previous parse success, including compile errors, but we cannot
15791567 // emit them until the file succeeds parsing.
15801568 for (module.failed_decls.items()) |entry| {
1581 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
1569 if (entry.key.namespace.file_scope.status == .parse_failure) {
15821570 continue;
15831571 }
15841572 total += 1;
15851573 }
15861574 for (module.emit_h_failed_decls.items()) |entry| {
1587 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
1575 if (entry.key.namespace.file_scope.status == .parse_failure) {
15881576 continue;
15891577 }
15901578 total += 1;
......@@ -1639,7 +1627,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
16391627 try AllErrors.add(module, &arena, &errors, entry.value.*);
16401628 }
16411629 for (module.failed_decls.items()) |entry| {
1642 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
1630 if (entry.key.namespace.file_scope.status == .parse_failure) {
16431631 // Skip errors for Decls within files that had a parse failure.
16441632 // We'll try again once parsing succeeds.
16451633 continue;
......@@ -1647,7 +1635,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
16471635 try AllErrors.add(module, &arena, &errors, entry.value.*);
16481636 }
16491637 for (module.emit_h_failed_decls.items()) |entry| {
1650 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
1638 if (entry.key.namespace.file_scope.status == .parse_failure) {
16511639 // Skip errors for Decls within files that had a parse failure.
16521640 // We'll try again once parsing succeeds.
16531641 continue;
......@@ -1719,17 +1707,37 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
17191707 defer main_progress_node.end();
17201708 if (self.color == .off) progress.terminal = null;
17211709
1722 var c_comp_progress_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
1723 defer c_comp_progress_node.end();
1710 // Here we queue up all the AstGen tasks first, followed by C object compilation.
1711 // We wait until the AstGen tasks are all completed before proceeding to the
1712 // (at least for now) single-threaded main work queue. However, C object compilation
1713 // only needs to be finished by the end of this function.
1714
1715 var zir_prog_node = main_progress_node.start("AstGen", self.astgen_work_queue.count);
1716 defer zir_prog_node.end();
1717
1718 var c_obj_prog_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
1719 defer c_obj_prog_node.end();
17241720
17251721 self.work_queue_wait_group.reset();
17261722 defer self.work_queue_wait_group.wait();
17271723
1728 while (self.c_object_work_queue.readItem()) |c_object| {
1729 self.work_queue_wait_group.start();
1730 try self.thread_pool.spawn(workerUpdateCObject, .{
1731 self, c_object, &c_comp_progress_node, &self.work_queue_wait_group,
1732 });
1724 {
1725 self.astgen_wait_group.reset();
1726 defer self.astgen_wait_group.wait();
1727
1728 while (self.astgen_work_queue.readItem()) |file| {
1729 self.astgen_wait_group.start();
1730 try self.thread_pool.spawn(workerAstGenFile, .{
1731 self, file, &zir_prog_node, &self.astgen_wait_group,
1732 });
1733 }
1734
1735 while (self.c_object_work_queue.readItem()) |c_object| {
1736 self.work_queue_wait_group.start();
1737 try self.thread_pool.spawn(workerUpdateCObject, .{
1738 self, c_object, &c_obj_prog_node, &self.work_queue_wait_group,
1739 });
1740 }
17331741 }
17341742
17351743 while (self.work_queue.readItem()) |work_item| switch (work_item) {
......@@ -2036,6 +2044,28 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
20362044 };
20372045}
20382046
2047fn workerAstGenFile(
2048 comp: *Compilation,
2049 file: *Module.Scope.File,
2050 prog_node: *std.Progress.Node,
2051 wg: *WaitGroup,
2052) void {
2053 defer wg.finish();
2054
2055 const mod = comp.bin_file.options.module.?;
2056 mod.astGenFile(file, prog_node) catch |err| switch (err) {
2057 error.AnalysisFail => return,
2058 else => {
2059 file.status = .retryable_failure;
2060 comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) {
2061 // Swallowing this error is OK because it's implied to be OOM when
2062 // there is a missing `failed_files` error message.
2063 error.OutOfMemory => {},
2064 };
2065 },
2066 };
2067}
2068
20392069pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
20402070 var man = comp.cache_parent.obtain();
20412071
......@@ -2235,7 +2265,32 @@ fn reportRetryableCObjectError(
22352265 }
22362266}
22372267
2238fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *std.Progress.Node) !void {
2268fn reportRetryableAstGenError(
2269 comp: *Compilation,
2270 file: *Module.Scope.File,
2271 err: anyerror,
2272) error{OutOfMemory}!void {
2273 const mod = comp.bin_file.options.module.?;
2274 const gpa = mod.gpa;
2275
2276 file.status = .retryable_failure;
2277
2278 const err_msg = try Module.ErrorMsg.create(gpa, .{
2279 .container = .{ .file_scope = file },
2280 .lazy = .entire_file,
2281 }, "unable to load {s}: {s}", .{
2282 file.sub_file_path, @errorName(err),
2283 });
2284 errdefer err_msg.destroy(gpa);
2285
2286 {
2287 const lock = comp.mutex.acquire();
2288 defer lock.release();
2289 try mod.failed_files.putNoClobber(gpa, file, err_msg);
2290 }
2291}
2292
2293fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void {
22392294 if (!build_options.have_llvm) {
22402295 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
22412296 }
......@@ -2302,8 +2357,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
23022357
23032358 const c_source_basename = std.fs.path.basename(c_object.src.src_path);
23042359
2305 c_comp_progress_node.activate();
2306 var child_progress_node = c_comp_progress_node.start(c_source_basename, 0);
2360 c_obj_prog_node.activate();
2361 var child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
23072362 child_progress_node.activate();
23082363 defer child_progress_node.end();
23092364
src/Module.zig+325-1278
......@@ -274,7 +274,7 @@ pub const Decl = struct {
274274 };
275275 }
276276
277 pub fn srcToken(decl: Decl) u32 {
277 pub fn srcToken(decl: Decl) ast.TokenIndex {
278278 const tree = &decl.namespace.file_scope.tree;
279279 return tree.firstToken(decl.src_node);
280280 }
......@@ -531,9 +531,9 @@ pub const Scope = struct {
531531 pub fn ownerDecl(scope: *Scope) ?*Decl {
532532 return switch (scope.tag) {
533533 .block => scope.cast(Block).?.sema.owner_decl,
534 .gen_zir => scope.cast(GenZir).?.astgen.decl,
535 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
536 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
534 .gen_zir => unreachable,
535 .local_val => unreachable,
536 .local_ptr => unreachable,
537537 .file => null,
538538 .namespace => null,
539539 .decl_ref => scope.cast(DeclRef).?.decl,
......@@ -543,9 +543,9 @@ pub const Scope = struct {
543543 pub fn srcDecl(scope: *Scope) ?*Decl {
544544 return switch (scope.tag) {
545545 .block => scope.cast(Block).?.src_decl,
546 .gen_zir => scope.cast(GenZir).?.astgen.decl,
547 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
548 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
546 .gen_zir => unreachable,
547 .local_val => unreachable,
548 .local_ptr => unreachable,
549549 .file => null,
550550 .namespace => null,
551551 .decl_ref => scope.cast(DeclRef).?.decl,
......@@ -556,28 +556,15 @@ pub const Scope = struct {
556556 pub fn namespace(scope: *Scope) *Namespace {
557557 switch (scope.tag) {
558558 .block => return scope.cast(Block).?.sema.owner_decl.namespace,
559 .gen_zir => return scope.cast(GenZir).?.astgen.decl.namespace,
560 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace,
561 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace,
559 .gen_zir => unreachable,
560 .local_val => unreachable,
561 .local_ptr => unreachable,
562562 .file => return scope.cast(File).?.namespace,
563563 .namespace => return scope.cast(Namespace).?,
564564 .decl_ref => return scope.cast(DeclRef).?.decl.namespace,
565565 }
566566 }
567567
568 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
569 pub fn tree(scope: *Scope) *const ast.Tree {
570 switch (scope.tag) {
571 .file => return &scope.cast(File).?.tree,
572 .block => return &scope.cast(Block).?.src_decl.namespace.file_scope.tree,
573 .gen_zir => return scope.cast(GenZir).?.tree(),
574 .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace.file_scope.tree,
575 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace.file_scope.tree,
576 .namespace => return &scope.cast(Namespace).?.file_scope.tree,
577 .decl_ref => return &scope.cast(DeclRef).?.decl.namespace.file_scope.tree,
578 }
579 }
580
581568 /// Asserts the scope is a child of a `GenZir` and returns it.
582569 pub fn getGenZir(scope: *Scope) *GenZir {
583570 return switch (scope.tag) {
......@@ -690,11 +677,14 @@ pub const Scope = struct {
690677 base: Scope = Scope{ .tag = base_tag },
691678 status: enum {
692679 never_loaded,
693 unloaded_success,
694 unloaded_parse_failure,
695 loaded_success,
680 parse_failure,
681 astgen_failure,
682 retryable_failure,
683 success,
696684 },
697685 source_loaded: bool,
686 tree_loaded: bool,
687 zir_loaded: bool,
698688 /// Relative to the owning package's root_src_dir.
699689 /// Memory is stored in gpa, owned by File.
700690 sub_file_path: []const u8,
......@@ -706,23 +696,27 @@ pub const Scope = struct {
706696 stat_inode: std.fs.File.INode,
707697 /// Whether this is populated depends on `status`.
708698 stat_mtime: i128,
709 /// Whether this is populated or not depends on `status`.
699 /// Whether this is populated or not depends on `tree_loaded`.
710700 tree: ast.Tree,
701 /// Whether this is populated or not depends on `zir_loaded`.
702 zir: Zir,
711703 /// Package that this file is a part of, managed externally.
712704 pkg: *Package,
713705 /// The namespace of the struct that represents this file.
706 /// Populated only when status is success.
714707 namespace: *Namespace,
715708
716709 pub fn unload(file: *File, gpa: *Allocator) void {
717710 file.unloadTree(gpa);
718711 file.unloadSource(gpa);
712 file.unloadZir(gpa);
719713 }
720714
721715 pub fn unloadTree(file: *File, gpa: *Allocator) void {
722 if (file.status == .loaded_success) {
716 if (file.tree_loaded) {
717 file.tree_loaded = false;
723718 file.tree.deinit(gpa);
724719 }
725 file.status = .unloaded_success;
726720 }
727721
728722 pub fn unloadSource(file: *File, gpa: *Allocator) void {
......@@ -732,21 +726,18 @@ pub const Scope = struct {
732726 }
733727 }
734728
729 pub fn unloadZir(file: *File, gpa: *Allocator) void {
730 if (file.zir_loaded) {
731 file.zir_loaded = false;
732 file.zir.deinit(gpa);
733 }
734 }
735
735736 pub fn deinit(file: *File, gpa: *Allocator) void {
736737 file.unload(gpa);
737738 file.* = undefined;
738739 }
739740
740 pub fn destroy(file: *File, gpa: *Allocator) void {
741 file.deinit(gpa);
742 gpa.destroy(file);
743 }
744
745 pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
746 const loc = std.zig.findLineColumn(file.source.bytes, src);
747 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
748 }
749
750741 pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
751742 if (file.source_loaded) return file.source;
752743
......@@ -757,31 +748,32 @@ pub const Scope = struct {
757748
758749 const stat = try f.stat();
759750
760 try file.finishGettingSource(gpa, f, stat);
761 assert(file.source_loaded);
762 return file.source;
763 }
764
765 pub fn finishGettingSource(
766 file: *File,
767 gpa: *Allocator,
768 f: std.fs.File,
769 stat: std.fs.File.Stat,
770 ) !void {
771751 if (stat.size > std.math.maxInt(u32))
772752 return error.FileTooBig;
773753
774754 const source = try gpa.allocSentinel(u8, stat.size, 0);
775 errdefer gpa.free(source);
755 defer if (!file.source_loaded) gpa.free(source);
776756 const amt = try f.readAll(source);
777757 if (amt != stat.size)
778758 return error.UnexpectedEndOfFile;
779759
780 file.stat_size = stat.size;
781 file.stat_inode = stat.inode;
782 file.stat_mtime = stat.mtime;
760 // Here we do not modify stat fields because this function is the one
761 // used for error reporting. We need to keep the stat fields stale so that
762 // astGenFile can know to regenerate ZIR.
763
783764 file.source = source;
784765 file.source_loaded = true;
766 return source;
767 }
768
769 pub fn destroy(file: *File, gpa: *Allocator) void {
770 file.deinit(gpa);
771 gpa.destroy(file);
772 }
773
774 pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
775 const loc = std.zig.findLineColumn(file.source.bytes, src);
776 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
785777 }
786778 };
787779
......@@ -1050,6 +1042,11 @@ pub const Scope = struct {
10501042 pub const base_tag: Tag = .gen_zir;
10511043 base: Scope = Scope{ .tag = base_tag },
10521044 force_comptime: bool,
1045 /// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert
1046 /// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters.
1047 ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len,
1048 /// The containing decl AST node.
1049 decl_node_index: ast.Node.Index,
10531050 /// Parents can be: `GenZir`, `File`
10541051 parent: *Scope,
10551052 /// All `GenZir` scopes for the same ZIR share this.
......@@ -1089,29 +1086,49 @@ pub const Scope = struct {
10891086 used: bool = false,
10901087 };
10911088
1092 /// Only valid to call on the top of the `GenZir` stack. Completes the
1093 /// `AstGen` into a `Zir`. Leaves the `AstGen` in an
1094 /// initialized, but empty, state.
1095 pub fn finish(gz: *GenZir) !Zir {
1096 const gpa = gz.astgen.mod.gpa;
1097 try gz.setBlockBody(0);
1098 return Zir{
1099 .instructions = gz.astgen.instructions.toOwnedSlice(),
1100 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
1101 .extra = gz.astgen.extra.toOwnedSlice(gpa),
1102 };
1089 pub fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {
1090 if (inst_ref == .unreachable_value) return true;
1091 if (gz.refToIndex(inst_ref)) |inst_index| {
1092 return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn();
1093 }
1094 return false;
11031095 }
11041096
11051097 pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc {
1106 return gz.astgen.decl.tokSrcLoc(token_index);
1098 return .{ .token_offset = token_index - gz.srcToken() };
11071099 }
11081100
11091101 pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc {
1110 return gz.astgen.decl.nodeSrcLoc(node_index);
1102 return .{ .node_offset = gz.nodeIndexToRelative(node_index) };
1103 }
1104
1105 pub fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 {
1106 return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index);
1107 }
1108
1109 pub fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 {
1110 return token - gz.srcToken();
1111 }
1112
1113 pub fn srcToken(gz: GenZir) ast.TokenIndex {
1114 return gz.astgen.file.tree.firstToken(gz.decl_node_index);
11111115 }
11121116
11131117 pub fn tree(gz: *const GenZir) *const ast.Tree {
1114 return &gz.astgen.decl.namespace.file_scope.tree;
1118 return &gz.astgen.file.tree;
1119 }
1120
1121 pub fn indexToRef(gz: GenZir, inst: Zir.Inst.Index) Zir.Inst.Ref {
1122 return @intToEnum(Zir.Inst.Ref, gz.ref_start_index + inst);
1123 }
1124
1125 pub fn refToIndex(gz: GenZir, inst: Zir.Inst.Ref) ?Zir.Inst.Index {
1126 const ref_int = @enumToInt(inst);
1127 if (ref_int >= gz.ref_start_index) {
1128 return ref_int - gz.ref_start_index;
1129 } else {
1130 return null;
1131 }
11151132 }
11161133
11171134 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
......@@ -1149,7 +1166,7 @@ pub const Scope = struct {
11491166 }
11501167
11511168 pub fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
1152 const gpa = gz.astgen.mod.gpa;
1169 const gpa = gz.astgen.gpa;
11531170 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
11541171 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
11551172 const zir_datas = gz.astgen.instructions.items(.data);
......@@ -1160,7 +1177,7 @@ pub const Scope = struct {
11601177 }
11611178
11621179 pub fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
1163 const gpa = gz.astgen.mod.gpa;
1180 const gpa = gz.astgen.gpa;
11641181 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
11651182 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
11661183 const zir_datas = gz.astgen.instructions.items(.data);
......@@ -1172,77 +1189,133 @@ pub const Scope = struct {
11721189
11731190 pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
11741191 const astgen = gz.astgen;
1175 const gpa = astgen.mod.gpa;
1192 const gpa = astgen.gpa;
11761193 const string_bytes = &astgen.string_bytes;
11771194 const str_index = @intCast(u32, string_bytes.items.len);
1178 try astgen.mod.appendIdentStr(&gz.base, ident_token, string_bytes);
1179 try string_bytes.append(gpa, 0);
1180 return str_index;
1195 try astgen.appendIdentStr(ident_token, string_bytes);
1196 const key = string_bytes.items[str_index..];
1197 const gop = try astgen.string_table.getOrPut(gpa, key);
1198 if (gop.found_existing) {
1199 string_bytes.shrinkRetainingCapacity(str_index);
1200 return gop.entry.value;
1201 } else {
1202 // We have to dupe the key into the arena, otherwise the memory
1203 // becomes invalidated when string_bytes gets data appended.
1204 // TODO https://github.com/ziglang/zig/issues/8528
1205 gop.entry.key = try astgen.arena.dupe(u8, key);
1206 gop.entry.value = str_index;
1207 try string_bytes.append(gpa, 0);
1208 return str_index;
1209 }
11811210 }
11821211
1183 pub fn addFnTypeCc(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
1212 pub const IndexSlice = struct { index: u32, len: u32 };
1213
1214 pub fn strLitAsString(gz: *GenZir, str_lit_token: ast.TokenIndex) !IndexSlice {
1215 const astgen = gz.astgen;
1216 const gpa = astgen.gpa;
1217 const string_bytes = &astgen.string_bytes;
1218 const str_index = @intCast(u32, string_bytes.items.len);
1219 const token_bytes = astgen.file.tree.tokenSlice(str_lit_token);
1220 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
1221 const key = string_bytes.items[str_index..];
1222 const gop = try astgen.string_table.getOrPut(gpa, key);
1223 if (gop.found_existing) {
1224 string_bytes.shrinkRetainingCapacity(str_index);
1225 return IndexSlice{
1226 .index = gop.entry.value,
1227 .len = @intCast(u32, key.len),
1228 };
1229 } else {
1230 // We have to dupe the key into the arena, otherwise the memory
1231 // becomes invalidated when string_bytes gets data appended.
1232 // TODO https://github.com/ziglang/zig/issues/8528
1233 gop.entry.key = try astgen.arena.dupe(u8, key);
1234 gop.entry.value = str_index;
1235 // Still need a null byte because we are using the same table
1236 // to lookup null terminated strings, so if we get a match, it has to
1237 // be null terminated for that to work.
1238 try string_bytes.append(gpa, 0);
1239 return IndexSlice{
1240 .index = str_index,
1241 .len = @intCast(u32, key.len),
1242 };
1243 }
1244 }
1245
1246 pub fn addFuncExtra(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
11841247 src_node: ast.Node.Index,
11851248 param_types: []const Zir.Inst.Ref,
11861249 ret_ty: Zir.Inst.Ref,
11871250 cc: Zir.Inst.Ref,
1251 body: []const Zir.Inst.Index,
1252 lib_name: u32,
11881253 }) !Zir.Inst.Ref {
11891254 assert(args.src_node != 0);
11901255 assert(args.ret_ty != .none);
11911256 assert(args.cc != .none);
1192 const gpa = gz.astgen.mod.gpa;
1257 const gpa = gz.astgen.gpa;
11931258 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
11941259 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
11951260 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
1196 @typeInfo(Zir.Inst.FnTypeCc).Struct.fields.len + args.param_types.len);
1261 @typeInfo(Zir.Inst.FuncExtra).Struct.fields.len + args.param_types.len +
1262 args.body.len);
11971263
1198 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FnTypeCc{
1264 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FuncExtra{
11991265 .return_type = args.ret_ty,
12001266 .cc = args.cc,
12011267 .param_types_len = @intCast(u32, args.param_types.len),
1268 .body_len = @intCast(u32, args.body.len),
1269 .lib_name = args.lib_name,
12021270 });
12031271 gz.astgen.appendRefsAssumeCapacity(args.param_types);
1272 gz.astgen.extra.appendSliceAssumeCapacity(args.body);
12041273
12051274 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
12061275 gz.astgen.instructions.appendAssumeCapacity(.{
12071276 .tag = tag,
12081277 .data = .{ .pl_node = .{
1209 .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node),
1278 .src_node = gz.nodeIndexToRelative(args.src_node),
12101279 .payload_index = payload_index,
12111280 } },
12121281 });
12131282 gz.instructions.appendAssumeCapacity(new_index);
1214 return gz.astgen.indexToRef(new_index);
1283 return gz.indexToRef(new_index);
12151284 }
12161285
1217 pub fn addFnType(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
1286 pub fn addFunc(gz: *GenZir, tag: Zir.Inst.Tag, args: struct {
12181287 src_node: ast.Node.Index,
12191288 ret_ty: Zir.Inst.Ref,
12201289 param_types: []const Zir.Inst.Ref,
1290 body: []const Zir.Inst.Index,
12211291 }) !Zir.Inst.Ref {
12221292 assert(args.src_node != 0);
12231293 assert(args.ret_ty != .none);
1224 const gpa = gz.astgen.mod.gpa;
1294 const gpa = gz.astgen.gpa;
12251295 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
12261296 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
12271297 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
1228 @typeInfo(Zir.Inst.FnType).Struct.fields.len + args.param_types.len);
1298 @typeInfo(Zir.Inst.Func).Struct.fields.len + args.param_types.len +
1299 args.body.len);
12291300
1230 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.FnType{
1301 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{
12311302 .return_type = args.ret_ty,
12321303 .param_types_len = @intCast(u32, args.param_types.len),
1304 .body_len = @intCast(u32, args.body.len),
12331305 });
12341306 gz.astgen.appendRefsAssumeCapacity(args.param_types);
1307 gz.astgen.extra.appendSliceAssumeCapacity(args.body);
12351308
12361309 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
12371310 gz.astgen.instructions.appendAssumeCapacity(.{
12381311 .tag = tag,
12391312 .data = .{ .pl_node = .{
1240 .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node),
1313 .src_node = gz.nodeIndexToRelative(args.src_node),
12411314 .payload_index = payload_index,
12421315 } },
12431316 });
12441317 gz.instructions.appendAssumeCapacity(new_index);
1245 return gz.astgen.indexToRef(new_index);
1318 return gz.indexToRef(new_index);
12461319 }
12471320
12481321 pub fn addCall(
......@@ -1255,7 +1328,7 @@ pub const Scope = struct {
12551328 ) !Zir.Inst.Ref {
12561329 assert(callee != .none);
12571330 assert(src_node != 0);
1258 const gpa = gz.astgen.mod.gpa;
1331 const gpa = gz.astgen.gpa;
12591332 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
12601333 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
12611334 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
......@@ -1271,12 +1344,12 @@ pub const Scope = struct {
12711344 gz.astgen.instructions.appendAssumeCapacity(.{
12721345 .tag = tag,
12731346 .data = .{ .pl_node = .{
1274 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1347 .src_node = gz.nodeIndexToRelative(src_node),
12751348 .payload_index = payload_index,
12761349 } },
12771350 });
12781351 gz.instructions.appendAssumeCapacity(new_index);
1279 return gz.astgen.indexToRef(new_index);
1352 return gz.indexToRef(new_index);
12801353 }
12811354
12821355 /// Note that this returns a `Zir.Inst.Index` not a ref.
......@@ -1287,7 +1360,7 @@ pub const Scope = struct {
12871360 lhs: Zir.Inst.Ref,
12881361 ) !Zir.Inst.Index {
12891362 assert(lhs != .none);
1290 const gpa = gz.astgen.mod.gpa;
1363 const gpa = gz.astgen.gpa;
12911364 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
12921365 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
12931366
......@@ -1314,7 +1387,7 @@ pub const Scope = struct {
13141387 return gz.add(.{
13151388 .tag = .float,
13161389 .data = .{ .float = .{
1317 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1390 .src_node = gz.nodeIndexToRelative(src_node),
13181391 .number = number,
13191392 } },
13201393 });
......@@ -1332,7 +1405,7 @@ pub const Scope = struct {
13321405 .tag = tag,
13331406 .data = .{ .un_node = .{
13341407 .operand = operand,
1335 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1408 .src_node = gz.nodeIndexToRelative(src_node),
13361409 } },
13371410 });
13381411 }
......@@ -1344,7 +1417,7 @@ pub const Scope = struct {
13441417 src_node: ast.Node.Index,
13451418 extra: anytype,
13461419 ) !Zir.Inst.Ref {
1347 const gpa = gz.astgen.mod.gpa;
1420 const gpa = gz.astgen.gpa;
13481421 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
13491422 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
13501423
......@@ -1353,12 +1426,12 @@ pub const Scope = struct {
13531426 gz.astgen.instructions.appendAssumeCapacity(.{
13541427 .tag = tag,
13551428 .data = .{ .pl_node = .{
1356 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1429 .src_node = gz.nodeIndexToRelative(src_node),
13571430 .payload_index = payload_index,
13581431 } },
13591432 });
13601433 gz.instructions.appendAssumeCapacity(new_index);
1361 return gz.astgen.indexToRef(new_index);
1434 return gz.indexToRef(new_index);
13621435 }
13631436
13641437 pub fn addArrayTypeSentinel(
......@@ -1367,7 +1440,7 @@ pub const Scope = struct {
13671440 sentinel: Zir.Inst.Ref,
13681441 elem_type: Zir.Inst.Ref,
13691442 ) !Zir.Inst.Ref {
1370 const gpa = gz.astgen.mod.gpa;
1443 const gpa = gz.astgen.gpa;
13711444 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
13721445 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
13731446
......@@ -1384,7 +1457,7 @@ pub const Scope = struct {
13841457 } },
13851458 });
13861459 gz.instructions.appendAssumeCapacity(new_index);
1387 return gz.astgen.indexToRef(new_index);
1460 return gz.indexToRef(new_index);
13881461 }
13891462
13901463 pub fn addUnTok(
......@@ -1399,7 +1472,7 @@ pub const Scope = struct {
13991472 .tag = tag,
14001473 .data = .{ .un_tok = .{
14011474 .operand = operand,
1402 .src_tok = abs_tok_index - gz.astgen.decl.srcToken(),
1475 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
14031476 } },
14041477 });
14051478 }
......@@ -1415,7 +1488,7 @@ pub const Scope = struct {
14151488 .tag = tag,
14161489 .data = .{ .str_tok = .{
14171490 .start = str_index,
1418 .src_tok = abs_tok_index - gz.astgen.decl.srcToken(),
1491 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
14191492 } },
14201493 });
14211494 }
......@@ -1461,7 +1534,7 @@ pub const Scope = struct {
14611534 return gz.add(.{
14621535 .tag = tag,
14631536 .data = .{ .pl_node = .{
1464 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1537 .src_node = gz.nodeIndexToRelative(src_node),
14651538 .payload_index = decl_index,
14661539 } },
14671540 });
......@@ -1475,7 +1548,7 @@ pub const Scope = struct {
14751548 ) !Zir.Inst.Ref {
14761549 return gz.add(.{
14771550 .tag = tag,
1478 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(src_node) },
1551 .data = .{ .node = gz.nodeIndexToRelative(src_node) },
14791552 });
14801553 }
14811554
......@@ -1500,11 +1573,11 @@ pub const Scope = struct {
15001573 /// Leaves the `payload_index` field undefined.
15011574 pub fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
15021575 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1503 const gpa = gz.astgen.mod.gpa;
1576 const gpa = gz.astgen.gpa;
15041577 try gz.astgen.instructions.append(gpa, .{
15051578 .tag = tag,
15061579 .data = .{ .pl_node = .{
1507 .src_node = gz.astgen.decl.nodeIndexToRelative(node),
1580 .src_node = gz.nodeIndexToRelative(node),
15081581 .payload_index = undefined,
15091582 } },
15101583 });
......@@ -1514,13 +1587,13 @@ pub const Scope = struct {
15141587 /// Note that this returns a `Zir.Inst.Index` not a ref.
15151588 /// Leaves the `payload_index` field undefined.
15161589 pub fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
1517 const gpa = gz.astgen.mod.gpa;
1590 const gpa = gz.astgen.gpa;
15181591 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
15191592 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
15201593 try gz.astgen.instructions.append(gpa, .{
15211594 .tag = tag,
15221595 .data = .{ .pl_node = .{
1523 .src_node = gz.astgen.decl.nodeIndexToRelative(node),
1596 .src_node = gz.nodeIndexToRelative(node),
15241597 .payload_index = undefined,
15251598 } },
15261599 });
......@@ -1529,11 +1602,11 @@ pub const Scope = struct {
15291602 }
15301603
15311604 pub fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {
1532 return gz.astgen.indexToRef(try gz.addAsIndex(inst));
1605 return gz.indexToRef(try gz.addAsIndex(inst));
15331606 }
15341607
15351608 pub fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index {
1536 const gpa = gz.astgen.mod.gpa;
1609 const gpa = gz.astgen.gpa;
15371610 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
15381611 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
15391612
......@@ -1556,7 +1629,7 @@ pub const Scope = struct {
15561629 name: []const u8,
15571630 inst: Zir.Inst.Ref,
15581631 /// Source location of the corresponding variable declaration.
1559 src: LazySrcLoc,
1632 token_src: ast.TokenIndex,
15601633 };
15611634
15621635 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -1571,7 +1644,7 @@ pub const Scope = struct {
15711644 name: []const u8,
15721645 ptr: Zir.Inst.Ref,
15731646 /// Source location of the corresponding variable declaration.
1574 src: LazySrcLoc,
1647 token_src: ast.TokenIndex,
15751648 };
15761649
15771650 pub const DeclRef = struct {
......@@ -1653,6 +1726,7 @@ pub const SrcLoc = struct {
16531726 .byte_abs,
16541727 .token_abs,
16551728 .node_abs,
1729 .entire_file,
16561730 => src_loc.container.file_scope,
16571731
16581732 .byte_offset,
......@@ -1686,16 +1760,17 @@ pub const SrcLoc = struct {
16861760 pub fn byteOffset(src_loc: SrcLoc) !u32 {
16871761 switch (src_loc.lazy) {
16881762 .unneeded => unreachable,
1763 .entire_file => unreachable,
16891764
16901765 .byte_abs => |byte_index| return byte_index,
16911766
16921767 .token_abs => |tok_index| {
1693 const tree = src_loc.container.file_scope.base.tree();
1768 const tree = src_loc.container.file_scope.tree;
16941769 const token_starts = tree.tokens.items(.start);
16951770 return token_starts[tok_index];
16961771 },
16971772 .node_abs => |node| {
1698 const tree = src_loc.container.file_scope.base.tree();
1773 const tree = src_loc.container.file_scope.tree;
16991774 const token_starts = tree.tokens.items(.start);
17001775 const tok_index = tree.firstToken(node);
17011776 return token_starts[tok_index];
......@@ -1707,14 +1782,14 @@ pub const SrcLoc = struct {
17071782 .token_offset => |tok_off| {
17081783 const decl = src_loc.container.decl;
17091784 const tok_index = decl.srcToken() + tok_off;
1710 const tree = decl.namespace.file_scope.base.tree();
1785 const tree = decl.namespace.file_scope.tree;
17111786 const token_starts = tree.tokens.items(.start);
17121787 return token_starts[tok_index];
17131788 },
17141789 .node_offset, .node_offset_bin_op => |node_off| {
17151790 const decl = src_loc.container.decl;
17161791 const node = decl.relativeToNodeIndex(node_off);
1717 const tree = decl.namespace.file_scope.base.tree();
1792 const tree = decl.namespace.file_scope.tree;
17181793 const main_tokens = tree.nodes.items(.main_token);
17191794 const tok_index = main_tokens[node];
17201795 const token_starts = tree.tokens.items(.start);
......@@ -1723,7 +1798,7 @@ pub const SrcLoc = struct {
17231798 .node_offset_back2tok => |node_off| {
17241799 const decl = src_loc.container.decl;
17251800 const node = decl.relativeToNodeIndex(node_off);
1726 const tree = decl.namespace.file_scope.base.tree();
1801 const tree = decl.namespace.file_scope.tree;
17271802 const tok_index = tree.firstToken(node) - 2;
17281803 const token_starts = tree.tokens.items(.start);
17291804 return token_starts[tok_index];
......@@ -1731,7 +1806,7 @@ pub const SrcLoc = struct {
17311806 .node_offset_var_decl_ty => |node_off| {
17321807 const decl = src_loc.container.decl;
17331808 const node = decl.relativeToNodeIndex(node_off);
1734 const tree = decl.namespace.file_scope.base.tree();
1809 const tree = decl.namespace.file_scope.tree;
17351810 const node_tags = tree.nodes.items(.tag);
17361811 const full = switch (node_tags[node]) {
17371812 .global_var_decl => tree.globalVarDecl(node),
......@@ -1751,7 +1826,7 @@ pub const SrcLoc = struct {
17511826 },
17521827 .node_offset_builtin_call_arg0 => |node_off| {
17531828 const decl = src_loc.container.decl;
1754 const tree = decl.namespace.file_scope.base.tree();
1829 const tree = decl.namespace.file_scope.tree;
17551830 const node_datas = tree.nodes.items(.data);
17561831 const node_tags = tree.nodes.items(.tag);
17571832 const node = decl.relativeToNodeIndex(node_off);
......@@ -1767,7 +1842,7 @@ pub const SrcLoc = struct {
17671842 },
17681843 .node_offset_builtin_call_arg1 => |node_off| {
17691844 const decl = src_loc.container.decl;
1770 const tree = decl.namespace.file_scope.base.tree();
1845 const tree = decl.namespace.file_scope.tree;
17711846 const node_datas = tree.nodes.items(.data);
17721847 const node_tags = tree.nodes.items(.tag);
17731848 const node = decl.relativeToNodeIndex(node_off);
......@@ -1783,7 +1858,7 @@ pub const SrcLoc = struct {
17831858 },
17841859 .node_offset_array_access_index => |node_off| {
17851860 const decl = src_loc.container.decl;
1786 const tree = decl.namespace.file_scope.base.tree();
1861 const tree = decl.namespace.file_scope.tree;
17871862 const node_datas = tree.nodes.items(.data);
17881863 const node_tags = tree.nodes.items(.tag);
17891864 const node = decl.relativeToNodeIndex(node_off);
......@@ -1794,7 +1869,7 @@ pub const SrcLoc = struct {
17941869 },
17951870 .node_offset_slice_sentinel => |node_off| {
17961871 const decl = src_loc.container.decl;
1797 const tree = decl.namespace.file_scope.base.tree();
1872 const tree = decl.namespace.file_scope.tree;
17981873 const node_datas = tree.nodes.items(.data);
17991874 const node_tags = tree.nodes.items(.tag);
18001875 const node = decl.relativeToNodeIndex(node_off);
......@@ -1811,7 +1886,7 @@ pub const SrcLoc = struct {
18111886 },
18121887 .node_offset_call_func => |node_off| {
18131888 const decl = src_loc.container.decl;
1814 const tree = decl.namespace.file_scope.base.tree();
1889 const tree = decl.namespace.file_scope.tree;
18151890 const node_datas = tree.nodes.items(.data);
18161891 const node_tags = tree.nodes.items(.tag);
18171892 const node = decl.relativeToNodeIndex(node_off);
......@@ -1838,7 +1913,7 @@ pub const SrcLoc = struct {
18381913 },
18391914 .node_offset_field_name => |node_off| {
18401915 const decl = src_loc.container.decl;
1841 const tree = decl.namespace.file_scope.base.tree();
1916 const tree = decl.namespace.file_scope.tree;
18421917 const node_datas = tree.nodes.items(.data);
18431918 const node_tags = tree.nodes.items(.tag);
18441919 const node = decl.relativeToNodeIndex(node_off);
......@@ -1851,7 +1926,7 @@ pub const SrcLoc = struct {
18511926 },
18521927 .node_offset_deref_ptr => |node_off| {
18531928 const decl = src_loc.container.decl;
1854 const tree = decl.namespace.file_scope.base.tree();
1929 const tree = decl.namespace.file_scope.tree;
18551930 const node_datas = tree.nodes.items(.data);
18561931 const node_tags = tree.nodes.items(.tag);
18571932 const node = decl.relativeToNodeIndex(node_off);
......@@ -1861,7 +1936,7 @@ pub const SrcLoc = struct {
18611936 },
18621937 .node_offset_asm_source => |node_off| {
18631938 const decl = src_loc.container.decl;
1864 const tree = decl.namespace.file_scope.base.tree();
1939 const tree = decl.namespace.file_scope.tree;
18651940 const node_datas = tree.nodes.items(.data);
18661941 const node_tags = tree.nodes.items(.tag);
18671942 const node = decl.relativeToNodeIndex(node_off);
......@@ -1877,7 +1952,7 @@ pub const SrcLoc = struct {
18771952 },
18781953 .node_offset_asm_ret_ty => |node_off| {
18791954 const decl = src_loc.container.decl;
1880 const tree = decl.namespace.file_scope.base.tree();
1955 const tree = decl.namespace.file_scope.tree;
18811956 const node_datas = tree.nodes.items(.data);
18821957 const node_tags = tree.nodes.items(.tag);
18831958 const node = decl.relativeToNodeIndex(node_off);
......@@ -1895,7 +1970,7 @@ pub const SrcLoc = struct {
18951970 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
18961971 const decl = src_loc.container.decl;
18971972 const node = decl.relativeToNodeIndex(node_off);
1898 const tree = decl.namespace.file_scope.base.tree();
1973 const tree = decl.namespace.file_scope.tree;
18991974 const node_tags = tree.nodes.items(.tag);
19001975 const src_node = switch (node_tags[node]) {
19011976 .if_simple => tree.ifSimple(node).ast.cond_expr,
......@@ -1915,7 +1990,7 @@ pub const SrcLoc = struct {
19151990 .node_offset_bin_lhs => |node_off| {
19161991 const decl = src_loc.container.decl;
19171992 const node = decl.relativeToNodeIndex(node_off);
1918 const tree = decl.namespace.file_scope.base.tree();
1993 const tree = decl.namespace.file_scope.tree;
19191994 const node_datas = tree.nodes.items(.data);
19201995 const src_node = node_datas[node].lhs;
19211996 const main_tokens = tree.nodes.items(.main_token);
......@@ -1926,7 +2001,7 @@ pub const SrcLoc = struct {
19262001 .node_offset_bin_rhs => |node_off| {
19272002 const decl = src_loc.container.decl;
19282003 const node = decl.relativeToNodeIndex(node_off);
1929 const tree = decl.namespace.file_scope.base.tree();
2004 const tree = decl.namespace.file_scope.tree;
19302005 const node_datas = tree.nodes.items(.data);
19312006 const src_node = node_datas[node].rhs;
19322007 const main_tokens = tree.nodes.items(.main_token);
......@@ -1938,7 +2013,7 @@ pub const SrcLoc = struct {
19382013 .node_offset_switch_operand => |node_off| {
19392014 const decl = src_loc.container.decl;
19402015 const node = decl.relativeToNodeIndex(node_off);
1941 const tree = decl.namespace.file_scope.base.tree();
2016 const tree = decl.namespace.file_scope.tree;
19422017 const node_datas = tree.nodes.items(.data);
19432018 const src_node = node_datas[node].lhs;
19442019 const main_tokens = tree.nodes.items(.main_token);
......@@ -1950,7 +2025,7 @@ pub const SrcLoc = struct {
19502025 .node_offset_switch_special_prong => |node_off| {
19512026 const decl = src_loc.container.decl;
19522027 const switch_node = decl.relativeToNodeIndex(node_off);
1953 const tree = decl.namespace.file_scope.base.tree();
2028 const tree = decl.namespace.file_scope.tree;
19542029 const node_datas = tree.nodes.items(.data);
19552030 const node_tags = tree.nodes.items(.tag);
19562031 const main_tokens = tree.nodes.items(.main_token);
......@@ -1977,7 +2052,7 @@ pub const SrcLoc = struct {
19772052 .node_offset_switch_range => |node_off| {
19782053 const decl = src_loc.container.decl;
19792054 const switch_node = decl.relativeToNodeIndex(node_off);
1980 const tree = decl.namespace.file_scope.base.tree();
2055 const tree = decl.namespace.file_scope.tree;
19812056 const node_datas = tree.nodes.items(.data);
19822057 const node_tags = tree.nodes.items(.tag);
19832058 const main_tokens = tree.nodes.items(.main_token);
......@@ -2007,7 +2082,7 @@ pub const SrcLoc = struct {
20072082
20082083 .node_offset_fn_type_cc => |node_off| {
20092084 const decl = src_loc.container.decl;
2010 const tree = decl.namespace.file_scope.base.tree();
2085 const tree = decl.namespace.file_scope.tree;
20112086 const node_datas = tree.nodes.items(.data);
20122087 const node_tags = tree.nodes.items(.tag);
20132088 const node = decl.relativeToNodeIndex(node_off);
......@@ -2027,7 +2102,7 @@ pub const SrcLoc = struct {
20272102
20282103 .node_offset_fn_type_ret_ty => |node_off| {
20292104 const decl = src_loc.container.decl;
2030 const tree = decl.namespace.file_scope.base.tree();
2105 const tree = decl.namespace.file_scope.tree;
20312106 const node_datas = tree.nodes.items(.data);
20322107 const node_tags = tree.nodes.items(.tag);
20332108 const node = decl.relativeToNodeIndex(node_off);
......@@ -2063,6 +2138,9 @@ pub const LazySrcLoc = union(enum) {
20632138 /// look into using reverse-continue with a memory watchpoint to see where the
20642139 /// value is being set to this tag.
20652140 unneeded,
2141 /// Means the source location points to an entire file; not any particular
2142 /// location within the file. `file_scope` union field will be active.
2143 entire_file,
20662144 /// The source location points to a byte offset within a source file,
20672145 /// offset from 0. The source file is determined contextually.
20682146 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
......@@ -2205,6 +2283,7 @@ pub const LazySrcLoc = union(enum) {
22052283 pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
22062284 return switch (lazy) {
22072285 .unneeded,
2286 .entire_file,
22082287 .byte_abs,
22092288 .token_abs,
22102289 .node_abs,
......@@ -2248,6 +2327,7 @@ pub const LazySrcLoc = union(enum) {
22482327 pub fn toSrcLocWithDecl(lazy: LazySrcLoc, decl: *Decl) SrcLoc {
22492328 return switch (lazy) {
22502329 .unneeded,
2330 .entire_file,
22512331 .byte_abs,
22522332 .token_abs,
22532333 .node_abs,
......@@ -2376,6 +2456,108 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
23762456 gpa.free(export_list);
23772457}
23782458
2459pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {
2460 const comp = mod.comp;
2461 const gpa = mod.gpa;
2462
2463 // In any case we need to examine the stat of the file to determine the course of action.
2464 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
2465 defer f.close();
2466
2467 const stat = try f.stat();
2468
2469 // Determine whether we need to reload the file from disk and redo parsing and AstGen.
2470 switch (file.status) {
2471 .never_loaded, .retryable_failure => {},
2472 .parse_failure, .astgen_failure, .success => {
2473 const unchanged_metadata =
2474 stat.size == file.stat_size and
2475 stat.mtime == file.stat_mtime and
2476 stat.inode == file.stat_inode;
2477
2478 if (unchanged_metadata) {
2479 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
2480 return;
2481 }
2482
2483 log.debug("metadata changed: {s}", .{file.sub_file_path});
2484 },
2485 }
2486 // Clear compile error for this file.
2487 switch (file.status) {
2488 .success, .retryable_failure => {},
2489 .never_loaded, .parse_failure, .astgen_failure => {
2490 const lock = comp.mutex.acquire();
2491 defer lock.release();
2492 if (mod.failed_files.swapRemove(file)) |entry| {
2493 entry.value.destroy(gpa); // Delete previous error message.
2494 }
2495 },
2496 }
2497 file.unload(gpa);
2498
2499 if (stat.size > std.math.maxInt(u32))
2500 return error.FileTooBig;
2501
2502 const source = try gpa.allocSentinel(u8, stat.size, 0);
2503 defer if (!file.source_loaded) gpa.free(source);
2504 const amt = try f.readAll(source);
2505 if (amt != stat.size)
2506 return error.UnexpectedEndOfFile;
2507
2508 file.stat_size = stat.size;
2509 file.stat_inode = stat.inode;
2510 file.stat_mtime = stat.mtime;
2511 file.source = source;
2512 file.source_loaded = true;
2513
2514 file.tree = try std.zig.parse(gpa, source);
2515 defer if (!file.tree_loaded) file.tree.deinit(gpa);
2516
2517 if (file.tree.errors.len != 0) {
2518 const parse_err = file.tree.errors[0];
2519
2520 var msg = std.ArrayList(u8).init(gpa);
2521 defer msg.deinit();
2522
2523 const token_starts = file.tree.tokens.items(.start);
2524
2525 try file.tree.renderError(parse_err, msg.writer());
2526 const err_msg = try gpa.create(ErrorMsg);
2527 err_msg.* = .{
2528 .src_loc = .{
2529 .container = .{ .file_scope = file },
2530 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
2531 },
2532 .msg = msg.toOwnedSlice(),
2533 };
2534
2535 {
2536 const lock = comp.mutex.acquire();
2537 defer lock.release();
2538 try mod.failed_files.putNoClobber(gpa, file, err_msg);
2539 }
2540 file.status = .parse_failure;
2541 return error.AnalysisFail;
2542 }
2543 file.tree_loaded = true;
2544
2545 file.zir = try AstGen.generate(gpa, file);
2546 file.zir_loaded = true;
2547
2548 if (file.zir.extra[1] != 0) {
2549 {
2550 const lock = comp.mutex.acquire();
2551 defer lock.release();
2552 try mod.failed_files.putNoClobber(gpa, file, undefined);
2553 }
2554 file.status = .astgen_failure;
2555 return error.AnalysisFail;
2556 }
2557
2558 file.status = .success;
2559}
2560
23792561pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
23802562 const tracy = trace(@src());
23812563 defer tracy.end();
......@@ -2417,7 +2599,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
24172599 .unreferenced => false,
24182600 };
24192601
2420 const type_changed = mod.astgenAndSemaDecl(decl) catch |err| switch (err) {
2602 const type_changed = mod.semaDecl(decl) catch |err| switch (err) {
24212603 error.OutOfMemory => return error.OutOfMemory,
24222604 error.AnalysisFail => return error.AnalysisFail,
24232605 else => {
......@@ -2462,822 +2644,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
24622644/// Returns `true` if the Decl type changed.
24632645/// Returns `true` if this is the first time analyzing the Decl.
24642646/// Returns `false` otherwise.
2465fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
2647fn semaDecl(mod: *Module, decl: *Decl) !bool {
24662648 const tracy = trace(@src());
24672649 defer tracy.end();
24682650
2469 const tree = try mod.getAstTree(decl.namespace.file_scope);
2470 const node_tags = tree.nodes.items(.tag);
2471 const node_datas = tree.nodes.items(.data);
2472 const decl_node = decl.src_node;
2473 switch (node_tags[decl_node]) {
2474 .fn_decl => {
2475 const fn_proto = node_datas[decl_node].lhs;
2476 const body = node_datas[decl_node].rhs;
2477 switch (node_tags[fn_proto]) {
2478 .fn_proto_simple => {
2479 var params: [1]ast.Node.Index = undefined;
2480 return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoSimple(&params, fn_proto));
2481 },
2482 .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoMulti(fn_proto)),
2483 .fn_proto_one => {
2484 var params: [1]ast.Node.Index = undefined;
2485 return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoOne(&params, fn_proto));
2486 },
2487 .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProto(fn_proto)),
2488 else => unreachable,
2489 }
2490 },
2491 .fn_proto_simple => {
2492 var params: [1]ast.Node.Index = undefined;
2493 return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoSimple(&params, decl_node));
2494 },
2495 .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoMulti(decl_node)),
2496 .fn_proto_one => {
2497 var params: [1]ast.Node.Index = undefined;
2498 return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoOne(&params, decl_node));
2499 },
2500 .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProto(decl_node)),
2501
2502 .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.globalVarDecl(decl_node)),
2503 .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.localVarDecl(decl_node)),
2504 .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.simpleVarDecl(decl_node)),
2505 .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.alignedVarDecl(decl_node)),
2506
2507 .@"comptime" => {
2508 decl.analysis = .in_progress;
2509
2510 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
2511 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
2512 defer analysis_arena.deinit();
2513
2514 var code: Zir = blk: {
2515 var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator);
2516 defer astgen.deinit();
2517
2518 var gen_scope: Scope.GenZir = .{
2519 .force_comptime = true,
2520 .parent = &decl.namespace.base,
2521 .astgen = &astgen,
2522 };
2523 defer gen_scope.instructions.deinit(mod.gpa);
2524
2525 const block_expr = node_datas[decl_node].lhs;
2526 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2527 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
2528
2529 const code = try gen_scope.finish();
2530 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2531 code.dump(mod.gpa, "comptime_block", &gen_scope.base, 0) catch {};
2532 }
2533 break :blk code;
2534 };
2535 defer code.deinit(mod.gpa);
2536
2537 var sema: Sema = .{
2538 .mod = mod,
2539 .gpa = mod.gpa,
2540 .arena = &analysis_arena.allocator,
2541 .code = code,
2542 .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len),
2543 .owner_decl = decl,
2544 .namespace = decl.namespace,
2545 .func = null,
2546 .owner_func = null,
2547 .param_inst_list = &.{},
2548 };
2549 var block_scope: Scope.Block = .{
2550 .parent = null,
2551 .sema = &sema,
2552 .src_decl = decl,
2553 .instructions = .{},
2554 .inlining = null,
2555 .is_comptime = true,
2556 };
2557 defer block_scope.instructions.deinit(mod.gpa);
2558
2559 _ = try sema.root(&block_scope);
2560
2561 decl.analysis = .complete;
2562 decl.generation = mod.generation;
2563 return true;
2564 },
2565 .@"usingnamespace" => {
2566 decl.analysis = .in_progress;
2567
2568 const type_expr = node_datas[decl_node].lhs;
2569 const is_pub = blk: {
2570 const main_tokens = tree.nodes.items(.main_token);
2571 const token_tags = tree.tokens.items(.tag);
2572 const main_token = main_tokens[decl_node];
2573 break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub);
2574 };
2575
2576 // A usingnamespace decl does not store any value so we can
2577 // deinit this arena after analysis is done.
2578 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
2579 defer analysis_arena.deinit();
2580
2581 var code: Zir = blk: {
2582 var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator);
2583 defer astgen.deinit();
2584
2585 var gen_scope: Scope.GenZir = .{
2586 .force_comptime = true,
2587 .parent = &decl.namespace.base,
2588 .astgen = &astgen,
2589 };
2590 defer gen_scope.instructions.deinit(mod.gpa);
2591
2592 const ns_type = try AstGen.typeExpr(&gen_scope, &gen_scope.base, type_expr);
2593 _ = try gen_scope.addBreak(.break_inline, 0, ns_type);
2594
2595 const code = try gen_scope.finish();
2596 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2597 code.dump(mod.gpa, "usingnamespace_type", &gen_scope.base, 0) catch {};
2598 }
2599 break :blk code;
2600 };
2601 defer code.deinit(mod.gpa);
2602
2603 var sema: Sema = .{
2604 .mod = mod,
2605 .gpa = mod.gpa,
2606 .arena = &analysis_arena.allocator,
2607 .code = code,
2608 .inst_map = try analysis_arena.allocator.alloc(*ir.Inst, code.instructions.len),
2609 .owner_decl = decl,
2610 .namespace = decl.namespace,
2611 .func = null,
2612 .owner_func = null,
2613 .param_inst_list = &.{},
2614 };
2615 var block_scope: Scope.Block = .{
2616 .parent = null,
2617 .sema = &sema,
2618 .src_decl = decl,
2619 .instructions = .{},
2620 .inlining = null,
2621 .is_comptime = true,
2622 };
2623 defer block_scope.instructions.deinit(mod.gpa);
2624
2625 const ty = try sema.rootAsType(&block_scope);
2626 try decl.namespace.usingnamespace_set.put(mod.gpa, ty.getNamespace().?, is_pub);
2627
2628 decl.analysis = .complete;
2629 decl.generation = mod.generation;
2630 return true;
2631 },
2632 else => unreachable,
2633 }
2634}
2635
2636fn astgenAndSemaFn(
2637 mod: *Module,
2638 decl: *Decl,
2639 tree: ast.Tree,
2640 body_node: ast.Node.Index,
2641 fn_proto: ast.full.FnProto,
2642) !bool {
2643 const tracy = trace(@src());
2644 defer tracy.end();
2645
2646 decl.analysis = .in_progress;
2647
2648 const token_tags = tree.tokens.items(.tag);
2649
2650 // This arena allocator's memory is discarded at the end of this function. It is used
2651 // to determine the type of the function, and hence the type of the decl, which is needed
2652 // to complete the Decl analysis.
2653 var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
2654 defer fn_type_scope_arena.deinit();
2655
2656 var fn_type_astgen = try AstGen.init(mod, decl, &fn_type_scope_arena.allocator);
2657 defer fn_type_astgen.deinit();
2658
2659 var fn_type_scope: Scope.GenZir = .{
2660 .force_comptime = true,
2661 .parent = &decl.namespace.base,
2662 .astgen = &fn_type_astgen,
2663 };
2664 defer fn_type_scope.instructions.deinit(mod.gpa);
2665
2666 decl.is_pub = fn_proto.visib_token != null;
2667
2668 // The AST params array does not contain anytype and ... parameters.
2669 // We must iterate to count how many param types to allocate.
2670 const param_count = blk: {
2671 var count: usize = 0;
2672 var it = fn_proto.iterate(tree);
2673 while (it.next()) |param| {
2674 if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
2675 count += 1;
2676 }
2677 break :blk count;
2678 };
2679 const param_types = try fn_type_scope_arena.allocator.alloc(Zir.Inst.Ref, param_count);
2680
2681 var is_var_args = false;
2682 {
2683 var param_type_i: usize = 0;
2684 var it = fn_proto.iterate(tree);
2685 while (it.next()) |param| : (param_type_i += 1) {
2686 if (param.anytype_ellipsis3) |token| {
2687 switch (token_tags[token]) {
2688 .keyword_anytype => return mod.failTok(
2689 &fn_type_scope.base,
2690 token,
2691 "TODO implement anytype parameter",
2692 .{},
2693 ),
2694 .ellipsis3 => {
2695 is_var_args = true;
2696 break;
2697 },
2698 else => unreachable,
2699 }
2700 }
2701 const param_type_node = param.type_expr;
2702 assert(param_type_node != 0);
2703 param_types[param_type_i] =
2704 try AstGen.expr(&fn_type_scope, &fn_type_scope.base, .{ .ty = .type_type }, param_type_node);
2705 }
2706 assert(param_type_i == param_count);
2707 }
2708 if (fn_proto.lib_name) |lib_name_token| blk: {
2709 // TODO call std.zig.parseStringLiteral
2710 const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name_token), "\"");
2711 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
2712 const target = mod.comp.getTarget();
2713 if (target_util.is_libc_lib_name(target, lib_name_str)) {
2714 if (!mod.comp.bin_file.options.link_libc) {
2715 return mod.failTok(
2716 &fn_type_scope.base,
2717 lib_name_token,
2718 "dependency on libc must be explicitly specified in the build command",
2719 .{},
2720 );
2721 }
2722 break :blk;
2723 }
2724 if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
2725 if (!mod.comp.bin_file.options.link_libcpp) {
2726 return mod.failTok(
2727 &fn_type_scope.base,
2728 lib_name_token,
2729 "dependency on libc++ must be explicitly specified in the build command",
2730 .{},
2731 );
2732 }
2733 break :blk;
2734 }
2735 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
2736 return mod.failTok(
2737 &fn_type_scope.base,
2738 lib_name_token,
2739 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
2740 .{ lib_name_str, lib_name_str },
2741 );
2742 }
2743 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
2744 return mod.failTok(
2745 &fn_type_scope.base,
2746 lib_name_token,
2747 "unable to add link lib '{s}': {s}",
2748 .{ lib_name_str, @errorName(err) },
2749 );
2750 };
2751 }
2752 if (fn_proto.ast.align_expr != 0) {
2753 return mod.failNode(
2754 &fn_type_scope.base,
2755 fn_proto.ast.align_expr,
2756 "TODO implement function align expression",
2757 .{},
2758 );
2759 }
2760 if (fn_proto.ast.section_expr != 0) {
2761 return mod.failNode(
2762 &fn_type_scope.base,
2763 fn_proto.ast.section_expr,
2764 "TODO implement function section expression",
2765 .{},
2766 );
2767 }
2768
2769 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
2770 if (token_tags[maybe_bang] == .bang) {
2771 return mod.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{});
2772 }
2773 const return_type_inst = try AstGen.expr(
2774 &fn_type_scope,
2775 &fn_type_scope.base,
2776 .{ .ty = .type_type },
2777 fn_proto.ast.return_type,
2778 );
2779
2780 const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
2781 token_tags[maybe_export_token] == .keyword_extern
2782 else
2783 false;
2784
2785 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
2786 // TODO instead of enum literal type, this needs to be the
2787 // std.builtin.CallingConvention enum. We need to implement importing other files
2788 // and enums in order to fix this.
2789 try AstGen.comptimeExpr(
2790 &fn_type_scope,
2791 &fn_type_scope.base,
2792 .{ .ty = .enum_literal_type },
2793 fn_proto.ast.callconv_expr,
2794 )
2795 else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
2796 try fn_type_scope.addSmallStr(.enum_literal_small, "C")
2797 else
2798 .none;
2799
2800 const fn_type_inst: Zir.Inst.Ref = if (cc != .none) fn_type: {
2801 const tag: Zir.Inst.Tag = if (is_var_args) .fn_type_cc_var_args else .fn_type_cc;
2802 break :fn_type try fn_type_scope.addFnTypeCc(tag, .{
2803 .src_node = fn_proto.ast.proto_node,
2804 .ret_ty = return_type_inst,
2805 .param_types = param_types,
2806 .cc = cc,
2807 });
2808 } else fn_type: {
2809 const tag: Zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type;
2810 break :fn_type try fn_type_scope.addFnType(tag, .{
2811 .src_node = fn_proto.ast.proto_node,
2812 .ret_ty = return_type_inst,
2813 .param_types = param_types,
2814 });
2815 };
2816 _ = try fn_type_scope.addBreak(.break_inline, 0, fn_type_inst);
2817
2818 // We need the memory for the Type to go into the arena for the Decl
2819 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
2820 errdefer decl_arena.deinit();
2821 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
2822
2823 var fn_type_code = try fn_type_scope.finish();
2824 defer fn_type_code.deinit(mod.gpa);
2825 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2826 fn_type_code.dump(mod.gpa, "fn_type", &fn_type_scope.base, 0) catch {};
2827 }
2828
2829 var fn_type_sema: Sema = .{
2830 .mod = mod,
2831 .gpa = mod.gpa,
2832 .arena = &decl_arena.allocator,
2833 .code = fn_type_code,
2834 .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len),
2835 .owner_decl = decl,
2836 .namespace = decl.namespace,
2837 .func = null,
2838 .owner_func = null,
2839 .param_inst_list = &.{},
2840 };
2841 var block_scope: Scope.Block = .{
2842 .parent = null,
2843 .sema = &fn_type_sema,
2844 .src_decl = decl,
2845 .instructions = .{},
2846 .inlining = null,
2847 .is_comptime = true,
2848 };
2849 defer block_scope.instructions.deinit(mod.gpa);
2850
2851 const fn_type = try fn_type_sema.rootAsType(&block_scope);
2852 if (body_node == 0) {
2853 if (!is_extern) {
2854 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
2855 }
2856
2857 // Extern function.
2858 var type_changed = true;
2859 if (decl.typedValueManaged()) |tvm| {
2860 type_changed = !tvm.typed_value.ty.eql(fn_type);
2861
2862 tvm.deinit(mod.gpa);
2863 }
2864 const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
2865
2866 decl_arena_state.* = decl_arena.state;
2867 decl.typed_value = .{
2868 .most_recent = .{
2869 .typed_value = .{ .ty = fn_type, .val = fn_val },
2870 .arena = decl_arena_state,
2871 },
2872 };
2873 decl.analysis = .complete;
2874 decl.generation = mod.generation;
2875
2876 try mod.comp.bin_file.allocateDeclIndexes(decl);
2877 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
2878
2879 if (type_changed and mod.emit_h != null) {
2880 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
2881 }
2882
2883 return type_changed;
2884 }
2885
2886 if (fn_type.fnIsVarArgs()) {
2887 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
2888 }
2889
2890 const new_func = try decl_arena.allocator.create(Fn);
2891 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
2892
2893 const fn_zir: Zir = blk: {
2894 // We put the ZIR inside the Decl arena.
2895 var astgen = try AstGen.init(mod, decl, &decl_arena.allocator);
2896 astgen.ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count);
2897 defer astgen.deinit();
2898
2899 var gen_scope: Scope.GenZir = .{
2900 .force_comptime = false,
2901 .parent = &decl.namespace.base,
2902 .astgen = &astgen,
2903 };
2904 defer gen_scope.instructions.deinit(mod.gpa);
2905
2906 // Iterate over the parameters. We put the param names as the first N
2907 // items inside `extra` so that debug info later can refer to the parameter names
2908 // even while the respective source code is unloaded.
2909 try astgen.extra.ensureCapacity(mod.gpa, param_count);
2910
2911 var params_scope = &gen_scope.base;
2912 var i: usize = 0;
2913 var it = fn_proto.iterate(tree);
2914 while (it.next()) |param| : (i += 1) {
2915 const name_token = param.name_token.?;
2916 const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);
2917 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
2918 sub_scope.* = .{
2919 .parent = params_scope,
2920 .gen_zir = &gen_scope,
2921 .name = param_name,
2922 // Implicit const list first, then implicit arg list.
2923 .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
2924 .src = decl.tokSrcLoc(name_token),
2925 };
2926 params_scope = &sub_scope.base;
2927
2928 // Additionally put the param name into `string_bytes` and reference it with
2929 // `extra` so that we have access to the data in codegen, for debug info.
2930 const str_index = @intCast(u32, astgen.string_bytes.items.len);
2931 astgen.extra.appendAssumeCapacity(str_index);
2932 const used_bytes = astgen.string_bytes.items.len;
2933 try astgen.string_bytes.ensureCapacity(mod.gpa, used_bytes + param_name.len + 1);
2934 astgen.string_bytes.appendSliceAssumeCapacity(param_name);
2935 astgen.string_bytes.appendAssumeCapacity(0);
2936 }
2937
2938 _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node);
2939
2940 if (gen_scope.instructions.items.len == 0 or
2941 !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
2942 .isNoReturn())
2943 {
2944 // astgen uses result location semantics to coerce return operands.
2945 // Since we are adding the return instruction here, we must handle the coercion.
2946 // We do this by using the `ret_coerce` instruction.
2947 _ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
2948 }
2949
2950 const code = try gen_scope.finish();
2951 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
2952 code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {};
2953 }
2954
2955 break :blk code;
2956 };
2957
2958 const is_inline = fn_type.fnCallingConvention() == .Inline;
2959 const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
2960
2961 new_func.* = .{
2962 .state = anal_state,
2963 .zir = fn_zir,
2964 .body = undefined,
2965 .owner_decl = decl,
2966 };
2967 fn_payload.* = .{
2968 .base = .{ .tag = .function },
2969 .data = new_func,
2970 };
2971
2972 var prev_type_has_bits = false;
2973 var prev_is_inline = false;
2974 var type_changed = true;
2975
2976 if (decl.typedValueManaged()) |tvm| {
2977 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
2978 type_changed = !tvm.typed_value.ty.eql(fn_type);
2979 if (tvm.typed_value.val.castTag(.function)) |payload| {
2980 const prev_func = payload.data;
2981 prev_is_inline = prev_func.state == .inline_only;
2982 prev_func.deinit(mod.gpa);
2983 }
2984
2985 tvm.deinit(mod.gpa);
2986 }
2987
2988 decl_arena_state.* = decl_arena.state;
2989 decl.typed_value = .{
2990 .most_recent = .{
2991 .typed_value = .{
2992 .ty = fn_type,
2993 .val = Value.initPayload(&fn_payload.base),
2994 },
2995 .arena = decl_arena_state,
2996 },
2997 };
2998 decl.analysis = .complete;
2999 decl.generation = mod.generation;
3000
3001 if (!is_inline and fn_type.hasCodeGenBits()) {
3002 // We don't fully codegen the decl until later, but we do need to reserve a global
3003 // offset table index for it. This allows us to codegen decls out of dependency order,
3004 // increasing how many computations can be done in parallel.
3005 try mod.comp.bin_file.allocateDeclIndexes(decl);
3006 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
3007 if (type_changed and mod.emit_h != null) {
3008 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
3009 }
3010 } else if (!prev_is_inline and prev_type_has_bits) {
3011 mod.comp.bin_file.freeDecl(decl);
3012 }
3013
3014 if (fn_proto.extern_export_token) |maybe_export_token| {
3015 if (token_tags[maybe_export_token] == .keyword_export) {
3016 if (is_inline) {
3017 return mod.failTok(
3018 &block_scope.base,
3019 maybe_export_token,
3020 "export of inline function",
3021 .{},
3022 );
3023 }
3024 const export_src = decl.tokSrcLoc(maybe_export_token);
3025 const name = tree.tokenSlice(fn_proto.name_token.?); // TODO identifierTokenString
3026 // The scope needs to have the decl in it.
3027 try mod.analyzeExport(&block_scope.base, export_src, name, decl);
3028 }
3029 }
3030 return type_changed or is_inline != prev_is_inline;
3031}
3032
3033fn astgenAndSemaVarDecl(
3034 mod: *Module,
3035 decl: *Decl,
3036 tree: ast.Tree,
3037 var_decl: ast.full.VarDecl,
3038) !bool {
3039 const tracy = trace(@src());
3040 defer tracy.end();
3041
3042 decl.analysis = .in_progress;
3043 decl.is_pub = var_decl.visib_token != null;
3044
3045 const token_tags = tree.tokens.items(.tag);
3046
3047 // We need the memory for the Type to go into the arena for the Decl
3048 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
3049 errdefer decl_arena.deinit();
3050 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
3051
3052 // Used for simple error reporting.
3053 var decl_scope: Scope.DeclRef = .{ .decl = decl };
3054
3055 const is_extern = blk: {
3056 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
3057 break :blk token_tags[maybe_extern_token] == .keyword_extern;
3058 };
3059
3060 if (var_decl.lib_name) |lib_name| {
3061 assert(is_extern);
3062 return mod.failTok(&decl_scope.base, lib_name, "TODO implement function library name", .{});
3063 }
3064 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
3065 const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: {
3066 if (!is_mutable) {
3067 return mod.failTok(&decl_scope.base, some, "threadlocal variable cannot be constant", .{});
3068 }
3069 break :blk true;
3070 } else false;
3071 assert(var_decl.comptime_token == null);
3072 if (var_decl.ast.align_node != 0) {
3073 return mod.failNode(
3074 &decl_scope.base,
3075 var_decl.ast.align_node,
3076 "TODO implement function align expression",
3077 .{},
3078 );
3079 }
3080 if (var_decl.ast.section_node != 0) {
3081 return mod.failNode(
3082 &decl_scope.base,
3083 var_decl.ast.section_node,
3084 "TODO implement function section expression",
3085 .{},
3086 );
3087 }
3088
3089 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
3090 if (is_extern) {
3091 return mod.failNode(
3092 &decl_scope.base,
3093 var_decl.ast.init_node,
3094 "extern variables have no initializers",
3095 .{},
3096 );
3097 }
3098
3099 var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
3100 defer gen_scope_arena.deinit();
3101
3102 var astgen = try AstGen.init(mod, decl, &gen_scope_arena.allocator);
3103 defer astgen.deinit();
3104
3105 var gen_scope: Scope.GenZir = .{
3106 .force_comptime = true,
3107 .parent = &decl.namespace.base,
3108 .astgen = &astgen,
3109 };
3110 defer gen_scope.instructions.deinit(mod.gpa);
3111
3112 const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
3113 .ty = try AstGen.expr(&gen_scope, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node),
3114 } else .none;
3115
3116 const init_inst = try AstGen.comptimeExpr(
3117 &gen_scope,
3118 &gen_scope.base,
3119 init_result_loc,
3120 var_decl.ast.init_node,
3121 );
3122 _ = try gen_scope.addBreak(.break_inline, 0, init_inst);
3123 var code = try gen_scope.finish();
3124 defer code.deinit(mod.gpa);
3125 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
3126 code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
3127 }
3128
3129 var sema: Sema = .{
3130 .mod = mod,
3131 .gpa = mod.gpa,
3132 .arena = &gen_scope_arena.allocator,
3133 .code = code,
3134 .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
3135 .owner_decl = decl,
3136 .namespace = decl.namespace,
3137 .func = null,
3138 .owner_func = null,
3139 .param_inst_list = &.{},
3140 };
3141 var block_scope: Scope.Block = .{
3142 .parent = null,
3143 .sema = &sema,
3144 .src_decl = decl,
3145 .instructions = .{},
3146 .inlining = null,
3147 .is_comptime = true,
3148 };
3149 defer block_scope.instructions.deinit(mod.gpa);
3150
3151 const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
3152 // The result location guarantees the type coercion.
3153 const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref);
3154 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
3155 const val = analyzed_init_inst.value().?;
3156
3157 break :vi .{
3158 .ty = try analyzed_init_inst.ty.copy(&decl_arena.allocator),
3159 .val = try val.copy(&decl_arena.allocator),
3160 };
3161 } else if (!is_extern) {
3162 return mod.failTok(
3163 &decl_scope.base,
3164 var_decl.ast.mut_token,
3165 "variables must be initialized",
3166 .{},
3167 );
3168 } else if (var_decl.ast.type_node != 0) vi: {
3169 var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
3170 defer type_scope_arena.deinit();
3171
3172 var astgen = try AstGen.init(mod, decl, &type_scope_arena.allocator);
3173 defer astgen.deinit();
3174
3175 var type_scope: Scope.GenZir = .{
3176 .force_comptime = true,
3177 .parent = &decl.namespace.base,
3178 .astgen = &astgen,
3179 };
3180 defer type_scope.instructions.deinit(mod.gpa);
3181
3182 const var_type = try AstGen.typeExpr(&type_scope, &type_scope.base, var_decl.ast.type_node);
3183 _ = try type_scope.addBreak(.break_inline, 0, var_type);
3184
3185 var code = try type_scope.finish();
3186 defer code.deinit(mod.gpa);
3187 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
3188 code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
3189 }
3190
3191 var sema: Sema = .{
3192 .mod = mod,
3193 .gpa = mod.gpa,
3194 .arena = &type_scope_arena.allocator,
3195 .code = code,
3196 .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
3197 .owner_decl = decl,
3198 .namespace = decl.namespace,
3199 .func = null,
3200 .owner_func = null,
3201 .param_inst_list = &.{},
3202 };
3203 var block_scope: Scope.Block = .{
3204 .parent = null,
3205 .sema = &sema,
3206 .src_decl = decl,
3207 .instructions = .{},
3208 .inlining = null,
3209 .is_comptime = true,
3210 };
3211 defer block_scope.instructions.deinit(mod.gpa);
3212
3213 const ty = try sema.rootAsType(&block_scope);
3214
3215 break :vi .{
3216 .ty = try ty.copy(&decl_arena.allocator),
3217 .val = null,
3218 };
3219 } else {
3220 return mod.failTok(
3221 &decl_scope.base,
3222 var_decl.ast.mut_token,
3223 "unable to infer variable type",
3224 .{},
3225 );
3226 };
3227
3228 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
3229 return mod.failTok(
3230 &decl_scope.base,
3231 var_decl.ast.mut_token,
3232 "variable of type '{}' must be const",
3233 .{var_info.ty},
3234 );
3235 }
3236
3237 var type_changed = true;
3238 if (decl.typedValueManaged()) |tvm| {
3239 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
3240
3241 tvm.deinit(mod.gpa);
3242 }
3243
3244 const new_variable = try decl_arena.allocator.create(Var);
3245 new_variable.* = .{
3246 .owner_decl = decl,
3247 .init = var_info.val orelse undefined,
3248 .is_extern = is_extern,
3249 .is_mutable = is_mutable,
3250 .is_threadlocal = is_threadlocal,
3251 };
3252 const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
3253
3254 decl_arena_state.* = decl_arena.state;
3255 decl.typed_value = .{
3256 .most_recent = .{
3257 .typed_value = .{
3258 .ty = var_info.ty,
3259 .val = var_val,
3260 },
3261 .arena = decl_arena_state,
3262 },
3263 };
3264 decl.analysis = .complete;
3265 decl.generation = mod.generation;
3266
3267 if (var_decl.extern_export_token) |maybe_export_token| {
3268 if (token_tags[maybe_export_token] == .keyword_export) {
3269 const export_src = decl.tokSrcLoc(maybe_export_token);
3270 const name_token = var_decl.ast.mut_token + 1;
3271 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
3272 // The scope needs to have the decl in it.
3273 try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
3274 }
3275 }
3276 return type_changed;
2651 @panic("TODO implement semaDecl");
32772652}
32782653
32792654/// Returns the depender's index of the dependee.
3280pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
2655pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
32812656 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);
32822657 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);
32832658
......@@ -3287,61 +2662,7 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3
32872662 }
32882663
32892664 dependee.dependants.putAssumeCapacity(depender, {});
3290 const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
3291 return @intCast(u32, gop.index);
3292}
3293
3294pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
3295 const tracy = trace(@src());
3296 defer tracy.end();
3297
3298 switch (file.status) {
3299 .never_loaded, .unloaded_success => {
3300 const gpa = mod.gpa;
3301
3302 try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1);
3303
3304 const source = try file.getSource(gpa);
3305
3306 var keep_tree = false;
3307 file.tree = try std.zig.parse(gpa, source);
3308 defer if (!keep_tree) file.tree.deinit(gpa);
3309
3310 const tree = &file.tree;
3311
3312 if (tree.errors.len != 0) {
3313 const parse_err = tree.errors[0];
3314
3315 var msg = std.ArrayList(u8).init(gpa);
3316 defer msg.deinit();
3317
3318 const token_starts = tree.tokens.items(.start);
3319
3320 try tree.renderError(parse_err, msg.writer());
3321 const err_msg = try gpa.create(ErrorMsg);
3322 err_msg.* = .{
3323 .src_loc = .{
3324 .container = .{ .file_scope = file },
3325 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
3326 },
3327 .msg = msg.toOwnedSlice(),
3328 };
3329
3330 mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
3331 file.status = .unloaded_parse_failure;
3332 return error.AnalysisFail;
3333 }
3334
3335 file.status = .loaded_success;
3336 keep_tree = true;
3337
3338 return tree;
3339 },
3340
3341 .unloaded_parse_failure => return error.AnalysisFail,
3342
3343 .loaded_success => return &file.tree,
3344 }
2665 depender.dependencies.putAssumeCapacity(dependee, {});
33452666}
33462667
33472668pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*Scope.File {
......@@ -3375,136 +2696,21 @@ pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*
33752696 .sub_file_path = resolved_path,
33762697 .source = undefined,
33772698 .source_loaded = false,
2699 .tree_loaded = false,
2700 .zir_loaded = false,
33782701 .stat_size = undefined,
33792702 .stat_inode = undefined,
33802703 .stat_mtime = undefined,
33812704 .tree = undefined,
2705 .zir = undefined,
33822706 .status = .never_loaded,
33832707 .pkg = found_pkg orelse cur_pkg,
33842708 .namespace = undefined,
33852709 };
33862710 keep_resolved_path = true;
3387
3388 const tree = try mod.getAstTree(new_file);
3389
3390 const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|
3391 pkg.namespace_hash
3392 else
3393 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
3394
3395 // We need a Decl to pass to AstGen and collect dependencies. But ultimately we
3396 // want to pass them on to the Decl for the struct that represents the file.
3397 var tmp_namespace: Scope.Namespace = .{
3398 .parent = null,
3399 .file_scope = new_file,
3400 .parent_name_hash = parent_name_hash,
3401 .ty = Type.initTag(.type),
3402 };
3403
3404 const top_decl = try mod.createNewDecl(
3405 &tmp_namespace,
3406 resolved_path,
3407 0,
3408 parent_name_hash,
3409 std.zig.hashSrc(tree.source),
3410 );
3411 defer {
3412 mod.decl_table.removeAssertDiscard(parent_name_hash);
3413 top_decl.destroy(mod);
3414 }
3415
3416 var gen_scope_arena = std.heap.ArenaAllocator.init(gpa);
3417 defer gen_scope_arena.deinit();
3418
3419 var astgen = try AstGen.init(mod, top_decl, &gen_scope_arena.allocator);
3420 defer astgen.deinit();
3421
3422 var gen_scope: Scope.GenZir = .{
3423 .force_comptime = true,
3424 .parent = &new_file.base,
3425 .astgen = &astgen,
3426 };
3427 defer gen_scope.instructions.deinit(gpa);
3428
3429 const container_decl: ast.full.ContainerDecl = .{
3430 .layout_token = null,
3431 .ast = .{
3432 .main_token = undefined,
3433 .enum_token = null,
3434 .members = tree.rootDecls(),
3435 .arg = 0,
3436 },
3437 };
3438
3439 const struct_decl_ref = try AstGen.structDeclInner(
3440 &gen_scope,
3441 &gen_scope.base,
3442 0,
3443 container_decl,
3444 .struct_decl,
3445 );
3446 _ = try gen_scope.addBreak(.break_inline, 0, struct_decl_ref);
3447
3448 var code = try gen_scope.finish();
3449 defer code.deinit(gpa);
3450 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
3451 code.dump(gpa, "import", &gen_scope.base, 0) catch {};
3452 }
3453
3454 var sema: Sema = .{
3455 .mod = mod,
3456 .gpa = gpa,
3457 .arena = &gen_scope_arena.allocator,
3458 .code = code,
3459 .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
3460 .owner_decl = top_decl,
3461 .namespace = top_decl.namespace,
3462 .func = null,
3463 .owner_func = null,
3464 .param_inst_list = &.{},
3465 };
3466 var block_scope: Scope.Block = .{
3467 .parent = null,
3468 .sema = &sema,
3469 .src_decl = top_decl,
3470 .instructions = .{},
3471 .inlining = null,
3472 .is_comptime = true,
3473 };
3474 defer block_scope.instructions.deinit(gpa);
3475
3476 const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
3477 const analyzed_struct_inst = try sema.resolveInst(init_inst_zir_ref);
3478 assert(analyzed_struct_inst.ty.zigTypeTag() == .Type);
3479 const val = analyzed_struct_inst.value().?;
3480 const struct_ty = try val.toType(&gen_scope_arena.allocator);
3481 const struct_decl = struct_ty.getOwnerDecl();
3482
3483 struct_decl.contents_hash = top_decl.contents_hash;
3484 new_file.namespace = struct_ty.getNamespace().?;
3485 new_file.namespace.parent = null;
3486 //new_file.namespace.parent_name_hash = tmp_namespace.parent_name_hash;
3487
3488 // Transfer the dependencies to `owner_decl`.
3489 assert(top_decl.dependants.count() == 0);
3490 for (top_decl.dependencies.items()) |entry| {
3491 const dep = entry.key;
3492 dep.removeDependant(top_decl);
3493 if (dep == struct_decl) continue;
3494 _ = try mod.declareDeclDependency(struct_decl, dep);
3495 }
3496
34972711 return new_file;
34982712}
34992713
3500pub fn analyzeFile(mod: *Module, file: *Scope.File) !void {
3501 // We call `getAstTree` here so that `analyzeFile` has the error set that includes
3502 // file system operations, but `analyzeNamespace` does not.
3503 const tree = try mod.getAstTree(file.namespace.file_scope);
3504 const decls = tree.rootDecls();
3505 return mod.analyzeNamespace(file.namespace, decls);
3506}
3507
35082714pub fn analyzeNamespace(
35092715 mod: *Module,
35102716 namespace: *Scope.Namespace,
......@@ -3515,7 +2721,7 @@ pub fn analyzeNamespace(
35152721
35162722 // We may be analyzing it for the first time, or this may be
35172723 // an incremental update. This code handles both cases.
3518 assert(namespace.file_scope.status == .loaded_success); // Caller must ensure tree loaded.
2724 assert(namespace.file_scope.tree_loaded); // Caller must ensure tree loaded.
35192725 const tree: *const ast.Tree = &namespace.file_scope.tree;
35202726 const node_tags = tree.nodes.items(.tag);
35212727 const node_datas = tree.nodes.items(.data);
......@@ -4449,20 +3655,6 @@ pub fn fail(
44493655 return mod.failWithOwnedErrorMsg(scope, err_msg);
44503656}
44513657
4452/// Same as `fail`, except given an absolute byte offset, and the function sets up the `LazySrcLoc`
4453/// for pointing at it relatively by subtracting from the containing `Decl`.
4454pub fn failOff(
4455 mod: *Module,
4456 scope: *Scope,
4457 byte_offset: u32,
4458 comptime format: []const u8,
4459 args: anytype,
4460) InnerError {
4461 const decl_byte_offset = scope.srcDecl().?.srcByteOffset();
4462 const src: LazySrcLoc = .{ .byte_offset = byte_offset - decl_byte_offset };
4463 return mod.fail(scope, src, format, args);
4464}
4465
44663658/// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc`
44673659/// for pointing at it relatively by subtracting from the containing `Decl`.
44683660pub fn failTok(
......@@ -4491,6 +3683,7 @@ pub fn failNode(
44913683
44923684pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
44933685 @setCold(true);
3686
44943687 {
44953688 errdefer err_msg.destroy(mod.gpa);
44963689 try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);
......@@ -4507,24 +3700,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In
45073700 }
45083701 mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg);
45093702 },
4510 .gen_zir => {
4511 const gen_zir = scope.cast(Scope.GenZir).?;
4512 gen_zir.astgen.decl.analysis = .sema_failure;
4513 gen_zir.astgen.decl.generation = mod.generation;
4514 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
4515 },
4516 .local_val => {
4517 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
4518 gen_zir.astgen.decl.analysis = .sema_failure;
4519 gen_zir.astgen.decl.generation = mod.generation;
4520 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
4521 },
4522 .local_ptr => {
4523 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
4524 gen_zir.astgen.decl.analysis = .sema_failure;
4525 gen_zir.astgen.decl.generation = mod.generation;
4526 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
4527 },
3703 .gen_zir, .local_val, .local_ptr => unreachable,
45283704 .file => unreachable,
45293705 .namespace => unreachable,
45303706 .decl_ref => {
......@@ -4873,132 +4049,3 @@ pub fn getTarget(mod: Module) Target {
48734049pub fn optimizeMode(mod: Module) std.builtin.Mode {
48744050 return mod.comp.bin_file.options.optimize_mode;
48754051}
4876
4877/// Given an identifier token, obtain the string for it.
4878/// If the token uses @"" syntax, parses as a string, reports errors if applicable,
4879/// and allocates the result within `scope.arena()`.
4880/// Otherwise, returns a reference to the source code bytes directly.
4881/// See also `appendIdentStr` and `parseStrLit`.
4882pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
4883 const tree = scope.tree();
4884 const token_tags = tree.tokens.items(.tag);
4885 assert(token_tags[token] == .identifier);
4886 const ident_name = tree.tokenSlice(token);
4887 if (!mem.startsWith(u8, ident_name, "@")) {
4888 return ident_name;
4889 }
4890 var buf: ArrayListUnmanaged(u8) = .{};
4891 defer buf.deinit(mod.gpa);
4892 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4893 const duped = try scope.arena().dupe(u8, buf.items);
4894 return duped;
4895}
4896
4897/// `scope` is only used for error reporting.
4898/// The string is stored in `arena` regardless of whether it uses @"" syntax.
4899pub fn identifierTokenStringTreeArena(
4900 mod: *Module,
4901 scope: *Scope,
4902 token: ast.TokenIndex,
4903 tree: *const ast.Tree,
4904 arena: *Allocator,
4905) InnerError![]u8 {
4906 const token_tags = tree.tokens.items(.tag);
4907 assert(token_tags[token] == .identifier);
4908 const ident_name = tree.tokenSlice(token);
4909 if (!mem.startsWith(u8, ident_name, "@")) {
4910 return arena.dupe(u8, ident_name);
4911 }
4912 var buf: ArrayListUnmanaged(u8) = .{};
4913 defer buf.deinit(mod.gpa);
4914 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4915 return arena.dupe(u8, buf.items);
4916}
4917
4918/// Given an identifier token, obtain the string for it (possibly parsing as a string
4919/// literal if it is @"" syntax), and append the string to `buf`.
4920/// See also `identifierTokenString` and `parseStrLit`.
4921pub fn appendIdentStr(
4922 mod: *Module,
4923 scope: *Scope,
4924 token: ast.TokenIndex,
4925 buf: *ArrayListUnmanaged(u8),
4926) InnerError!void {
4927 const tree = scope.tree();
4928 const token_tags = tree.tokens.items(.tag);
4929 assert(token_tags[token] == .identifier);
4930 const ident_name = tree.tokenSlice(token);
4931 if (!mem.startsWith(u8, ident_name, "@")) {
4932 return buf.appendSlice(mod.gpa, ident_name);
4933 } else {
4934 return mod.parseStrLit(scope, token, buf, ident_name, 1);
4935 }
4936}
4937
4938/// Appends the result to `buf`.
4939pub fn parseStrLit(
4940 mod: *Module,
4941 scope: *Scope,
4942 token: ast.TokenIndex,
4943 buf: *ArrayListUnmanaged(u8),
4944 bytes: []const u8,
4945 offset: u32,
4946) InnerError!void {
4947 const tree = scope.tree();
4948 const token_starts = tree.tokens.items(.start);
4949 const raw_string = bytes[offset..];
4950 var buf_managed = buf.toManaged(mod.gpa);
4951 const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string);
4952 buf.* = buf_managed.toUnmanaged();
4953 switch (try result) {
4954 .success => return,
4955 .invalid_character => |bad_index| {
4956 return mod.failOff(
4957 scope,
4958 token_starts[token] + offset + @intCast(u32, bad_index),
4959 "invalid string literal character: '{c}'",
4960 .{raw_string[bad_index]},
4961 );
4962 },
4963 .expected_hex_digits => |bad_index| {
4964 return mod.failOff(
4965 scope,
4966 token_starts[token] + offset + @intCast(u32, bad_index),
4967 "expected hex digits after '\\x'",
4968 .{},
4969 );
4970 },
4971 .invalid_hex_escape => |bad_index| {
4972 return mod.failOff(
4973 scope,
4974 token_starts[token] + offset + @intCast(u32, bad_index),
4975 "invalid hex digit: '{c}'",
4976 .{raw_string[bad_index]},
4977 );
4978 },
4979 .invalid_unicode_escape => |bad_index| {
4980 return mod.failOff(
4981 scope,
4982 token_starts[token] + offset + @intCast(u32, bad_index),
4983 "invalid unicode digit: '{c}'",
4984 .{raw_string[bad_index]},
4985 );
4986 },
4987 .missing_matching_rbrace => |bad_index| {
4988 return mod.failOff(
4989 scope,
4990 token_starts[token] + offset + @intCast(u32, bad_index),
4991 "missing matching '}}' character",
4992 .{},
4993 );
4994 },
4995 .expected_unicode_digits => |bad_index| {
4996 return mod.failOff(
4997 scope,
4998 token_starts[token] + offset + @intCast(u32, bad_index),
4999 "expected unicode digits after '\\u'",
5000 .{},
5001 );
5002 },
5003 }
5004}
src/Sema.zig+11-14
......@@ -199,10 +199,10 @@ pub fn analyzeBody(
199199 .field_val => try sema.zirFieldVal(block, inst),
200200 .field_val_named => try sema.zirFieldValNamed(block, inst),
201201 .floatcast => try sema.zirFloatcast(block, inst),
202 .fn_type => try sema.zirFnType(block, inst, false),
203 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
204 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
205 .fn_type_var_args => try sema.zirFnType(block, inst, true),
202 .func => try sema.zirFunc(block, inst, false),
203 .func_extra => try sema.zirFuncExtra(block, inst, false),
204 .func_extra_var_args => try sema.zirFuncExtra(block, inst, true),
205 .func_var_args => try sema.zirFunc(block, inst, true),
206206 .has_decl => try sema.zirHasDecl(block, inst),
207207 .import => try sema.zirImport(block, inst),
208208 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
......@@ -2513,16 +2513,16 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
25132513 }
25142514}
25152515
2516fn zirFnType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
2516fn zirFunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
25172517 const tracy = trace(@src());
25182518 defer tracy.end();
25192519
25202520 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
25212521 const src = inst_data.src();
2522 const extra = sema.code.extraData(Zir.Inst.FnType, inst_data.payload_index);
2522 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
25232523 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
25242524
2525 return sema.fnTypeCommon(
2525 return sema.funcCommon(
25262526 block,
25272527 inst_data.src_node,
25282528 param_types,
......@@ -2532,14 +2532,14 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: b
25322532 );
25332533}
25342534
2535fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
2535fn zirFuncExtra(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
25362536 const tracy = trace(@src());
25372537 defer tracy.end();
25382538
25392539 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
25402540 const src = inst_data.src();
25412541 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
2542 const extra = sema.code.extraData(Zir.Inst.FnTypeCc, inst_data.payload_index);
2542 const extra = sema.code.extraData(Zir.Inst.FuncExtra, inst_data.payload_index);
25432543 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
25442544
25452545 const cc_tv = try sema.resolveInstConst(block, cc_src, extra.data.cc);
......@@ -2548,7 +2548,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:
25482548 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
25492549 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
25502550 return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str});
2551 return sema.fnTypeCommon(
2551 return sema.funcCommon(
25522552 block,
25532553 inst_data.src_node,
25542554 param_types,
......@@ -2558,7 +2558,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:
25582558 );
25592559}
25602560
2561fn fnTypeCommon(
2561fn funcCommon(
25622562 sema: *Sema,
25632563 block: *Scope.Block,
25642564 src_node_offset: i32,
......@@ -3921,9 +3921,6 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
39213921 error.ImportOutsidePkgPath => {
39223922 return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
39233923 },
3924 error.FileNotFound => {
3925 return mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
3926 },
39273924 else => {
39283925 // TODO: these errors are file system errors; make sure an update() will
39293926 // retry this and not cache the file system error, which may be transient.
src/Zir.zig+103-38
......@@ -26,8 +26,6 @@ const ir = @import("ir.zig");
2626const Module = @import("Module.zig");
2727const LazySrcLoc = Module.LazySrcLoc;
2828
29/// There is always implicitly a `block` instruction at index 0.
30/// This is so that `break_inline` can break from the root block.
3129instructions: std.MultiArrayList(Inst).Slice,
3230/// In order to store references to strings in fewer bytes, we copy all
3331/// string bytes into here. String bytes can be null. It is up to whomever
......@@ -36,6 +34,12 @@ instructions: std.MultiArrayList(Inst).Slice,
3634/// `string_bytes` array is agnostic to either usage.
3735string_bytes: []u8,
3836/// The meaning of this data is determined by `Inst.Tag` value.
37/// Indexes 0 and 1 are reserved for:
38/// 0. struct_decl: Ref
39/// - the main struct decl for this file
40/// 1. errors_payload_index: u32
41/// - if this is 0, no compile errors. Otherwise there is a `CompileErrors`
42/// payload at this index.
3943extra: []u32,
4044
4145/// Returns the requested data, as well as the new index which is at the start of the
......@@ -358,16 +362,19 @@ pub const Inst = struct {
358362 /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
359363 /// Payload is `Bin` with lhs as the dest type, rhs the operand.
360364 floatcast,
361 /// Returns a function type, assuming unspecified calling convention.
362 /// Uses the `pl_node` union field. `payload_index` points to a `FnType`.
363 fn_type,
364 /// Same as `fn_type` but the function is variadic.
365 fn_type_var_args,
366 /// Returns a function type, with a calling convention instruction operand.
367 /// Uses the `pl_node` union field. `payload_index` points to a `FnTypeCc`.
368 fn_type_cc,
369 /// Same as `fn_type_cc` but the function is variadic.
370 fn_type_cc_var_args,
365 /// Returns a function type, or a function instance, depending on whether
366 /// the body_len is 0. Calling convention is auto.
367 /// Uses the `pl_node` union field. `payload_index` points to a `Func`.
368 func,
369 /// Same as `func` but the function is variadic.
370 func_var_args,
371 /// Same as `func` but with extra fields:
372 /// * calling convention
373 /// * extern lib name
374 /// Uses the `pl_node` union field. `payload_index` points to a `FuncExtra`.
375 func_extra,
376 /// Same as `func_extra` but the function is variadic.
377 func_extra_var_args,
371378 /// Implements the `@hasDecl` builtin.
372379 /// Uses the `pl_node` union field. Payload is `Bin`.
373380 has_decl,
......@@ -769,10 +776,10 @@ pub const Inst = struct {
769776 .field_val,
770777 .field_ptr_named,
771778 .field_val_named,
772 .fn_type,
773 .fn_type_var_args,
774 .fn_type_cc,
775 .fn_type_cc_var_args,
779 .func,
780 .func_var_args,
781 .func_extra,
782 .func_extra_var_args,
776783 .has_decl,
777784 .int,
778785 .float,
......@@ -1372,21 +1379,25 @@ pub const Inst = struct {
13721379 clobbers_len: u32,
13731380 };
13741381
1375 /// This data is stored inside extra, with trailing parameter type indexes
1376 /// according to `param_types_len`.
1377 /// Each param type is a `Ref`.
1378 pub const FnTypeCc = struct {
1379 return_type: Ref,
1382 /// Trailing:
1383 /// 0. param_type: Ref // for each param_types_len
1384 /// 1. body: Index // for each body_len
1385 pub const FuncExtra = struct {
13801386 cc: Ref,
1387 /// null terminated string index, or 0 to mean none.
1388 lib_name: u32,
1389 return_type: Ref,
13811390 param_types_len: u32,
1391 body_len: u32,
13821392 };
13831393
1384 /// This data is stored inside extra, with trailing parameter type indexes
1385 /// according to `param_types_len`.
1386 /// Each param type is a `Ref`.
1387 pub const FnType = struct {
1394 /// Trailing:
1395 /// 0. param_type: Ref // for each param_types_len
1396 /// 1. body: Index // for each body_len
1397 pub const Func = struct {
13881398 return_type: Ref,
13891399 param_types_len: u32,
1400 body_len: u32,
13901401 };
13911402
13921403 /// This data is stored inside extra, with trailing operands according to `operands_len`.
......@@ -1531,9 +1542,18 @@ pub const Inst = struct {
15311542 /// align: Ref, // if corresponding bit is set
15321543 /// default_value: Ref, // if corresponding bit is set
15331544 /// }
1545 /// 3. decl_bits: u32 // for every 16 decls
1546 /// - sets of 2 bits:
1547 /// 0b0X: whether corresponding decl is pub
1548 /// 0bX0: whether corresponding decl is exported
1549 /// 4. decl: { // for every decls_len
1550 /// name: u32, // null terminated string index
1551 /// value: Ref,
1552 /// }
15341553 pub const StructDecl = struct {
15351554 body_len: u32,
15361555 fields_len: u32,
1556 decls_len: u32,
15371557 };
15381558
15391559 /// Trailing:
......@@ -1600,6 +1620,26 @@ pub const Inst = struct {
16001620 /// Offset into `string_bytes`, null terminated.
16011621 name_start: u32,
16021622 };
1623
1624 /// Trailing: `CompileErrors.Item` for each `items_len`.
1625 pub const CompileErrors = struct {
1626 items_len: u32,
1627
1628 /// Trailing: `note_payload_index: u32` for each `notes_len`.
1629 /// It's a payload index of another `Item`.
1630 pub const Item = struct {
1631 /// null terminated string index
1632 msg: u32,
1633 node: ast.Node.Index,
1634 /// If node is 0 then this will be populated.
1635 token: ast.TokenIndex,
1636 /// Can be used in combination with `token`.
1637 byte_offset: u32,
1638 /// 0 or a payload index of a `Block`, each is a payload
1639 /// index of another `Item`.
1640 notes: u32,
1641 };
1642 };
16031643};
16041644
16051645pub const SpecialProng = enum { none, @"else", under };
......@@ -1819,10 +1859,10 @@ const Writer = struct {
18191859 .decl_val_named,
18201860 => try self.writeStrTok(stream, inst),
18211861
1822 .fn_type => try self.writeFnType(stream, inst, false),
1823 .fn_type_cc => try self.writeFnTypeCc(stream, inst, false),
1824 .fn_type_var_args => try self.writeFnType(stream, inst, true),
1825 .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),
1862 .func => try self.writeFunc(stream, inst, false),
1863 .func_extra => try self.writeFuncExtra(stream, inst, false),
1864 .func_var_args => try self.writeFunc(stream, inst, true),
1865 .func_extra_var_args => try self.writeFuncExtra(stream, inst, true),
18261866
18271867 .@"unreachable" => try self.writeUnreachable(stream, inst),
18281868
......@@ -2383,7 +2423,7 @@ const Writer = struct {
23832423 try self.writeSrc(stream, inst_data.src());
23842424 }
23852425
2386 fn writeFnType(
2426 fn writeFunc(
23872427 self: *Writer,
23882428 stream: anytype,
23892429 inst: Inst.Index,
......@@ -2391,23 +2431,41 @@ const Writer = struct {
23912431 ) !void {
23922432 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
23932433 const src = inst_data.src();
2394 const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);
2434 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);
23952435 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
2396 return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, .none, src);
2436 const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
2437 return self.writeFuncCommon(
2438 stream,
2439 param_types,
2440 extra.data.return_type,
2441 var_args,
2442 .none,
2443 body,
2444 src,
2445 );
23972446 }
23982447
2399 fn writeFnTypeCc(
2448 fn writeFuncExtra(
24002449 self: *Writer,
24012450 stream: anytype,
24022451 inst: Inst.Index,
24032452 var_args: bool,
2404 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2453 ) !void {
24052454 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
24062455 const src = inst_data.src();
2407 const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);
2456 const extra = self.code.extraData(Inst.FuncExtra, inst_data.payload_index);
24082457 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
24092458 const cc = extra.data.cc;
2410 return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, cc, src);
2459 const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
2460 return self.writeFuncCommon(
2461 stream,
2462 param_types,
2463 extra.data.return_type,
2464 var_args,
2465 cc,
2466 body,
2467 src,
2468 );
24112469 }
24122470
24132471 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
......@@ -2449,13 +2507,14 @@ const Writer = struct {
24492507 try self.writeSrc(stream, inst_data.src());
24502508 }
24512509
2452 fn writeFnTypeCommon(
2510 fn writeFuncCommon(
24532511 self: *Writer,
24542512 stream: anytype,
24552513 param_types: []const Inst.Ref,
24562514 ret_ty: Inst.Ref,
24572515 var_args: bool,
24582516 cc: Inst.Ref,
2517 body: []const Inst.Index,
24592518 src: LazySrcLoc,
24602519 ) !void {
24612520 try stream.writeAll("[");
......@@ -2467,7 +2526,13 @@ const Writer = struct {
24672526 try self.writeInstRef(stream, ret_ty);
24682527 try self.writeOptionalInstRef(stream, ", cc=", cc);
24692528 try self.writeFlag(stream, ", var_args", var_args);
2470 try stream.writeAll(") ");
2529
2530 try stream.writeAll(", {\n");
2531 self.indent += 2;
2532 try self.writeBody(stream, body);
2533 self.indent -= 2;
2534 try stream.writeByteNTimes(' ', self.indent);
2535 try stream.writeAll("}) ");
24712536 try self.writeSrc(stream, src);
24722537 }
24732538