Commit 8387307807
Changed files (3)
src/AstGen.zig
@@ -1491,7 +1491,7 @@ fn varDecl(
}
if (var_decl.ast.init_node == 0) {
- return astgen.failTok(name_token, "variables must be initialized", .{});
+ return astgen.failNode(node, "variables must be initialized", .{});
}
switch (token_tags[var_decl.ast.mut_token]) {
@@ -1851,10 +1851,12 @@ fn fnDecl(
const is_pub = fn_proto.visib_token != null;
const is_export = blk: {
- if (fn_proto.extern_export_token) |maybe_export_token| {
- break :blk token_tags[maybe_export_token] == .keyword_export;
- }
- break :blk false;
+ const maybe_export_token = fn_proto.extern_export_token orelse break :blk false;
+ break :blk token_tags[maybe_export_token] == .keyword_export;
+ };
+ const is_extern = blk: {
+ const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false;
+ break :blk token_tags[maybe_extern_token] == .keyword_extern;
};
if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) {
try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
@@ -1937,11 +1939,6 @@ fn fnDecl(
fn_proto.ast.return_type,
);
- const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
- token_tags[maybe_export_token] == .keyword_extern
- else
- false;
-
const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
// TODO instead of enum literal type, this needs to be the
// std.builtin.CallingConvention enum. We need to implement importing other files
@@ -2070,10 +2067,94 @@ fn fnDecl(
fn globalVarDecl(
astgen: *AstGen,
gz: *GenZir,
+ scope: *Scope,
wip_decls: *WipDecls,
+ node: ast.Node.Index,
var_decl: ast.full.VarDecl,
) InnerError!void {
- @panic("TODO astgen globalVarDecl");
+ const gpa = astgen.gpa;
+ const tree = &astgen.file.tree;
+ const token_tags = tree.tokens.items(.tag);
+
+ const is_pub = var_decl.visib_token != null;
+ const is_export = blk: {
+ const maybe_export_token = var_decl.extern_export_token orelse break :blk false;
+ break :blk token_tags[maybe_export_token] == .keyword_export;
+ };
+ const is_extern = blk: {
+ const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
+ break :blk token_tags[maybe_extern_token] == .keyword_extern;
+ };
+ if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) {
+ try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
+ wip_decls.cur_bit_bag = 0;
+ }
+ wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> 2) |
+ (@as(u32, @boolToInt(is_pub)) << 30) |
+ (@as(u32, @boolToInt(is_export)) << 31);
+ wip_decls.decl_index += 1;
+
+ const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
+ const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
+ if (!is_mutable) {
+ return astgen.failTok(tok, "threadlocal variable cannot be constant", .{});
+ }
+ break :blk true;
+ } else false;
+
+ const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: {
+ const lib_name_str = try gz.strLitAsString(lib_name_token);
+ break :blk lib_name_str.index;
+ } else 0;
+
+ assert(var_decl.comptime_token == null); // handled by parser
+ if (var_decl.ast.align_node != 0) {
+ return astgen.failNode(var_decl.ast.align_node, "TODO implement alignment on globals", .{});
+ }
+ if (var_decl.ast.section_node != 0) {
+ return astgen.failNode(var_decl.ast.section_node, "TODO linksection on globals", .{});
+ }
+
+ const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: {
+ if (is_extern) {
+ return astgen.failNode(
+ var_decl.ast.init_node,
+ "extern variables have no initializers",
+ .{},
+ );
+ }
+
+ const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
+ .ty = try expr(gz, scope, .{ .ty = .type_type }, var_decl.ast.type_node),
+ } else .none;
+
+ const init_inst = try expr(gz, scope, init_result_loc, var_decl.ast.init_node);
+
+ if (!is_mutable) {
+ // const globals are just their instruction. mutable globals have
+ // a special ZIR form.
+ break :vi init_inst;
+ }
+
+ @panic("TODO astgen global variable");
+ } else if (!is_extern) {
+ return astgen.failNode(node, "variables must be initialized", .{});
+ } else if (var_decl.ast.type_node != 0) {
+ // Extern variable which has an explicit type.
+
+ const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
+
+ @panic("TODO AstGen extern global variable");
+ } else {
+ return astgen.failNode(node, "unable to infer variable type", .{});
+ };
+
+ const name_token = var_decl.ast.mut_token + 1;
+ const name_str_index = try gz.identAsString(name_token);
+
+ try wip_decls.name_and_value.ensureCapacity(gpa, wip_decls.name_and_value.items.len + 2);
+ wip_decls.name_and_value.appendAssumeCapacity(name_str_index);
+ wip_decls.name_and_value.appendAssumeCapacity(@enumToInt(var_inst));
}
fn comptimeDecl(
@@ -2191,19 +2272,19 @@ fn structDeclInner(
},
.global_var_decl => {
- try astgen.globalVarDecl(gz, &wip_decls, tree.globalVarDecl(member_node));
+ try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node));
continue;
},
.local_var_decl => {
- try astgen.globalVarDecl(gz, &wip_decls, tree.localVarDecl(member_node));
+ try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node));
continue;
},
.simple_var_decl => {
- try astgen.globalVarDecl(gz, &wip_decls, tree.simpleVarDecl(member_node));
+ try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node));
continue;
},
.aligned_var_decl => {
- try astgen.globalVarDecl(gz, &wip_decls, tree.alignedVarDecl(member_node));
+ try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node));
continue;
},
src/Module.zig
@@ -2457,6 +2457,9 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
}
pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const comp = mod.comp;
const gpa = mod.gpa;
@@ -2468,7 +2471,9 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
// Determine whether we need to reload the file from disk and redo parsing and AstGen.
switch (file.status) {
- .never_loaded, .retryable_failure => {},
+ .never_loaded, .retryable_failure => {
+ log.debug("first-time AstGen: {s}", .{file.sub_file_path});
+ },
.parse_failure, .astgen_failure, .success => {
const unchanged_metadata =
stat.size == file.stat_size and
BRANCH_TODO
@@ -1,4 +1,5 @@
* get rid of failed_root_src_file
+ * get rid of Scope.DeclRef
* handle decl collision with usingnamespace
* the decl doing the looking up needs to create a decl dependency
on each usingnamespace decl
@@ -106,42 +107,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
}
- // Detect which source files changed.
- for (module.import_table.items()) |entry| {
- const file = entry.value;
- var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
- defer f.close();
-
- // TODO handle error here by populating a retryable compile error
- const stat = try f.stat();
- const unchanged_metadata =
- stat.size == file.stat_size and
- stat.mtime == file.stat_mtime and
- stat.inode == file.stat_inode;
-
- if (unchanged_metadata) {
- log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
- continue;
- }
-
- log.debug("metadata changed: {s}", .{file.sub_file_path});
- if (file.status == .unloaded_parse_failure) {
- module.failed_files.swapRemove(file).?.value.destroy(module.gpa);
- }
-
- file.unload(module.gpa);
- // TODO handle error here by populating a retryable compile error
- try file.finishGettingSource(module.gpa, f, stat);
-
- module.analyzeFile(file) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.AnalysisFail => continue,
- else => |e| return e,
- };
- }
-
-
-
const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|
pkg.namespace_hash
else
@@ -256,68 +221,6 @@ fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenInd
-pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
- const tracy = trace(@src());
- defer tracy.end();
-
- if (file.tree_loaded) {
- return &file.tree;
- }
-
- switch (file.status) {
- .never_loaded, .success, .retryable_failure => {},
- .parse_failure, .astgen_failure => return error.AnalysisFail,
- }
-
- switch (file.status) {
- .never_loaded, .unloaded_success => {
- const gpa = mod.gpa;
-
- try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1);
-
- const source = try file.getSource(gpa);
-
- var keep_tree = false;
- file.tree = try std.zig.parse(gpa, source);
- defer if (!keep_tree) file.tree.deinit(gpa);
-
- const tree = &file.tree;
-
- if (tree.errors.len != 0) {
- const parse_err = tree.errors[0];
-
- var msg = std.ArrayList(u8).init(gpa);
- defer msg.deinit();
-
- const token_starts = tree.tokens.items(.start);
-
- try tree.renderError(parse_err, msg.writer());
- const err_msg = try gpa.create(ErrorMsg);
- err_msg.* = .{
- .src_loc = .{
- .container = .{ .file_scope = file },
- .lazy = .{ .byte_abs = token_starts[parse_err.token] },
- },
- .msg = msg.toOwnedSlice(),
- };
-
- mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
- file.status = .unloaded_parse_failure;
- return error.AnalysisFail;
- }
-
- file.status = .success;
- file.tree_loaded = true;
- keep_tree = true;
-
- return tree;
- },
-
- .unloaded_parse_failure => return error.AnalysisFail,
-
- .success => return &file.tree,
- }
-}
@@ -510,131 +413,6 @@ fn astgenAndSemaFn(
body_node: ast.Node.Index,
fn_proto: ast.full.FnProto,
) !bool {
- var fn_type_sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &decl_arena.allocator,
- .code = fn_type_code,
- .inst_map = try fn_type_scope_arena.allocator.alloc(*ir.Inst, fn_type_code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &fn_type_sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const fn_type = try fn_type_sema.rootAsType(&block_scope);
- if (body_node == 0) {
- // Extern function.
- var type_changed = true;
- if (decl.typedValueManaged()) |tvm| {
- type_changed = !tvm.typed_value.ty.eql(fn_type);
-
- tvm.deinit(mod.gpa);
- }
- const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
-
- decl_arena_state.* = decl_arena.state;
- decl.typed_value = .{
- .most_recent = .{
- .typed_value = .{ .ty = fn_type, .val = fn_val },
- .arena = decl_arena_state,
- },
- };
- decl.analysis = .complete;
- decl.generation = mod.generation;
-
- try mod.comp.bin_file.allocateDeclIndexes(decl);
- try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
-
- if (type_changed and mod.emit_h != null) {
- try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
- }
-
- return type_changed;
- }
-
- if (fn_type.fnIsVarArgs()) {
- return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
- }
-
- const new_func = try decl_arena.allocator.create(Fn);
- const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
-
- const fn_zir: Zir = blk: {
- // We put the ZIR inside the Decl arena.
- var astgen = try AstGen.init(mod, decl, &decl_arena.allocator);
- astgen.ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len + param_count);
- defer astgen.deinit();
-
- var gen_scope: Scope.GenZir = .{
- .force_comptime = false,
- .parent = &decl.namespace.base,
- .astgen = &astgen,
- };
- defer gen_scope.instructions.deinit(mod.gpa);
-
- // Iterate over the parameters. We put the param names as the first N
- // items inside `extra` so that debug info later can refer to the parameter names
- // even while the respective source code is unloaded.
- try astgen.extra.ensureCapacity(mod.gpa, param_count);
-
- var params_scope = &gen_scope.base;
- var i: usize = 0;
- var it = fn_proto.iterate(tree);
- while (it.next()) |param| : (i += 1) {
- const name_token = param.name_token.?;
- const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);
- const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
- sub_scope.* = .{
- .parent = params_scope,
- .gen_zir = &gen_scope,
- .name = param_name,
- // Implicit const list first, then implicit arg list.
- .inst = @intToEnum(Zir.Inst.Ref, @intCast(u32, Zir.Inst.Ref.typed_value_map.len + i)),
- .src = decl.tokSrcLoc(name_token),
- };
- params_scope = &sub_scope.base;
-
- // Additionally put the param name into `string_bytes` and reference it with
- // `extra` so that we have access to the data in codegen, for debug info.
- const str_index = @intCast(u32, astgen.string_bytes.items.len);
- astgen.extra.appendAssumeCapacity(str_index);
- const used_bytes = astgen.string_bytes.items.len;
- try astgen.string_bytes.ensureCapacity(mod.gpa, used_bytes + param_name.len + 1);
- astgen.string_bytes.appendSliceAssumeCapacity(param_name);
- astgen.string_bytes.appendAssumeCapacity(0);
- }
-
- _ = try AstGen.expr(&gen_scope, params_scope, .none, body_node);
-
- if (gen_scope.instructions.items.len == 0 or
- !astgen.instructions.items(.tag)[gen_scope.instructions.items.len - 1]
- .isNoReturn())
- {
- // astgen uses result location semantics to coerce return operands.
- // Since we are adding the return instruction here, we must handle the coercion.
- // We do this by using the `ret_coerce` instruction.
- _ = try gen_scope.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
- }
-
- const code = try gen_scope.finish();
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "fn_body", &gen_scope.base, param_count) catch {};
- }
-
- break :blk code;
- };
-
const is_inline = fn_type.fnCallingConvention() == .Inline;
const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
@@ -716,264 +494,11 @@ fn astgenAndSemaVarDecl(
tree: ast.Tree,
var_decl: ast.full.VarDecl,
) !bool {
- const tracy = trace(@src());
- defer tracy.end();
-
- decl.analysis = .in_progress;
- decl.is_pub = var_decl.visib_token != null;
-
const token_tags = tree.tokens.items(.tag);
- // We need the memory for the Type to go into the arena for the Decl
- var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
- errdefer decl_arena.deinit();
- const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
-
- // Used for simple error reporting.
- var decl_scope: Scope.DeclRef = .{ .decl = decl };
-
- const is_extern = blk: {
- const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
- break :blk token_tags[maybe_extern_token] == .keyword_extern;
- };
-
- if (var_decl.lib_name) |lib_name| {
- assert(is_extern);
- return mod.failTok(&decl_scope.base, lib_name, "TODO implement function library name", .{});
- }
- const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
- const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: {
- if (!is_mutable) {
- return mod.failTok(&decl_scope.base, some, "threadlocal variable cannot be constant", .{});
- }
- break :blk true;
- } else false;
- assert(var_decl.comptime_token == null);
- if (var_decl.ast.align_node != 0) {
- return mod.failNode(
- &decl_scope.base,
- var_decl.ast.align_node,
- "TODO implement function align expression",
- .{},
- );
- }
- if (var_decl.ast.section_node != 0) {
- return mod.failNode(
- &decl_scope.base,
- var_decl.ast.section_node,
- "TODO implement function section expression",
- .{},
- );
- }
-
- const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
- if (is_extern) {
- return mod.failNode(
- &decl_scope.base,
- var_decl.ast.init_node,
- "extern variables have no initializers",
- .{},
- );
- }
-
- var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
- defer gen_scope_arena.deinit();
-
- var astgen = try AstGen.init(mod, decl, &gen_scope_arena.allocator);
- defer astgen.deinit();
-
- var gen_scope: Scope.GenZir = .{
- .force_comptime = true,
- .parent = &decl.namespace.base,
- .astgen = &astgen,
- };
- defer gen_scope.instructions.deinit(mod.gpa);
-
- const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{
- .ty = try AstGen.expr(&gen_scope, &gen_scope.base, .{ .ty = .type_type }, var_decl.ast.type_node),
- } else .none;
-
- const init_inst = try AstGen.comptimeExpr(
- &gen_scope,
- &gen_scope.base,
- init_result_loc,
- var_decl.ast.init_node,
- );
- _ = try gen_scope.addBreak(.break_inline, 0, init_inst);
- var code = try gen_scope.finish();
- defer code.deinit(mod.gpa);
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
- }
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &gen_scope_arena.allocator,
- .code = code,
- .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
- // The result location guarantees the type coercion.
- const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref);
- // The is_comptime in the Scope.Block guarantees the result is comptime-known.
- const val = analyzed_init_inst.value().?;
-
- break :vi .{
- .ty = try analyzed_init_inst.ty.copy(&decl_arena.allocator),
- .val = try val.copy(&decl_arena.allocator),
- };
- } else if (!is_extern) {
- return mod.failTok(
- &decl_scope.base,
- var_decl.ast.mut_token,
- "variables must be initialized",
- .{},
- );
- } else if (var_decl.ast.type_node != 0) vi: {
- var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
- defer type_scope_arena.deinit();
-
- var astgen = try AstGen.init(mod, decl, &type_scope_arena.allocator);
- defer astgen.deinit();
-
- var type_scope: Scope.GenZir = .{
- .force_comptime = true,
- .parent = &decl.namespace.base,
- .astgen = &astgen,
- };
- defer type_scope.instructions.deinit(mod.gpa);
-
- const var_type = try AstGen.typeExpr(&type_scope, &type_scope.base, var_decl.ast.type_node);
- _ = try type_scope.addBreak(.break_inline, 0, var_type);
-
- var code = try type_scope.finish();
- defer code.deinit(mod.gpa);
- if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
- code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
- }
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = mod.gpa,
- .arena = &type_scope_arena.allocator,
- .code = code,
- .inst_map = try type_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
- .owner_decl = decl,
- .namespace = decl.namespace,
- .func = null,
- .owner_func = null,
- .param_inst_list = &.{},
- };
- var block_scope: Scope.Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer block_scope.instructions.deinit(mod.gpa);
-
- const ty = try sema.rootAsType(&block_scope);
-
- break :vi .{
- .ty = try ty.copy(&decl_arena.allocator),
- .val = null,
- };
- } else {
- return mod.failTok(
- &decl_scope.base,
- var_decl.ast.mut_token,
- "unable to infer variable type",
- .{},
- );
- };
-
- if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
- return mod.failTok(
- &decl_scope.base,
- var_decl.ast.mut_token,
- "variable of type '{}' must be const",
- .{var_info.ty},
- );
- }
-
- var type_changed = true;
- if (decl.typedValueManaged()) |tvm| {
- type_changed = !tvm.typed_value.ty.eql(var_info.ty);
-
- tvm.deinit(mod.gpa);
- }
-
- const new_variable = try decl_arena.allocator.create(Var);
- new_variable.* = .{
- .owner_decl = decl,
- .init = var_info.val orelse undefined,
- .is_extern = is_extern,
- .is_mutable = is_mutable,
- .is_threadlocal = is_threadlocal,
- };
- const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
-
- decl_arena_state.* = decl_arena.state;
- decl.typed_value = .{
- .most_recent = .{
- .typed_value = .{
- .ty = var_info.ty,
- .val = var_val,
- },
- .arena = decl_arena_state,
- },
- };
- decl.analysis = .complete;
- decl.generation = mod.generation;
-
- if (var_decl.extern_export_token) |maybe_export_token| {
- if (token_tags[maybe_export_token] == .keyword_export) {
- const export_src = decl.tokSrcLoc(maybe_export_token);
- const name_token = var_decl.ast.mut_token + 1;
- const name = tree.tokenSlice(name_token); // TODO identifierTokenString
- // The scope needs to have the decl in it.
- try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
- }
- }
- return type_changed;
}
-/// Call `deinit` on the result.
-pub fn init(mod: *Module, decl: *Decl, arena: *Allocator) !AstGen {
- var astgen: AstGen = .{
- .mod = mod,
- .decl = decl,
- .arena = arena,
- };
- // Must be a block instruction at index 0 with the root body.
- try astgen.instructions.append(mod.gpa, .{
- .tag = .block,
- .data = .{ .pl_node = .{
- .src_node = 0,
- .payload_index = undefined,
- } },
- });
- return astgen;
-}
/// Asserts the scope is a child of a File and has an AST tree and returns the tree.
pub fn tree(scope: *Scope) *const ast.Tree {
switch (scope.tag) {
@@ -1181,26 +706,6 @@ fn errorSetDecl(
}
-/// The string is stored in `arena` regardless of whether it uses @"" syntax.
-pub fn identifierTokenStringTreeArena(
- astgen: *AstGen,
- token: ast.TokenIndex,
- tree: *const ast.Tree,
- arena: *Allocator,
-) InnerError![]u8 {
- const token_tags = tree.tokens.items(.tag);
- assert(token_tags[token] == .identifier);
- const ident_name = tree.tokenSlice(token);
- if (!mem.startsWith(u8, ident_name, "@")) {
- return arena.dupe(u8, ident_name);
- }
- var buf: ArrayListUnmanaged(u8) = .{};
- defer buf.deinit(astgen.gpa);
- try astgen.parseStrLit(token, &buf, ident_name, 1);
- return arena.dupe(u8, buf.items);
-}
-
-
if (mod.lookupIdentifier(scope, ident_name)) |decl| {
const msg = msg: {
@@ -1217,3 +722,54 @@ pub fn identifierTokenStringTreeArena(
return mod.failWithOwnedErrorMsg(scope, msg);
}
+
+ var type_changed = true;
+ if (decl.typedValueManaged()) |tvm| {
+ type_changed = !tvm.typed_value.ty.eql(var_info.ty);
+
+ tvm.deinit(mod.gpa);
+ }
+
+ const new_variable = try decl_arena.allocator.create(Var);
+ new_variable.* = .{
+ .owner_decl = decl,
+ .init = var_info.val orelse undefined,
+ .is_extern = is_extern,
+ .is_mutable = is_mutable,
+ .is_threadlocal = is_threadlocal,
+ };
+ const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
+
+ decl_arena_state.* = decl_arena.state;
+ decl.typed_value = .{
+ .most_recent = .{
+ .typed_value = .{
+ .ty = var_info.ty,
+ .val = var_val,
+ },
+ .arena = decl_arena_state,
+ },
+ };
+ decl.analysis = .complete;
+ decl.generation = mod.generation;
+
+
+
+ if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
+ return mod.failTok(
+ &decl_scope.base,
+ var_decl.ast.mut_token,
+ "variable of type '{}' must be const",
+ .{var_info.ty},
+ );
+ }
+
+ if (var_decl.extern_export_token) |maybe_export_token| {
+ if (token_tags[maybe_export_token] == .keyword_export) {
+ const export_src = decl.tokSrcLoc(maybe_export_token);
+ const name_token = var_decl.ast.mut_token + 1;
+ const name = tree.tokenSlice(name_token); // TODO identifierTokenString
+ // The scope needs to have the decl in it.
+ try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
+ }
+ }