| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | * get rid of failed_root_src_file | 1 | * get rid of failed_root_src_file |
| | 2 | * get rid of Scope.DeclRef |
| 2 | * handle decl collision with usingnamespace | 3 | * handle decl collision with usingnamespace |
| 3 | * the decl doing the looking up needs to create a decl dependency | 4 | * the decl doing the looking up needs to create a decl dependency |
| 4 | on each usingnamespace decl | 5 | on each usingnamespace decl |
| ... | @@ -106,42 +107,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd | ... | @@ -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 | const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg| | 110 | const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg| |
| 146 | pkg.namespace_hash | 111 | pkg.namespace_hash |
| 147 | else | 112 | else |
| ... | @@ -256,68 +221,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd | ... | @@ -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,131 +413,6 @@ fn astgenAndSemaFn( |
| 510 | body_node: ast.Node.Index, | 413 | body_node: ast.Node.Index, |
| 511 | fn_proto: ast.full.FnProto, | 414 | fn_proto: ast.full.FnProto, |
| 512 | ) !bool { | 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 | const is_inline = fn_type.fnCallingConvention() == .Inline; | 416 | const is_inline = fn_type.fnCallingConvention() == .Inline; |
| 639 | const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued; | 417 | const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued; |
| 640 | | 418 | |
| ... | @@ -716,264 +494,11 @@ fn astgenAndSemaVarDecl( | ... | @@ -716,264 +494,11 @@ fn astgenAndSemaVarDecl( |
| 716 | tree: ast.Tree, | 494 | tree: ast.Tree, |
| 717 | var_decl: ast.full.VarDecl, | 495 | var_decl: ast.full.VarDecl, |
| 718 | ) !bool { | 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 | const token_tags = tree.tokens.items(.tag); | 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 | /// Asserts the scope is a child of a File and has an AST tree and returns the tree. | 502 | /// 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 { | 503 | pub fn tree(scope: *Scope) *const ast.Tree { |
| 979 | switch (scope.tag) { | 504 | switch (scope.tag) { |
| ... | @@ -1181,26 +706,6 @@ fn errorSetDecl( | ... | @@ -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 | if (mod.lookupIdentifier(scope, ident_name)) |decl| { | 710 | if (mod.lookupIdentifier(scope, ident_name)) |decl| { |
| 1206 | const msg = msg: { | 711 | const msg = msg: { |
| ... | @@ -1217,3 +722,54 @@ pub fn identifierTokenStringTreeArena( | ... | @@ -1217,3 +722,54 @@ pub fn identifierTokenStringTreeArena( |
| 1217 | return mod.failWithOwnedErrorMsg(scope, msg); | 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 | } |