| ... | ... | @@ -276,11 +276,16 @@ pub const Decl = struct { |
| 276 | 276 | |
| 277 | 277 | pub fn destroy(decl: *Decl, module: *Module) void { |
| 278 | 278 | const gpa = module.gpa; |
| 279 | log.debug("destroy Decl {s}", .{decl.name}); |
| 279 | 280 | decl.clearName(gpa); |
| 280 | 281 | if (decl.has_tv) { |
| 281 | 282 | if (decl.val.castTag(.function)) |payload| { |
| 282 | 283 | const func = payload.data; |
| 283 | 284 | func.deinit(gpa); |
| 285 | } else if (decl.val.getTypeNamespace()) |namespace| { |
| 286 | if (namespace.getDecl() == decl) { |
| 287 | namespace.clearDecls(module); |
| 288 | } |
| 284 | 289 | } |
| 285 | 290 | decl.clearValues(gpa); |
| 286 | 291 | } |
| ... | ... | @@ -303,6 +308,13 @@ pub const Decl = struct { |
| 303 | 308 | } |
| 304 | 309 | } |
| 305 | 310 | |
| 311 | pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void { |
| 312 | assert(decl.value_arena == null); |
| 313 | const arena_state = try arena.allocator.create(std.heap.ArenaAllocator.State); |
| 314 | arena_state.* = arena.state; |
| 315 | decl.value_arena = arena_state; |
| 316 | } |
| 317 | |
| 306 | 318 | /// This name is relative to the containing namespace of the decl. |
| 307 | 319 | /// The memory is owned by the containing File ZIR. |
| 308 | 320 | pub fn getName(decl: Decl) ?[:0]const u8 { |
| ... | ... | @@ -719,13 +731,20 @@ pub const Scope = struct { |
| 719 | 731 | decls: std.StringArrayHashMapUnmanaged(*Decl) = .{}, |
| 720 | 732 | |
| 721 | 733 | pub fn deinit(ns: *Namespace, mod: *Module) void { |
| 734 | ns.clearDecls(mod); |
| 735 | ns.* = undefined; |
| 736 | } |
| 737 | |
| 738 | pub fn clearDecls(ns: *Namespace, mod: *Module) void { |
| 722 | 739 | const gpa = mod.gpa; |
| 723 | 740 | |
| 724 | | for (ns.decls.items()) |entry| { |
| 741 | var decls = ns.decls; |
| 742 | ns.decls = .{}; |
| 743 | |
| 744 | for (decls.items()) |entry| { |
| 725 | 745 | entry.value.destroy(mod); |
| 726 | 746 | } |
| 727 | | ns.decls.deinit(gpa); |
| 728 | | ns.* = undefined; |
| 747 | decls.deinit(gpa); |
| 729 | 748 | } |
| 730 | 749 | |
| 731 | 750 | pub fn removeDecl(ns: *Namespace, child: *Decl) void { |
| ... | ... | @@ -775,14 +794,9 @@ pub const Scope = struct { |
| 775 | 794 | /// Package that this file is a part of, managed externally. |
| 776 | 795 | pkg: *Package, |
| 777 | 796 | /// The namespace of the struct that represents this file. |
| 778 | | /// Populated only when status is success. |
| 797 | /// Populated only when status is `success_air`. |
| 779 | 798 | /// Owned by its owner Decl Value. |
| 780 | 799 | namespace: *Namespace, |
| 781 | | /// All namespaces that this file contains. This is here so that |
| 782 | | /// when a file is updated, and new ZIR code is generated, the |
| 783 | | /// old and new ZIR code can be compared side by side and references |
| 784 | | /// to old ZIR updated to new ZIR, and a changelist generated. |
| 785 | | namespace_set: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{}, |
| 786 | 800 | |
| 787 | 801 | pub fn unload(file: *File, gpa: *Allocator) void { |
| 788 | 802 | file.unloadTree(gpa); |
| ... | ... | @@ -813,6 +827,10 @@ pub const Scope = struct { |
| 813 | 827 | |
| 814 | 828 | pub fn deinit(file: *File, mod: *Module) void { |
| 815 | 829 | const gpa = mod.gpa; |
| 830 | log.debug("deinit File {s}", .{file.sub_file_path}); |
| 831 | if (file.status == .success_air) { |
| 832 | file.namespace.getDecl().destroy(mod); |
| 833 | } |
| 816 | 834 | gpa.free(file.sub_file_path); |
| 817 | 835 | file.unload(gpa); |
| 818 | 836 | file.* = undefined; |
| ... | ... | @@ -866,6 +884,18 @@ pub const Scope = struct { |
| 866 | 884 | gpa.destroy(file); |
| 867 | 885 | } |
| 868 | 886 | |
| 887 | pub fn fullyQualifiedNameZ(file: File, gpa: *Allocator) ![:0]u8 { |
| 888 | // Convert all the slashes into dots and truncate the extension. |
| 889 | const ext = std.fs.path.extension(file.sub_file_path); |
| 890 | const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; |
| 891 | const duped = try gpa.dupeZ(u8, noext); |
| 892 | for (duped) |*byte| switch (byte.*) { |
| 893 | '/', '\\' => byte.* = '.', |
| 894 | else => continue, |
| 895 | }; |
| 896 | return duped; |
| 897 | } |
| 898 | |
| 869 | 899 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { |
| 870 | 900 | const loc = std.zig.findLineColumn(file.source.bytes, src); |
| 871 | 901 | 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 { |
| 3297 | 3327 | assert(file.zir_loaded); |
| 3298 | 3328 | |
| 3299 | 3329 | const gpa = mod.gpa; |
| 3300 | | var decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 3301 | | defer decl_arena.deinit(); |
| 3302 | | |
| 3303 | | // We need a Decl to pass to Sema and collect dependencies. But ultimately we |
| 3304 | | // want to pass them on to the Decl for the struct that represents the file. |
| 3305 | | var tmp_namespace: Scope.Namespace = .{ |
| 3306 | | .parent = null, |
| 3307 | | .file_scope = file, |
| 3308 | | .ty = Type.initTag(.type), |
| 3330 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 3331 | errdefer new_decl_arena.deinit(); |
| 3332 | |
| 3333 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); |
| 3334 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); |
| 3335 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); |
| 3336 | struct_obj.* = .{ |
| 3337 | .owner_decl = undefined, // set below |
| 3338 | .fields = .{}, |
| 3339 | .node_offset = 0, // it's the struct for the root file |
| 3340 | .namespace = .{ |
| 3341 | .parent = null, |
| 3342 | .ty = struct_ty, |
| 3343 | .file_scope = file, |
| 3344 | }, |
| 3309 | 3345 | }; |
| 3310 | | var top_decl: Decl = .{ |
| 3311 | | .name = "", |
| 3312 | | .namespace = &tmp_namespace, |
| 3313 | | .generation = mod.generation, |
| 3314 | | .src_node = 0, // the root AST node for the file |
| 3315 | | .analysis = .in_progress, |
| 3316 | | .deletion_flag = false, |
| 3317 | | .is_pub = true, |
| 3318 | | .is_exported = false, |
| 3319 | | .has_linksection = false, |
| 3320 | | .has_align = false, |
| 3321 | | .link = undefined, // don't try to codegen this |
| 3322 | | .fn_link = undefined, // not a function |
| 3323 | | .zir_decl_index = undefined, |
| 3346 | file.namespace = &struct_obj.namespace; |
| 3347 | const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0); |
| 3348 | struct_obj.owner_decl = new_decl; |
| 3349 | new_decl.name = try file.fullyQualifiedNameZ(gpa); |
| 3350 | new_decl.is_pub = true; |
| 3351 | new_decl.is_exported = false; |
| 3352 | new_decl.has_align = false; |
| 3353 | new_decl.has_linksection = false; |
| 3354 | new_decl.zir_decl_index = undefined; |
| 3355 | new_decl.ty = struct_ty; |
| 3356 | new_decl.val = struct_val; |
| 3357 | new_decl.has_tv = true; |
| 3358 | new_decl.analysis = .complete; |
| 3359 | new_decl.generation = mod.generation; |
| 3324 | 3360 | |
| 3325 | | .has_tv = false, |
| 3326 | | .ty = undefined, |
| 3327 | | .val = undefined, |
| 3328 | | .align_val = undefined, |
| 3329 | | .linksection_val = undefined, |
| 3330 | | }; |
| 3331 | | defer top_decl.dependencies.deinit(gpa); |
| 3361 | var sema_arena = std.heap.ArenaAllocator.init(gpa); |
| 3362 | defer sema_arena.deinit(); |
| 3332 | 3363 | |
| 3333 | 3364 | var sema: Sema = .{ |
| 3334 | 3365 | .mod = mod, |
| 3335 | 3366 | .gpa = gpa, |
| 3336 | | .arena = &decl_arena.allocator, |
| 3367 | .arena = &sema_arena.allocator, |
| 3337 | 3368 | .code = file.zir, |
| 3338 | 3369 | // TODO use a map because this array is too big |
| 3339 | | .inst_map = try decl_arena.allocator.alloc(*ir.Inst, file.zir.instructions.len), |
| 3340 | | .owner_decl = &top_decl, |
| 3341 | | .namespace = &tmp_namespace, |
| 3370 | .inst_map = try sema_arena.allocator.alloc(*ir.Inst, file.zir.instructions.len), |
| 3371 | .owner_decl = new_decl, |
| 3372 | .namespace = &struct_obj.namespace, |
| 3342 | 3373 | .func = null, |
| 3343 | 3374 | .owner_func = null, |
| 3344 | 3375 | .param_inst_list = &.{}, |
| ... | ... | @@ -3346,7 +3377,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 3346 | 3377 | var block_scope: Scope.Block = .{ |
| 3347 | 3378 | .parent = null, |
| 3348 | 3379 | .sema = &sema, |
| 3349 | | .src_decl = &top_decl, |
| 3380 | .src_decl = new_decl, |
| 3350 | 3381 | .instructions = .{}, |
| 3351 | 3382 | .inlining = null, |
| 3352 | 3383 | .is_comptime = true, |
| ... | ... | @@ -3355,23 +3386,9 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 3355 | 3386 | |
| 3356 | 3387 | const main_struct_inst = file.zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] - |
| 3357 | 3388 | @intCast(u32, Zir.Inst.Ref.typed_value_map.len); |
| 3358 | | const air_inst = try sema.zirStructDecl(&block_scope, main_struct_inst, .Auto); |
| 3359 | | assert(air_inst.ty.zigTypeTag() == .Type); |
| 3360 | | const val = air_inst.value().?; |
| 3361 | | const struct_ty = try val.toType(&decl_arena.allocator); |
| 3362 | | const struct_decl = struct_ty.getOwnerDecl(); |
| 3363 | | |
| 3364 | | file.namespace = struct_ty.getNamespace().?; |
| 3365 | | file.namespace.parent = null; |
| 3366 | | |
| 3367 | | // Transfer the dependencies to `owner_decl`. |
| 3368 | | assert(top_decl.dependants.count() == 0); |
| 3369 | | for (top_decl.dependencies.items()) |entry| { |
| 3370 | | const dep = entry.key; |
| 3371 | | dep.removeDependant(&top_decl); |
| 3372 | | if (dep == struct_decl) continue; |
| 3373 | | _ = try mod.declareDeclDependency(struct_decl, dep); |
| 3374 | | } |
| 3389 | try sema.analyzeStructDecl(&block_scope, &new_decl_arena, new_decl, main_struct_inst, .Auto, struct_obj); |
| 3390 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 3391 | |
| 3375 | 3392 | file.status = .success_air; |
| 3376 | 3393 | } |
| 3377 | 3394 | |
| ... | ... | @@ -4319,23 +4336,17 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b |
| 4319 | 4336 | } |
| 4320 | 4337 | } |
| 4321 | 4338 | |
| 4322 | | pub fn createAnonymousDecl( |
| 4323 | | mod: *Module, |
| 4324 | | scope: *Scope, |
| 4325 | | decl_arena: *std.heap.ArenaAllocator, |
| 4326 | | typed_value: TypedValue, |
| 4327 | | ) !*Decl { |
| 4339 | pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { |
| 4328 | 4340 | const name_index = mod.getNextAnonNameIndex(); |
| 4329 | 4341 | const scope_decl = scope.ownerDecl().?; |
| 4342 | const namespace = scope_decl.namespace; |
| 4343 | try namespace.decls.ensureCapacity(mod.gpa, namespace.decls.count() + 1); |
| 4330 | 4344 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index }); |
| 4331 | 4345 | errdefer mod.gpa.free(name); |
| 4332 | | const namespace = scope_decl.namespace; |
| 4333 | 4346 | const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node); |
| 4334 | | new_decl.name = name; |
| 4347 | namespace.decls.putAssumeCapacityNoClobber(name, new_decl); |
| 4335 | 4348 | |
| 4336 | | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); |
| 4337 | | |
| 4338 | | decl_arena_state.* = decl_arena.state; |
| 4349 | new_decl.name = name; |
| 4339 | 4350 | new_decl.ty = typed_value.ty; |
| 4340 | 4351 | new_decl.val = typed_value.val; |
| 4341 | 4352 | new_decl.has_tv = true; |