| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | * get rid of failed_root_src_file |
| 2 | * get rid of Scope.DeclRef |
| 2 | 3 | * handle decl collision with usingnamespace |
| 3 | 4 | * the decl doing the looking up needs to create a decl dependency |
| 4 | 5 | on each usingnamespace decl |
| ... | ... | @@ -106,42 +107,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd |
| 106 | 107 | } |
| 107 | 108 | |
| 108 | 109 | |
| 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 | 110 | const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg| |
| 146 | 111 | pkg.namespace_hash |
| 147 | 112 | else |
| ... | ... | @@ -256,68 +221,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd |
| 256 | 221 | |
| 257 | 222 | |
| 258 | 223 | |
| 259 | | pub 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 | 224 | |
| 322 | 225 | |
| 323 | 226 | |
| ... | ... | @@ -510,131 +413,6 @@ fn astgenAndSemaFn( |
| 510 | 413 | body_node: ast.Node.Index, |
| 511 | 414 | fn_proto: ast.full.FnProto, |
| 512 | 415 | ) !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 | 416 | const is_inline = fn_type.fnCallingConvention() == .Inline; |
| 639 | 417 | const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued; |
| 640 | 418 | |
| ... | ... | @@ -716,264 +494,11 @@ fn astgenAndSemaVarDecl( |
| 716 | 494 | tree: ast.Tree, |
| 717 | 495 | var_decl: ast.full.VarDecl, |
| 718 | 496 | ) !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 | 497 | const token_tags = tree.tokens.items(.tag); |
| 726 | 498 | |
| 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 | 499 | } |
| 958 | 500 | |
| 959 | 501 | |
| 960 | | /// Call `deinit` on the result. |
| 961 | | pub 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 | 502 | /// Asserts the scope is a child of a File and has an AST tree and returns the tree. |
| 978 | 503 | pub fn tree(scope: *Scope) *const ast.Tree { |
| 979 | 504 | switch (scope.tag) { |
| ... | ... | @@ -1181,26 +706,6 @@ fn errorSetDecl( |
| 1181 | 706 | } |
| 1182 | 707 | |
| 1183 | 708 | |
| 1184 | | /// The string is stored in `arena` regardless of whether it uses @"" syntax. |
| 1185 | | pub 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 | 709 | |
| 1205 | 710 | if (mod.lookupIdentifier(scope, ident_name)) |decl| { |
| 1206 | 711 | const msg = msg: { |
| ... | ... | @@ -1217,3 +722,54 @@ pub fn identifierTokenStringTreeArena( |
| 1217 | 722 | return mod.failWithOwnedErrorMsg(scope, msg); |
| 1218 | 723 | } |
| 1219 | 724 | |
| 725 | |
| 726 | var type_changed = true; |
| 727 | if (decl.typedValueManaged()) |tvm| { |
| 728 | type_changed = !tvm.typed_value.ty.eql(var_info.ty); |
| 729 | |
| 730 | tvm.deinit(mod.gpa); |
| 731 | } |
| 732 | |
| 733 | const new_variable = try decl_arena.allocator.create(Var); |
| 734 | new_variable.* = .{ |
| 735 | .owner_decl = decl, |
| 736 | .init = var_info.val orelse undefined, |
| 737 | .is_extern = is_extern, |
| 738 | .is_mutable = is_mutable, |
| 739 | .is_threadlocal = is_threadlocal, |
| 740 | }; |
| 741 | const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable); |
| 742 | |
| 743 | decl_arena_state.* = decl_arena.state; |
| 744 | decl.typed_value = .{ |
| 745 | .most_recent = .{ |
| 746 | .typed_value = .{ |
| 747 | .ty = var_info.ty, |
| 748 | .val = var_val, |
| 749 | }, |
| 750 | .arena = decl_arena_state, |
| 751 | }, |
| 752 | }; |
| 753 | decl.analysis = .complete; |
| 754 | decl.generation = mod.generation; |
| 755 | |
| 756 | |
| 757 | |
| 758 | if (is_mutable and !var_info.ty.isValidVarType(is_extern)) { |
| 759 | return mod.failTok( |
| 760 | &decl_scope.base, |
| 761 | var_decl.ast.mut_token, |
| 762 | "variable of type '{}' must be const", |
| 763 | .{var_info.ty}, |
| 764 | ); |
| 765 | } |
| 766 | |
| 767 | if (var_decl.extern_export_token) |maybe_export_token| { |
| 768 | if (token_tags[maybe_export_token] == .keyword_export) { |
| 769 | const export_src = decl.tokSrcLoc(maybe_export_token); |
| 770 | const name_token = var_decl.ast.mut_token + 1; |
| 771 | const name = tree.tokenSlice(name_token); // TODO identifierTokenString |
| 772 | // The scope needs to have the decl in it. |
| 773 | try mod.analyzeExport(&decl_scope.base, export_src, name, decl); |
| 774 | } |
| 775 | } |