diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 155 | ||||
| -rw-r--r-- | src/Sema.zig | 76 | ||||
| -rw-r--r-- | src/value.zig | 8 |
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()) { |
