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 @@...@@ -4,6 +4,13 @@
4 on each usingnamespace decl4 on each usingnamespace decl
5 * handle usingnamespace cycles5 * 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
8 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|15 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
9 pkg.namespace_hash16 pkg.namespace_hash
...@@ -99,3 +106,1114 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd...@@ -99,3 +106,1114 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
99}106}
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;...@@ -25,37 +25,20 @@ const Decl = Module.Decl;
25const LazySrcLoc = Module.LazySrcLoc;25const LazySrcLoc = Module.LazySrcLoc;
26const BuiltinFn = @import("BuiltinFn.zig");26const BuiltinFn = @import("BuiltinFn.zig");
2727
28gpa: *Allocator,
29file: *Scope.File,
28instructions: std.MultiArrayList(Zir.Inst) = .{},30instructions: std.MultiArrayList(Zir.Inst) = .{},
29string_bytes: ArrayListUnmanaged(u8) = .{},
30extra: ArrayListUnmanaged(u32) = .{},31extra: ArrayListUnmanaged(u32) = .{},
31/// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert32string_bytes: ArrayListUnmanaged(u8) = .{},
32/// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters.33/// Used for temporary allocations; freed after AstGen is complete.
33ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len,34/// The resulting ZIR code has no references to anything in this arena.
34mod: *Module,
35decl: *Decl,
36arena: *Allocator,35arena: *Allocator,
3736string_table: std.StringHashMapUnmanaged(u32) = .{},
38/// Call `deinit` on the result.37compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
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}
5538
56pub fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {39pub fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {
57 const fields = std.meta.fields(@TypeOf(extra));40 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);
59 return addExtraAssumeCapacity(astgen, extra);42 return addExtraAssumeCapacity(astgen, extra);
60}43}
6144
...@@ -74,7 +57,7 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {...@@ -74,7 +57,7 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
7457
75pub fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void {58pub fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void {
76 const coerced = @bitCast([]const u32, refs);59 const coerced = @bitCast([]const u32, refs);
77 return astgen.extra.appendSlice(astgen.mod.gpa, coerced);60 return astgen.extra.appendSlice(astgen.gpa, coerced);
78}61}
7962
80pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void {63pub 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...@@ -82,32 +65,75 @@ pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) voi
82 astgen.extra.appendSliceAssumeCapacity(coerced);65 astgen.extra.appendSliceAssumeCapacity(coerced);
83}66}
8467
85pub fn refIsNoReturn(astgen: AstGen, inst_ref: Zir.Inst.Ref) bool {68pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir {
86 if (inst_ref == .unreachable_value) return true;69 var arena = std.heap.ArenaAllocator.init(gpa);
87 if (astgen.refToIndex(inst_ref)) |inst_index| {70 defer arena.deinit();
88 return astgen.instructions.items(.tag)[inst_index].isNoReturn();
89 }
90 return false;
91}
9271
93pub fn indexToRef(astgen: AstGen, inst: Zir.Inst.Index) Zir.Inst.Ref {72 var astgen: AstGen = .{
94 return @intToEnum(Zir.Inst.Ref, astgen.ref_start_index + inst);73 .gpa = gpa,
95}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 {108 if (astgen.compile_errors.items.len == 0) {
98 const ref_int = @enumToInt(inst);109 astgen.extra.items[1] = 0;
99 if (ref_int >= astgen.ref_start_index) {
100 return ref_int - astgen.ref_start_index;
101 } else {110 } 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 }
103 }122 }
123
124 return Zir{
125 .instructions = astgen.instructions.toOwnedSlice(),
126 .string_bytes = astgen.string_bytes.toOwnedSlice(gpa),
127 .extra = astgen.extra.toOwnedSlice(gpa),
128 };
104}129}
105130
106pub fn deinit(astgen: *AstGen) void {131pub fn deinit(astgen: *AstGen, gpa: *Allocator) void {
107 const gpa = astgen.mod.gpa;
108 astgen.instructions.deinit(gpa);132 astgen.instructions.deinit(gpa);
109 astgen.extra.deinit(gpa);133 astgen.extra.deinit(gpa);
134 astgen.string_table.deinit(gpa);
110 astgen.string_bytes.deinit(gpa);135 astgen.string_bytes.deinit(gpa);
136 astgen.compile_errors.deinit(gpa);
111}137}
112138
113pub const ResultLoc = union(enum) {139pub const ResultLoc = union(enum) {
...@@ -193,7 +219,8 @@ pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerErro...@@ -193,7 +219,8 @@ pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerErro
193}219}
194220
195fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {221fn 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;
197 const node_tags = tree.nodes.items(.tag);224 const node_tags = tree.nodes.items(.tag);
198 const main_tokens = tree.nodes.items(.main_token);225 const main_tokens = tree.nodes.items(.main_token);
199 switch (node_tags[node]) {226 switch (node_tags[node]) {
...@@ -351,7 +378,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins...@@ -351,7 +378,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins
351 .@"comptime",378 .@"comptime",
352 .@"nosuspend",379 .@"nosuspend",
353 .error_value,380 .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
356 .builtin_call,383 .builtin_call,
357 .builtin_call_comma,384 .builtin_call_comma,
...@@ -364,7 +391,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins...@@ -364,7 +391,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins
364 // let it pass, and the error will be "invalid builtin function" later.391 // let it pass, and the error will be "invalid builtin function" later.
365 if (BuiltinFn.list.get(builtin_name)) |info| {392 if (BuiltinFn.list.get(builtin_name)) |info| {
366 if (!info.allows_lvalue) {393 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", .{});
368 }395 }
369 }396 }
370 },397 },
...@@ -387,8 +414,8 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins...@@ -387,8 +414,8 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins
387/// result instruction can be used to inspect whether it is isNoReturn() but that is it,414/// result instruction can be used to inspect whether it is isNoReturn() but that is it,
388/// it must otherwise not be used.415/// it must otherwise not be used.
389pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {416pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
390 const mod = gz.astgen.mod;417 const astgen = gz.astgen;
391 const tree = gz.tree();418 const tree = &astgen.file.tree;
392 const main_tokens = tree.nodes.items(.main_token);419 const main_tokens = tree.nodes.items(.main_token);
393 const token_tags = tree.tokens.items(.tag);420 const token_tags = tree.tokens.items(.tag);
394 const node_datas = tree.nodes.items(.data);421 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...@@ -548,7 +575,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
548 .tag = .@"unreachable",575 .tag = .@"unreachable",
549 .data = .{ .@"unreachable" = .{576 .data = .{ .@"unreachable" = .{
550 .safety = true,577 .safety = true,
551 .src_node = gz.astgen.decl.nodeIndexToRelative(node),578 .src_node = gz.nodeIndexToRelative(node),
552 } },579 } },
553 });580 });
554 return Zir.Inst.Ref.unreachable_value;581 return Zir.Inst.Ref.unreachable_value;
...@@ -654,8 +681,8 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -654,8 +681,8 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
654 },681 },
655 .enum_literal => return simpleStrTok(gz, scope, rl, main_tokens[node], node, .enum_literal),682 .enum_literal => return simpleStrTok(gz, scope, rl, main_tokens[node], node, .enum_literal),
656 .error_value => return simpleStrTok(gz, scope, rl, node_datas[node].rhs, node, .error_value),683 .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", .{}),684 .anyframe_literal => return astgen.failNode(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", .{}),685 .anyframe_type => return astgen.failNode(node, "async and related features are not yet supported", .{}),
659 .@"catch" => {686 .@"catch" => {
660 const catch_token = main_tokens[node];687 const catch_token = main_tokens[node];
661 const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)688 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...@@ -754,14 +781,14 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
754 .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),781 .@"comptime" => return comptimeExpr(gz, scope, rl, node_datas[node].lhs),
755 .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),782 .@"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", .{}),784 .@"nosuspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
758 .@"suspend" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),785 .@"suspend" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
759 .@"await" => return mod.failNode(scope, node, "async and related features are not yet supported", .{}),786 .@"await" => return astgen.failNode(node, "async and related features are not yet supported", .{}),
760 .@"resume" => return mod.failNode(scope, 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", .{}),789 .@"defer" => return astgen.failNode(node, "TODO implement astgen.expr for .defer", .{}),
763 .@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}),790 .@"errdefer" => return astgen.failNode(node, "TODO implement astgen.expr for .errdefer", .{}),
764 .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),791 .@"try" => return astgen.failNode(node, "TODO implement astgen.expr for .Try", .{}),
765792
766 .array_init_one,793 .array_init_one,
767 .array_init_one_comma,794 .array_init_one_comma,
...@@ -771,7 +798,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -771,7 +798,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
771 .array_init_dot_comma,798 .array_init_dot_comma,
772 .array_init,799 .array_init,
773 .array_init_comma,800 .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
776 .struct_init_one, .struct_init_one_comma => {803 .struct_init_one, .struct_init_one_comma => {
777 var fields: [1]ast.Node.Index = undefined;804 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...@@ -788,12 +815,12 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
788 .struct_init_comma,815 .struct_init_comma,
789 => return structInitExpr(gz, scope, rl, node, tree.structInit(node)),816 => 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", .{}),
792 .fn_proto_simple,819 .fn_proto_simple,
793 .fn_proto_multi,820 .fn_proto_multi,
794 .fn_proto_one,821 .fn_proto_one,
795 .fn_proto,822 .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", .{}),
797 }824 }
798}825}
799826
...@@ -804,10 +831,9 @@ pub fn structInitExpr(...@@ -804,10 +831,9 @@ pub fn structInitExpr(
804 node: ast.Node.Index,831 node: ast.Node.Index,
805 struct_init: ast.full.StructInit,832 struct_init: ast.full.StructInit,
806) InnerError!Zir.Inst.Ref {833) InnerError!Zir.Inst.Ref {
807 const tree = gz.tree();
808 const astgen = gz.astgen;834 const astgen = gz.astgen;
809 const mod = astgen.mod;835 const tree = &astgen.file.tree;
810 const gpa = mod.gpa;836 const gpa = astgen.gpa;
811837
812 if (struct_init.ast.fields.len == 0) {838 if (struct_init.ast.fields.len == 0) {
813 if (struct_init.ast.type_expr == 0) {839 if (struct_init.ast.type_expr == 0) {
...@@ -819,8 +845,8 @@ pub fn structInitExpr(...@@ -819,8 +845,8 @@ pub fn structInitExpr(
819 }845 }
820 }846 }
821 switch (rl) {847 switch (rl) {
822 .discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),848 .discard => return astgen.failNode(node, "TODO implement structInitExpr discard", .{}),
823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),849 .none, .none_or_ref => return astgen.failNode(node, "TODO implement structInitExpr none", .{}),
824 .ref => unreachable, // struct literal not valid as l-value850 .ref => unreachable, // struct literal not valid as l-value
825 .ty => |ty_inst| {851 .ty => |ty_inst| {
826 const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len);852 const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len);
...@@ -835,7 +861,7 @@ pub fn structInitExpr(...@@ -835,7 +861,7 @@ pub fn structInitExpr(
835 .name_start = str_index,861 .name_start = str_index,
836 });862 });
837 fields_list[i] = .{863 fields_list[i] = .{
838 .field_type = astgen.refToIndex(field_ty_inst).?,864 .field_type = gz.refToIndex(field_ty_inst).?,
839 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),865 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
840 };866 };
841 }867 }
...@@ -860,7 +886,7 @@ pub fn structInitExpr(...@@ -860,7 +886,7 @@ pub fn structInitExpr(
860 .lhs = ptr_inst,886 .lhs = ptr_inst,
861 .field_name_start = str_index,887 .field_name_start = str_index,
862 });888 });
863 field_ptr_list[i] = astgen.refToIndex(field_ptr).?;889 field_ptr_list[i] = gz.refToIndex(field_ptr).?;
864 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);890 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
865 }891 }
866 const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{892 const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
...@@ -870,10 +896,10 @@ pub fn structInitExpr(...@@ -870,10 +896,10 @@ pub fn structInitExpr(
870 return validate_inst;896 return validate_inst;
871 },897 },
872 .inferred_ptr => |ptr_inst| {898 .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", .{});
874 },900 },
875 .block_ptr => |block_gz| {901 .block_ptr => |block_gz| {
876 return mod.failNode(scope, node, "TODO implement structInitExpr block", .{});902 return astgen.failNode(node, "TODO implement structInitExpr block", .{});
877 },903 },
878 }904 }
879}905}
...@@ -892,8 +918,8 @@ pub fn comptimeExpr(...@@ -892,8 +918,8 @@ pub fn comptimeExpr(
892}918}
893919
894fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {920fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
895 const mod = parent_gz.astgen.mod;921 const astgen = parent_gz.astgen;
896 const tree = parent_gz.tree();922 const tree = &astgen.file.tree;
897 const node_datas = tree.nodes.items(.data);923 const node_datas = tree.nodes.items(.data);
898 const break_label = node_datas[node].lhs;924 const break_label = node_datas[node].lhs;
899 const rhs = node_datas[node].rhs;925 const rhs = node_datas[node].rhs;
...@@ -908,7 +934,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn...@@ -908,7 +934,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
908 const block_inst = blk: {934 const block_inst = blk: {
909 if (break_label != 0) {935 if (break_label != 0) {
910 if (block_gz.label) |*label| {936 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)) {
912 label.used = true;938 label.used = true;
913 break :blk label.block_inst;939 break :blk label.block_inst;
914 }940 }
...@@ -932,7 +958,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn...@@ -932,7 +958,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
932 const br = try parent_gz.addBreak(.@"break", block_inst, operand);958 const br = try parent_gz.addBreak(.@"break", block_inst, operand);
933959
934 if (block_gz.break_result_loc == .block_ptr) {960 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
937 if (have_store_to_block) {963 if (have_store_to_block) {
938 const zir_tags = parent_gz.astgen.instructions.items(.tag);964 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...@@ -940,7 +966,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
940 const store_inst = @intCast(u32, zir_tags.len - 2);966 const store_inst = @intCast(u32, zir_tags.len - 2);
941 assert(zir_tags[store_inst] == .store_to_block_ptr);967 assert(zir_tags[store_inst] == .store_to_block_ptr);
942 assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr);968 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);
944 }970 }
945 }971 }
946 return Zir.Inst.Ref.unreachable_value;972 return Zir.Inst.Ref.unreachable_value;
...@@ -948,18 +974,18 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn...@@ -948,18 +974,18 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
948 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,974 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
949 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,975 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
950 else => if (break_label != 0) {976 else => if (break_label != 0) {
951 const label_name = try mod.identifierTokenString(parent_scope, break_label);977 const label_name = try astgen.identifierTokenString(break_label);
952 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});978 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
953 } else {979 } else {
954 return mod.failNode(parent_scope, node, "break expression outside loop", .{});980 return astgen.failNode(node, "break expression outside loop", .{});
955 },981 },
956 }982 }
957 }983 }
958}984}
959985
960fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {986fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
961 const mod = parent_gz.astgen.mod;987 const astgen = parent_gz.astgen;
962 const tree = parent_gz.tree();988 const tree = &astgen.file.tree;
963 const node_datas = tree.nodes.items(.data);989 const node_datas = tree.nodes.items(.data);
964 const break_label = node_datas[node].lhs;990 const break_label = node_datas[node].lhs;
965991
...@@ -976,7 +1002,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)...@@ -976,7 +1002,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
976 }1002 }
977 if (break_label != 0) blk: {1003 if (break_label != 0) blk: {
978 if (gen_zir.label) |*label| {1004 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)) {
980 label.used = true;1006 label.used = true;
981 break :blk;1007 break :blk;
982 }1008 }
...@@ -993,10 +1019,10 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)...@@ -993,10 +1019,10 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
993 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,1019 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
994 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,1020 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
995 else => if (break_label != 0) {1021 else => if (break_label != 0) {
996 const label_name = try mod.identifierTokenString(parent_scope, break_label);1022 const label_name = try astgen.identifierTokenString(break_label);
997 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});1023 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name});
998 } else {1024 } else {
999 return mod.failNode(parent_scope, node, "continue expression outside loop", .{});1025 return astgen.failNode(node, "continue expression outside loop", .{});
1000 },1026 },
1001 }1027 }
1002 }1028 }
...@@ -1012,7 +1038,8 @@ pub fn blockExpr(...@@ -1012,7 +1038,8 @@ pub fn blockExpr(
1012 const tracy = trace(@src());1038 const tracy = trace(@src());
1013 defer tracy.end();1039 defer tracy.end();
10141040
1015 const tree = gz.tree();1041 const astgen = gz.astgen;
1042 const tree = &astgen.file.tree;
1016 const main_tokens = tree.nodes.items(.main_token);1043 const main_tokens = tree.nodes.items(.main_token);
1017 const token_tags = tree.tokens.items(.tag);1044 const token_tags = tree.tokens.items(.tag);
10181045
...@@ -1027,7 +1054,7 @@ pub fn blockExpr(...@@ -1027,7 +1054,7 @@ pub fn blockExpr(
1027 return rvalue(gz, scope, rl, .void_value, block_node);1054 return rvalue(gz, scope, rl, .void_value, block_node);
1028}1055}
10291056
1030fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIndex) !void {1057fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.TokenIndex) !void {
1031 // Look for the label in the scope.1058 // Look for the label in the scope.
1032 var scope = parent_scope;1059 var scope = parent_scope;
1033 while (true) {1060 while (true) {
...@@ -1035,29 +1062,20 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn...@@ -1035,29 +1062,20 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
1035 .gen_zir => {1062 .gen_zir => {
1036 const gen_zir = scope.cast(GenZir).?;1063 const gen_zir = scope.cast(GenZir).?;
1037 if (gen_zir.label) |prev_label| {1064 if (gen_zir.label) |prev_label| {
1038 if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) {1065 if (try astgen.tokenIdentEql(label, prev_label.token)) {
1039 const tree = parent_scope.tree();1066 const tree = &astgen.file.tree;
1040 const main_tokens = tree.nodes.items(.main_token);1067 const main_tokens = tree.nodes.items(.main_token);
10411068
1042 const label_name = try mod.identifierTokenString(parent_scope, label);1069 const label_name = try astgen.identifierTokenString(label);
1043 const msg = msg: {1070 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{
1044 const msg = try mod.errMsg(1071 label_name,
1045 parent_scope,1072 }, &[_]u32{
1046 gen_zir.tokSrcLoc(label),1073 try astgen.errNoteTok(
1047 "redefinition of label '{s}'",1074 prev_label.token,
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,
1055 "previous definition is here",1075 "previous definition is here",
1056 .{},1076 .{},
1057 );1077 ),
1058 break :msg msg;1078 });
1059 };
1060 return mod.failWithOwnedErrorMsg(parent_scope, msg);
1061 }1079 }
1062 }1080 }
1063 scope = gen_zir.parent;1081 scope = gen_zir.parent;
...@@ -1082,8 +1100,8 @@ fn labeledBlockExpr(...@@ -1082,8 +1100,8 @@ fn labeledBlockExpr(
10821100
1083 assert(zir_tag == .block);1101 assert(zir_tag == .block);
10841102
1085 const mod = gz.astgen.mod;1103 const astgen = gz.astgen;
1086 const tree = gz.tree();1104 const tree = &astgen.file.tree;
1087 const main_tokens = tree.nodes.items(.main_token);1105 const main_tokens = tree.nodes.items(.main_token);
1088 const token_tags = tree.tokens.items(.tag);1106 const token_tags = tree.tokens.items(.tag);
10891107
...@@ -1091,15 +1109,16 @@ fn labeledBlockExpr(...@@ -1091,15 +1109,16 @@ fn labeledBlockExpr(
1091 const label_token = lbrace - 2;1109 const label_token = lbrace - 2;
1092 assert(token_tags[label_token] == .identifier);1110 assert(token_tags[label_token] == .identifier);
10931111
1094 try checkLabelRedefinition(mod, parent_scope, label_token);1112 try astgen.checkLabelRedefinition(parent_scope, label_token);
10951113
1096 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct1114 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
1097 // so that break statements can reference it.1115 // so that break statements can reference it.
1098 const block_inst = try gz.addBlock(zir_tag, block_node);1116 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
1101 var block_scope: GenZir = .{1119 var block_scope: GenZir = .{
1102 .parent = parent_scope,1120 .parent = parent_scope,
1121 .decl_node_index = gz.decl_node_index,
1103 .astgen = gz.astgen,1122 .astgen = gz.astgen,
1104 .force_comptime = gz.force_comptime,1123 .force_comptime = gz.force_comptime,
1105 .instructions = .{},1124 .instructions = .{},
...@@ -1110,14 +1129,14 @@ fn labeledBlockExpr(...@@ -1110,14 +1129,14 @@ fn labeledBlockExpr(
1110 }),1129 }),
1111 };1130 };
1112 block_scope.setBreakResultLoc(rl);1131 block_scope.setBreakResultLoc(rl);
1113 defer block_scope.instructions.deinit(mod.gpa);1132 defer block_scope.instructions.deinit(astgen.gpa);
1114 defer block_scope.labeled_breaks.deinit(mod.gpa);1133 defer block_scope.labeled_breaks.deinit(astgen.gpa);
1115 defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa);1134 defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
11161135
1117 try blockExprStmts(&block_scope, &block_scope.base, block_node, statements);1136 try blockExprStmts(&block_scope, &block_scope.base, block_node, statements);
11181137
1119 if (!block_scope.label.?.used) {1138 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", .{});
1121 }1140 }
11221141
1123 const zir_tags = gz.astgen.instructions.items(.tag);1142 const zir_tags = gz.astgen.instructions.items(.tag);
...@@ -1133,7 +1152,7 @@ fn labeledBlockExpr(...@@ -1133,7 +1152,7 @@ fn labeledBlockExpr(
1133 }1152 }
1134 try block_scope.setBlockBody(block_inst);1153 try block_scope.setBlockBody(block_inst);
11351154
1136 return gz.astgen.indexToRef(block_inst);1155 return gz.indexToRef(block_inst);
1137 },1156 },
1138 .break_operand => {1157 .break_operand => {
1139 // All break operands are values that did not use the result location pointer.1158 // All break operands are values that did not use the result location pointer.
...@@ -1146,7 +1165,7 @@ fn labeledBlockExpr(...@@ -1146,7 +1165,7 @@ fn labeledBlockExpr(
1146 // would be better still to elide the ones that are in this list.1165 // would be better still to elide the ones that are in this list.
1147 }1166 }
1148 try block_scope.setBlockBody(block_inst);1167 try block_scope.setBlockBody(block_inst);
1149 const block_ref = gz.astgen.indexToRef(block_inst);1168 const block_ref = gz.indexToRef(block_inst);
1150 switch (rl) {1169 switch (rl) {
1151 .ref => return block_ref,1170 .ref => return block_ref,
1152 else => return rvalue(gz, parent_scope, rl, block_ref, block_node),1171 else => return rvalue(gz, parent_scope, rl, block_ref, block_node),
...@@ -1161,11 +1180,12 @@ fn blockExprStmts(...@@ -1161,11 +1180,12 @@ fn blockExprStmts(
1161 node: ast.Node.Index,1180 node: ast.Node.Index,
1162 statements: []const ast.Node.Index,1181 statements: []const ast.Node.Index,
1163) !void {1182) !void {
1164 const tree = gz.tree();1183 const astgen = gz.astgen;
1184 const tree = &astgen.file.tree;
1165 const main_tokens = tree.nodes.items(.main_token);1185 const main_tokens = tree.nodes.items(.main_token);
1166 const node_tags = tree.nodes.items(.tag);1186 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);
1169 defer block_arena.deinit();1189 defer block_arena.deinit();
11701190
1171 var scope = parent_scope;1191 var scope = parent_scope;
...@@ -1198,7 +1218,7 @@ fn blockExprStmts(...@@ -1198,7 +1218,7 @@ fn blockExprStmts(
1198 // We need to emit an error if the result is not `noreturn` or `void`, but1218 // We need to emit an error if the result is not `noreturn` or `void`, but
1199 // we want to avoid adding the ZIR instruction if possible for performance.1219 // we want to avoid adding the ZIR instruction if possible for performance.
1200 const maybe_unused_result = try expr(gz, scope, .none, statement);1220 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: {
1202 // Note that this array becomes invalid after appending more items to it1222 // Note that this array becomes invalid after appending more items to it
1203 // in the above while loop.1223 // in the above while loop.
1204 const zir_tags = gz.astgen.instructions.items(.tag);1224 const zir_tags = gz.astgen.instructions.items(.tag);
...@@ -1267,10 +1287,10 @@ fn blockExprStmts(...@@ -1267,10 +1287,10 @@ fn blockExprStmts(
1267 .field_val,1287 .field_val,
1268 .field_ptr_named,1288 .field_ptr_named,
1269 .field_val_named,1289 .field_val_named,
1270 .fn_type,1290 .func,
1271 .fn_type_var_args,1291 .func_var_args,
1272 .fn_type_cc,1292 .func_extra,
1273 .fn_type_cc_var_args,1293 .func_extra_var_args,
1274 .has_decl,1294 .has_decl,
1275 .int,1295 .int,
1276 .float,1296 .float,
...@@ -1416,21 +1436,19 @@ fn varDecl(...@@ -1416,21 +1436,19 @@ fn varDecl(
1416 block_arena: *Allocator,1436 block_arena: *Allocator,
1417 var_decl: ast.full.VarDecl,1437 var_decl: ast.full.VarDecl,
1418) InnerError!*Scope {1438) InnerError!*Scope {
1419 const mod = gz.astgen.mod;1439 const astgen = gz.astgen;
1420 if (var_decl.comptime_token) |comptime_token| {1440 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", .{});
1422 }1442 }
1423 if (var_decl.ast.align_node != 0) {1443 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", .{});
1425 }1445 }
1426 const astgen = gz.astgen;1446 const gpa = astgen.gpa;
1427 const gpa = mod.gpa;1447 const tree = &astgen.file.tree;
1428 const tree = gz.tree();
1429 const token_tags = tree.tokens.items(.tag);1448 const token_tags = tree.tokens.items(.tag);
14301449
1431 const name_token = var_decl.ast.mut_token + 1;1450 const name_token = var_decl.ast.mut_token + 1;
1432 const name_src = gz.tokSrcLoc(name_token);1451 const ident_name = try astgen.identifierTokenString(name_token);
1433 const ident_name = try mod.identifierTokenString(scope, name_token);
14341452
1435 // Local variables shadowing detection, including function parameters.1453 // Local variables shadowing detection, including function parameters.
1436 {1454 {
...@@ -1439,55 +1457,41 @@ fn varDecl(...@@ -1439,55 +1457,41 @@ fn varDecl(
1439 .local_val => {1457 .local_val => {
1440 const local_val = s.cast(Scope.LocalVal).?;1458 const local_val = s.cast(Scope.LocalVal).?;
1441 if (mem.eql(u8, local_val.name, ident_name)) {1459 if (mem.eql(u8, local_val.name, ident_name)) {
1442 const msg = msg: {1460 return astgen.failTokNotes(name_token, "redefinition of '{s}'", .{
1443 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{1461 ident_name,
1444 ident_name,1462 }, &[_]u32{
1445 });1463 try astgen.errNoteTok(
1446 errdefer msg.destroy(gpa);1464 local_val.token_src,
1447 try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{});1465 "previous definition is here",
1448 break :msg msg;1466 .{},
1449 };1467 ),
1450 return mod.failWithOwnedErrorMsg(scope, msg);1468 });
1451 }1469 }
1452 s = local_val.parent;1470 s = local_val.parent;
1453 },1471 },
1454 .local_ptr => {1472 .local_ptr => {
1455 const local_ptr = s.cast(Scope.LocalPtr).?;1473 const local_ptr = s.cast(Scope.LocalPtr).?;
1456 if (mem.eql(u8, local_ptr.name, ident_name)) {1474 if (mem.eql(u8, local_ptr.name, ident_name)) {
1457 const msg = msg: {1475 return astgen.failTokNotes(name_token, "redefinition of '{s}'", .{
1458 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{1476 ident_name,
1459 ident_name,1477 }, &[_]u32{
1460 });1478 try astgen.errNoteTok(
1461 errdefer msg.destroy(gpa);1479 local_ptr.token_src,
1462 try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{});1480 "previous definition is here",
1463 break :msg msg;1481 .{},
1464 };1482 ),
1465 return mod.failWithOwnedErrorMsg(scope, msg);1483 });
1466 }1484 }
1467 s = local_ptr.parent;1485 s = local_ptr.parent;
1468 },1486 },
1469 .gen_zir => s = s.cast(GenZir).?.parent,1487 .gen_zir => s = s.cast(GenZir).?.parent,
1470 else => break,1488 .file => break,
1489 else => unreachable,
1471 };1490 };
1472 }1491 }
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 }
1489 if (var_decl.ast.init_node == 0) {1493 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", .{});
1491 }1495 }
14921496
1493 switch (token_tags[var_decl.ast.mut_token]) {1497 switch (token_tags[var_decl.ast.mut_token]) {
...@@ -1506,7 +1510,7 @@ fn varDecl(...@@ -1506,7 +1510,7 @@ fn varDecl(
1506 .gen_zir = gz,1510 .gen_zir = gz,
1507 .name = ident_name,1511 .name = ident_name,
1508 .inst = init_inst,1512 .inst = init_inst,
1509 .src = name_src,1513 .token_src = name_token,
1510 };1514 };
1511 return &sub_scope.base;1515 return &sub_scope.base;
1512 }1516 }
...@@ -1515,6 +1519,7 @@ fn varDecl(...@@ -1515,6 +1519,7 @@ fn varDecl(
1515 // result location pointer.1519 // result location pointer.
1516 var init_scope: GenZir = .{1520 var init_scope: GenZir = .{
1517 .parent = scope,1521 .parent = scope,
1522 .decl_node_index = gz.decl_node_index,
1518 .force_comptime = gz.force_comptime,1523 .force_comptime = gz.force_comptime,
1519 .astgen = astgen,1524 .astgen = astgen,
1520 };1525 };
...@@ -1546,7 +1551,7 @@ fn varDecl(...@@ -1546,7 +1551,7 @@ fn varDecl(
1546 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;1551 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;
1547 try parent_zir.ensureCapacity(gpa, expected_len);1552 try parent_zir.ensureCapacity(gpa, expected_len);
1548 for (init_scope.instructions.items) |src_inst| {1553 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;
1550 if (zir_tags[src_inst] == .store_to_block_ptr) {1555 if (zir_tags[src_inst] == .store_to_block_ptr) {
1551 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;1556 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
1552 }1557 }
...@@ -1560,7 +1565,7 @@ fn varDecl(...@@ -1560,7 +1565,7 @@ fn varDecl(
1560 .gen_zir = gz,1565 .gen_zir = gz,
1561 .name = ident_name,1566 .name = ident_name,
1562 .inst = init_inst,1567 .inst = init_inst,
1563 .src = name_src,1568 .token_src = name_token,
1564 };1569 };
1565 return &sub_scope.base;1570 return &sub_scope.base;
1566 }1571 }
...@@ -1588,7 +1593,7 @@ fn varDecl(...@@ -1588,7 +1593,7 @@ fn varDecl(
1588 .gen_zir = gz,1593 .gen_zir = gz,
1589 .name = ident_name,1594 .name = ident_name,
1590 .ptr = init_scope.rl_ptr,1595 .ptr = init_scope.rl_ptr,
1591 .src = name_src,1596 .token_src = name_token,
1592 };1597 };
1593 return &sub_scope.base;1598 return &sub_scope.base;
1594 },1599 },
...@@ -1617,7 +1622,7 @@ fn varDecl(...@@ -1617,7 +1622,7 @@ fn varDecl(
1617 .gen_zir = gz,1622 .gen_zir = gz,
1618 .name = ident_name,1623 .name = ident_name,
1619 .ptr = var_data.alloc,1624 .ptr = var_data.alloc,
1620 .src = name_src,1625 .token_src = name_token,
1621 };1626 };
1622 return &sub_scope.base;1627 return &sub_scope.base;
1623 },1628 },
...@@ -1626,7 +1631,8 @@ fn varDecl(...@@ -1626,7 +1631,8 @@ fn varDecl(
1626}1631}
16271632
1628fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void {1633fn 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;
1630 const node_datas = tree.nodes.items(.data);1636 const node_datas = tree.nodes.items(.data);
1631 const main_tokens = tree.nodes.items(.main_token);1637 const main_tokens = tree.nodes.items(.main_token);
1632 const node_tags = tree.nodes.items(.tag);1638 const node_tags = tree.nodes.items(.tag);
...@@ -1651,7 +1657,8 @@ fn assignOp(...@@ -1651,7 +1657,8 @@ fn assignOp(
1651 infix_node: ast.Node.Index,1657 infix_node: ast.Node.Index,
1652 op_inst_tag: Zir.Inst.Tag,1658 op_inst_tag: Zir.Inst.Tag,
1653) InnerError!void {1659) InnerError!void {
1654 const tree = gz.tree();1660 const astgen = gz.astgen;
1661 const tree = &astgen.file.tree;
1655 const node_datas = tree.nodes.items(.data);1662 const node_datas = tree.nodes.items(.data);
16561663
1657 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);1664 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
...@@ -1667,7 +1674,8 @@ fn assignOp(...@@ -1667,7 +1674,8 @@ fn assignOp(
1667}1674}
16681675
1669fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {1676fn 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;
1671 const node_datas = tree.nodes.items(.data);1679 const node_datas = tree.nodes.items(.data);
16721680
1673 const operand = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs);1681 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...@@ -1676,7 +1684,8 @@ fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inne
1676}1684}
16771685
1678fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {1686fn 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;
1680 const node_datas = tree.nodes.items(.data);1689 const node_datas = tree.nodes.items(.data);
16811690
1682 const operand = try expr(gz, scope, .none, node_datas[node].lhs);1691 const operand = try expr(gz, scope, .none, node_datas[node].lhs);
...@@ -1691,7 +1700,8 @@ fn negation(...@@ -1691,7 +1700,8 @@ fn negation(
1691 node: ast.Node.Index,1700 node: ast.Node.Index,
1692 tag: Zir.Inst.Tag,1701 tag: Zir.Inst.Tag,
1693) InnerError!Zir.Inst.Ref {1702) InnerError!Zir.Inst.Ref {
1694 const tree = gz.tree();1703 const astgen = gz.astgen;
1704 const tree = &astgen.file.tree;
1695 const node_datas = tree.nodes.items(.data);1705 const node_datas = tree.nodes.items(.data);
16961706
1697 const operand = try expr(gz, scope, .none, node_datas[node].lhs);1707 const operand = try expr(gz, scope, .none, node_datas[node].lhs);
...@@ -1706,7 +1716,8 @@ fn ptrType(...@@ -1706,7 +1716,8 @@ fn ptrType(
1706 node: ast.Node.Index,1716 node: ast.Node.Index,
1707 ptr_info: ast.full.PtrType,1717 ptr_info: ast.full.PtrType,
1708) InnerError!Zir.Inst.Ref {1718) InnerError!Zir.Inst.Ref {
1709 const tree = gz.tree();1719 const astgen = gz.astgen;
1720 const tree = &astgen.file.tree;
17101721
1711 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);1722 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
17121723
...@@ -1748,7 +1759,7 @@ fn ptrType(...@@ -1748,7 +1759,7 @@ fn ptrType(
1748 trailing_count += 2;1759 trailing_count += 2;
1749 }1760 }
17501761
1751 const gpa = gz.astgen.mod.gpa;1762 const gpa = gz.astgen.gpa;
1752 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1763 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1753 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1764 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
1754 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1765 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
...@@ -1767,7 +1778,7 @@ fn ptrType(...@@ -1767,7 +1778,7 @@ fn ptrType(
1767 }1778 }
17681779
1769 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);1780 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);
1771 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{1782 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{
1772 .ptr_type = .{1783 .ptr_type = .{
1773 .flags = .{1784 .flags = .{
...@@ -1788,7 +1799,8 @@ fn ptrType(...@@ -1788,7 +1799,8 @@ fn ptrType(
1788}1799}
17891800
1790fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {1801fn 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;
1792 const node_datas = tree.nodes.items(.data);1804 const node_datas = tree.nodes.items(.data);
17931805
1794 // TODO check for [_]T1806 // TODO check for [_]T
...@@ -1800,7 +1812,8 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Z...@@ -1800,7 +1812,8 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Z
1800}1812}
18011813
1802fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {1814fn 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;
1804 const node_datas = tree.nodes.items(.data);1817 const node_datas = tree.nodes.items(.data);
1805 const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);1818 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...@@ -1813,7 +1826,275 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.I
1813 return rvalue(gz, scope, rl, result, node);1826 return rvalue(gz, scope, rl, result, node);
1814}1827}
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(
1817 gz: *GenZir,2098 gz: *GenZir,
1818 scope: *Scope,2099 scope: *Scope,
1819 node: ast.Node.Index,2100 node: ast.Node.Index,
...@@ -1821,25 +2102,33 @@ pub fn structDeclInner(...@@ -1821,25 +2102,33 @@ pub fn structDeclInner(
1821 tag: Zir.Inst.Tag,2102 tag: Zir.Inst.Tag,
1822) InnerError!Zir.Inst.Ref {2103) InnerError!Zir.Inst.Ref {
1823 if (container_decl.ast.members.len == 0) {2104 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 });
1825 }2110 }
18262111
1827 const astgen = gz.astgen;2112 const astgen = gz.astgen;
1828 const mod = astgen.mod;2113 const gpa = astgen.gpa;
1829 const gpa = mod.gpa;2114 const tree = &astgen.file.tree;
1830 const tree = gz.tree();
1831 const node_tags = tree.nodes.items(.tag);2115 const node_tags = tree.nodes.items(.tag);
2116 const node_datas = tree.nodes.items(.data);
18322117
1833 // The struct_decl instruction introduces a scope in which the decls of the struct2118 // The struct_decl instruction introduces a scope in which the decls of the struct
1834 // are in scope, so that field types, alignments, and default value expressions2119 // are in scope, so that field types, alignments, and default value expressions
1835 // can refer to decls within the struct itself.2120 // can refer to decls within the struct itself.
1836 var block_scope: GenZir = .{2121 var block_scope: GenZir = .{
1837 .parent = scope,2122 .parent = scope,
2123 .decl_node_index = node,
1838 .astgen = astgen,2124 .astgen = astgen,
1839 .force_comptime = true,2125 .force_comptime = true,
1840 };2126 };
1841 defer block_scope.instructions.deinit(gpa);2127 defer block_scope.instructions.deinit(gpa);
18422128
2129 var wip_decls: WipDecls = .{};
2130 defer wip_decls.deinit(gpa);
2131
1843 // We don't know which members are fields until we iterate, so cannot do2132 // We don't know which members are fields until we iterate, so cannot do
1844 // an accurate ensureCapacity yet.2133 // an accurate ensureCapacity yet.
1845 var fields_data = ArrayListUnmanaged(u32){};2134 var fields_data = ArrayListUnmanaged(u32){};
...@@ -1856,14 +2145,84 @@ pub fn structDeclInner(...@@ -1856,14 +2145,84 @@ pub fn structDeclInner(
1856 .container_field_init => tree.containerFieldInit(member_node),2145 .container_field_init => tree.containerFieldInit(member_node),
1857 .container_field_align => tree.containerFieldAlign(member_node),2146 .container_field_align => tree.containerFieldAlign(member_node),
1858 .container_field => tree.containerField(member_node),2147 .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,
1860 };2219 };
1861 if (field_index % 16 == 0 and field_index != 0) {2220 if (field_index % 16 == 0 and field_index != 0) {
1862 try bit_bag.append(gpa, cur_bit_bag);2221 try bit_bag.append(gpa, cur_bit_bag);
1863 cur_bit_bag = 0;2222 cur_bit_bag = 0;
1864 }2223 }
1865 if (member.comptime_token) |comptime_token| {2224 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", .{});
1867 }2226 }
1868 try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);2227 try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);
18692228
...@@ -1890,11 +2249,14 @@ pub fn structDeclInner(...@@ -1890,11 +2249,14 @@ pub fn structDeclInner(
18902249
1891 field_index += 1;2250 field_index += 1;
1892 }2251 }
1893 if (field_index == 0) {2252 if (field_index != 0) {
1894 return gz.addPlNode(tag, node, Zir.Inst.StructDecl{ .fields_len = 0, .body_len = 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);
1895 }2259 }
1896 const empty_slot_count = 16 - (field_index % 16);
1897 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18982260
1899 const decl_inst = try gz.addBlock(tag, node);2261 const decl_inst = try gz.addBlock(tag, node);
1900 try gz.instructions.append(gpa, decl_inst);2262 try gz.instructions.append(gpa, decl_inst);
...@@ -1903,17 +2265,25 @@ pub fn structDeclInner(...@@ -1903,17 +2265,25 @@ pub fn structDeclInner(
1903 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +2265 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
1904 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +2266 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
1905 bit_bag.items.len + 1 + fields_data.items.len +2267 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);
1907 const zir_datas = astgen.instructions.items(.data);2270 const zir_datas = astgen.instructions.items(.data);
1908 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{2271 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
1909 .body_len = @intCast(u32, block_scope.instructions.items.len),2272 .body_len = @intCast(u32, block_scope.instructions.items.len),
1910 .fields_len = @intCast(u32, field_index),2273 .fields_len = @intCast(u32, field_index),
2274 .decls_len = @intCast(u32, wip_decls.decl_index),
1911 });2275 });
1912 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);2276 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
2277
1913 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.2278 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
1914 astgen.extra.appendAssumeCapacity(cur_bit_bag);2279 astgen.extra.appendAssumeCapacity(cur_bit_bag);
1915 astgen.extra.appendSliceAssumeCapacity(fields_data.items);2280 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);
1917}2287}
19182288
1919fn containerDecl(2289fn containerDecl(
...@@ -1924,9 +2294,8 @@ fn containerDecl(...@@ -1924,9 +2294,8 @@ fn containerDecl(
1924 container_decl: ast.full.ContainerDecl,2294 container_decl: ast.full.ContainerDecl,
1925) InnerError!Zir.Inst.Ref {2295) InnerError!Zir.Inst.Ref {
1926 const astgen = gz.astgen;2296 const astgen = gz.astgen;
1927 const mod = astgen.mod;2297 const gpa = astgen.gpa;
1928 const gpa = mod.gpa;2298 const tree = &astgen.file.tree;
1929 const tree = gz.tree();
1930 const token_tags = tree.tokens.items(.tag);2299 const token_tags = tree.tokens.items(.tag);
1931 const node_tags = tree.nodes.items(.tag);2300 const node_tags = tree.nodes.items(.tag);
19322301
...@@ -1952,11 +2321,11 @@ fn containerDecl(...@@ -1952,11 +2321,11 @@ fn containerDecl(
1952 return rvalue(gz, scope, rl, result, node);2321 return rvalue(gz, scope, rl, result, node);
1953 },2322 },
1954 .keyword_union => {2323 .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", .{});
1956 },2325 },
1957 .keyword_enum => {2326 .keyword_enum => {
1958 if (container_decl.layout_token) |t| {2327 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", .{});
1960 }2329 }
1961 // Count total fields as well as how many have explicitly provided tag values.2330 // Count total fields as well as how many have explicitly provided tag values.
1962 const counts = blk: {2331 const counts = blk: {
...@@ -1975,10 +2344,10 @@ fn containerDecl(...@@ -1975,10 +2344,10 @@ fn containerDecl(
1975 },2344 },
1976 };2345 };
1977 if (member.comptime_token) |comptime_token| {2346 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", .{});
1979 }2348 }
1980 if (member.ast.type_expr != 0) {2349 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", .{});
1982 }2351 }
1983 // Alignment expressions in enums are caught by the parser.2352 // Alignment expressions in enums are caught by the parser.
1984 assert(member.ast.align_expr == 0);2353 assert(member.ast.align_expr == 0);
...@@ -1986,30 +2355,29 @@ fn containerDecl(...@@ -1986,30 +2355,29 @@ fn containerDecl(
1986 const name_token = member.ast.name_token;2355 const name_token = member.ast.name_token;
1987 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {2356 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
1988 if (nonexhaustive_node != 0) {2357 if (nonexhaustive_node != 0) {
1989 const msg = msg: {2358 return astgen.failNodeNotes(
1990 const msg = try mod.errMsg(2359 member_node,
1991 scope,2360 "redundant non-exhaustive enum mark",
1992 gz.nodeSrcLoc(member_node),2361 .{},
1993 "redundant non-exhaustive enum mark",2362 &[_]u32{
1994 .{},2363 try astgen.errNoteNode(
1995 );2364 nonexhaustive_node,
1996 errdefer msg.destroy(gpa);2365 "other mark here",
1997 const other_src = gz.nodeSrcLoc(nonexhaustive_node);2366 .{},
1998 try mod.errNote(scope, other_src, msg, "other mark here", .{});2367 ),
1999 break :msg msg;2368 },
2000 };2369 );
2001 return mod.failWithOwnedErrorMsg(scope, msg);
2002 }2370 }
2003 nonexhaustive_node = member_node;2371 nonexhaustive_node = member_node;
2004 if (member.ast.value_expr != 0) {2372 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", .{});
2006 }2374 }
2007 continue;2375 continue;
2008 }2376 }
2009 total_fields += 1;2377 total_fields += 1;
2010 if (member.ast.value_expr != 0) {2378 if (member.ast.value_expr != 0) {
2011 if (arg_inst == .none) {2379 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", .{});
2013 }2381 }
2014 values += 1;2382 values += 1;
2015 }2383 }
...@@ -2025,104 +2393,27 @@ fn containerDecl(...@@ -2025,104 +2393,27 @@ fn containerDecl(
2025 // One can construct an enum with no tags, and it functions the same as `noreturn`. But2393 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
2026 // this is only useful for generic code; when explicitly using `enum {}` syntax, there2394 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
2027 // must be at least one tag.2395 // 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", .{});
2029 }2397 }
2030 if (counts.nonexhaustive_node != 0 and arg_inst == .none) {2398 if (counts.nonexhaustive_node != 0 and arg_inst == .none) {
2031 const msg = msg: {2399 return astgen.failNodeNotes(
2032 const msg = try mod.errMsg(2400 node,
2033 scope,2401 "non-exhaustive enum missing integer tag type",
2034 gz.nodeSrcLoc(node),2402 .{},
2035 "non-exhaustive enum missing integer tag type",2403 &[_]u32{
2036 .{},2404 try astgen.errNoteNode(
2037 );2405 counts.nonexhaustive_node,
2038 errdefer msg.destroy(gpa);2406 "marked non-exhaustive here",
2039 const other_src = gz.nodeSrcLoc(counts.nonexhaustive_node);2407 .{},
2040 try mod.errNote(scope, other_src, msg, "marked non-exhaustive here", .{});2408 ),
2041 break :msg msg;2409 },
2042 };2410 );
2043 return mod.failWithOwnedErrorMsg(scope, msg);
2044 }2411 }
2045 if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {2412 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,2413 @panic("AstGen simple enum");
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);
2122 }2414 }
2123 // In this case we must generate ZIR code for the tag values, similar to2415 // 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 in2416 // how structs are handled above.
2125 // Sema, not AstGen.
2126 const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)2417 const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)
2127 .enum_decl2418 .enum_decl
2128 else2419 else
...@@ -2139,6 +2430,7 @@ fn containerDecl(...@@ -2139,6 +2430,7 @@ fn containerDecl(
2139 // are in scope, so that tag values can refer to decls within the enum itself.2430 // are in scope, so that tag values can refer to decls within the enum itself.
2140 var block_scope: GenZir = .{2431 var block_scope: GenZir = .{
2141 .parent = scope,2432 .parent = scope,
2433 .decl_node_index = node,
2142 .astgen = astgen,2434 .astgen = astgen,
2143 .force_comptime = true,2435 .force_comptime = true,
2144 };2436 };
...@@ -2207,7 +2499,7 @@ fn containerDecl(...@@ -2207,7 +2499,7 @@ fn containerDecl(
2207 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.2499 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
2208 astgen.extra.appendAssumeCapacity(cur_bit_bag);2500 astgen.extra.appendAssumeCapacity(cur_bit_bag);
2209 astgen.extra.appendSliceAssumeCapacity(fields_data.items);2501 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);
2211 },2503 },
2212 .keyword_opaque => {2504 .keyword_opaque => {
2213 const result = try gz.addNode(.opaque_decl, node);2505 const result = try gz.addNode(.opaque_decl, node);
...@@ -2224,63 +2516,11 @@ fn errorSetDecl(...@@ -2224,63 +2516,11 @@ fn errorSetDecl(
2224 node: ast.Node.Index,2516 node: ast.Node.Index,
2225) InnerError!Zir.Inst.Ref {2517) InnerError!Zir.Inst.Ref {
2226 const astgen = gz.astgen;2518 const astgen = gz.astgen;
2227 const mod = astgen.mod;2519 const tree = &astgen.file.tree;
2228 const tree = gz.tree();
2229 const main_tokens = tree.nodes.items(.main_token);2520 const main_tokens = tree.nodes.items(.main_token);
2230 const token_tags = tree.tokens.items(.tag);2521 const token_tags = tree.tokens.items(.tag);
22312522
2232 // Count how many fields there are.2523 @panic("TODO AstGen errorSetDecl");
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);
2284}2524}
22852525
2286fn orelseCatchExpr(2526fn orelseCatchExpr(
...@@ -2295,17 +2535,18 @@ fn orelseCatchExpr(...@@ -2295,17 +2535,18 @@ fn orelseCatchExpr(
2295 rhs: ast.Node.Index,2535 rhs: ast.Node.Index,
2296 payload_token: ?ast.TokenIndex,2536 payload_token: ?ast.TokenIndex,
2297) InnerError!Zir.Inst.Ref {2537) InnerError!Zir.Inst.Ref {
2298 const mod = parent_gz.astgen.mod;2538 const astgen = parent_gz.astgen;
2299 const tree = parent_gz.tree();2539 const tree = &astgen.file.tree;
23002540
2301 var block_scope: GenZir = .{2541 var block_scope: GenZir = .{
2302 .parent = scope,2542 .parent = scope,
2543 .decl_node_index = parent_gz.decl_node_index,
2303 .astgen = parent_gz.astgen,2544 .astgen = parent_gz.astgen,
2304 .force_comptime = parent_gz.force_comptime,2545 .force_comptime = parent_gz.force_comptime,
2305 .instructions = .{},2546 .instructions = .{},
2306 };2547 };
2307 block_scope.setBreakResultLoc(rl);2548 block_scope.setBreakResultLoc(rl);
2308 defer block_scope.instructions.deinit(mod.gpa);2549 defer block_scope.instructions.deinit(astgen.gpa);
23092550
2310 // This could be a pointer or value depending on the `operand_rl` parameter.2551 // This could be a pointer or value depending on the `operand_rl` parameter.
2311 // We cannot use `block_scope.break_result_loc` because that has the bare2552 // We cannot use `block_scope.break_result_loc` because that has the bare
...@@ -2331,30 +2572,31 @@ fn orelseCatchExpr(...@@ -2331,30 +2572,31 @@ fn orelseCatchExpr(
2331 const condbr = try block_scope.addCondBr(.condbr, node);2572 const condbr = try block_scope.addCondBr(.condbr, node);
23322573
2333 const block = try parent_gz.addBlock(.block, node);2574 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);
2335 try block_scope.setBlockBody(block);2576 try block_scope.setBlockBody(block);
23362577
2337 var then_scope: GenZir = .{2578 var then_scope: GenZir = .{
2338 .parent = scope,2579 .parent = scope,
2580 .decl_node_index = parent_gz.decl_node_index,
2339 .astgen = parent_gz.astgen,2581 .astgen = parent_gz.astgen,
2340 .force_comptime = block_scope.force_comptime,2582 .force_comptime = block_scope.force_comptime,
2341 .instructions = .{},2583 .instructions = .{},
2342 };2584 };
2343 defer then_scope.instructions.deinit(mod.gpa);2585 defer then_scope.instructions.deinit(astgen.gpa);
23442586
2345 var err_val_scope: Scope.LocalVal = undefined;2587 var err_val_scope: Scope.LocalVal = undefined;
2346 const then_sub_scope = blk: {2588 const then_sub_scope = blk: {
2347 const payload = payload_token orelse break :blk &then_scope.base;2589 const payload = payload_token orelse break :blk &then_scope.base;
2348 if (mem.eql(u8, tree.tokenSlice(payload), "_")) {2590 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", .{});
2350 }2592 }
2351 const err_name = try mod.identifierTokenString(scope, payload);2593 const err_name = try astgen.identifierTokenString(payload);
2352 err_val_scope = .{2594 err_val_scope = .{
2353 .parent = &then_scope.base,2595 .parent = &then_scope.base,
2354 .gen_zir = &then_scope,2596 .gen_zir = &then_scope,
2355 .name = err_name,2597 .name = err_name,
2356 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),2598 .inst = try then_scope.addUnNode(unwrap_code_op, operand, node),
2357 .src = parent_gz.tokSrcLoc(payload),2599 .token_src = payload,
2358 };2600 };
2359 break :blk &err_val_scope.base;2601 break :blk &err_val_scope.base;
2360 };2602 };
...@@ -2367,11 +2609,12 @@ fn orelseCatchExpr(...@@ -2367,11 +2609,12 @@ fn orelseCatchExpr(
23672609
2368 var else_scope: GenZir = .{2610 var else_scope: GenZir = .{
2369 .parent = scope,2611 .parent = scope,
2612 .decl_node_index = parent_gz.decl_node_index,
2370 .astgen = parent_gz.astgen,2613 .astgen = parent_gz.astgen,
2371 .force_comptime = block_scope.force_comptime,2614 .force_comptime = block_scope.force_comptime,
2372 .instructions = .{},2615 .instructions = .{},
2373 };2616 };
2374 defer else_scope.instructions.deinit(mod.gpa);2617 defer else_scope.instructions.deinit(astgen.gpa);
23752618
2376 // This could be a pointer or value depending on `unwrap_op`.2619 // This could be a pointer or value depending on `unwrap_op`.
2377 const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node);2620 const unwrapped_payload = try else_scope.addUnNode(unwrap_op, operand, node);
...@@ -2424,23 +2667,23 @@ fn finishThenElseBlock(...@@ -2424,23 +2667,23 @@ fn finishThenElseBlock(
2424 const astgen = block_scope.astgen;2667 const astgen = block_scope.astgen;
2425 switch (strat.tag) {2668 switch (strat.tag) {
2426 .break_void => {2669 .break_void => {
2427 if (!astgen.refIsNoReturn(then_result)) {2670 if (!parent_gz.refIsNoReturn(then_result)) {
2428 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value);2671 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value);
2429 }2672 }
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;
2431 if (!elide_else) {2674 if (!elide_else) {
2432 _ = try else_scope.addBreak(break_tag, main_block, .void_value);2675 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
2433 }2676 }
2434 assert(!strat.elide_store_to_block_ptr_instructions);2677 assert(!strat.elide_store_to_block_ptr_instructions);
2435 try setCondBrPayload(condbr, cond, then_scope, else_scope);2678 try setCondBrPayload(condbr, cond, then_scope, else_scope);
2436 return astgen.indexToRef(main_block);2679 return parent_gz.indexToRef(main_block);
2437 },2680 },
2438 .break_operand => {2681 .break_operand => {
2439 if (!astgen.refIsNoReturn(then_result)) {2682 if (!parent_gz.refIsNoReturn(then_result)) {
2440 _ = try then_scope.addBreak(break_tag, then_break_block, then_result);2683 _ = try then_scope.addBreak(break_tag, then_break_block, then_result);
2441 }2684 }
2442 if (else_result != .none) {2685 if (else_result != .none) {
2443 if (!astgen.refIsNoReturn(else_result)) {2686 if (!parent_gz.refIsNoReturn(else_result)) {
2444 _ = try else_scope.addBreak(break_tag, main_block, else_result);2687 _ = try else_scope.addBreak(break_tag, main_block, else_result);
2445 }2688 }
2446 } else {2689 } else {
...@@ -2451,7 +2694,7 @@ fn finishThenElseBlock(...@@ -2451,7 +2694,7 @@ fn finishThenElseBlock(
2451 } else {2694 } else {
2452 try setCondBrPayload(condbr, cond, then_scope, else_scope);2695 try setCondBrPayload(condbr, cond, then_scope, else_scope);
2453 }2696 }
2454 const block_ref = astgen.indexToRef(main_block);2697 const block_ref = parent_gz.indexToRef(main_block);
2455 switch (rl) {2698 switch (rl) {
2456 .ref => return block_ref,2699 .ref => return block_ref,
2457 else => return rvalue(parent_gz, parent_scope, rl, block_ref, node),2700 else => return rvalue(parent_gz, parent_scope, rl, block_ref, node),
...@@ -2464,9 +2707,9 @@ fn finishThenElseBlock(...@@ -2464,9 +2707,9 @@ fn finishThenElseBlock(
2464/// tokens without allocating.2707/// tokens without allocating.
2465/// OK in theory it could do it without allocating. This implementation2708/// OK in theory it could do it without allocating. This implementation
2466/// allocates when the @"" form is used.2709/// allocates when the @"" form is used.
2467fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {2710fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
2468 const ident_name_1 = try mod.identifierTokenString(scope, token1);2711 const ident_name_1 = try astgen.identifierTokenString(token1);
2469 const ident_name_2 = try mod.identifierTokenString(scope, token2);2712 const ident_name_2 = try astgen.identifierTokenString(token2);
2470 return mem.eql(u8, ident_name_1, ident_name_2);2713 return mem.eql(u8, ident_name_1, ident_name_2);
2471}2714}
24722715
...@@ -2477,8 +2720,7 @@ pub fn fieldAccess(...@@ -2477,8 +2720,7 @@ pub fn fieldAccess(
2477 node: ast.Node.Index,2720 node: ast.Node.Index,
2478) InnerError!Zir.Inst.Ref {2721) InnerError!Zir.Inst.Ref {
2479 const astgen = gz.astgen;2722 const astgen = gz.astgen;
2480 const mod = astgen.mod;2723 const tree = &astgen.file.tree;
2481 const tree = gz.tree();
2482 const main_tokens = tree.nodes.items(.main_token);2724 const main_tokens = tree.nodes.items(.main_token);
2483 const node_datas = tree.nodes.items(.data);2725 const node_datas = tree.nodes.items(.data);
24842726
...@@ -2504,7 +2746,8 @@ fn arrayAccess(...@@ -2504,7 +2746,8 @@ fn arrayAccess(
2504 rl: ResultLoc,2746 rl: ResultLoc,
2505 node: ast.Node.Index,2747 node: ast.Node.Index,
2506) InnerError!Zir.Inst.Ref {2748) InnerError!Zir.Inst.Ref {
2507 const tree = gz.tree();2749 const astgen = gz.astgen;
2750 const tree = &astgen.file.tree;
2508 const main_tokens = tree.nodes.items(.main_token);2751 const main_tokens = tree.nodes.items(.main_token);
2509 const node_datas = tree.nodes.items(.data);2752 const node_datas = tree.nodes.items(.data);
2510 switch (rl) {2753 switch (rl) {
...@@ -2528,7 +2771,8 @@ fn simpleBinOp(...@@ -2528,7 +2771,8 @@ fn simpleBinOp(
2528 node: ast.Node.Index,2771 node: ast.Node.Index,
2529 op_inst_tag: Zir.Inst.Tag,2772 op_inst_tag: Zir.Inst.Tag,
2530) InnerError!Zir.Inst.Ref {2773) InnerError!Zir.Inst.Ref {
2531 const tree = gz.tree();2774 const astgen = gz.astgen;
2775 const tree = &astgen.file.tree;
2532 const node_datas = tree.nodes.items(.data);2776 const node_datas = tree.nodes.items(.data);
25332777
2534 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{2778 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{
...@@ -2565,15 +2809,16 @@ fn boolBinOp(...@@ -2565,15 +2809,16 @@ fn boolBinOp(
25652809
2566 var rhs_scope: GenZir = .{2810 var rhs_scope: GenZir = .{
2567 .parent = scope,2811 .parent = scope,
2812 .decl_node_index = gz.decl_node_index,
2568 .astgen = gz.astgen,2813 .astgen = gz.astgen,
2569 .force_comptime = gz.force_comptime,2814 .force_comptime = gz.force_comptime,
2570 };2815 };
2571 defer rhs_scope.instructions.deinit(gz.astgen.mod.gpa);2816 defer rhs_scope.instructions.deinit(gz.astgen.gpa);
2572 const rhs = try expr(&rhs_scope, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs);2817 const rhs = try expr(&rhs_scope, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs);
2573 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);2818 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
2574 try rhs_scope.setBoolBrBody(bool_br);2819 try rhs_scope.setBoolBrBody(bool_br);
25752820
2576 const block_ref = gz.astgen.indexToRef(bool_br);2821 const block_ref = gz.indexToRef(bool_br);
2577 return rvalue(gz, scope, rl, block_ref, node);2822 return rvalue(gz, scope, rl, block_ref, node);
2578}2823}
25792824
...@@ -2584,23 +2829,23 @@ fn ifExpr(...@@ -2584,23 +2829,23 @@ fn ifExpr(
2584 node: ast.Node.Index,2829 node: ast.Node.Index,
2585 if_full: ast.full.If,2830 if_full: ast.full.If,
2586) InnerError!Zir.Inst.Ref {2831) InnerError!Zir.Inst.Ref {
2587 const mod = parent_gz.astgen.mod;2832 const astgen = parent_gz.astgen;
2588
2589 var block_scope: GenZir = .{2833 var block_scope: GenZir = .{
2590 .parent = scope,2834 .parent = scope,
2591 .astgen = parent_gz.astgen,2835 .decl_node_index = parent_gz.decl_node_index,
2836 .astgen = astgen,
2592 .force_comptime = parent_gz.force_comptime,2837 .force_comptime = parent_gz.force_comptime,
2593 .instructions = .{},2838 .instructions = .{},
2594 };2839 };
2595 block_scope.setBreakResultLoc(rl);2840 block_scope.setBreakResultLoc(rl);
2596 defer block_scope.instructions.deinit(mod.gpa);2841 defer block_scope.instructions.deinit(astgen.gpa);
25972842
2598 const cond = c: {2843 const cond = c: {
2599 // TODO https://github.com/ziglang/zig/issues/79292844 // TODO https://github.com/ziglang/zig/issues/7929
2600 if (if_full.error_token) |error_token| {2845 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", .{});
2602 } else if (if_full.payload_token) |payload_token| {2847 } 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", .{});
2604 } else {2849 } else {
2605 break :c try expr(&block_scope, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr);2850 break :c try expr(&block_scope, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr);
2606 }2851 }
...@@ -2609,16 +2854,17 @@ fn ifExpr(...@@ -2609,16 +2854,17 @@ fn ifExpr(
2609 const condbr = try block_scope.addCondBr(.condbr, node);2854 const condbr = try block_scope.addCondBr(.condbr, node);
26102855
2611 const block = try parent_gz.addBlock(.block, node);2856 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);
2613 try block_scope.setBlockBody(block);2858 try block_scope.setBlockBody(block);
26142859
2615 var then_scope: GenZir = .{2860 var then_scope: GenZir = .{
2616 .parent = scope,2861 .parent = scope,
2617 .astgen = parent_gz.astgen,2862 .decl_node_index = parent_gz.decl_node_index,
2863 .astgen = astgen,
2618 .force_comptime = block_scope.force_comptime,2864 .force_comptime = block_scope.force_comptime,
2619 .instructions = .{},2865 .instructions = .{},
2620 };2866 };
2621 defer then_scope.instructions.deinit(mod.gpa);2867 defer then_scope.instructions.deinit(astgen.gpa);
26222868
2623 // declare payload to the then_scope2869 // declare payload to the then_scope
2624 const then_sub_scope = &then_scope.base;2870 const then_sub_scope = &then_scope.base;
...@@ -2631,11 +2877,12 @@ fn ifExpr(...@@ -2631,11 +2877,12 @@ fn ifExpr(
26312877
2632 var else_scope: GenZir = .{2878 var else_scope: GenZir = .{
2633 .parent = scope,2879 .parent = scope,
2634 .astgen = parent_gz.astgen,2880 .decl_node_index = parent_gz.decl_node_index,
2881 .astgen = astgen,
2635 .force_comptime = block_scope.force_comptime,2882 .force_comptime = block_scope.force_comptime,
2636 .instructions = .{},2883 .instructions = .{},
2637 };2884 };
2638 defer else_scope.instructions.deinit(mod.gpa);2885 defer else_scope.instructions.deinit(astgen.gpa);
26392886
2640 const else_node = if_full.ast.else_expr;2887 const else_node = if_full.ast.else_expr;
2641 const else_info: struct {2888 const else_info: struct {
...@@ -2681,7 +2928,7 @@ fn setCondBrPayload(...@@ -2681,7 +2928,7 @@ fn setCondBrPayload(
2681) !void {2928) !void {
2682 const astgen = then_scope.astgen;2929 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 +
2685 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +2932 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
2686 then_scope.instructions.items.len + else_scope.instructions.items.len);2933 then_scope.instructions.items.len + else_scope.instructions.items.len);
26872934
...@@ -2704,7 +2951,7 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -2704,7 +2951,7 @@ fn setCondBrPayloadElideBlockStorePtr(
2704) !void {2951) !void {
2705 const astgen = then_scope.astgen;2952 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 +
2708 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +2955 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
2709 then_scope.instructions.items.len + else_scope.instructions.items.len - 2);2956 then_scope.instructions.items.len + else_scope.instructions.items.len - 2);
27102957
...@@ -2732,39 +2979,42 @@ fn whileExpr(...@@ -2732,39 +2979,42 @@ fn whileExpr(
2732 node: ast.Node.Index,2979 node: ast.Node.Index,
2733 while_full: ast.full.While,2980 while_full: ast.full.While,
2734) InnerError!Zir.Inst.Ref {2981) InnerError!Zir.Inst.Ref {
2735 const mod = parent_gz.astgen.mod;2982 const astgen = parent_gz.astgen;
2983
2736 if (while_full.label_token) |label_token| {2984 if (while_full.label_token) |label_token| {
2737 try checkLabelRedefinition(mod, scope, label_token);2985 try astgen.checkLabelRedefinition(scope, label_token);
2738 }2986 }
27392987
2740 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;2988 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
2741 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;2989 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
2742 const loop_block = try parent_gz.addBlock(loop_tag, node);2990 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
2745 var loop_scope: GenZir = .{2993 var loop_scope: GenZir = .{
2746 .parent = scope,2994 .parent = scope,
2747 .astgen = parent_gz.astgen,2995 .decl_node_index = parent_gz.decl_node_index,
2996 .astgen = astgen,
2748 .force_comptime = parent_gz.force_comptime,2997 .force_comptime = parent_gz.force_comptime,
2749 .instructions = .{},2998 .instructions = .{},
2750 };2999 };
2751 loop_scope.setBreakResultLoc(rl);3000 loop_scope.setBreakResultLoc(rl);
2752 defer loop_scope.instructions.deinit(mod.gpa);3001 defer loop_scope.instructions.deinit(astgen.gpa);
27533002
2754 var continue_scope: GenZir = .{3003 var continue_scope: GenZir = .{
2755 .parent = &loop_scope.base,3004 .parent = &loop_scope.base,
2756 .astgen = parent_gz.astgen,3005 .decl_node_index = parent_gz.decl_node_index,
3006 .astgen = astgen,
2757 .force_comptime = loop_scope.force_comptime,3007 .force_comptime = loop_scope.force_comptime,
2758 .instructions = .{},3008 .instructions = .{},
2759 };3009 };
2760 defer continue_scope.instructions.deinit(mod.gpa);3010 defer continue_scope.instructions.deinit(astgen.gpa);
27613011
2762 const cond = c: {3012 const cond = c: {
2763 // TODO https://github.com/ziglang/zig/issues/79293013 // TODO https://github.com/ziglang/zig/issues/7929
2764 if (while_full.error_token) |error_token| {3014 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", .{});
2766 } else if (while_full.payload_token) |payload_token| {3016 } 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", .{});
2768 } else {3018 } else {
2769 const bool_type_rl: ResultLoc = .{ .ty = .bool_type };3019 const bool_type_rl: ResultLoc = .{ .ty = .bool_type };
2770 break :c try expr(&continue_scope, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr);3020 break :c try expr(&continue_scope, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr);
...@@ -2775,7 +3025,7 @@ fn whileExpr(...@@ -2775,7 +3025,7 @@ fn whileExpr(
2775 const condbr = try continue_scope.addCondBr(condbr_tag, node);3025 const condbr = try continue_scope.addCondBr(condbr_tag, node);
2776 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;3026 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
2777 const cond_block = try loop_scope.addBlock(block_tag, node);3027 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);
2779 try continue_scope.setBlockBody(cond_block);3029 try continue_scope.setBlockBody(cond_block);
27803030
2781 // TODO avoid emitting the continue expr when there3031 // TODO avoid emitting the continue expr when there
...@@ -2799,11 +3049,12 @@ fn whileExpr(...@@ -2799,11 +3049,12 @@ fn whileExpr(
27993049
2800 var then_scope: GenZir = .{3050 var then_scope: GenZir = .{
2801 .parent = &continue_scope.base,3051 .parent = &continue_scope.base,
2802 .astgen = parent_gz.astgen,3052 .decl_node_index = parent_gz.decl_node_index,
3053 .astgen = astgen,
2803 .force_comptime = continue_scope.force_comptime,3054 .force_comptime = continue_scope.force_comptime,
2804 .instructions = .{},3055 .instructions = .{},
2805 };3056 };
2806 defer then_scope.instructions.deinit(mod.gpa);3057 defer then_scope.instructions.deinit(astgen.gpa);
28073058
2808 const then_sub_scope = &then_scope.base;3059 const then_sub_scope = &then_scope.base;
28093060
...@@ -2812,11 +3063,12 @@ fn whileExpr(...@@ -2812,11 +3063,12 @@ fn whileExpr(
28123063
2813 var else_scope: GenZir = .{3064 var else_scope: GenZir = .{
2814 .parent = &continue_scope.base,3065 .parent = &continue_scope.base,
2815 .astgen = parent_gz.astgen,3066 .decl_node_index = parent_gz.decl_node_index,
3067 .astgen = astgen,
2816 .force_comptime = continue_scope.force_comptime,3068 .force_comptime = continue_scope.force_comptime,
2817 .instructions = .{},3069 .instructions = .{},
2818 };3070 };
2819 defer else_scope.instructions.deinit(mod.gpa);3071 defer else_scope.instructions.deinit(astgen.gpa);
28203072
2821 const else_node = while_full.ast.else_expr;3073 const else_node = while_full.ast.else_expr;
2822 const else_info: struct {3074 const else_info: struct {
...@@ -2836,7 +3088,7 @@ fn whileExpr(...@@ -2836,7 +3088,7 @@ fn whileExpr(
28363088
2837 if (loop_scope.label) |some| {3089 if (loop_scope.label) |some| {
2838 if (!some.used) {3090 if (!some.used) {
2839 return mod.failTok(scope, some.token, "unused while loop label", .{});3091 return astgen.failTok(some.token, "unused while loop label", .{});
2840 }3092 }
2841 }3093 }
2842 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";3094 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
...@@ -2867,13 +3119,14 @@ fn forExpr(...@@ -2867,13 +3119,14 @@ fn forExpr(
2867 node: ast.Node.Index,3119 node: ast.Node.Index,
2868 for_full: ast.full.While,3120 for_full: ast.full.While,
2869) InnerError!Zir.Inst.Ref {3121) InnerError!Zir.Inst.Ref {
2870 const mod = parent_gz.astgen.mod;3122 const astgen = parent_gz.astgen;
3123
2871 if (for_full.label_token) |label_token| {3124 if (for_full.label_token) |label_token| {
2872 try checkLabelRedefinition(mod, scope, label_token);3125 try astgen.checkLabelRedefinition(scope, label_token);
2873 }3126 }
2874 // Set up variables and constants.3127 // Set up variables and constants.
2875 const is_inline = parent_gz.force_comptime or for_full.inline_token != null;3128 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;
2877 const token_tags = tree.tokens.items(.tag);3130 const token_tags = tree.tokens.items(.tag);
28783131
2879 const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr);3132 const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr);
...@@ -2888,24 +3141,26 @@ fn forExpr(...@@ -2888,24 +3141,26 @@ fn forExpr(
28883141
2889 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;3142 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
2890 const loop_block = try parent_gz.addBlock(loop_tag, node);3143 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
2893 var loop_scope: GenZir = .{3146 var loop_scope: GenZir = .{
2894 .parent = scope,3147 .parent = scope,
2895 .astgen = parent_gz.astgen,3148 .decl_node_index = parent_gz.decl_node_index,
3149 .astgen = astgen,
2896 .force_comptime = parent_gz.force_comptime,3150 .force_comptime = parent_gz.force_comptime,
2897 .instructions = .{},3151 .instructions = .{},
2898 };3152 };
2899 loop_scope.setBreakResultLoc(rl);3153 loop_scope.setBreakResultLoc(rl);
2900 defer loop_scope.instructions.deinit(mod.gpa);3154 defer loop_scope.instructions.deinit(astgen.gpa);
29013155
2902 var cond_scope: GenZir = .{3156 var cond_scope: GenZir = .{
2903 .parent = &loop_scope.base,3157 .parent = &loop_scope.base,
2904 .astgen = parent_gz.astgen,3158 .decl_node_index = parent_gz.decl_node_index,
3159 .astgen = astgen,
2905 .force_comptime = loop_scope.force_comptime,3160 .force_comptime = loop_scope.force_comptime,
2906 .instructions = .{},3161 .instructions = .{},
2907 };3162 };
2908 defer cond_scope.instructions.deinit(mod.gpa);3163 defer cond_scope.instructions.deinit(astgen.gpa);
29093164
2910 // check condition i < array_expr.len3165 // check condition i < array_expr.len
2911 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);3166 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
...@@ -2918,7 +3173,7 @@ fn forExpr(...@@ -2918,7 +3173,7 @@ fn forExpr(
2918 const condbr = try cond_scope.addCondBr(condbr_tag, node);3173 const condbr = try cond_scope.addCondBr(condbr_tag, node);
2919 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;3174 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
2920 const cond_block = try loop_scope.addBlock(block_tag, node);3175 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);
2922 try cond_scope.setBlockBody(cond_block);3177 try cond_scope.setBlockBody(cond_block);
29233178
2924 // Increment the index variable.3179 // Increment the index variable.
...@@ -2943,11 +3198,12 @@ fn forExpr(...@@ -2943,11 +3198,12 @@ fn forExpr(
29433198
2944 var then_scope: GenZir = .{3199 var then_scope: GenZir = .{
2945 .parent = &cond_scope.base,3200 .parent = &cond_scope.base,
2946 .astgen = parent_gz.astgen,3201 .decl_node_index = parent_gz.decl_node_index,
3202 .astgen = astgen,
2947 .force_comptime = cond_scope.force_comptime,3203 .force_comptime = cond_scope.force_comptime,
2948 .instructions = .{},3204 .instructions = .{},
2949 };3205 };
2950 defer then_scope.instructions.deinit(mod.gpa);3206 defer then_scope.instructions.deinit(astgen.gpa);
29513207
2952 var index_scope: Scope.LocalPtr = undefined;3208 var index_scope: Scope.LocalPtr = undefined;
2953 const then_sub_scope = blk: {3209 const then_sub_scope = blk: {
...@@ -2959,9 +3215,9 @@ fn forExpr(...@@ -2959,9 +3215,9 @@ fn forExpr(
2959 const is_ptr = ident != payload_token;3215 const is_ptr = ident != payload_token;
2960 const value_name = tree.tokenSlice(ident);3216 const value_name = tree.tokenSlice(ident);
2961 if (!mem.eql(u8, value_name, "_")) {3217 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", .{});
2963 } else if (is_ptr) {3219 } 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", .{});
2965 }3221 }
29663222
2967 const index_token = if (token_tags[ident + 1] == .comma)3223 const index_token = if (token_tags[ident + 1] == .comma)
...@@ -2969,15 +3225,15 @@ fn forExpr(...@@ -2969,15 +3225,15 @@ fn forExpr(
2969 else3225 else
2970 break :blk &then_scope.base;3226 break :blk &then_scope.base;
2971 if (mem.eql(u8, tree.tokenSlice(index_token), "_")) {3227 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", .{});
2973 }3229 }
2974 const index_name = try mod.identifierTokenString(&then_scope.base, index_token);3230 const index_name = try astgen.identifierTokenString(index_token);
2975 index_scope = .{3231 index_scope = .{
2976 .parent = &then_scope.base,3232 .parent = &then_scope.base,
2977 .gen_zir = &then_scope,3233 .gen_zir = &then_scope,
2978 .name = index_name,3234 .name = index_name,
2979 .ptr = index_ptr,3235 .ptr = index_ptr,
2980 .src = parent_gz.tokSrcLoc(index_token),3236 .token_src = index_token,
2981 };3237 };
2982 break :blk &index_scope.base;3238 break :blk &index_scope.base;
2983 };3239 };
...@@ -2987,11 +3243,12 @@ fn forExpr(...@@ -2987,11 +3243,12 @@ fn forExpr(
29873243
2988 var else_scope: GenZir = .{3244 var else_scope: GenZir = .{
2989 .parent = &cond_scope.base,3245 .parent = &cond_scope.base,
2990 .astgen = parent_gz.astgen,3246 .decl_node_index = parent_gz.decl_node_index,
3247 .astgen = astgen,
2991 .force_comptime = cond_scope.force_comptime,3248 .force_comptime = cond_scope.force_comptime,
2992 .instructions = .{},3249 .instructions = .{},
2993 };3250 };
2994 defer else_scope.instructions.deinit(mod.gpa);3251 defer else_scope.instructions.deinit(astgen.gpa);
29953252
2996 const else_node = for_full.ast.else_expr;3253 const else_node = for_full.ast.else_expr;
2997 const else_info: struct {3254 const else_info: struct {
...@@ -3011,7 +3268,7 @@ fn forExpr(...@@ -3011,7 +3268,7 @@ fn forExpr(
30113268
3012 if (loop_scope.label) |some| {3269 if (loop_scope.label) |some| {
3013 if (!some.used) {3270 if (!some.used) {
3014 return mod.failTok(scope, some.token, "unused for loop label", .{});3271 return astgen.failTok(some.token, "unused for loop label", .{});
3015 }3272 }
3016 }3273 }
3017 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";3274 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
...@@ -3069,7 +3326,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -3069,7 +3326,7 @@ pub const SwitchProngSrc = union(enum) {
3069 ) LazySrcLoc {3326 ) LazySrcLoc {
3070 @setCold(true);3327 @setCold(true);
3071 const switch_node = decl.relativeToNodeIndex(switch_node_offset);3328 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;
3073 const main_tokens = tree.nodes.items(.main_token);3330 const main_tokens = tree.nodes.items(.main_token);
3074 const node_datas = tree.nodes.items(.data);3331 const node_datas = tree.nodes.items(.data);
3075 const node_tags = tree.nodes.items(.tag);3332 const node_tags = tree.nodes.items(.tag);
...@@ -3147,9 +3404,8 @@ fn switchExpr(...@@ -3147,9 +3404,8 @@ fn switchExpr(
3147 switch_node: ast.Node.Index,3404 switch_node: ast.Node.Index,
3148) InnerError!Zir.Inst.Ref {3405) InnerError!Zir.Inst.Ref {
3149 const astgen = parent_gz.astgen;3406 const astgen = parent_gz.astgen;
3150 const mod = astgen.mod;3407 const gpa = astgen.gpa;
3151 const gpa = mod.gpa;3408 const tree = &astgen.file.tree;
3152 const tree = parent_gz.tree();
3153 const node_datas = tree.nodes.items(.data);3409 const node_datas = tree.nodes.items(.data);
3154 const node_tags = tree.nodes.items(.tag);3410 const node_tags = tree.nodes.items(.tag);
3155 const main_tokens = tree.nodes.items(.main_token);3411 const main_tokens = tree.nodes.items(.main_token);
...@@ -3166,8 +3422,8 @@ fn switchExpr(...@@ -3166,8 +3422,8 @@ fn switchExpr(
3166 var multi_cases_len: u32 = 0;3422 var multi_cases_len: u32 = 0;
3167 var special_prong: Zir.SpecialProng = .none;3423 var special_prong: Zir.SpecialProng = .none;
3168 var special_node: ast.Node.Index = 0;3424 var special_node: ast.Node.Index = 0;
3169 var else_src: ?LazySrcLoc = null;3425 var else_src: ?ast.TokenIndex = null;
3170 var underscore_src: ?LazySrcLoc = null;3426 var underscore_src: ?ast.TokenIndex = null;
3171 for (case_nodes) |case_node| {3427 for (case_nodes) |case_node| {
3172 const case = switch (node_tags[case_node]) {3428 const case = switch (node_tags[case_node]) {
3173 .switch_case_one => tree.switchCaseOne(case_node),3429 .switch_case_one => tree.switchCaseOne(case_node),
...@@ -3181,34 +3437,38 @@ fn switchExpr(...@@ -3181,34 +3437,38 @@ fn switchExpr(
3181 }3437 }
3182 // Check for else/`_` prong.3438 // Check for else/`_` prong.
3183 if (case.ast.values.len == 0) {3439 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;
3185 if (else_src) |src| {3441 if (else_src) |src| {
3186 const msg = msg: {3442 return astgen.failTokNotes(
3187 const msg = try mod.errMsg(3443 case_src,
3188 scope,3444 "multiple else prongs in switch expression",
3189 case_src,3445 .{},
3190 "multiple else prongs in switch expression",3446 &[_]u32{
3191 .{},3447 try astgen.errNoteTok(
3192 );3448 src,
3193 errdefer msg.destroy(gpa);3449 "previous else prong is here",
3194 try mod.errNote(scope, src, msg, "previous else prong is here", .{});3450 .{},
3195 break :msg msg;3451 ),
3196 };3452 },
3197 return mod.failWithOwnedErrorMsg(scope, msg);3453 );
3198 } else if (underscore_src) |some_underscore| {3454 } else if (underscore_src) |some_underscore| {
3199 const msg = msg: {3455 return astgen.failNodeNotes(
3200 const msg = try mod.errMsg(3456 switch_node,
3201 scope,3457 "else and '_' prong in switch expression",
3202 parent_gz.nodeSrcLoc(switch_node),3458 .{},
3203 "else and '_' prong in switch expression",3459 &[_]u32{
3204 .{},3460 try astgen.errNoteTok(
3205 );3461 case_src,
3206 errdefer msg.destroy(gpa);3462 "else prong is here",
3207 try mod.errNote(scope, case_src, msg, "else prong is here", .{});3463 .{},
3208 try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{});3464 ),
3209 break :msg msg;3465 try astgen.errNoteTok(
3210 };3466 some_underscore,
3211 return mod.failWithOwnedErrorMsg(scope, msg);3467 "'_' prong is here",
3468 .{},
3469 ),
3470 },
3471 );
3212 }3472 }
3213 special_node = case_node;3473 special_node = case_node;
3214 special_prong = .@"else";3474 special_prong = .@"else";
...@@ -3218,34 +3478,38 @@ fn switchExpr(...@@ -3218,34 +3478,38 @@ fn switchExpr(
3218 node_tags[case.ast.values[0]] == .identifier and3478 node_tags[case.ast.values[0]] == .identifier and
3219 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))3479 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_"))
3220 {3480 {
3221 const case_src = parent_gz.tokSrcLoc(case.ast.arrow_token - 1);3481 const case_src = case.ast.arrow_token - 1;
3222 if (underscore_src) |src| {3482 if (underscore_src) |src| {
3223 const msg = msg: {3483 return astgen.failTokNotes(
3224 const msg = try mod.errMsg(3484 case_src,
3225 scope,3485 "multiple '_' prongs in switch expression",
3226 case_src,3486 .{},
3227 "multiple '_' prongs in switch expression",3487 &[_]u32{
3228 .{},3488 try astgen.errNoteTok(
3229 );3489 src,
3230 errdefer msg.destroy(gpa);3490 "previous '_' prong is here",
3231 try mod.errNote(scope, src, msg, "previous '_' prong is here", .{});3491 .{},
3232 break :msg msg;3492 ),
3233 };3493 },
3234 return mod.failWithOwnedErrorMsg(scope, msg);3494 );
3235 } else if (else_src) |some_else| {3495 } else if (else_src) |some_else| {
3236 const msg = msg: {3496 return astgen.failNodeNotes(
3237 const msg = try mod.errMsg(3497 switch_node,
3238 scope,3498 "else and '_' prong in switch expression",
3239 parent_gz.nodeSrcLoc(switch_node),3499 .{},
3240 "else and '_' prong in switch expression",3500 &[_]u32{
3241 .{},3501 try astgen.errNoteTok(
3242 );3502 some_else,
3243 errdefer msg.destroy(gpa);3503 "else prong is here",
3244 try mod.errNote(scope, some_else, msg, "else prong is here", .{});3504 .{},
3245 try mod.errNote(scope, case_src, msg, "'_' prong is here", .{});3505 ),
3246 break :msg msg;3506 try astgen.errNoteTok(
3247 };3507 case_src,
3248 return mod.failWithOwnedErrorMsg(scope, msg);3508 "'_' prong is here",
3509 .{},
3510 ),
3511 },
3512 );
3249 }3513 }
3250 special_node = case_node;3514 special_node = case_node;
3251 special_prong = .under;3515 special_prong = .under;
...@@ -3281,6 +3545,7 @@ fn switchExpr(...@@ -3281,6 +3545,7 @@ fn switchExpr(
32813545
3282 var block_scope: GenZir = .{3546 var block_scope: GenZir = .{
3283 .parent = scope,3547 .parent = scope,
3548 .decl_node_index = parent_gz.decl_node_index,
3284 .astgen = astgen,3549 .astgen = astgen,
3285 .force_comptime = parent_gz.force_comptime,3550 .force_comptime = parent_gz.force_comptime,
3286 .instructions = .{},3551 .instructions = .{},
...@@ -3294,6 +3559,7 @@ fn switchExpr(...@@ -3294,6 +3559,7 @@ fn switchExpr(
3294 // We re-use this same scope for all cases, including the special prong, if any.3559 // We re-use this same scope for all cases, including the special prong, if any.
3295 var case_scope: GenZir = .{3560 var case_scope: GenZir = .{
3296 .parent = &block_scope.base,3561 .parent = &block_scope.base,
3562 .decl_node_index = parent_gz.decl_node_index,
3297 .astgen = astgen,3563 .astgen = astgen,
3298 .force_comptime = parent_gz.force_comptime,3564 .force_comptime = parent_gz.force_comptime,
3299 .instructions = .{},3565 .instructions = .{},
...@@ -3317,7 +3583,7 @@ fn switchExpr(...@@ -3317,7 +3583,7 @@ fn switchExpr(
3317 const is_ptr = ident != payload_token;3583 const is_ptr = ident != payload_token;
3318 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {3584 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
3319 if (is_ptr) {3585 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", .{});
3321 }3587 }
3322 break :blk &case_scope.base;3588 break :blk &case_scope.base;
3323 }3589 }
...@@ -3332,18 +3598,18 @@ fn switchExpr(...@@ -3332,18 +3598,18 @@ fn switchExpr(
3332 .prong_index = undefined,3598 .prong_index = undefined,
3333 } },3599 } },
3334 });3600 });
3335 const capture_name = try mod.identifierTokenString(&parent_gz.base, payload_token);3601 const capture_name = try astgen.identifierTokenString(payload_token);
3336 capture_val_scope = .{3602 capture_val_scope = .{
3337 .parent = &case_scope.base,3603 .parent = &case_scope.base,
3338 .gen_zir = &case_scope,3604 .gen_zir = &case_scope,
3339 .name = capture_name,3605 .name = capture_name,
3340 .inst = capture,3606 .inst = capture,
3341 .src = parent_gz.tokSrcLoc(payload_token),3607 .token_src = payload_token,
3342 };3608 };
3343 break :blk &capture_val_scope.base;3609 break :blk &capture_val_scope.base;
3344 };3610 };
3345 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);3611 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)) {
3347 block_scope.break_count += 1;3613 block_scope.break_count += 1;
3348 _ = try case_scope.addBreak(.@"break", switch_block, case_result);3614 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
3349 }3615 }
...@@ -3398,7 +3664,7 @@ fn switchExpr(...@@ -3398,7 +3664,7 @@ fn switchExpr(
3398 const is_ptr = ident != payload_token;3664 const is_ptr = ident != payload_token;
3399 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {3665 if (mem.eql(u8, tree.tokenSlice(ident), "_")) {
3400 if (is_ptr) {3666 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", .{});
3402 }3668 }
3403 break :blk &case_scope.base;3669 break :blk &case_scope.base;
3404 }3670 }
...@@ -3424,13 +3690,13 @@ fn switchExpr(...@@ -3424,13 +3690,13 @@ fn switchExpr(
3424 .prong_index = capture_index,3690 .prong_index = capture_index,
3425 } },3691 } },
3426 });3692 });
3427 const capture_name = try mod.identifierTokenString(&parent_gz.base, payload_token);3693 const capture_name = try astgen.identifierTokenString(payload_token);
3428 capture_val_scope = .{3694 capture_val_scope = .{
3429 .parent = &case_scope.base,3695 .parent = &case_scope.base,
3430 .gen_zir = &case_scope,3696 .gen_zir = &case_scope,
3431 .name = capture_name,3697 .name = capture_name,
3432 .inst = capture,3698 .inst = capture,
3433 .src = parent_gz.tokSrcLoc(payload_token),3699 .token_src = payload_token,
3434 };3700 };
3435 break :blk &capture_val_scope.base;3701 break :blk &capture_val_scope.base;
3436 };3702 };
...@@ -3464,7 +3730,7 @@ fn switchExpr(...@@ -3464,7 +3730,7 @@ fn switchExpr(
3464 }3730 }
34653731
3466 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);3732 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)) {
3468 block_scope.break_count += 1;3734 block_scope.break_count += 1;
3469 _ = try case_scope.addBreak(.@"break", switch_block, case_result);3735 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
3470 }3736 }
...@@ -3477,7 +3743,7 @@ fn switchExpr(...@@ -3477,7 +3743,7 @@ fn switchExpr(
3477 const item_node = case.ast.values[0];3743 const item_node = case.ast.values[0];
3478 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);3744 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node);
3479 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);3745 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)) {
3481 block_scope.break_count += 1;3747 block_scope.break_count += 1;
3482 _ = try case_scope.addBreak(.@"break", switch_block, case_result);3748 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
3483 }3749 }
...@@ -3529,7 +3795,7 @@ fn switchExpr(...@@ -3529,7 +3795,7 @@ fn switchExpr(
3529 if (!strat.elide_store_to_block_ptr_instructions) {3795 if (!strat.elide_store_to_block_ptr_instructions) {
3530 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);3796 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
3531 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);3797 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
3532 return astgen.indexToRef(switch_block);3798 return parent_gz.indexToRef(switch_block);
3533 }3799 }
35343800
3535 // There will necessarily be a store_to_block_ptr for3801 // There will necessarily be a store_to_block_ptr for
...@@ -3571,7 +3837,7 @@ fn switchExpr(...@@ -3571,7 +3837,7 @@ fn switchExpr(
3571 .lhs = block_scope.rl_ty_inst,3837 .lhs = block_scope.rl_ty_inst,
3572 .rhs = zir_datas[break_inst].@"break".operand,3838 .rhs = zir_datas[break_inst].@"break".operand,
3573 };3839 };
3574 zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst);3840 zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst);
3575 } else {3841 } else {
3576 scalar_cases_payload.items[body_len_index] -= 1;3842 scalar_cases_payload.items[body_len_index] -= 1;
3577 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);3843 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]);
...@@ -3611,7 +3877,7 @@ fn switchExpr(...@@ -3611,7 +3877,7 @@ fn switchExpr(
3611 .lhs = block_scope.rl_ty_inst,3877 .lhs = block_scope.rl_ty_inst,
3612 .rhs = zir_datas[break_inst].@"break".operand,3878 .rhs = zir_datas[break_inst].@"break".operand,
3613 };3879 };
3614 zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst);3880 zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst);
3615 } else {3881 } else {
3616 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);3882 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
3617 scalar_cases_payload.items[body_len_index] -= 1;3883 scalar_cases_payload.items[body_len_index] -= 1;
...@@ -3656,7 +3922,7 @@ fn switchExpr(...@@ -3656,7 +3922,7 @@ fn switchExpr(
3656 .lhs = block_scope.rl_ty_inst,3922 .lhs = block_scope.rl_ty_inst,
3657 .rhs = zir_datas[break_inst].@"break".operand,3923 .rhs = zir_datas[break_inst].@"break".operand,
3658 };3924 };
3659 zir_datas[break_inst].@"break".operand = astgen.indexToRef(store_inst);3925 zir_datas[break_inst].@"break".operand = parent_gz.indexToRef(store_inst);
3660 } else {3926 } else {
3661 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);3927 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr);
3662 multi_cases_payload.items[body_len_index] -= 1;3928 multi_cases_payload.items[body_len_index] -= 1;
...@@ -3667,7 +3933,7 @@ fn switchExpr(...@@ -3667,7 +3933,7 @@ fn switchExpr(
3667 }3933 }
3668 }3934 }
36693935
3670 const block_ref = astgen.indexToRef(switch_block);3936 const block_ref = parent_gz.indexToRef(switch_block);
3671 switch (rl) {3937 switch (rl) {
3672 .ref => return block_ref,3938 .ref => return block_ref,
3673 else => return rvalue(parent_gz, scope, rl, block_ref, switch_node),3939 else => return rvalue(parent_gz, scope, rl, block_ref, switch_node),
...@@ -3727,13 +3993,14 @@ fn switchExpr(...@@ -3727,13 +3993,14 @@ fn switchExpr(
3727 }3993 }
3728 }3994 }
37293995
3730 return astgen.indexToRef(switch_block);3996 return parent_gz.indexToRef(switch_block);
3731 },3997 },
3732 }3998 }
3733}3999}
37344000
3735fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {4001fn 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;
3737 const node_datas = tree.nodes.items(.data);4004 const node_datas = tree.nodes.items(.data);
3738 const main_tokens = tree.nodes.items(.main_token);4005 const main_tokens = tree.nodes.items(.main_token);
37394006
...@@ -3760,14 +4027,13 @@ fn identifier(...@@ -3760,14 +4027,13 @@ fn identifier(
3760 defer tracy.end();4027 defer tracy.end();
37614028
3762 const astgen = gz.astgen;4029 const astgen = gz.astgen;
3763 const mod = astgen.mod;4030 const tree = &astgen.file.tree;
3764 const tree = gz.tree();
3765 const main_tokens = tree.nodes.items(.main_token);4031 const main_tokens = tree.nodes.items(.main_token);
37664032
3767 const ident_token = main_tokens[ident];4033 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);
3769 if (mem.eql(u8, ident_name, "_")) {4035 if (mem.eql(u8, ident_name, "_")) {
3770 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});4036 return astgen.failNode(ident, "TODO implement '_' identifier", .{});
3771 }4037 }
37724038
3773 if (simple_types.get(ident_name)) |zir_const_ref| {4039 if (simple_types.get(ident_name)) |zir_const_ref| {
...@@ -3782,8 +4048,7 @@ fn identifier(...@@ -3782,8 +4048,7 @@ fn identifier(
3782 false => .unsigned,4048 false => .unsigned,
3783 };4049 };
3784 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {4050 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
3785 error.Overflow => return mod.failNode(4051 error.Overflow => return astgen.failNode(
3786 scope,
3787 ident,4052 ident,
3788 "primitive integer type '{s}' exceeds maximum bit width of 65535",4053 "primitive integer type '{s}' exceeds maximum bit width of 65535",
3789 .{ident_name},4054 .{ident_name},
...@@ -3793,7 +4058,7 @@ fn identifier(...@@ -3793,7 +4058,7 @@ fn identifier(
3793 const result = try gz.add(.{4058 const result = try gz.add(.{
3794 .tag = .int_type,4059 .tag = .int_type,
3795 .data = .{ .int_type = .{4060 .data = .{ .int_type = .{
3796 .src_node = astgen.decl.nodeIndexToRelative(ident),4061 .src_node = gz.nodeIndexToRelative(ident),
3797 .signedness = signedness,4062 .signedness = signedness,
3798 .bit_count = bit_count,4063 .bit_count = bit_count,
3799 } },4064 } },
...@@ -3850,19 +4115,15 @@ fn stringLiteral(...@@ -3850,19 +4115,15 @@ fn stringLiteral(
3850 rl: ResultLoc,4115 rl: ResultLoc,
3851 node: ast.Node.Index,4116 node: ast.Node.Index,
3852) InnerError!Zir.Inst.Ref {4117) InnerError!Zir.Inst.Ref {
3853 const tree = gz.tree();4118 const tree = gz.astgen.file.tree;
3854 const main_tokens = tree.nodes.items(.main_token);4119 const main_tokens = tree.nodes.items(.main_token);
3855 const string_bytes = &gz.astgen.string_bytes;
3856 const str_index = string_bytes.items.len;
3857 const str_lit_token = main_tokens[node];4120 const str_lit_token = main_tokens[node];
3858 const token_bytes = tree.tokenSlice(str_lit_token);4121 const str = try gz.strLitAsString(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;
3861 const result = try gz.add(.{4122 const result = try gz.add(.{
3862 .tag = .str,4123 .tag = .str,
3863 .data = .{ .str = .{4124 .data = .{ .str = .{
3864 .start = @intCast(u32, str_index),4125 .start = str.index,
3865 .len = @intCast(u32, str_len),4126 .len = str.len,
3866 } },4127 } },
3867 });4128 });
3868 return rvalue(gz, scope, rl, result, node);4129 return rvalue(gz, scope, rl, result, node);
...@@ -3874,14 +4135,15 @@ fn multilineStringLiteral(...@@ -3874,14 +4135,15 @@ fn multilineStringLiteral(
3874 rl: ResultLoc,4135 rl: ResultLoc,
3875 node: ast.Node.Index,4136 node: ast.Node.Index,
3876) InnerError!Zir.Inst.Ref {4137) InnerError!Zir.Inst.Ref {
3877 const tree = gz.tree();4138 const astgen = gz.astgen;
4139 const tree = &astgen.file.tree;
3878 const node_datas = tree.nodes.items(.data);4140 const node_datas = tree.nodes.items(.data);
3879 const main_tokens = tree.nodes.items(.main_token);4141 const main_tokens = tree.nodes.items(.main_token);
38804142
3881 const start = node_datas[node].lhs;4143 const start = node_datas[node].lhs;
3882 const end = node_datas[node].rhs;4144 const end = node_datas[node].rhs;
38834145
3884 const gpa = gz.astgen.mod.gpa;4146 const gpa = gz.astgen.gpa;
3885 const string_bytes = &gz.astgen.string_bytes;4147 const string_bytes = &gz.astgen.string_bytes;
3886 const str_index = string_bytes.items.len;4148 const str_index = string_bytes.items.len;
38874149
...@@ -3912,8 +4174,8 @@ fn multilineStringLiteral(...@@ -3912,8 +4174,8 @@ fn multilineStringLiteral(
3912}4174}
39134175
3914fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {4176fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
3915 const mod = gz.astgen.mod;4177 const astgen = gz.astgen;
3916 const tree = gz.tree();4178 const tree = &astgen.file.tree;
3917 const main_tokens = tree.nodes.items(.main_token);4179 const main_tokens = tree.nodes.items(.main_token);
3918 const main_token = main_tokens[node];4180 const main_token = main_tokens[node];
3919 const slice = tree.tokenSlice(main_token);4181 const slice = tree.tokenSlice(main_token);
...@@ -3923,8 +4185,12 @@ fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index)...@@ -3923,8 +4185,12 @@ fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index)
3923 error.InvalidCharacter => {4185 error.InvalidCharacter => {
3924 const bad_byte = slice[bad_index];4186 const bad_byte = slice[bad_index];
3925 const token_starts = tree.tokens.items(.start);4187 const token_starts = tree.tokens.items(.start);
3926 const src_off = @intCast(u32, token_starts[main_token] + bad_index);4188 return astgen.failOff(
3927 return mod.failOff(scope, src_off, "invalid character: '{c}'\n", .{bad_byte});4189 main_token,
4190 @intCast(u32, bad_index),
4191 "invalid character: '{c}'\n",
4192 .{bad_byte},
4193 );
3928 },4194 },
3929 };4195 };
3930 const result = try gz.addInt(value);4196 const result = try gz.addInt(value);
...@@ -3937,7 +4203,8 @@ fn integerLiteral(...@@ -3937,7 +4203,8 @@ fn integerLiteral(
3937 rl: ResultLoc,4203 rl: ResultLoc,
3938 node: ast.Node.Index,4204 node: ast.Node.Index,
3939) InnerError!Zir.Inst.Ref {4205) InnerError!Zir.Inst.Ref {
3940 const tree = gz.tree();4206 const astgen = gz.astgen;
4207 const tree = &astgen.file.tree;
3941 const main_tokens = tree.nodes.items(.main_token);4208 const main_tokens = tree.nodes.items(.main_token);
3942 const int_token = main_tokens[node];4209 const int_token = main_tokens[node];
3943 const prefixed_bytes = tree.tokenSlice(int_token);4210 const prefixed_bytes = tree.tokenSlice(int_token);
...@@ -3949,7 +4216,7 @@ fn integerLiteral(...@@ -3949,7 +4216,7 @@ fn integerLiteral(
3949 };4216 };
3950 return rvalue(gz, scope, rl, result, node);4217 return rvalue(gz, scope, rl, result, node);
3951 } else |err| {4218 } 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", .{});
3953 }4220 }
3954}4221}
39554222
...@@ -3959,15 +4226,16 @@ fn floatLiteral(...@@ -3959,15 +4226,16 @@ fn floatLiteral(
3959 rl: ResultLoc,4226 rl: ResultLoc,
3960 node: ast.Node.Index,4227 node: ast.Node.Index,
3961) InnerError!Zir.Inst.Ref {4228) InnerError!Zir.Inst.Ref {
3962 const arena = gz.astgen.arena;4229 const astgen = gz.astgen;
3963 const tree = gz.tree();4230 const arena = astgen.arena;
4231 const tree = &astgen.file.tree;
3964 const main_tokens = tree.nodes.items(.main_token);4232 const main_tokens = tree.nodes.items(.main_token);
39654233
3966 const main_token = main_tokens[node];4234 const main_token = main_tokens[node];
3967 const bytes = tree.tokenSlice(main_token);4235 const bytes = tree.tokenSlice(main_token);
3968 if (bytes.len > 2 and bytes[1] == 'x') {4236 if (bytes.len > 2 and bytes[1] == 'x') {
3969 assert(bytes[0] == '0'); // validated by tokenizer4237 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", .{});
3971 }4239 }
3972 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {4240 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
3973 error.InvalidCharacter => unreachable, // validated by tokenizer4241 error.InvalidCharacter => unreachable, // validated by tokenizer
...@@ -3999,9 +4267,9 @@ fn asmExpr(...@@ -3999,9 +4267,9 @@ fn asmExpr(
3999 node: ast.Node.Index,4267 node: ast.Node.Index,
4000 full: ast.full.Asm,4268 full: ast.full.Asm,
4001) InnerError!Zir.Inst.Ref {4269) InnerError!Zir.Inst.Ref {
4002 const mod = gz.astgen.mod;4270 const astgen = gz.astgen;
4003 const arena = gz.astgen.arena;4271 const arena = astgen.arena;
4004 const tree = gz.tree();4272 const tree = &astgen.file.tree;
4005 const main_tokens = tree.nodes.items(.main_token);4273 const main_tokens = tree.nodes.items(.main_token);
4006 const node_datas = tree.nodes.items(.data);4274 const node_datas = tree.nodes.items(.data);
40074275
...@@ -4010,7 +4278,7 @@ fn asmExpr(...@@ -4010,7 +4278,7 @@ fn asmExpr(
4010 if (full.outputs.len != 0) {4278 if (full.outputs.len != 0) {
4011 // when implementing this be sure to add test coverage for the asm return type4279 // when implementing this be sure to add test coverage for the asm return type
4012 // not resolving into a type (the node_offset_asm_ret_ty field of LazySrcLoc)4280 // 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", .{});
4014 }4282 }
40154283
4016 const constraints = try arena.alloc(u32, full.inputs.len);4284 const constraints = try arena.alloc(u32, full.inputs.len);
...@@ -4018,11 +4286,11 @@ fn asmExpr(...@@ -4018,11 +4286,11 @@ fn asmExpr(
40184286
4019 for (full.inputs) |input, i| {4287 for (full.inputs) |input, i| {
4020 const constraint_token = main_tokens[input] + 2;4288 const constraint_token = main_tokens[input] + 2;
4021 const string_bytes = &gz.astgen.string_bytes;4289 const string_bytes = &astgen.string_bytes;
4022 constraints[i] = @intCast(u32, string_bytes.items.len);4290 constraints[i] = @intCast(u32, string_bytes.items.len);
4023 const token_bytes = tree.tokenSlice(constraint_token);4291 const token_bytes = tree.tokenSlice(constraint_token);
4024 try mod.parseStrLit(scope, constraint_token, string_bytes, token_bytes, 0);4292 try astgen.parseStrLit(constraint_token, string_bytes, token_bytes, 0);
4025 try string_bytes.append(mod.gpa, 0);4293 try string_bytes.append(astgen.gpa, 0);
40264294
4027 args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs);4295 args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs);
4028 }4296 }
...@@ -4036,10 +4304,10 @@ fn asmExpr(...@@ -4036,10 +4304,10 @@ fn asmExpr(
4036 .clobbers_len = 0, // TODO implement asm clobbers4304 .clobbers_len = 0, // TODO implement asm clobbers
4037 });4305 });
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 +
4040 args.len + constraints.len);4308 args.len + constraints.len);
4041 gz.astgen.appendRefsAssumeCapacity(args);4309 astgen.appendRefsAssumeCapacity(args);
4042 gz.astgen.extra.appendSliceAssumeCapacity(constraints);4310 astgen.extra.appendSliceAssumeCapacity(constraints);
40434311
4044 return rvalue(gz, scope, rl, result, node);4312 return rvalue(gz, scope, rl, result, node);
4045}4313}
...@@ -4068,7 +4336,7 @@ fn as(...@@ -4068,7 +4336,7 @@ fn as(
40684336
4069 .inferred_ptr => |result_alloc| {4337 .inferred_ptr => |result_alloc| {
4070 // TODO here we should be able to resolve the inference; we now have a type for the result.4338 // 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", .{});
4072 },4340 },
4073 }4341 }
4074}4342}
...@@ -4088,11 +4356,12 @@ fn asRlPtr(...@@ -4088,11 +4356,12 @@ fn asRlPtr(
40884356
4089 var as_scope: GenZir = .{4357 var as_scope: GenZir = .{
4090 .parent = scope,4358 .parent = scope,
4359 .decl_node_index = parent_gz.decl_node_index,
4091 .astgen = astgen,4360 .astgen = astgen,
4092 .force_comptime = parent_gz.force_comptime,4361 .force_comptime = parent_gz.force_comptime,
4093 .instructions = .{},4362 .instructions = .{},
4094 };4363 };
4095 defer as_scope.instructions.deinit(astgen.mod.gpa);4364 defer as_scope.instructions.deinit(astgen.gpa);
40964365
4097 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);4366 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
4098 const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);4367 const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);
...@@ -4102,9 +4371,9 @@ fn asRlPtr(...@@ -4102,9 +4371,9 @@ fn asRlPtr(
4102 const zir_tags = astgen.instructions.items(.tag);4371 const zir_tags = astgen.instructions.items(.tag);
4103 const zir_datas = astgen.instructions.items(.data);4372 const zir_datas = astgen.instructions.items(.data);
4104 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;4373 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);
4106 for (as_scope.instructions.items) |src_inst| {4375 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;
4108 if (zir_tags[src_inst] == .store_to_block_ptr) {4377 if (zir_tags[src_inst] == .store_to_block_ptr) {
4109 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;4378 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
4110 }4379 }
...@@ -4114,7 +4383,7 @@ fn asRlPtr(...@@ -4114,7 +4383,7 @@ fn asRlPtr(
4114 const casted_result = try parent_gz.addBin(.as, dest_type, result);4383 const casted_result = try parent_gz.addBin(.as, dest_type, result);
4115 return rvalue(parent_gz, scope, rl, casted_result, operand_node);4384 return rvalue(parent_gz, scope, rl, casted_result, operand_node);
4116 } else {4385 } else {
4117 try parent_zir.appendSlice(astgen.mod.gpa, as_scope.instructions.items);4386 try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
4118 return result;4387 return result;
4119 }4388 }
4120}4389}
...@@ -4127,7 +4396,7 @@ fn bitCast(...@@ -4127,7 +4396,7 @@ fn bitCast(
4127 lhs: ast.Node.Index,4396 lhs: ast.Node.Index,
4128 rhs: ast.Node.Index,4397 rhs: ast.Node.Index,
4129) InnerError!Zir.Inst.Ref {4398) InnerError!Zir.Inst.Ref {
4130 const mod = gz.astgen.mod;4399 const astgen = gz.astgen;
4131 const dest_type = try typeExpr(gz, scope, lhs);4400 const dest_type = try typeExpr(gz, scope, lhs);
4132 switch (rl) {4401 switch (rl) {
4133 .none, .discard, .ty => {4402 .none, .discard, .ty => {
...@@ -4144,11 +4413,11 @@ fn bitCast(...@@ -4144,11 +4413,11 @@ fn bitCast(
4144 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);4413 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);
4145 },4414 },
4146 .block_ptr => |block_ptr| {4415 .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", .{});
4148 },4417 },
4149 .inferred_ptr => |result_alloc| {4418 .inferred_ptr => |result_alloc| {
4150 // TODO here we should be able to resolve the inference; we now have a type for the result.4419 // 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", .{});
4152 },4421 },
4153 }4422 }
4154}4423}
...@@ -4161,7 +4430,7 @@ fn typeOf(...@@ -4161,7 +4430,7 @@ fn typeOf(
4161 params: []const ast.Node.Index,4430 params: []const ast.Node.Index,
4162) InnerError!Zir.Inst.Ref {4431) InnerError!Zir.Inst.Ref {
4163 if (params.len < 1) {4432 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", .{});
4165 }4434 }
4166 if (params.len == 1) {4435 if (params.len == 1) {
4167 const result = try gz.addUnNode(.typeof, try expr(gz, scope, .none, params[0]), node);4436 const result = try gz.addUnNode(.typeof, try expr(gz, scope, .none, params[0]), node);
...@@ -4188,8 +4457,8 @@ fn builtinCall(...@@ -4188,8 +4457,8 @@ fn builtinCall(
4188 node: ast.Node.Index,4457 node: ast.Node.Index,
4189 params: []const ast.Node.Index,4458 params: []const ast.Node.Index,
4190) InnerError!Zir.Inst.Ref {4459) InnerError!Zir.Inst.Ref {
4191 const mod = gz.astgen.mod;4460 const astgen = gz.astgen;
4192 const tree = gz.tree();4461 const tree = &astgen.file.tree;
4193 const main_tokens = tree.nodes.items(.main_token);4462 const main_tokens = tree.nodes.items(.main_token);
41944463
4195 const builtin_token = main_tokens[node];4464 const builtin_token = main_tokens[node];
...@@ -4201,14 +4470,14 @@ fn builtinCall(...@@ -4201,14 +4470,14 @@ fn builtinCall(
4201 // Also, some builtins have a variable number of parameters.4470 // Also, some builtins have a variable number of parameters.
42024471
4203 const info = BuiltinFn.list.get(builtin_name) orelse {4472 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}'", .{
4205 builtin_name,4474 builtin_name,
4206 });4475 });
4207 };4476 };
4208 if (info.param_count) |expected| {4477 if (info.param_count) |expected| {
4209 if (expected != params.len) {4478 if (expected != params.len) {
4210 const s = if (expected == 1) "" else "s";4479 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}", .{
4212 expected, s, params.len,4481 expected, s, params.len,
4213 });4482 });
4214 }4483 }
...@@ -4241,7 +4510,7 @@ fn builtinCall(...@@ -4241,7 +4510,7 @@ fn builtinCall(
4241 .breakpoint => {4510 .breakpoint => {
4242 _ = try gz.add(.{4511 _ = try gz.add(.{
4243 .tag = .breakpoint,4512 .tag = .breakpoint,
4244 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(node) },4513 .data = .{ .node = gz.nodeIndexToRelative(node) },
4245 });4514 });
4246 return rvalue(gz, scope, rl, .void_value, node);4515 return rvalue(gz, scope, rl, .void_value, node);
4247 },4516 },
...@@ -4271,8 +4540,8 @@ fn builtinCall(...@@ -4271,8 +4540,8 @@ fn builtinCall(
4271 return rvalue(gz, scope, rl, result, node);4540 return rvalue(gz, scope, rl, result, node);
4272 },4541 },
4273 .compile_log => {4542 .compile_log => {
4274 const arg_refs = try mod.gpa.alloc(Zir.Inst.Ref, params.len);4543 const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len);
4275 defer mod.gpa.free(arg_refs);4544 defer astgen.gpa.free(arg_refs);
42764545
4277 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);4546 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);
42784547
...@@ -4432,7 +4701,7 @@ fn builtinCall(...@@ -4432,7 +4701,7 @@ fn builtinCall(
4432 .Type,4701 .Type,
4433 .type_name,4702 .type_name,
4434 .union_init,4703 .union_init,
4435 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{4704 => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
4436 builtin_name,4705 builtin_name,
4437 }),4706 }),
44384707
...@@ -4441,7 +4710,7 @@ fn builtinCall(...@@ -4441,7 +4710,7 @@ fn builtinCall(
4441 .Frame,4710 .Frame,
4442 .frame_address,4711 .frame_address,
4443 .frame_size,4712 .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", .{}),
4445 }4714 }
4446}4715}
44474716
...@@ -4452,14 +4721,14 @@ fn callExpr(...@@ -4452,14 +4721,14 @@ fn callExpr(
4452 node: ast.Node.Index,4721 node: ast.Node.Index,
4453 call: ast.full.Call,4722 call: ast.full.Call,
4454) InnerError!Zir.Inst.Ref {4723) InnerError!Zir.Inst.Ref {
4455 const mod = gz.astgen.mod;4724 const astgen = gz.astgen;
4456 if (call.async_token) |async_token| {4725 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", .{});
4458 }4727 }
4459 const lhs = try expr(gz, scope, .none, call.ast.fn_expr);4728 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);4730 const args = try astgen.gpa.alloc(Zir.Inst.Ref, call.ast.params.len);
4462 defer mod.gpa.free(args);4731 defer astgen.gpa.free(args);
44634732
4464 for (call.ast.params) |param_node, i| {4733 for (call.ast.params) |param_node, i| {
4465 const param_type = try gz.add(.{4734 const param_type = try gz.add(.{
...@@ -4482,10 +4751,10 @@ fn callExpr(...@@ -4482,10 +4751,10 @@ fn callExpr(
4482 true => break :res try gz.addUnNode(.call_none, lhs, node),4751 true => break :res try gz.addUnNode(.call_none, lhs, node),
4483 false => .call,4752 false => .call,
4484 },4753 },
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", .{}),
4486 .never_tail => unreachable,4755 .never_tail => unreachable,
4487 .never_inline => unreachable,4756 .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", .{}),
4489 .always_tail => unreachable,4758 .always_tail => unreachable,
4490 .always_inline => unreachable,4759 .always_inline => unreachable,
4491 .compile_time => .call_compile_time,4760 .compile_time => .call_compile_time,
...@@ -4768,7 +5037,7 @@ fn rvalue(...@@ -4768,7 +5037,7 @@ fn rvalue(
4768 },5037 },
4769 .ref => {5038 .ref => {
4770 // We need a pointer but we have a value.5039 // We need a pointer but we have a value.
4771 const tree = gz.tree();5040 const tree = &gz.astgen.file.tree;
4772 const src_token = tree.firstToken(src_node);5041 const src_token = tree.firstToken(src_node);
4773 return gz.addUnTok(.ref, result, src_token);5042 return gz.addUnTok(.ref, result, src_token);
4774 },5043 },
...@@ -4854,3 +5123,263 @@ fn rvalue(...@@ -4854,3 +5123,263 @@ fn rvalue(
4854 },5123 },
4855 }5124 }
4856}5125}
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),...@@ -49,6 +49,11 @@ work_queue: std.fifo.LinearFifo(Job, .Dynamic),
49/// gets linked with the Compilation.49/// gets linked with the Compilation.
50c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),50c_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
52/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.57/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
53/// This data is accessed by multiple threads and is protected by `mutex`.58/// This data is accessed by multiple threads and is protected by `mutex`.
54failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},59failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
...@@ -141,6 +146,7 @@ emit_analysis: ?EmitLoc,...@@ -141,6 +146,7 @@ emit_analysis: ?EmitLoc,
141emit_docs: ?EmitLoc,146emit_docs: ?EmitLoc,
142147
143work_queue_wait_group: WaitGroup,148work_queue_wait_group: WaitGroup,
149astgen_wait_group: WaitGroup,
144150
145pub const InnerError = Module.InnerError;151pub const InnerError = Module.InnerError;
146152
...@@ -1210,6 +1216,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1210,6 +1216,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1210 .emit_docs = options.emit_docs,1216 .emit_docs = options.emit_docs,
1211 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),1217 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
1212 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),1218 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
1219 .astgen_work_queue = std.fifo.LinearFifo(*Module.Scope.File, .Dynamic).init(gpa),
1213 .keep_source_files_loaded = options.keep_source_files_loaded,1220 .keep_source_files_loaded = options.keep_source_files_loaded,
1214 .use_clang = use_clang,1221 .use_clang = use_clang,
1215 .clang_argv = options.clang_argv,1222 .clang_argv = options.clang_argv,
...@@ -1238,6 +1245,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1238,6 +1245,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1238 .test_evented_io = options.test_evented_io,1245 .test_evented_io = options.test_evented_io,
1239 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,1246 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
1240 .work_queue_wait_group = undefined,1247 .work_queue_wait_group = undefined,
1248 .astgen_wait_group = undefined,
1241 };1249 };
1242 break :comp comp;1250 break :comp comp;
1243 };1251 };
...@@ -1246,6 +1254,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1246,6 +1254,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1246 try comp.work_queue_wait_group.init();1254 try comp.work_queue_wait_group.init();
1247 errdefer comp.work_queue_wait_group.deinit();1255 errdefer comp.work_queue_wait_group.deinit();
12481256
1257 try comp.astgen_wait_group.init();
1258 errdefer comp.astgen_wait_group.deinit();
1259
1249 if (comp.bin_file.options.module) |mod| {1260 if (comp.bin_file.options.module) |mod| {
1250 try comp.work_queue.writeItem(.{ .generate_builtin_zig = {} });1261 try comp.work_queue.writeItem(.{ .generate_builtin_zig = {} });
1251 }1262 }
...@@ -1381,6 +1392,7 @@ pub fn destroy(self: *Compilation) void {...@@ -1381,6 +1392,7 @@ pub fn destroy(self: *Compilation) void {
1381 const gpa = self.gpa;1392 const gpa = self.gpa;
1382 self.work_queue.deinit();1393 self.work_queue.deinit();
1383 self.c_object_work_queue.deinit();1394 self.c_object_work_queue.deinit();
1395 self.astgen_work_queue.deinit();
13841396
1385 {1397 {
1386 var it = self.crt_files.iterator();1398 var it = self.crt_files.iterator();
...@@ -1431,6 +1443,7 @@ pub fn destroy(self: *Compilation) void {...@@ -1431,6 +1443,7 @@ pub fn destroy(self: *Compilation) void {
1431 if (self.owned_link_dir) |*dir| dir.close();1443 if (self.owned_link_dir) |*dir| dir.close();
14321444
1433 self.work_queue_wait_group.deinit();1445 self.work_queue_wait_group.deinit();
1446 self.astgen_wait_group.deinit();
14341447
1435 // This destroys `self`.1448 // This destroys `self`.
1436 self.arena_state.promote(gpa).deinit();1449 self.arena_state.promote(gpa).deinit();
...@@ -1470,42 +1483,17 @@ pub fn update(self: *Compilation) !void {...@@ -1470,42 +1483,17 @@ pub fn update(self: *Compilation) !void {
1470 module.compile_log_text.shrinkAndFree(module.gpa, 0);1483 module.compile_log_text.shrinkAndFree(module.gpa, 0);
1471 module.generation += 1;1484 module.generation += 1;
14721485
1473 // Detect which source files changed.1486 // Make sure std.zig is inside the import_table. We unconditionally need
1474 for (module.import_table.items()) |entry| {1487 // it for start.zig.
1475 const file = entry.value;1488 _ = try module.importFile(module.root_pkg, "std");
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);
14991489
1500 module.analyzeFile(file) catch |err| switch (err) {1490 // Put a work item in for every known source file to detect if
1501 error.OutOfMemory => return error.OutOfMemory,1491 // it changed, and, if so, re-compute ZIR and then queue the job
1502 error.AnalysisFail => continue,1492 // to update it.
1503 else => |e| return e,1493 try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count());
1504 };1494 for (module.import_table.items()) |entry| {
1495 self.astgen_work_queue.writeItemAssumeCapacity(entry.value);
1505 }1496 }
1506
1507 // Simulate `_ = @import("std");` which in turn imports start.zig.
1508 _ = try module.importFile(module.root_pkg, "std");
1509 }1497 }
1510 }1498 }
15111499
...@@ -1578,13 +1566,13 @@ pub fn totalErrorCount(self: *Compilation) usize {...@@ -1578,13 +1566,13 @@ pub fn totalErrorCount(self: *Compilation) usize {
1578 // the previous parse success, including compile errors, but we cannot1566 // the previous parse success, including compile errors, but we cannot
1579 // emit them until the file succeeds parsing.1567 // emit them until the file succeeds parsing.
1580 for (module.failed_decls.items()) |entry| {1568 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) {
1582 continue;1570 continue;
1583 }1571 }
1584 total += 1;1572 total += 1;
1585 }1573 }
1586 for (module.emit_h_failed_decls.items()) |entry| {1574 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) {
1588 continue;1576 continue;
1589 }1577 }
1590 total += 1;1578 total += 1;
...@@ -1639,7 +1627,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1639,7 +1627,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1639 try AllErrors.add(module, &arena, &errors, entry.value.*);1627 try AllErrors.add(module, &arena, &errors, entry.value.*);
1640 }1628 }
1641 for (module.failed_decls.items()) |entry| {1629 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) {
1643 // Skip errors for Decls within files that had a parse failure.1631 // Skip errors for Decls within files that had a parse failure.
1644 // We'll try again once parsing succeeds.1632 // We'll try again once parsing succeeds.
1645 continue;1633 continue;
...@@ -1647,7 +1635,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1647,7 +1635,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1647 try AllErrors.add(module, &arena, &errors, entry.value.*);1635 try AllErrors.add(module, &arena, &errors, entry.value.*);
1648 }1636 }
1649 for (module.emit_h_failed_decls.items()) |entry| {1637 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) {
1651 // Skip errors for Decls within files that had a parse failure.1639 // Skip errors for Decls within files that had a parse failure.
1652 // We'll try again once parsing succeeds.1640 // We'll try again once parsing succeeds.
1653 continue;1641 continue;
...@@ -1719,17 +1707,37 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -1719,17 +1707,37 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
1719 defer main_progress_node.end();1707 defer main_progress_node.end();
1720 if (self.color == .off) progress.terminal = null;1708 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);1710 // Here we queue up all the AstGen tasks first, followed by C object compilation.
1723 defer c_comp_progress_node.end();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
1725 self.work_queue_wait_group.reset();1721 self.work_queue_wait_group.reset();
1726 defer self.work_queue_wait_group.wait();1722 defer self.work_queue_wait_group.wait();
17271723
1728 while (self.c_object_work_queue.readItem()) |c_object| {1724 {
1729 self.work_queue_wait_group.start();1725 self.astgen_wait_group.reset();
1730 try self.thread_pool.spawn(workerUpdateCObject, .{1726 defer self.astgen_wait_group.wait();
1731 self, c_object, &c_comp_progress_node, &self.work_queue_wait_group,1727
1732 });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 }
1733 }1741 }
17341742
1735 while (self.work_queue.readItem()) |work_item| switch (work_item) {1743 while (self.work_queue.readItem()) |work_item| switch (work_item) {
...@@ -2036,6 +2044,28 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2036,6 +2044,28 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2036 };2044 };
2037}2045}
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
2039pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {2069pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
2040 var man = comp.cache_parent.obtain();2070 var man = comp.cache_parent.obtain();
20412071
...@@ -2235,7 +2265,32 @@ fn reportRetryableCObjectError(...@@ -2235,7 +2265,32 @@ fn reportRetryableCObjectError(
2235 }2265 }
2236}2266}
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 {
2239 if (!build_options.have_llvm) {2294 if (!build_options.have_llvm) {
2240 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});2295 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
2241 }2296 }
...@@ -2302,8 +2357,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *...@@ -2302,8 +2357,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
23022357
2303 const c_source_basename = std.fs.path.basename(c_object.src.src_path);2358 const c_source_basename = std.fs.path.basename(c_object.src.src_path);
23042359
2305 c_comp_progress_node.activate();2360 c_obj_prog_node.activate();
2306 var child_progress_node = c_comp_progress_node.start(c_source_basename, 0);2361 var child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
2307 child_progress_node.activate();2362 child_progress_node.activate();
2308 defer child_progress_node.end();2363 defer child_progress_node.end();
23092364
src/Module.zig+325-1278
...@@ -274,7 +274,7 @@ pub const Decl = struct {...@@ -274,7 +274,7 @@ pub const Decl = struct {
274 };274 };
275 }275 }
276276
277 pub fn srcToken(decl: Decl) u32 {277 pub fn srcToken(decl: Decl) ast.TokenIndex {
278 const tree = &decl.namespace.file_scope.tree;278 const tree = &decl.namespace.file_scope.tree;
279 return tree.firstToken(decl.src_node);279 return tree.firstToken(decl.src_node);
280 }280 }
...@@ -531,9 +531,9 @@ pub const Scope = struct {...@@ -531,9 +531,9 @@ pub const Scope = struct {
531 pub fn ownerDecl(scope: *Scope) ?*Decl {531 pub fn ownerDecl(scope: *Scope) ?*Decl {
532 return switch (scope.tag) {532 return switch (scope.tag) {
533 .block => scope.cast(Block).?.sema.owner_decl,533 .block => scope.cast(Block).?.sema.owner_decl,
534 .gen_zir => scope.cast(GenZir).?.astgen.decl,534 .gen_zir => unreachable,
535 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,535 .local_val => unreachable,
536 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,536 .local_ptr => unreachable,
537 .file => null,537 .file => null,
538 .namespace => null,538 .namespace => null,
539 .decl_ref => scope.cast(DeclRef).?.decl,539 .decl_ref => scope.cast(DeclRef).?.decl,
...@@ -543,9 +543,9 @@ pub const Scope = struct {...@@ -543,9 +543,9 @@ pub const Scope = struct {
543 pub fn srcDecl(scope: *Scope) ?*Decl {543 pub fn srcDecl(scope: *Scope) ?*Decl {
544 return switch (scope.tag) {544 return switch (scope.tag) {
545 .block => scope.cast(Block).?.src_decl,545 .block => scope.cast(Block).?.src_decl,
546 .gen_zir => scope.cast(GenZir).?.astgen.decl,546 .gen_zir => unreachable,
547 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,547 .local_val => unreachable,
548 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,548 .local_ptr => unreachable,
549 .file => null,549 .file => null,
550 .namespace => null,550 .namespace => null,
551 .decl_ref => scope.cast(DeclRef).?.decl,551 .decl_ref => scope.cast(DeclRef).?.decl,
...@@ -556,28 +556,15 @@ pub const Scope = struct {...@@ -556,28 +556,15 @@ pub const Scope = struct {
556 pub fn namespace(scope: *Scope) *Namespace {556 pub fn namespace(scope: *Scope) *Namespace {
557 switch (scope.tag) {557 switch (scope.tag) {
558 .block => return scope.cast(Block).?.sema.owner_decl.namespace,558 .block => return scope.cast(Block).?.sema.owner_decl.namespace,
559 .gen_zir => return scope.cast(GenZir).?.astgen.decl.namespace,559 .gen_zir => unreachable,
560 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace,560 .local_val => unreachable,
561 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace,561 .local_ptr => unreachable,
562 .file => return scope.cast(File).?.namespace,562 .file => return scope.cast(File).?.namespace,
563 .namespace => return scope.cast(Namespace).?,563 .namespace => return scope.cast(Namespace).?,
564 .decl_ref => return scope.cast(DeclRef).?.decl.namespace,564 .decl_ref => return scope.cast(DeclRef).?.decl.namespace,
565 }565 }
566 }566 }
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
581 /// Asserts the scope is a child of a `GenZir` and returns it.568 /// Asserts the scope is a child of a `GenZir` and returns it.
582 pub fn getGenZir(scope: *Scope) *GenZir {569 pub fn getGenZir(scope: *Scope) *GenZir {
583 return switch (scope.tag) {570 return switch (scope.tag) {
...@@ -690,11 +677,14 @@ pub const Scope = struct {...@@ -690,11 +677,14 @@ pub const Scope = struct {
690 base: Scope = Scope{ .tag = base_tag },677 base: Scope = Scope{ .tag = base_tag },
691 status: enum {678 status: enum {
692 never_loaded,679 never_loaded,
693 unloaded_success,680 parse_failure,
694 unloaded_parse_failure,681 astgen_failure,
695 loaded_success,682 retryable_failure,
683 success,
696 },684 },
697 source_loaded: bool,685 source_loaded: bool,
686 tree_loaded: bool,
687 zir_loaded: bool,
698 /// Relative to the owning package's root_src_dir.688 /// Relative to the owning package's root_src_dir.
699 /// Memory is stored in gpa, owned by File.689 /// Memory is stored in gpa, owned by File.
700 sub_file_path: []const u8,690 sub_file_path: []const u8,
...@@ -706,23 +696,27 @@ pub const Scope = struct {...@@ -706,23 +696,27 @@ pub const Scope = struct {
706 stat_inode: std.fs.File.INode,696 stat_inode: std.fs.File.INode,
707 /// Whether this is populated depends on `status`.697 /// Whether this is populated depends on `status`.
708 stat_mtime: i128,698 stat_mtime: i128,
709 /// Whether this is populated or not depends on `status`.699 /// Whether this is populated or not depends on `tree_loaded`.
710 tree: ast.Tree,700 tree: ast.Tree,
701 /// Whether this is populated or not depends on `zir_loaded`.
702 zir: Zir,
711 /// Package that this file is a part of, managed externally.703 /// Package that this file is a part of, managed externally.
712 pkg: *Package,704 pkg: *Package,
713 /// The namespace of the struct that represents this file.705 /// The namespace of the struct that represents this file.
706 /// Populated only when status is success.
714 namespace: *Namespace,707 namespace: *Namespace,
715708
716 pub fn unload(file: *File, gpa: *Allocator) void {709 pub fn unload(file: *File, gpa: *Allocator) void {
717 file.unloadTree(gpa);710 file.unloadTree(gpa);
718 file.unloadSource(gpa);711 file.unloadSource(gpa);
712 file.unloadZir(gpa);
719 }713 }
720714
721 pub fn unloadTree(file: *File, gpa: *Allocator) void {715 pub fn unloadTree(file: *File, gpa: *Allocator) void {
722 if (file.status == .loaded_success) {716 if (file.tree_loaded) {
717 file.tree_loaded = false;
723 file.tree.deinit(gpa);718 file.tree.deinit(gpa);
724 }719 }
725 file.status = .unloaded_success;
726 }720 }
727721
728 pub fn unloadSource(file: *File, gpa: *Allocator) void {722 pub fn unloadSource(file: *File, gpa: *Allocator) void {
...@@ -732,21 +726,18 @@ pub const Scope = struct {...@@ -732,21 +726,18 @@ pub const Scope = struct {
732 }726 }
733 }727 }
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
735 pub fn deinit(file: *File, gpa: *Allocator) void {736 pub fn deinit(file: *File, gpa: *Allocator) void {
736 file.unload(gpa);737 file.unload(gpa);
737 file.* = undefined;738 file.* = undefined;
738 }739 }
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
750 pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {741 pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
751 if (file.source_loaded) return file.source;742 if (file.source_loaded) return file.source;
752743
...@@ -757,31 +748,32 @@ pub const Scope = struct {...@@ -757,31 +748,32 @@ pub const Scope = struct {
757748
758 const stat = try f.stat();749 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 {
771 if (stat.size > std.math.maxInt(u32))751 if (stat.size > std.math.maxInt(u32))
772 return error.FileTooBig;752 return error.FileTooBig;
773753
774 const source = try gpa.allocSentinel(u8, stat.size, 0);754 const source = try gpa.allocSentinel(u8, stat.size, 0);
775 errdefer gpa.free(source);755 defer if (!file.source_loaded) gpa.free(source);
776 const amt = try f.readAll(source);756 const amt = try f.readAll(source);
777 if (amt != stat.size)757 if (amt != stat.size)
778 return error.UnexpectedEndOfFile;758 return error.UnexpectedEndOfFile;
779759
780 file.stat_size = stat.size;760 // Here we do not modify stat fields because this function is the one
781 file.stat_inode = stat.inode;761 // used for error reporting. We need to keep the stat fields stale so that
782 file.stat_mtime = stat.mtime;762 // astGenFile can know to regenerate ZIR.
763
783 file.source = source;764 file.source = source;
784 file.source_loaded = true;765 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 });
785 }777 }
786 };778 };
787779
...@@ -1050,6 +1042,11 @@ pub const Scope = struct {...@@ -1050,6 +1042,11 @@ pub const Scope = struct {
1050 pub const base_tag: Tag = .gen_zir;1042 pub const base_tag: Tag = .gen_zir;
1051 base: Scope = Scope{ .tag = base_tag },1043 base: Scope = Scope{ .tag = base_tag },
1052 force_comptime: bool,1044 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,
1053 /// Parents can be: `GenZir`, `File`1050 /// Parents can be: `GenZir`, `File`
1054 parent: *Scope,1051 parent: *Scope,
1055 /// All `GenZir` scopes for the same ZIR share this.1052 /// All `GenZir` scopes for the same ZIR share this.
...@@ -1089,29 +1086,49 @@ pub const Scope = struct {...@@ -1089,29 +1086,49 @@ pub const Scope = struct {
1089 used: bool = false,1086 used: bool = false,
1090 };1087 };
10911088
1092 /// Only valid to call on the top of the `GenZir` stack. Completes the1089 pub fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {
1093 /// `AstGen` into a `Zir`. Leaves the `AstGen` in an1090 if (inst_ref == .unreachable_value) return true;
1094 /// initialized, but empty, state.1091 if (gz.refToIndex(inst_ref)) |inst_index| {
1095 pub fn finish(gz: *GenZir) !Zir {1092 return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn();
1096 const gpa = gz.astgen.mod.gpa;1093 }
1097 try gz.setBlockBody(0);1094 return false;
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 };
1103 }1095 }
11041096
1105 pub fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc {1097 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() };
1107 }1099 }
11081100
1109 pub fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc {1101 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);
1111 }1115 }
11121116
1113 pub fn tree(gz: *const GenZir) *const ast.Tree {1117 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 }
1115 }1132 }
11161133
1117 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {1134 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
...@@ -1149,7 +1166,7 @@ pub const Scope = struct {...@@ -1149,7 +1166,7 @@ pub const Scope = struct {
1149 }1166 }
11501167
1151 pub fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {1168 pub fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
1152 const gpa = gz.astgen.mod.gpa;1169 const gpa = gz.astgen.gpa;
1153 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1170 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
1154 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);1171 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
1155 const zir_datas = gz.astgen.instructions.items(.data);1172 const zir_datas = gz.astgen.instructions.items(.data);
...@@ -1160,7 +1177,7 @@ pub const Scope = struct {...@@ -1160,7 +1177,7 @@ pub const Scope = struct {
1160 }1177 }
11611178
1162 pub fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {1179 pub fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
1163 const gpa = gz.astgen.mod.gpa;1180 const gpa = gz.astgen.gpa;
1164 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1181 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
1165 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);1182 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
1166 const zir_datas = gz.astgen.instructions.items(.data);1183 const zir_datas = gz.astgen.instructions.items(.data);
...@@ -1172,77 +1189,133 @@ pub const Scope = struct {...@@ -1172,77 +1189,133 @@ pub const Scope = struct {
11721189
1173 pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {1190 pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
1174 const astgen = gz.astgen;1191 const astgen = gz.astgen;
1175 const gpa = astgen.mod.gpa;1192 const gpa = astgen.gpa;
1176 const string_bytes = &astgen.string_bytes;1193 const string_bytes = &astgen.string_bytes;
1177 const str_index = @intCast(u32, string_bytes.items.len);1194 const str_index = @intCast(u32, string_bytes.items.len);
1178 try astgen.mod.appendIdentStr(&gz.base, ident_token, string_bytes);1195 try astgen.appendIdentStr(ident_token, string_bytes);
1179 try string_bytes.append(gpa, 0);1196 const key = string_bytes.items[str_index..];
1180 return 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 }
1181 }1210 }
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 {
1184 src_node: ast.Node.Index,1247 src_node: ast.Node.Index,
1185 param_types: []const Zir.Inst.Ref,1248 param_types: []const Zir.Inst.Ref,
1186 ret_ty: Zir.Inst.Ref,1249 ret_ty: Zir.Inst.Ref,
1187 cc: Zir.Inst.Ref,1250 cc: Zir.Inst.Ref,
1251 body: []const Zir.Inst.Index,
1252 lib_name: u32,
1188 }) !Zir.Inst.Ref {1253 }) !Zir.Inst.Ref {
1189 assert(args.src_node != 0);1254 assert(args.src_node != 0);
1190 assert(args.ret_ty != .none);1255 assert(args.ret_ty != .none);
1191 assert(args.cc != .none);1256 assert(args.cc != .none);
1192 const gpa = gz.astgen.mod.gpa;1257 const gpa = gz.astgen.gpa;
1193 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1258 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1194 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1259 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
1195 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1260 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{
1199 .return_type = args.ret_ty,1265 .return_type = args.ret_ty,
1200 .cc = args.cc,1266 .cc = args.cc,
1201 .param_types_len = @intCast(u32, args.param_types.len),1267 .param_types_len = @intCast(u32, args.param_types.len),
1268 .body_len = @intCast(u32, args.body.len),
1269 .lib_name = args.lib_name,
1202 });1270 });
1203 gz.astgen.appendRefsAssumeCapacity(args.param_types);1271 gz.astgen.appendRefsAssumeCapacity(args.param_types);
1272 gz.astgen.extra.appendSliceAssumeCapacity(args.body);
12041273
1205 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);1274 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1206 gz.astgen.instructions.appendAssumeCapacity(.{1275 gz.astgen.instructions.appendAssumeCapacity(.{
1207 .tag = tag,1276 .tag = tag,
1208 .data = .{ .pl_node = .{1277 .data = .{ .pl_node = .{
1209 .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node),1278 .src_node = gz.nodeIndexToRelative(args.src_node),
1210 .payload_index = payload_index,1279 .payload_index = payload_index,
1211 } },1280 } },
1212 });1281 });
1213 gz.instructions.appendAssumeCapacity(new_index);1282 gz.instructions.appendAssumeCapacity(new_index);
1214 return gz.astgen.indexToRef(new_index);1283 return gz.indexToRef(new_index);
1215 }1284 }
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 {
1218 src_node: ast.Node.Index,1287 src_node: ast.Node.Index,
1219 ret_ty: Zir.Inst.Ref,1288 ret_ty: Zir.Inst.Ref,
1220 param_types: []const Zir.Inst.Ref,1289 param_types: []const Zir.Inst.Ref,
1290 body: []const Zir.Inst.Index,
1221 }) !Zir.Inst.Ref {1291 }) !Zir.Inst.Ref {
1222 assert(args.src_node != 0);1292 assert(args.src_node != 0);
1223 assert(args.ret_ty != .none);1293 assert(args.ret_ty != .none);
1224 const gpa = gz.astgen.mod.gpa;1294 const gpa = gz.astgen.gpa;
1225 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1295 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1226 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1296 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
1227 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1297 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{
1231 .return_type = args.ret_ty,1302 .return_type = args.ret_ty,
1232 .param_types_len = @intCast(u32, args.param_types.len),1303 .param_types_len = @intCast(u32, args.param_types.len),
1304 .body_len = @intCast(u32, args.body.len),
1233 });1305 });
1234 gz.astgen.appendRefsAssumeCapacity(args.param_types);1306 gz.astgen.appendRefsAssumeCapacity(args.param_types);
1307 gz.astgen.extra.appendSliceAssumeCapacity(args.body);
12351308
1236 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);1309 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1237 gz.astgen.instructions.appendAssumeCapacity(.{1310 gz.astgen.instructions.appendAssumeCapacity(.{
1238 .tag = tag,1311 .tag = tag,
1239 .data = .{ .pl_node = .{1312 .data = .{ .pl_node = .{
1240 .src_node = gz.astgen.decl.nodeIndexToRelative(args.src_node),1313 .src_node = gz.nodeIndexToRelative(args.src_node),
1241 .payload_index = payload_index,1314 .payload_index = payload_index,
1242 } },1315 } },
1243 });1316 });
1244 gz.instructions.appendAssumeCapacity(new_index);1317 gz.instructions.appendAssumeCapacity(new_index);
1245 return gz.astgen.indexToRef(new_index);1318 return gz.indexToRef(new_index);
1246 }1319 }
12471320
1248 pub fn addCall(1321 pub fn addCall(
...@@ -1255,7 +1328,7 @@ pub const Scope = struct {...@@ -1255,7 +1328,7 @@ pub const Scope = struct {
1255 ) !Zir.Inst.Ref {1328 ) !Zir.Inst.Ref {
1256 assert(callee != .none);1329 assert(callee != .none);
1257 assert(src_node != 0);1330 assert(src_node != 0);
1258 const gpa = gz.astgen.mod.gpa;1331 const gpa = gz.astgen.gpa;
1259 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1332 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1260 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1333 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
1261 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1334 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
...@@ -1271,12 +1344,12 @@ pub const Scope = struct {...@@ -1271,12 +1344,12 @@ pub const Scope = struct {
1271 gz.astgen.instructions.appendAssumeCapacity(.{1344 gz.astgen.instructions.appendAssumeCapacity(.{
1272 .tag = tag,1345 .tag = tag,
1273 .data = .{ .pl_node = .{1346 .data = .{ .pl_node = .{
1274 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),1347 .src_node = gz.nodeIndexToRelative(src_node),
1275 .payload_index = payload_index,1348 .payload_index = payload_index,
1276 } },1349 } },
1277 });1350 });
1278 gz.instructions.appendAssumeCapacity(new_index);1351 gz.instructions.appendAssumeCapacity(new_index);
1279 return gz.astgen.indexToRef(new_index);1352 return gz.indexToRef(new_index);
1280 }1353 }
12811354
1282 /// Note that this returns a `Zir.Inst.Index` not a ref.1355 /// Note that this returns a `Zir.Inst.Index` not a ref.
...@@ -1287,7 +1360,7 @@ pub const Scope = struct {...@@ -1287,7 +1360,7 @@ pub const Scope = struct {
1287 lhs: Zir.Inst.Ref,1360 lhs: Zir.Inst.Ref,
1288 ) !Zir.Inst.Index {1361 ) !Zir.Inst.Index {
1289 assert(lhs != .none);1362 assert(lhs != .none);
1290 const gpa = gz.astgen.mod.gpa;1363 const gpa = gz.astgen.gpa;
1291 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1364 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1292 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1365 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
12931366
...@@ -1314,7 +1387,7 @@ pub const Scope = struct {...@@ -1314,7 +1387,7 @@ pub const Scope = struct {
1314 return gz.add(.{1387 return gz.add(.{
1315 .tag = .float,1388 .tag = .float,
1316 .data = .{ .float = .{1389 .data = .{ .float = .{
1317 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),1390 .src_node = gz.nodeIndexToRelative(src_node),
1318 .number = number,1391 .number = number,
1319 } },1392 } },
1320 });1393 });
...@@ -1332,7 +1405,7 @@ pub const Scope = struct {...@@ -1332,7 +1405,7 @@ pub const Scope = struct {
1332 .tag = tag,1405 .tag = tag,
1333 .data = .{ .un_node = .{1406 .data = .{ .un_node = .{
1334 .operand = operand,1407 .operand = operand,
1335 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),1408 .src_node = gz.nodeIndexToRelative(src_node),
1336 } },1409 } },
1337 });1410 });
1338 }1411 }
...@@ -1344,7 +1417,7 @@ pub const Scope = struct {...@@ -1344,7 +1417,7 @@ pub const Scope = struct {
1344 src_node: ast.Node.Index,1417 src_node: ast.Node.Index,
1345 extra: anytype,1418 extra: anytype,
1346 ) !Zir.Inst.Ref {1419 ) !Zir.Inst.Ref {
1347 const gpa = gz.astgen.mod.gpa;1420 const gpa = gz.astgen.gpa;
1348 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1421 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1349 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1422 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
13501423
...@@ -1353,12 +1426,12 @@ pub const Scope = struct {...@@ -1353,12 +1426,12 @@ pub const Scope = struct {
1353 gz.astgen.instructions.appendAssumeCapacity(.{1426 gz.astgen.instructions.appendAssumeCapacity(.{
1354 .tag = tag,1427 .tag = tag,
1355 .data = .{ .pl_node = .{1428 .data = .{ .pl_node = .{
1356 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),1429 .src_node = gz.nodeIndexToRelative(src_node),
1357 .payload_index = payload_index,1430 .payload_index = payload_index,
1358 } },1431 } },
1359 });1432 });
1360 gz.instructions.appendAssumeCapacity(new_index);1433 gz.instructions.appendAssumeCapacity(new_index);
1361 return gz.astgen.indexToRef(new_index);1434 return gz.indexToRef(new_index);
1362 }1435 }
13631436
1364 pub fn addArrayTypeSentinel(1437 pub fn addArrayTypeSentinel(
...@@ -1367,7 +1440,7 @@ pub const Scope = struct {...@@ -1367,7 +1440,7 @@ pub const Scope = struct {
1367 sentinel: Zir.Inst.Ref,1440 sentinel: Zir.Inst.Ref,
1368 elem_type: Zir.Inst.Ref,1441 elem_type: Zir.Inst.Ref,
1369 ) !Zir.Inst.Ref {1442 ) !Zir.Inst.Ref {
1370 const gpa = gz.astgen.mod.gpa;1443 const gpa = gz.astgen.gpa;
1371 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1444 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1372 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1445 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
13731446
...@@ -1384,7 +1457,7 @@ pub const Scope = struct {...@@ -1384,7 +1457,7 @@ pub const Scope = struct {
1384 } },1457 } },
1385 });1458 });
1386 gz.instructions.appendAssumeCapacity(new_index);1459 gz.instructions.appendAssumeCapacity(new_index);
1387 return gz.astgen.indexToRef(new_index);1460 return gz.indexToRef(new_index);
1388 }1461 }
13891462
1390 pub fn addUnTok(1463 pub fn addUnTok(
...@@ -1399,7 +1472,7 @@ pub const Scope = struct {...@@ -1399,7 +1472,7 @@ pub const Scope = struct {
1399 .tag = tag,1472 .tag = tag,
1400 .data = .{ .un_tok = .{1473 .data = .{ .un_tok = .{
1401 .operand = operand,1474 .operand = operand,
1402 .src_tok = abs_tok_index - gz.astgen.decl.srcToken(),1475 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
1403 } },1476 } },
1404 });1477 });
1405 }1478 }
...@@ -1415,7 +1488,7 @@ pub const Scope = struct {...@@ -1415,7 +1488,7 @@ pub const Scope = struct {
1415 .tag = tag,1488 .tag = tag,
1416 .data = .{ .str_tok = .{1489 .data = .{ .str_tok = .{
1417 .start = str_index,1490 .start = str_index,
1418 .src_tok = abs_tok_index - gz.astgen.decl.srcToken(),1491 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
1419 } },1492 } },
1420 });1493 });
1421 }1494 }
...@@ -1461,7 +1534,7 @@ pub const Scope = struct {...@@ -1461,7 +1534,7 @@ pub const Scope = struct {
1461 return gz.add(.{1534 return gz.add(.{
1462 .tag = tag,1535 .tag = tag,
1463 .data = .{ .pl_node = .{1536 .data = .{ .pl_node = .{
1464 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),1537 .src_node = gz.nodeIndexToRelative(src_node),
1465 .payload_index = decl_index,1538 .payload_index = decl_index,
1466 } },1539 } },
1467 });1540 });
...@@ -1475,7 +1548,7 @@ pub const Scope = struct {...@@ -1475,7 +1548,7 @@ pub const Scope = struct {
1475 ) !Zir.Inst.Ref {1548 ) !Zir.Inst.Ref {
1476 return gz.add(.{1549 return gz.add(.{
1477 .tag = tag,1550 .tag = tag,
1478 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(src_node) },1551 .data = .{ .node = gz.nodeIndexToRelative(src_node) },
1479 });1552 });
1480 }1553 }
14811554
...@@ -1500,11 +1573,11 @@ pub const Scope = struct {...@@ -1500,11 +1573,11 @@ pub const Scope = struct {
1500 /// Leaves the `payload_index` field undefined.1573 /// Leaves the `payload_index` field undefined.
1501 pub fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {1574 pub fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
1502 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);1575 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1503 const gpa = gz.astgen.mod.gpa;1576 const gpa = gz.astgen.gpa;
1504 try gz.astgen.instructions.append(gpa, .{1577 try gz.astgen.instructions.append(gpa, .{
1505 .tag = tag,1578 .tag = tag,
1506 .data = .{ .pl_node = .{1579 .data = .{ .pl_node = .{
1507 .src_node = gz.astgen.decl.nodeIndexToRelative(node),1580 .src_node = gz.nodeIndexToRelative(node),
1508 .payload_index = undefined,1581 .payload_index = undefined,
1509 } },1582 } },
1510 });1583 });
...@@ -1514,13 +1587,13 @@ pub const Scope = struct {...@@ -1514,13 +1587,13 @@ pub const Scope = struct {
1514 /// Note that this returns a `Zir.Inst.Index` not a ref.1587 /// Note that this returns a `Zir.Inst.Index` not a ref.
1515 /// Leaves the `payload_index` field undefined.1588 /// Leaves the `payload_index` field undefined.
1516 pub fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {1589 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;
1518 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1591 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1519 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);1592 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1520 try gz.astgen.instructions.append(gpa, .{1593 try gz.astgen.instructions.append(gpa, .{
1521 .tag = tag,1594 .tag = tag,
1522 .data = .{ .pl_node = .{1595 .data = .{ .pl_node = .{
1523 .src_node = gz.astgen.decl.nodeIndexToRelative(node),1596 .src_node = gz.nodeIndexToRelative(node),
1524 .payload_index = undefined,1597 .payload_index = undefined,
1525 } },1598 } },
1526 });1599 });
...@@ -1529,11 +1602,11 @@ pub const Scope = struct {...@@ -1529,11 +1602,11 @@ pub const Scope = struct {
1529 }1602 }
15301603
1531 pub fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref {1604 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));
1533 }1606 }
15341607
1535 pub fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index {1608 pub fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index {
1536 const gpa = gz.astgen.mod.gpa;1609 const gpa = gz.astgen.gpa;
1537 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1610 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1538 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1611 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
15391612
...@@ -1556,7 +1629,7 @@ pub const Scope = struct {...@@ -1556,7 +1629,7 @@ pub const Scope = struct {
1556 name: []const u8,1629 name: []const u8,
1557 inst: Zir.Inst.Ref,1630 inst: Zir.Inst.Ref,
1558 /// Source location of the corresponding variable declaration.1631 /// Source location of the corresponding variable declaration.
1559 src: LazySrcLoc,1632 token_src: ast.TokenIndex,
1560 };1633 };
15611634
1562 /// This could be a `const` or `var` local. It has a pointer instead of a value.1635 /// This could be a `const` or `var` local. It has a pointer instead of a value.
...@@ -1571,7 +1644,7 @@ pub const Scope = struct {...@@ -1571,7 +1644,7 @@ pub const Scope = struct {
1571 name: []const u8,1644 name: []const u8,
1572 ptr: Zir.Inst.Ref,1645 ptr: Zir.Inst.Ref,
1573 /// Source location of the corresponding variable declaration.1646 /// Source location of the corresponding variable declaration.
1574 src: LazySrcLoc,1647 token_src: ast.TokenIndex,
1575 };1648 };
15761649
1577 pub const DeclRef = struct {1650 pub const DeclRef = struct {
...@@ -1653,6 +1726,7 @@ pub const SrcLoc = struct {...@@ -1653,6 +1726,7 @@ pub const SrcLoc = struct {
1653 .byte_abs,1726 .byte_abs,
1654 .token_abs,1727 .token_abs,
1655 .node_abs,1728 .node_abs,
1729 .entire_file,
1656 => src_loc.container.file_scope,1730 => src_loc.container.file_scope,
16571731
1658 .byte_offset,1732 .byte_offset,
...@@ -1686,16 +1760,17 @@ pub const SrcLoc = struct {...@@ -1686,16 +1760,17 @@ pub const SrcLoc = struct {
1686 pub fn byteOffset(src_loc: SrcLoc) !u32 {1760 pub fn byteOffset(src_loc: SrcLoc) !u32 {
1687 switch (src_loc.lazy) {1761 switch (src_loc.lazy) {
1688 .unneeded => unreachable,1762 .unneeded => unreachable,
1763 .entire_file => unreachable,
16891764
1690 .byte_abs => |byte_index| return byte_index,1765 .byte_abs => |byte_index| return byte_index,
16911766
1692 .token_abs => |tok_index| {1767 .token_abs => |tok_index| {
1693 const tree = src_loc.container.file_scope.base.tree();1768 const tree = src_loc.container.file_scope.tree;
1694 const token_starts = tree.tokens.items(.start);1769 const token_starts = tree.tokens.items(.start);
1695 return token_starts[tok_index];1770 return token_starts[tok_index];
1696 },1771 },
1697 .node_abs => |node| {1772 .node_abs => |node| {
1698 const tree = src_loc.container.file_scope.base.tree();1773 const tree = src_loc.container.file_scope.tree;
1699 const token_starts = tree.tokens.items(.start);1774 const token_starts = tree.tokens.items(.start);
1700 const tok_index = tree.firstToken(node);1775 const tok_index = tree.firstToken(node);
1701 return token_starts[tok_index];1776 return token_starts[tok_index];
...@@ -1707,14 +1782,14 @@ pub const SrcLoc = struct {...@@ -1707,14 +1782,14 @@ pub const SrcLoc = struct {
1707 .token_offset => |tok_off| {1782 .token_offset => |tok_off| {
1708 const decl = src_loc.container.decl;1783 const decl = src_loc.container.decl;
1709 const tok_index = decl.srcToken() + tok_off;1784 const tok_index = decl.srcToken() + tok_off;
1710 const tree = decl.namespace.file_scope.base.tree();1785 const tree = decl.namespace.file_scope.tree;
1711 const token_starts = tree.tokens.items(.start);1786 const token_starts = tree.tokens.items(.start);
1712 return token_starts[tok_index];1787 return token_starts[tok_index];
1713 },1788 },
1714 .node_offset, .node_offset_bin_op => |node_off| {1789 .node_offset, .node_offset_bin_op => |node_off| {
1715 const decl = src_loc.container.decl;1790 const decl = src_loc.container.decl;
1716 const node = decl.relativeToNodeIndex(node_off);1791 const node = decl.relativeToNodeIndex(node_off);
1717 const tree = decl.namespace.file_scope.base.tree();1792 const tree = decl.namespace.file_scope.tree;
1718 const main_tokens = tree.nodes.items(.main_token);1793 const main_tokens = tree.nodes.items(.main_token);
1719 const tok_index = main_tokens[node];1794 const tok_index = main_tokens[node];
1720 const token_starts = tree.tokens.items(.start);1795 const token_starts = tree.tokens.items(.start);
...@@ -1723,7 +1798,7 @@ pub const SrcLoc = struct {...@@ -1723,7 +1798,7 @@ pub const SrcLoc = struct {
1723 .node_offset_back2tok => |node_off| {1798 .node_offset_back2tok => |node_off| {
1724 const decl = src_loc.container.decl;1799 const decl = src_loc.container.decl;
1725 const node = decl.relativeToNodeIndex(node_off);1800 const node = decl.relativeToNodeIndex(node_off);
1726 const tree = decl.namespace.file_scope.base.tree();1801 const tree = decl.namespace.file_scope.tree;
1727 const tok_index = tree.firstToken(node) - 2;1802 const tok_index = tree.firstToken(node) - 2;
1728 const token_starts = tree.tokens.items(.start);1803 const token_starts = tree.tokens.items(.start);
1729 return token_starts[tok_index];1804 return token_starts[tok_index];
...@@ -1731,7 +1806,7 @@ pub const SrcLoc = struct {...@@ -1731,7 +1806,7 @@ pub const SrcLoc = struct {
1731 .node_offset_var_decl_ty => |node_off| {1806 .node_offset_var_decl_ty => |node_off| {
1732 const decl = src_loc.container.decl;1807 const decl = src_loc.container.decl;
1733 const node = decl.relativeToNodeIndex(node_off);1808 const node = decl.relativeToNodeIndex(node_off);
1734 const tree = decl.namespace.file_scope.base.tree();1809 const tree = decl.namespace.file_scope.tree;
1735 const node_tags = tree.nodes.items(.tag);1810 const node_tags = tree.nodes.items(.tag);
1736 const full = switch (node_tags[node]) {1811 const full = switch (node_tags[node]) {
1737 .global_var_decl => tree.globalVarDecl(node),1812 .global_var_decl => tree.globalVarDecl(node),
...@@ -1751,7 +1826,7 @@ pub const SrcLoc = struct {...@@ -1751,7 +1826,7 @@ pub const SrcLoc = struct {
1751 },1826 },
1752 .node_offset_builtin_call_arg0 => |node_off| {1827 .node_offset_builtin_call_arg0 => |node_off| {
1753 const decl = src_loc.container.decl;1828 const decl = src_loc.container.decl;
1754 const tree = decl.namespace.file_scope.base.tree();1829 const tree = decl.namespace.file_scope.tree;
1755 const node_datas = tree.nodes.items(.data);1830 const node_datas = tree.nodes.items(.data);
1756 const node_tags = tree.nodes.items(.tag);1831 const node_tags = tree.nodes.items(.tag);
1757 const node = decl.relativeToNodeIndex(node_off);1832 const node = decl.relativeToNodeIndex(node_off);
...@@ -1767,7 +1842,7 @@ pub const SrcLoc = struct {...@@ -1767,7 +1842,7 @@ pub const SrcLoc = struct {
1767 },1842 },
1768 .node_offset_builtin_call_arg1 => |node_off| {1843 .node_offset_builtin_call_arg1 => |node_off| {
1769 const decl = src_loc.container.decl;1844 const decl = src_loc.container.decl;
1770 const tree = decl.namespace.file_scope.base.tree();1845 const tree = decl.namespace.file_scope.tree;
1771 const node_datas = tree.nodes.items(.data);1846 const node_datas = tree.nodes.items(.data);
1772 const node_tags = tree.nodes.items(.tag);1847 const node_tags = tree.nodes.items(.tag);
1773 const node = decl.relativeToNodeIndex(node_off);1848 const node = decl.relativeToNodeIndex(node_off);
...@@ -1783,7 +1858,7 @@ pub const SrcLoc = struct {...@@ -1783,7 +1858,7 @@ pub const SrcLoc = struct {
1783 },1858 },
1784 .node_offset_array_access_index => |node_off| {1859 .node_offset_array_access_index => |node_off| {
1785 const decl = src_loc.container.decl;1860 const decl = src_loc.container.decl;
1786 const tree = decl.namespace.file_scope.base.tree();1861 const tree = decl.namespace.file_scope.tree;
1787 const node_datas = tree.nodes.items(.data);1862 const node_datas = tree.nodes.items(.data);
1788 const node_tags = tree.nodes.items(.tag);1863 const node_tags = tree.nodes.items(.tag);
1789 const node = decl.relativeToNodeIndex(node_off);1864 const node = decl.relativeToNodeIndex(node_off);
...@@ -1794,7 +1869,7 @@ pub const SrcLoc = struct {...@@ -1794,7 +1869,7 @@ pub const SrcLoc = struct {
1794 },1869 },
1795 .node_offset_slice_sentinel => |node_off| {1870 .node_offset_slice_sentinel => |node_off| {
1796 const decl = src_loc.container.decl;1871 const decl = src_loc.container.decl;
1797 const tree = decl.namespace.file_scope.base.tree();1872 const tree = decl.namespace.file_scope.tree;
1798 const node_datas = tree.nodes.items(.data);1873 const node_datas = tree.nodes.items(.data);
1799 const node_tags = tree.nodes.items(.tag);1874 const node_tags = tree.nodes.items(.tag);
1800 const node = decl.relativeToNodeIndex(node_off);1875 const node = decl.relativeToNodeIndex(node_off);
...@@ -1811,7 +1886,7 @@ pub const SrcLoc = struct {...@@ -1811,7 +1886,7 @@ pub const SrcLoc = struct {
1811 },1886 },
1812 .node_offset_call_func => |node_off| {1887 .node_offset_call_func => |node_off| {
1813 const decl = src_loc.container.decl;1888 const decl = src_loc.container.decl;
1814 const tree = decl.namespace.file_scope.base.tree();1889 const tree = decl.namespace.file_scope.tree;
1815 const node_datas = tree.nodes.items(.data);1890 const node_datas = tree.nodes.items(.data);
1816 const node_tags = tree.nodes.items(.tag);1891 const node_tags = tree.nodes.items(.tag);
1817 const node = decl.relativeToNodeIndex(node_off);1892 const node = decl.relativeToNodeIndex(node_off);
...@@ -1838,7 +1913,7 @@ pub const SrcLoc = struct {...@@ -1838,7 +1913,7 @@ pub const SrcLoc = struct {
1838 },1913 },
1839 .node_offset_field_name => |node_off| {1914 .node_offset_field_name => |node_off| {
1840 const decl = src_loc.container.decl;1915 const decl = src_loc.container.decl;
1841 const tree = decl.namespace.file_scope.base.tree();1916 const tree = decl.namespace.file_scope.tree;
1842 const node_datas = tree.nodes.items(.data);1917 const node_datas = tree.nodes.items(.data);
1843 const node_tags = tree.nodes.items(.tag);1918 const node_tags = tree.nodes.items(.tag);
1844 const node = decl.relativeToNodeIndex(node_off);1919 const node = decl.relativeToNodeIndex(node_off);
...@@ -1851,7 +1926,7 @@ pub const SrcLoc = struct {...@@ -1851,7 +1926,7 @@ pub const SrcLoc = struct {
1851 },1926 },
1852 .node_offset_deref_ptr => |node_off| {1927 .node_offset_deref_ptr => |node_off| {
1853 const decl = src_loc.container.decl;1928 const decl = src_loc.container.decl;
1854 const tree = decl.namespace.file_scope.base.tree();1929 const tree = decl.namespace.file_scope.tree;
1855 const node_datas = tree.nodes.items(.data);1930 const node_datas = tree.nodes.items(.data);
1856 const node_tags = tree.nodes.items(.tag);1931 const node_tags = tree.nodes.items(.tag);
1857 const node = decl.relativeToNodeIndex(node_off);1932 const node = decl.relativeToNodeIndex(node_off);
...@@ -1861,7 +1936,7 @@ pub const SrcLoc = struct {...@@ -1861,7 +1936,7 @@ pub const SrcLoc = struct {
1861 },1936 },
1862 .node_offset_asm_source => |node_off| {1937 .node_offset_asm_source => |node_off| {
1863 const decl = src_loc.container.decl;1938 const decl = src_loc.container.decl;
1864 const tree = decl.namespace.file_scope.base.tree();1939 const tree = decl.namespace.file_scope.tree;
1865 const node_datas = tree.nodes.items(.data);1940 const node_datas = tree.nodes.items(.data);
1866 const node_tags = tree.nodes.items(.tag);1941 const node_tags = tree.nodes.items(.tag);
1867 const node = decl.relativeToNodeIndex(node_off);1942 const node = decl.relativeToNodeIndex(node_off);
...@@ -1877,7 +1952,7 @@ pub const SrcLoc = struct {...@@ -1877,7 +1952,7 @@ pub const SrcLoc = struct {
1877 },1952 },
1878 .node_offset_asm_ret_ty => |node_off| {1953 .node_offset_asm_ret_ty => |node_off| {
1879 const decl = src_loc.container.decl;1954 const decl = src_loc.container.decl;
1880 const tree = decl.namespace.file_scope.base.tree();1955 const tree = decl.namespace.file_scope.tree;
1881 const node_datas = tree.nodes.items(.data);1956 const node_datas = tree.nodes.items(.data);
1882 const node_tags = tree.nodes.items(.tag);1957 const node_tags = tree.nodes.items(.tag);
1883 const node = decl.relativeToNodeIndex(node_off);1958 const node = decl.relativeToNodeIndex(node_off);
...@@ -1895,7 +1970,7 @@ pub const SrcLoc = struct {...@@ -1895,7 +1970,7 @@ pub const SrcLoc = struct {
1895 .node_offset_for_cond, .node_offset_if_cond => |node_off| {1970 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
1896 const decl = src_loc.container.decl;1971 const decl = src_loc.container.decl;
1897 const node = decl.relativeToNodeIndex(node_off);1972 const node = decl.relativeToNodeIndex(node_off);
1898 const tree = decl.namespace.file_scope.base.tree();1973 const tree = decl.namespace.file_scope.tree;
1899 const node_tags = tree.nodes.items(.tag);1974 const node_tags = tree.nodes.items(.tag);
1900 const src_node = switch (node_tags[node]) {1975 const src_node = switch (node_tags[node]) {
1901 .if_simple => tree.ifSimple(node).ast.cond_expr,1976 .if_simple => tree.ifSimple(node).ast.cond_expr,
...@@ -1915,7 +1990,7 @@ pub const SrcLoc = struct {...@@ -1915,7 +1990,7 @@ pub const SrcLoc = struct {
1915 .node_offset_bin_lhs => |node_off| {1990 .node_offset_bin_lhs => |node_off| {
1916 const decl = src_loc.container.decl;1991 const decl = src_loc.container.decl;
1917 const node = decl.relativeToNodeIndex(node_off);1992 const node = decl.relativeToNodeIndex(node_off);
1918 const tree = decl.namespace.file_scope.base.tree();1993 const tree = decl.namespace.file_scope.tree;
1919 const node_datas = tree.nodes.items(.data);1994 const node_datas = tree.nodes.items(.data);
1920 const src_node = node_datas[node].lhs;1995 const src_node = node_datas[node].lhs;
1921 const main_tokens = tree.nodes.items(.main_token);1996 const main_tokens = tree.nodes.items(.main_token);
...@@ -1926,7 +2001,7 @@ pub const SrcLoc = struct {...@@ -1926,7 +2001,7 @@ pub const SrcLoc = struct {
1926 .node_offset_bin_rhs => |node_off| {2001 .node_offset_bin_rhs => |node_off| {
1927 const decl = src_loc.container.decl;2002 const decl = src_loc.container.decl;
1928 const node = decl.relativeToNodeIndex(node_off);2003 const node = decl.relativeToNodeIndex(node_off);
1929 const tree = decl.namespace.file_scope.base.tree();2004 const tree = decl.namespace.file_scope.tree;
1930 const node_datas = tree.nodes.items(.data);2005 const node_datas = tree.nodes.items(.data);
1931 const src_node = node_datas[node].rhs;2006 const src_node = node_datas[node].rhs;
1932 const main_tokens = tree.nodes.items(.main_token);2007 const main_tokens = tree.nodes.items(.main_token);
...@@ -1938,7 +2013,7 @@ pub const SrcLoc = struct {...@@ -1938,7 +2013,7 @@ pub const SrcLoc = struct {
1938 .node_offset_switch_operand => |node_off| {2013 .node_offset_switch_operand => |node_off| {
1939 const decl = src_loc.container.decl;2014 const decl = src_loc.container.decl;
1940 const node = decl.relativeToNodeIndex(node_off);2015 const node = decl.relativeToNodeIndex(node_off);
1941 const tree = decl.namespace.file_scope.base.tree();2016 const tree = decl.namespace.file_scope.tree;
1942 const node_datas = tree.nodes.items(.data);2017 const node_datas = tree.nodes.items(.data);
1943 const src_node = node_datas[node].lhs;2018 const src_node = node_datas[node].lhs;
1944 const main_tokens = tree.nodes.items(.main_token);2019 const main_tokens = tree.nodes.items(.main_token);
...@@ -1950,7 +2025,7 @@ pub const SrcLoc = struct {...@@ -1950,7 +2025,7 @@ pub const SrcLoc = struct {
1950 .node_offset_switch_special_prong => |node_off| {2025 .node_offset_switch_special_prong => |node_off| {
1951 const decl = src_loc.container.decl;2026 const decl = src_loc.container.decl;
1952 const switch_node = decl.relativeToNodeIndex(node_off);2027 const switch_node = decl.relativeToNodeIndex(node_off);
1953 const tree = decl.namespace.file_scope.base.tree();2028 const tree = decl.namespace.file_scope.tree;
1954 const node_datas = tree.nodes.items(.data);2029 const node_datas = tree.nodes.items(.data);
1955 const node_tags = tree.nodes.items(.tag);2030 const node_tags = tree.nodes.items(.tag);
1956 const main_tokens = tree.nodes.items(.main_token);2031 const main_tokens = tree.nodes.items(.main_token);
...@@ -1977,7 +2052,7 @@ pub const SrcLoc = struct {...@@ -1977,7 +2052,7 @@ pub const SrcLoc = struct {
1977 .node_offset_switch_range => |node_off| {2052 .node_offset_switch_range => |node_off| {
1978 const decl = src_loc.container.decl;2053 const decl = src_loc.container.decl;
1979 const switch_node = decl.relativeToNodeIndex(node_off);2054 const switch_node = decl.relativeToNodeIndex(node_off);
1980 const tree = decl.namespace.file_scope.base.tree();2055 const tree = decl.namespace.file_scope.tree;
1981 const node_datas = tree.nodes.items(.data);2056 const node_datas = tree.nodes.items(.data);
1982 const node_tags = tree.nodes.items(.tag);2057 const node_tags = tree.nodes.items(.tag);
1983 const main_tokens = tree.nodes.items(.main_token);2058 const main_tokens = tree.nodes.items(.main_token);
...@@ -2007,7 +2082,7 @@ pub const SrcLoc = struct {...@@ -2007,7 +2082,7 @@ pub const SrcLoc = struct {
20072082
2008 .node_offset_fn_type_cc => |node_off| {2083 .node_offset_fn_type_cc => |node_off| {
2009 const decl = src_loc.container.decl;2084 const decl = src_loc.container.decl;
2010 const tree = decl.namespace.file_scope.base.tree();2085 const tree = decl.namespace.file_scope.tree;
2011 const node_datas = tree.nodes.items(.data);2086 const node_datas = tree.nodes.items(.data);
2012 const node_tags = tree.nodes.items(.tag);2087 const node_tags = tree.nodes.items(.tag);
2013 const node = decl.relativeToNodeIndex(node_off);2088 const node = decl.relativeToNodeIndex(node_off);
...@@ -2027,7 +2102,7 @@ pub const SrcLoc = struct {...@@ -2027,7 +2102,7 @@ pub const SrcLoc = struct {
20272102
2028 .node_offset_fn_type_ret_ty => |node_off| {2103 .node_offset_fn_type_ret_ty => |node_off| {
2029 const decl = src_loc.container.decl;2104 const decl = src_loc.container.decl;
2030 const tree = decl.namespace.file_scope.base.tree();2105 const tree = decl.namespace.file_scope.tree;
2031 const node_datas = tree.nodes.items(.data);2106 const node_datas = tree.nodes.items(.data);
2032 const node_tags = tree.nodes.items(.tag);2107 const node_tags = tree.nodes.items(.tag);
2033 const node = decl.relativeToNodeIndex(node_off);2108 const node = decl.relativeToNodeIndex(node_off);
...@@ -2063,6 +2138,9 @@ pub const LazySrcLoc = union(enum) {...@@ -2063,6 +2138,9 @@ pub const LazySrcLoc = union(enum) {
2063 /// look into using reverse-continue with a memory watchpoint to see where the2138 /// look into using reverse-continue with a memory watchpoint to see where the
2064 /// value is being set to this tag.2139 /// value is being set to this tag.
2065 unneeded,2140 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,
2066 /// The source location points to a byte offset within a source file,2144 /// The source location points to a byte offset within a source file,
2067 /// offset from 0. The source file is determined contextually.2145 /// offset from 0. The source file is determined contextually.
2068 /// Inside a `SrcLoc`, the `file_scope` union field will be active.2146 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
...@@ -2205,6 +2283,7 @@ pub const LazySrcLoc = union(enum) {...@@ -2205,6 +2283,7 @@ pub const LazySrcLoc = union(enum) {
2205 pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {2283 pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
2206 return switch (lazy) {2284 return switch (lazy) {
2207 .unneeded,2285 .unneeded,
2286 .entire_file,
2208 .byte_abs,2287 .byte_abs,
2209 .token_abs,2288 .token_abs,
2210 .node_abs,2289 .node_abs,
...@@ -2248,6 +2327,7 @@ pub const LazySrcLoc = union(enum) {...@@ -2248,6 +2327,7 @@ pub const LazySrcLoc = union(enum) {
2248 pub fn toSrcLocWithDecl(lazy: LazySrcLoc, decl: *Decl) SrcLoc {2327 pub fn toSrcLocWithDecl(lazy: LazySrcLoc, decl: *Decl) SrcLoc {
2249 return switch (lazy) {2328 return switch (lazy) {
2250 .unneeded,2329 .unneeded,
2330 .entire_file,
2251 .byte_abs,2331 .byte_abs,
2252 .token_abs,2332 .token_abs,
2253 .node_abs,2333 .node_abs,
...@@ -2376,6 +2456,108 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {...@@ -2376,6 +2456,108 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
2376 gpa.free(export_list);2456 gpa.free(export_list);
2377}2457}
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
2379pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {2561pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2380 const tracy = trace(@src());2562 const tracy = trace(@src());
2381 defer tracy.end();2563 defer tracy.end();
...@@ -2417,7 +2599,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2417,7 +2599,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2417 .unreferenced => false,2599 .unreferenced => false,
2418 };2600 };
24192601
2420 const type_changed = mod.astgenAndSemaDecl(decl) catch |err| switch (err) {2602 const type_changed = mod.semaDecl(decl) catch |err| switch (err) {
2421 error.OutOfMemory => return error.OutOfMemory,2603 error.OutOfMemory => return error.OutOfMemory,
2422 error.AnalysisFail => return error.AnalysisFail,2604 error.AnalysisFail => return error.AnalysisFail,
2423 else => {2605 else => {
...@@ -2462,822 +2644,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2462,822 +2644,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2462/// Returns `true` if the Decl type changed.2644/// Returns `true` if the Decl type changed.
2463/// Returns `true` if this is the first time analyzing the Decl.2645/// Returns `true` if this is the first time analyzing the Decl.
2464/// Returns `false` otherwise.2646/// Returns `false` otherwise.
2465fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {2647fn semaDecl(mod: *Module, decl: *Decl) !bool {
2466 const tracy = trace(@src());2648 const tracy = trace(@src());
2467 defer tracy.end();2649 defer tracy.end();
24682650
2469 const tree = try mod.getAstTree(decl.namespace.file_scope);2651 @panic("TODO implement semaDecl");
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;
3277}2652}
32782653
3279/// Returns the depender's index of the dependee.2654/// 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 {
3281 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);2656 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);
3282 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);2657 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...@@ -3287,61 +2662,7 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3
3287 }2662 }
32882663
3289 dependee.dependants.putAssumeCapacity(depender, {});2664 dependee.dependants.putAssumeCapacity(depender, {});
3290 const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);2665 depender.dependencies.putAssumeCapacity(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 }
3345}2666}
33462667
3347pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*Scope.File {2668pub 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) !*...@@ -3375,136 +2696,21 @@ pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*
3375 .sub_file_path = resolved_path,2696 .sub_file_path = resolved_path,
3376 .source = undefined,2697 .source = undefined,
3377 .source_loaded = false,2698 .source_loaded = false,
2699 .tree_loaded = false,
2700 .zir_loaded = false,
3378 .stat_size = undefined,2701 .stat_size = undefined,
3379 .stat_inode = undefined,2702 .stat_inode = undefined,
3380 .stat_mtime = undefined,2703 .stat_mtime = undefined,
3381 .tree = undefined,2704 .tree = undefined,
2705 .zir = undefined,
3382 .status = .never_loaded,2706 .status = .never_loaded,
3383 .pkg = found_pkg orelse cur_pkg,2707 .pkg = found_pkg orelse cur_pkg,
3384 .namespace = undefined,2708 .namespace = undefined,
3385 };2709 };
3386 keep_resolved_path = true;2710 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
3497 return new_file;2711 return new_file;
3498}2712}
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
3508pub fn analyzeNamespace(2714pub fn analyzeNamespace(
3509 mod: *Module,2715 mod: *Module,
3510 namespace: *Scope.Namespace,2716 namespace: *Scope.Namespace,
...@@ -3515,7 +2721,7 @@ pub fn analyzeNamespace(...@@ -3515,7 +2721,7 @@ pub fn analyzeNamespace(
35152721
3516 // We may be analyzing it for the first time, or this may be2722 // We may be analyzing it for the first time, or this may be
3517 // an incremental update. This code handles both cases.2723 // 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.
3519 const tree: *const ast.Tree = &namespace.file_scope.tree;2725 const tree: *const ast.Tree = &namespace.file_scope.tree;
3520 const node_tags = tree.nodes.items(.tag);2726 const node_tags = tree.nodes.items(.tag);
3521 const node_datas = tree.nodes.items(.data);2727 const node_datas = tree.nodes.items(.data);
...@@ -4449,20 +3655,6 @@ pub fn fail(...@@ -4449,20 +3655,6 @@ pub fn fail(
4449 return mod.failWithOwnedErrorMsg(scope, err_msg);3655 return mod.failWithOwnedErrorMsg(scope, err_msg);
4450}3656}
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
4466/// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc`3658/// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc`
4467/// for pointing at it relatively by subtracting from the containing `Decl`.3659/// for pointing at it relatively by subtracting from the containing `Decl`.
4468pub fn failTok(3660pub fn failTok(
...@@ -4491,6 +3683,7 @@ pub fn failNode(...@@ -4491,6 +3683,7 @@ pub fn failNode(
44913683
4492pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {3684pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
4493 @setCold(true);3685 @setCold(true);
3686
4494 {3687 {
4495 errdefer err_msg.destroy(mod.gpa);3688 errdefer err_msg.destroy(mod.gpa);
4496 try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);3689 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...@@ -4507,24 +3700,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In
4507 }3700 }
4508 mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg);3701 mod.failed_decls.putAssumeCapacityNoClobber(block.sema.owner_decl, err_msg);
4509 },3702 },
4510 .gen_zir => {3703 .gen_zir, .local_val, .local_ptr => unreachable,
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 },
4528 .file => unreachable,3704 .file => unreachable,
4529 .namespace => unreachable,3705 .namespace => unreachable,
4530 .decl_ref => {3706 .decl_ref => {
...@@ -4873,132 +4049,3 @@ pub fn getTarget(mod: Module) Target {...@@ -4873,132 +4049,3 @@ pub fn getTarget(mod: Module) Target {
4873pub fn optimizeMode(mod: Module) std.builtin.Mode {4049pub fn optimizeMode(mod: Module) std.builtin.Mode {
4874 return mod.comp.bin_file.options.optimize_mode;4050 return mod.comp.bin_file.options.optimize_mode;
4875}4051}
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(...@@ -199,10 +199,10 @@ pub fn analyzeBody(
199 .field_val => try sema.zirFieldVal(block, inst),199 .field_val => try sema.zirFieldVal(block, inst),
200 .field_val_named => try sema.zirFieldValNamed(block, inst),200 .field_val_named => try sema.zirFieldValNamed(block, inst),
201 .floatcast => try sema.zirFloatcast(block, inst),201 .floatcast => try sema.zirFloatcast(block, inst),
202 .fn_type => try sema.zirFnType(block, inst, false),202 .func => try sema.zirFunc(block, inst, false),
203 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),203 .func_extra => try sema.zirFuncExtra(block, inst, false),
204 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),204 .func_extra_var_args => try sema.zirFuncExtra(block, inst, true),
205 .fn_type_var_args => try sema.zirFnType(block, inst, true),205 .func_var_args => try sema.zirFunc(block, inst, true),
206 .has_decl => try sema.zirHasDecl(block, inst),206 .has_decl => try sema.zirHasDecl(block, inst),
207 .import => try sema.zirImport(block, inst),207 .import => try sema.zirImport(block, inst),
208 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),208 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
...@@ -2513,16 +2513,16 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde...@@ -2513,16 +2513,16 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
2513 }2513 }
2514}2514}
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 {
2517 const tracy = trace(@src());2517 const tracy = trace(@src());
2518 defer tracy.end();2518 defer tracy.end();
25192519
2520 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;2520 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2521 const src = inst_data.src();2521 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);
2523 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);2523 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
25242524
2525 return sema.fnTypeCommon(2525 return sema.funcCommon(
2526 block,2526 block,
2527 inst_data.src_node,2527 inst_data.src_node,
2528 param_types,2528 param_types,
...@@ -2532,14 +2532,14 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: b...@@ -2532,14 +2532,14 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: b
2532 );2532 );
2533}2533}
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 {
2536 const tracy = trace(@src());2536 const tracy = trace(@src());
2537 defer tracy.end();2537 defer tracy.end();
25382538
2539 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;2539 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2540 const src = inst_data.src();2540 const src = inst_data.src();
2541 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };2541 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);
2543 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);2543 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
25442544
2545 const cc_tv = try sema.resolveInstConst(block, cc_src, extra.data.cc);2545 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:...@@ -2548,7 +2548,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:
2548 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;2548 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
2549 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse2549 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
2550 return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str});2550 return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str});
2551 return sema.fnTypeCommon(2551 return sema.funcCommon(
2552 block,2552 block,
2553 inst_data.src_node,2553 inst_data.src_node,
2554 param_types,2554 param_types,
...@@ -2558,7 +2558,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:...@@ -2558,7 +2558,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:
2558 );2558 );
2559}2559}
25602560
2561fn fnTypeCommon(2561fn funcCommon(
2562 sema: *Sema,2562 sema: *Sema,
2563 block: *Scope.Block,2563 block: *Scope.Block,
2564 src_node_offset: i32,2564 src_node_offset: i32,
...@@ -3921,9 +3921,6 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -3921,9 +3921,6 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
3921 error.ImportOutsidePkgPath => {3921 error.ImportOutsidePkgPath => {
3922 return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});3922 return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
3923 },3923 },
3924 error.FileNotFound => {
3925 return mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
3926 },
3927 else => {3924 else => {
3928 // TODO: these errors are file system errors; make sure an update() will3925 // TODO: these errors are file system errors; make sure an update() will
3929 // retry this and not cache the file system error, which may be transient.3926 // 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");...@@ -26,8 +26,6 @@ const ir = @import("ir.zig");
26const Module = @import("Module.zig");26const Module = @import("Module.zig");
27const LazySrcLoc = Module.LazySrcLoc;27const 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.
31instructions: std.MultiArrayList(Inst).Slice,29instructions: std.MultiArrayList(Inst).Slice,
32/// In order to store references to strings in fewer bytes, we copy all30/// In order to store references to strings in fewer bytes, we copy all
33/// string bytes into here. String bytes can be null. It is up to whomever31/// string bytes into here. String bytes can be null. It is up to whomever
...@@ -36,6 +34,12 @@ instructions: std.MultiArrayList(Inst).Slice,...@@ -36,6 +34,12 @@ instructions: std.MultiArrayList(Inst).Slice,
36/// `string_bytes` array is agnostic to either usage.34/// `string_bytes` array is agnostic to either usage.
37string_bytes: []u8,35string_bytes: []u8,
38/// The meaning of this data is determined by `Inst.Tag` value.36/// 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.
39extra: []u32,43extra: []u32,
4044
41/// Returns the requested data, as well as the new index which is at the start of the45/// 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 {...@@ -358,16 +362,19 @@ pub const Inst = struct {
358 /// Uses the `pl_node` field. AST is the `@floatCast` syntax.362 /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
359 /// Payload is `Bin` with lhs as the dest type, rhs the operand.363 /// Payload is `Bin` with lhs as the dest type, rhs the operand.
360 floatcast,364 floatcast,
361 /// Returns a function type, assuming unspecified calling convention.365 /// Returns a function type, or a function instance, depending on whether
362 /// Uses the `pl_node` union field. `payload_index` points to a `FnType`.366 /// the body_len is 0. Calling convention is auto.
363 fn_type,367 /// Uses the `pl_node` union field. `payload_index` points to a `Func`.
364 /// Same as `fn_type` but the function is variadic.368 func,
365 fn_type_var_args,369 /// Same as `func` but the function is variadic.
366 /// Returns a function type, with a calling convention instruction operand.370 func_var_args,
367 /// Uses the `pl_node` union field. `payload_index` points to a `FnTypeCc`.371 /// Same as `func` but with extra fields:
368 fn_type_cc,372 /// * calling convention
369 /// Same as `fn_type_cc` but the function is variadic.373 /// * extern lib name
370 fn_type_cc_var_args,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,
371 /// Implements the `@hasDecl` builtin.378 /// Implements the `@hasDecl` builtin.
372 /// Uses the `pl_node` union field. Payload is `Bin`.379 /// Uses the `pl_node` union field. Payload is `Bin`.
373 has_decl,380 has_decl,
...@@ -769,10 +776,10 @@ pub const Inst = struct {...@@ -769,10 +776,10 @@ pub const Inst = struct {
769 .field_val,776 .field_val,
770 .field_ptr_named,777 .field_ptr_named,
771 .field_val_named,778 .field_val_named,
772 .fn_type,779 .func,
773 .fn_type_var_args,780 .func_var_args,
774 .fn_type_cc,781 .func_extra,
775 .fn_type_cc_var_args,782 .func_extra_var_args,
776 .has_decl,783 .has_decl,
777 .int,784 .int,
778 .float,785 .float,
...@@ -1372,21 +1379,25 @@ pub const Inst = struct {...@@ -1372,21 +1379,25 @@ pub const Inst = struct {
1372 clobbers_len: u32,1379 clobbers_len: u32,
1373 };1380 };
13741381
1375 /// This data is stored inside extra, with trailing parameter type indexes1382 /// Trailing:
1376 /// according to `param_types_len`.1383 /// 0. param_type: Ref // for each param_types_len
1377 /// Each param type is a `Ref`.1384 /// 1. body: Index // for each body_len
1378 pub const FnTypeCc = struct {1385 pub const FuncExtra = struct {
1379 return_type: Ref,
1380 cc: Ref,1386 cc: Ref,
1387 /// null terminated string index, or 0 to mean none.
1388 lib_name: u32,
1389 return_type: Ref,
1381 param_types_len: u32,1390 param_types_len: u32,
1391 body_len: u32,
1382 };1392 };
13831393
1384 /// This data is stored inside extra, with trailing parameter type indexes1394 /// Trailing:
1385 /// according to `param_types_len`.1395 /// 0. param_type: Ref // for each param_types_len
1386 /// Each param type is a `Ref`.1396 /// 1. body: Index // for each body_len
1387 pub const FnType = struct {1397 pub const Func = struct {
1388 return_type: Ref,1398 return_type: Ref,
1389 param_types_len: u32,1399 param_types_len: u32,
1400 body_len: u32,
1390 };1401 };
13911402
1392 /// This data is stored inside extra, with trailing operands according to `operands_len`.1403 /// This data is stored inside extra, with trailing operands according to `operands_len`.
...@@ -1531,9 +1542,18 @@ pub const Inst = struct {...@@ -1531,9 +1542,18 @@ pub const Inst = struct {
1531 /// align: Ref, // if corresponding bit is set1542 /// align: Ref, // if corresponding bit is set
1532 /// default_value: Ref, // if corresponding bit is set1543 /// default_value: Ref, // if corresponding bit is set
1533 /// }1544 /// }
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 /// }
1534 pub const StructDecl = struct {1553 pub const StructDecl = struct {
1535 body_len: u32,1554 body_len: u32,
1536 fields_len: u32,1555 fields_len: u32,
1556 decls_len: u32,
1537 };1557 };
15381558
1539 /// Trailing:1559 /// Trailing:
...@@ -1600,6 +1620,26 @@ pub const Inst = struct {...@@ -1600,6 +1620,26 @@ pub const Inst = struct {
1600 /// Offset into `string_bytes`, null terminated.1620 /// Offset into `string_bytes`, null terminated.
1601 name_start: u32,1621 name_start: u32,
1602 };1622 };
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 };
1603};1643};
16041644
1605pub const SpecialProng = enum { none, @"else", under };1645pub const SpecialProng = enum { none, @"else", under };
...@@ -1819,10 +1859,10 @@ const Writer = struct {...@@ -1819,10 +1859,10 @@ const Writer = struct {
1819 .decl_val_named,1859 .decl_val_named,
1820 => try self.writeStrTok(stream, inst),1860 => try self.writeStrTok(stream, inst),
18211861
1822 .fn_type => try self.writeFnType(stream, inst, false),1862 .func => try self.writeFunc(stream, inst, false),
1823 .fn_type_cc => try self.writeFnTypeCc(stream, inst, false),1863 .func_extra => try self.writeFuncExtra(stream, inst, false),
1824 .fn_type_var_args => try self.writeFnType(stream, inst, true),1864 .func_var_args => try self.writeFunc(stream, inst, true),
1825 .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),1865 .func_extra_var_args => try self.writeFuncExtra(stream, inst, true),
18261866
1827 .@"unreachable" => try self.writeUnreachable(stream, inst),1867 .@"unreachable" => try self.writeUnreachable(stream, inst),
18281868
...@@ -2383,7 +2423,7 @@ const Writer = struct {...@@ -2383,7 +2423,7 @@ const Writer = struct {
2383 try self.writeSrc(stream, inst_data.src());2423 try self.writeSrc(stream, inst_data.src());
2384 }2424 }
23852425
2386 fn writeFnType(2426 fn writeFunc(
2387 self: *Writer,2427 self: *Writer,
2388 stream: anytype,2428 stream: anytype,
2389 inst: Inst.Index,2429 inst: Inst.Index,
...@@ -2391,23 +2431,41 @@ const Writer = struct {...@@ -2391,23 +2431,41 @@ const Writer = struct {
2391 ) !void {2431 ) !void {
2392 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2432 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2393 const src = inst_data.src();2433 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);
2395 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);2435 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 );
2397 }2446 }
23982447
2399 fn writeFnTypeCc(2448 fn writeFuncExtra(
2400 self: *Writer,2449 self: *Writer,
2401 stream: anytype,2450 stream: anytype,
2402 inst: Inst.Index,2451 inst: Inst.Index,
2403 var_args: bool,2452 var_args: bool,
2404 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {2453 ) !void {
2405 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2454 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2406 const src = inst_data.src();2455 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);
2408 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);2457 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
2409 const cc = extra.data.cc;2458 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 );
2411 }2469 }
24122470
2413 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {2471 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
...@@ -2449,13 +2507,14 @@ const Writer = struct {...@@ -2449,13 +2507,14 @@ const Writer = struct {
2449 try self.writeSrc(stream, inst_data.src());2507 try self.writeSrc(stream, inst_data.src());
2450 }2508 }
24512509
2452 fn writeFnTypeCommon(2510 fn writeFuncCommon(
2453 self: *Writer,2511 self: *Writer,
2454 stream: anytype,2512 stream: anytype,
2455 param_types: []const Inst.Ref,2513 param_types: []const Inst.Ref,
2456 ret_ty: Inst.Ref,2514 ret_ty: Inst.Ref,
2457 var_args: bool,2515 var_args: bool,
2458 cc: Inst.Ref,2516 cc: Inst.Ref,
2517 body: []const Inst.Index,
2459 src: LazySrcLoc,2518 src: LazySrcLoc,
2460 ) !void {2519 ) !void {
2461 try stream.writeAll("[");2520 try stream.writeAll("[");
...@@ -2467,7 +2526,13 @@ const Writer = struct {...@@ -2467,7 +2526,13 @@ const Writer = struct {
2467 try self.writeInstRef(stream, ret_ty);2526 try self.writeInstRef(stream, ret_ty);
2468 try self.writeOptionalInstRef(stream, ", cc=", cc);2527 try self.writeOptionalInstRef(stream, ", cc=", cc);
2469 try self.writeFlag(stream, ", var_args", var_args);2528 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("}) ");
2471 try self.writeSrc(stream, src);2536 try self.writeSrc(stream, src);
2472 }2537 }
24732538