aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig155
-rw-r--r--src/Sema.zig76
-rw-r--r--src/value.zig8
3 files changed, 138 insertions, 101 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 5ef0448849..f0810d00a5 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -276,11 +276,16 @@ pub const Decl = struct {
pub fn destroy(decl: *Decl, module: *Module) void {
const gpa = module.gpa;
+ log.debug("destroy Decl {s}", .{decl.name});
decl.clearName(gpa);
if (decl.has_tv) {
if (decl.val.castTag(.function)) |payload| {
const func = payload.data;
func.deinit(gpa);
+ } else if (decl.val.getTypeNamespace()) |namespace| {
+ if (namespace.getDecl() == decl) {
+ namespace.clearDecls(module);
+ }
}
decl.clearValues(gpa);
}
@@ -303,6 +308,13 @@ pub const Decl = struct {
}
}
+ pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void {
+ assert(decl.value_arena == null);
+ const arena_state = try arena.allocator.create(std.heap.ArenaAllocator.State);
+ arena_state.* = arena.state;
+ decl.value_arena = arena_state;
+ }
+
/// This name is relative to the containing namespace of the decl.
/// The memory is owned by the containing File ZIR.
pub fn getName(decl: Decl) ?[:0]const u8 {
@@ -719,13 +731,20 @@ pub const Scope = struct {
decls: std.StringArrayHashMapUnmanaged(*Decl) = .{},
pub fn deinit(ns: *Namespace, mod: *Module) void {
+ ns.clearDecls(mod);
+ ns.* = undefined;
+ }
+
+ pub fn clearDecls(ns: *Namespace, mod: *Module) void {
const gpa = mod.gpa;
- for (ns.decls.items()) |entry| {
+ var decls = ns.decls;
+ ns.decls = .{};
+
+ for (decls.items()) |entry| {
entry.value.destroy(mod);
}
- ns.decls.deinit(gpa);
- ns.* = undefined;
+ decls.deinit(gpa);
}
pub fn removeDecl(ns: *Namespace, child: *Decl) void {
@@ -775,14 +794,9 @@ pub const Scope = struct {
/// Package that this file is a part of, managed externally.
pkg: *Package,
/// The namespace of the struct that represents this file.
- /// Populated only when status is success.
+ /// Populated only when status is `success_air`.
/// Owned by its owner Decl Value.
namespace: *Namespace,
- /// All namespaces that this file contains. This is here so that
- /// when a file is updated, and new ZIR code is generated, the
- /// old and new ZIR code can be compared side by side and references
- /// to old ZIR updated to new ZIR, and a changelist generated.
- namespace_set: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{},
pub fn unload(file: *File, gpa: *Allocator) void {
file.unloadTree(gpa);
@@ -813,6 +827,10 @@ pub const Scope = struct {
pub fn deinit(file: *File, mod: *Module) void {
const gpa = mod.gpa;
+ log.debug("deinit File {s}", .{file.sub_file_path});
+ if (file.status == .success_air) {
+ file.namespace.getDecl().destroy(mod);
+ }
gpa.free(file.sub_file_path);
file.unload(gpa);
file.* = undefined;
@@ -866,6 +884,18 @@ pub const Scope = struct {
gpa.destroy(file);
}
+ pub fn fullyQualifiedNameZ(file: File, gpa: *Allocator) ![:0]u8 {
+ // Convert all the slashes into dots and truncate the extension.
+ const ext = std.fs.path.extension(file.sub_file_path);
+ const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len];
+ const duped = try gpa.dupeZ(u8, noext);
+ for (duped) |*byte| switch (byte.*) {
+ '/', '\\' => byte.* = '.',
+ else => continue,
+ };
+ return duped;
+ }
+
pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
const loc = std.zig.findLineColumn(file.source.bytes, src);
std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
@@ -3297,48 +3327,49 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {
assert(file.zir_loaded);
const gpa = mod.gpa;
- var decl_arena = std.heap.ArenaAllocator.init(gpa);
- defer decl_arena.deinit();
-
- // We need a Decl to pass to Sema and collect dependencies. But ultimately we
- // want to pass them on to the Decl for the struct that represents the file.
- var tmp_namespace: Scope.Namespace = .{
- .parent = null,
- .file_scope = file,
- .ty = Type.initTag(.type),
+ var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
+ errdefer new_decl_arena.deinit();
+
+ const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
+ const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
+ const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
+ struct_obj.* = .{
+ .owner_decl = undefined, // set below
+ .fields = .{},
+ .node_offset = 0, // it's the struct for the root file
+ .namespace = .{
+ .parent = null,
+ .ty = struct_ty,
+ .file_scope = file,
+ },
};
- var top_decl: Decl = .{
- .name = "",
- .namespace = &tmp_namespace,
- .generation = mod.generation,
- .src_node = 0, // the root AST node for the file
- .analysis = .in_progress,
- .deletion_flag = false,
- .is_pub = true,
- .is_exported = false,
- .has_linksection = false,
- .has_align = false,
- .link = undefined, // don't try to codegen this
- .fn_link = undefined, // not a function
- .zir_decl_index = undefined,
+ file.namespace = &struct_obj.namespace;
+ const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0);
+ struct_obj.owner_decl = new_decl;
+ new_decl.name = try file.fullyQualifiedNameZ(gpa);
+ new_decl.is_pub = true;
+ new_decl.is_exported = false;
+ new_decl.has_align = false;
+ new_decl.has_linksection = false;
+ new_decl.zir_decl_index = undefined;
+ new_decl.ty = struct_ty;
+ new_decl.val = struct_val;
+ new_decl.has_tv = true;
+ new_decl.analysis = .complete;
+ new_decl.generation = mod.generation;
- .has_tv = false,
- .ty = undefined,
- .val = undefined,
- .align_val = undefined,
- .linksection_val = undefined,
- };
- defer top_decl.dependencies.deinit(gpa);
+ var sema_arena = std.heap.ArenaAllocator.init(gpa);
+ defer sema_arena.deinit();
var sema: Sema = .{
.mod = mod,
.gpa = gpa,
- .arena = &decl_arena.allocator,
+ .arena = &sema_arena.allocator,
.code = file.zir,
// TODO use a map because this array is too big
- .inst_map = try decl_arena.allocator.alloc(*ir.Inst, file.zir.instructions.len),
- .owner_decl = &top_decl,
- .namespace = &tmp_namespace,
+ .inst_map = try sema_arena.allocator.alloc(*ir.Inst, file.zir.instructions.len),
+ .owner_decl = new_decl,
+ .namespace = &struct_obj.namespace,
.func = null,
.owner_func = null,
.param_inst_list = &.{},
@@ -3346,7 +3377,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {
var block_scope: Scope.Block = .{
.parent = null,
.sema = &sema,
- .src_decl = &top_decl,
+ .src_decl = new_decl,
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -3355,23 +3386,9 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void {
const main_struct_inst = file.zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] -
@intCast(u32, Zir.Inst.Ref.typed_value_map.len);
- const air_inst = try sema.zirStructDecl(&block_scope, main_struct_inst, .Auto);
- assert(air_inst.ty.zigTypeTag() == .Type);
- const val = air_inst.value().?;
- const struct_ty = try val.toType(&decl_arena.allocator);
- const struct_decl = struct_ty.getOwnerDecl();
-
- file.namespace = struct_ty.getNamespace().?;
- file.namespace.parent = null;
-
- // Transfer the dependencies to `owner_decl`.
- assert(top_decl.dependants.count() == 0);
- for (top_decl.dependencies.items()) |entry| {
- const dep = entry.key;
- dep.removeDependant(&top_decl);
- if (dep == struct_decl) continue;
- _ = try mod.declareDeclDependency(struct_decl, dep);
- }
+ try sema.analyzeStructDecl(&block_scope, &new_decl_arena, new_decl, main_struct_inst, .Auto, struct_obj);
+ try new_decl.finalizeNewArena(&new_decl_arena);
+
file.status = .success_air;
}
@@ -4319,23 +4336,17 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b
}
}
-pub fn createAnonymousDecl(
- mod: *Module,
- scope: *Scope,
- decl_arena: *std.heap.ArenaAllocator,
- typed_value: TypedValue,
-) !*Decl {
+pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl {
const name_index = mod.getNextAnonNameIndex();
const scope_decl = scope.ownerDecl().?;
+ const namespace = scope_decl.namespace;
+ try namespace.decls.ensureCapacity(mod.gpa, namespace.decls.count() + 1);
const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
errdefer mod.gpa.free(name);
- const namespace = scope_decl.namespace;
const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node);
- new_decl.name = name;
+ namespace.decls.putAssumeCapacityNoClobber(name, new_decl);
- const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
-
- decl_arena_state.* = decl_arena.state;
+ new_decl.name = name;
new_decl.ty = typed_value.ty;
new_decl.val = typed_value.val;
new_decl.has_tv = true;
diff --git a/src/Sema.zig b/src/Sema.zig
index d1893a82f9..bb9a608b7c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -634,15 +634,19 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{});
}
-pub fn zirStructDecl(
+pub fn analyzeStructDecl(
sema: *Sema,
block: *Scope.Block,
+ new_decl_arena: *std.heap.ArenaAllocator,
+ new_decl: *Decl,
inst: Zir.Inst.Index,
layout: std.builtin.TypeInfo.ContainerLayout,
-) InnerError!*Inst {
+ struct_obj: *Module.Struct,
+) InnerError!void {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const gpa = sema.gpa;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
@@ -650,27 +654,7 @@ pub fn zirStructDecl(
const fields_len = extra.data.fields_len;
const decls_len = extra.data.decls_len;
- var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
-
- const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
- const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
- const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
- const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
- .ty = Type.initTag(.type),
- .val = struct_val,
- });
- struct_obj.* = .{
- .owner_decl = sema.owner_decl,
- .fields = .{},
- .node_offset = inst_data.src_node,
- .namespace = .{
- .parent = sema.owner_decl.namespace,
- .ty = struct_ty,
- .file_scope = block.getFileScope(),
- },
- };
-
- var extra_index: usize = try sema.mod.scanNamespace(
+ var extra_index: usize = try mod.scanNamespace(
&struct_obj.namespace,
extra.end,
decls_len,
@@ -680,7 +664,7 @@ pub fn zirStructDecl(
const body = sema.code.extra[extra_index..][0..extra.data.body_len];
if (fields_len == 0) {
assert(body.len == 0);
- return sema.analyzeDeclVal(block, src, new_decl);
+ return;
}
try struct_obj.fields.ensureCapacity(&new_decl_arena.allocator, fields_len);
@@ -691,7 +675,7 @@ pub fn zirStructDecl(
// Within the field type, default value, and alignment expressions, the "owner decl"
// should be the struct itself. Thus we need a new Sema.
var struct_sema: Sema = .{
- .mod = sema.mod,
+ .mod = mod,
.gpa = gpa,
.arena = &new_decl_arena.allocator,
.code = sema.code,
@@ -752,7 +736,7 @@ pub fn zirStructDecl(
// This string needs to outlive the ZIR code.
const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir);
if (field_type_ref == .none) {
- return sema.mod.fail(&block.base, src, "TODO: implement anytype struct field", .{});
+ return mod.fail(&block.base, src, "TODO: implement anytype struct field", .{});
}
const field_ty: Type = if (field_type_ref == .none)
Type.initTag(.noreturn)
@@ -788,7 +772,38 @@ pub fn zirStructDecl(
gop.entry.value.default_val = (try sema.resolveInstConst(block, src, default_ref)).val;
}
}
+}
+
+fn zirStructDecl(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+ layout: std.builtin.TypeInfo.ContainerLayout,
+) InnerError!*Inst {
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
+
+ var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
+ const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
+ const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
+ const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
+ const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{
+ .ty = Type.initTag(.type),
+ .val = struct_val,
+ });
+ struct_obj.* = .{
+ .owner_decl = sema.owner_decl,
+ .fields = .{},
+ .node_offset = inst_data.src_node,
+ .namespace = .{
+ .parent = sema.owner_decl.namespace,
+ .ty = struct_ty,
+ .file_scope = block.getFileScope(),
+ },
+ };
+ try sema.analyzeStructDecl(block, &new_decl_arena, new_decl, inst, layout, struct_obj);
+ try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclVal(block, src, new_decl);
}
@@ -822,14 +837,14 @@ fn zirEnumDecl(
};
const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull);
- const enum_ty_payload = try gpa.create(Type.Payload.EnumFull);
+ const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull);
enum_ty_payload.* = .{
.base = .{ .tag = if (nonexhaustive) .enum_nonexhaustive else .enum_full },
.data = enum_obj,
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
- const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
+ const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{
.ty = Type.initTag(.type),
.val = enum_val,
});
@@ -856,6 +871,7 @@ fn zirEnumDecl(
const body = sema.code.extra[extra_index..][0..extra.data.body_len];
if (fields_len == 0) {
assert(body.len == 0);
+ try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclVal(block, src, new_decl);
}
@@ -942,6 +958,7 @@ fn zirEnumDecl(
}
}
+ try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclVal(block, src, new_decl);
}
@@ -1424,10 +1441,11 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*In
const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes);
- const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
+ const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{
.ty = decl_ty,
.val = decl_val,
});
+ try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclRef(block, .unneeded, new_decl);
}
diff --git a/src/value.zig b/src/value.zig
index d2d7be3007..04608878c0 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -593,6 +593,14 @@ pub const Value = extern union {
unreachable;
}
+ /// Returns null if not a type or if the type has no namespace.
+ pub fn getTypeNamespace(self: Value) ?*Module.Scope.Namespace {
+ return switch (self.tag()) {
+ .ty => self.castTag(.ty).?.data.getNamespace(),
+ else => null,
+ };
+ }
+
/// Asserts that the value is representable as a type.
pub fn toType(self: Value, allocator: *Allocator) !Type {
return switch (self.tag()) {