| ... | @@ -276,11 +276,16 @@ pub const Decl = struct { | ... | @@ -276,11 +276,16 @@ pub const Decl = struct { |
| 276 | | 276 | |
| 277 | pub fn destroy(decl: *Decl, module: *Module) void { | 277 | pub fn destroy(decl: *Decl, module: *Module) void { |
| 278 | const gpa = module.gpa; | 278 | const gpa = module.gpa; |
| | 279 | log.debug("destroy Decl {s}", .{decl.name}); |
| 279 | decl.clearName(gpa); | 280 | decl.clearName(gpa); |
| 280 | if (decl.has_tv) { | 281 | if (decl.has_tv) { |
| 281 | if (decl.val.castTag(.function)) |payload| { | 282 | if (decl.val.castTag(.function)) |payload| { |
| 282 | const func = payload.data; | 283 | const func = payload.data; |
| 283 | func.deinit(gpa); | 284 | func.deinit(gpa); |
| | 285 | } else if (decl.val.getTypeNamespace()) |namespace| { |
| | 286 | if (namespace.getDecl() == decl) { |
| | 287 | namespace.clearDecls(module); |
| | 288 | } |
| 284 | } | 289 | } |
| 285 | decl.clearValues(gpa); | 290 | decl.clearValues(gpa); |
| 286 | } | 291 | } |
| ... | @@ -303,6 +308,13 @@ pub const Decl = struct { | ... | @@ -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 | /// This name is relative to the containing namespace of the decl. | 318 | /// This name is relative to the containing namespace of the decl. |
| 307 | /// The memory is owned by the containing File ZIR. | 319 | /// The memory is owned by the containing File ZIR. |
| 308 | pub fn getName(decl: Decl) ?[:0]const u8 { | 320 | pub fn getName(decl: Decl) ?[:0]const u8 { |
| ... | @@ -719,13 +731,20 @@ pub const Scope = struct { | ... | @@ -719,13 +731,20 @@ pub const Scope = struct { |
| 719 | decls: std.StringArrayHashMapUnmanaged(*Decl) = .{}, | 731 | decls: std.StringArrayHashMapUnmanaged(*Decl) = .{}, |
| 720 | | 732 | |
| 721 | pub fn deinit(ns: *Namespace, mod: *Module) void { | 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 | const gpa = mod.gpa; | 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 | entry.value.destroy(mod); | 745 | entry.value.destroy(mod); |
| 726 | } | 746 | } |
| 727 | ns.decls.deinit(gpa); | 747 | decls.deinit(gpa); |
| 728 | ns.* = undefined; | | |
| 729 | } | 748 | } |
| 730 | | 749 | |
| 731 | pub fn removeDecl(ns: *Namespace, child: *Decl) void { | 750 | pub fn removeDecl(ns: *Namespace, child: *Decl) void { |
| ... | @@ -775,14 +794,9 @@ pub const Scope = struct { | ... | @@ -775,14 +794,9 @@ pub const Scope = struct { |
| 775 | /// Package that this file is a part of, managed externally. | 794 | /// Package that this file is a part of, managed externally. |
| 776 | pkg: *Package, | 795 | pkg: *Package, |
| 777 | /// The namespace of the struct that represents this file. | 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 | /// Owned by its owner Decl Value. | 798 | /// Owned by its owner Decl Value. |
| 780 | namespace: *Namespace, | 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 | pub fn unload(file: *File, gpa: *Allocator) void { | 801 | pub fn unload(file: *File, gpa: *Allocator) void { |
| 788 | file.unloadTree(gpa); | 802 | file.unloadTree(gpa); |
| ... | @@ -813,6 +827,10 @@ pub const Scope = struct { | ... | @@ -813,6 +827,10 @@ pub const Scope = struct { |
| 813 | | 827 | |
| 814 | pub fn deinit(file: *File, mod: *Module) void { | 828 | pub fn deinit(file: *File, mod: *Module) void { |
| 815 | const gpa = mod.gpa; | 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 | gpa.free(file.sub_file_path); | 834 | gpa.free(file.sub_file_path); |
| 817 | file.unload(gpa); | 835 | file.unload(gpa); |
| 818 | file.* = undefined; | 836 | file.* = undefined; |
| ... | @@ -866,6 +884,18 @@ pub const Scope = struct { | ... | @@ -866,6 +884,18 @@ pub const Scope = struct { |
| 866 | gpa.destroy(file); | 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 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { | 899 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { |
| 870 | const loc = std.zig.findLineColumn(file.source.bytes, src); | 900 | const loc = std.zig.findLineColumn(file.source.bytes, src); |
| 871 | std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 }); | 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,48 +3327,49 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 3297 | assert(file.zir_loaded); | 3327 | assert(file.zir_loaded); |
| 3298 | | 3328 | |
| 3299 | const gpa = mod.gpa; | 3329 | const gpa = mod.gpa; |
| 3300 | var decl_arena = std.heap.ArenaAllocator.init(gpa); | 3330 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); |
| 3301 | defer decl_arena.deinit(); | 3331 | errdefer new_decl_arena.deinit(); |
| 3302 | | 3332 | |
| 3303 | // We need a Decl to pass to Sema and collect dependencies. But ultimately we | 3333 | const struct_obj = try new_decl_arena.allocator.create(Module.Struct); |
| 3304 | // want to pass them on to the Decl for the struct that represents the file. | 3334 | const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); |
| 3305 | var tmp_namespace: Scope.Namespace = .{ | 3335 | const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); |
| 3306 | .parent = null, | 3336 | struct_obj.* = .{ |
| 3307 | .file_scope = file, | 3337 | .owner_decl = undefined, // set below |
| 3308 | .ty = Type.initTag(.type), | 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 = .{ | 3346 | file.namespace = &struct_obj.namespace; |
| 3311 | .name = "", | 3347 | const new_decl = try mod.allocateNewDecl(&struct_obj.namespace, 0); |
| 3312 | .namespace = &tmp_namespace, | 3348 | struct_obj.owner_decl = new_decl; |
| 3313 | .generation = mod.generation, | 3349 | new_decl.name = try file.fullyQualifiedNameZ(gpa); |
| 3314 | .src_node = 0, // the root AST node for the file | 3350 | new_decl.is_pub = true; |
| 3315 | .analysis = .in_progress, | 3351 | new_decl.is_exported = false; |
| 3316 | .deletion_flag = false, | 3352 | new_decl.has_align = false; |
| 3317 | .is_pub = true, | 3353 | new_decl.has_linksection = false; |
| 3318 | .is_exported = false, | 3354 | new_decl.zir_decl_index = undefined; |
| 3319 | .has_linksection = false, | 3355 | new_decl.ty = struct_ty; |
| 3320 | .has_align = false, | 3356 | new_decl.val = struct_val; |
| 3321 | .link = undefined, // don't try to codegen this | 3357 | new_decl.has_tv = true; |
| 3322 | .fn_link = undefined, // not a function | 3358 | new_decl.analysis = .complete; |
| 3323 | .zir_decl_index = undefined, | 3359 | new_decl.generation = mod.generation; |
| 3324 | | 3360 | |
| 3325 | .has_tv = false, | 3361 | var sema_arena = std.heap.ArenaAllocator.init(gpa); |
| 3326 | .ty = undefined, | 3362 | defer sema_arena.deinit(); |
| 3327 | .val = undefined, | | |
| 3328 | .align_val = undefined, | | |
| 3329 | .linksection_val = undefined, | | |
| 3330 | }; | | |
| 3331 | defer top_decl.dependencies.deinit(gpa); | | |
| 3332 | | 3363 | |
| 3333 | var sema: Sema = .{ | 3364 | var sema: Sema = .{ |
| 3334 | .mod = mod, | 3365 | .mod = mod, |
| 3335 | .gpa = gpa, | 3366 | .gpa = gpa, |
| 3336 | .arena = &decl_arena.allocator, | 3367 | .arena = &sema_arena.allocator, |
| 3337 | .code = file.zir, | 3368 | .code = file.zir, |
| 3338 | // TODO use a map because this array is too big | 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), | 3370 | .inst_map = try sema_arena.allocator.alloc(*ir.Inst, file.zir.instructions.len), |
| 3340 | .owner_decl = &top_decl, | 3371 | .owner_decl = new_decl, |
| 3341 | .namespace = &tmp_namespace, | 3372 | .namespace = &struct_obj.namespace, |
| 3342 | .func = null, | 3373 | .func = null, |
| 3343 | .owner_func = null, | 3374 | .owner_func = null, |
| 3344 | .param_inst_list = &.{}, | 3375 | .param_inst_list = &.{}, |
| ... | @@ -3346,7 +3377,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { | ... | @@ -3346,7 +3377,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 3346 | var block_scope: Scope.Block = .{ | 3377 | var block_scope: Scope.Block = .{ |
| 3347 | .parent = null, | 3378 | .parent = null, |
| 3348 | .sema = &sema, | 3379 | .sema = &sema, |
| 3349 | .src_decl = &top_decl, | 3380 | .src_decl = new_decl, |
| 3350 | .instructions = .{}, | 3381 | .instructions = .{}, |
| 3351 | .inlining = null, | 3382 | .inlining = null, |
| 3352 | .is_comptime = true, | 3383 | .is_comptime = true, |
| ... | @@ -3355,23 +3386,9 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { | ... | @@ -3355,23 +3386,9 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 3355 | | 3386 | |
| 3356 | const main_struct_inst = file.zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] - | 3387 | const main_struct_inst = file.zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] - |
| 3357 | @intCast(u32, Zir.Inst.Ref.typed_value_map.len); | 3388 | @intCast(u32, Zir.Inst.Ref.typed_value_map.len); |
| 3358 | const air_inst = try sema.zirStructDecl(&block_scope, main_struct_inst, .Auto); | 3389 | try sema.analyzeStructDecl(&block_scope, &new_decl_arena, new_decl, main_struct_inst, .Auto, struct_obj); |
| 3359 | assert(air_inst.ty.zigTypeTag() == .Type); | 3390 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 3360 | const val = air_inst.value().?; | 3391 | |
| 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 | } | | |
| 3375 | file.status = .success_air; | 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,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( | 4339 | pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { |
| 4323 | mod: *Module, | | |
| 4324 | scope: *Scope, | | |
| 4325 | decl_arena: *std.heap.ArenaAllocator, | | |
| 4326 | typed_value: TypedValue, | | |
| 4327 | ) !*Decl { | | |
| 4328 | const name_index = mod.getNextAnonNameIndex(); | 4340 | const name_index = mod.getNextAnonNameIndex(); |
| 4329 | const scope_decl = scope.ownerDecl().?; | 4341 | const scope_decl = scope.ownerDecl().?; |
| | 4342 | const namespace = scope_decl.namespace; |
| | 4343 | try namespace.decls.ensureCapacity(mod.gpa, namespace.decls.count() + 1); |
| 4330 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index }); | 4344 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index }); |
| 4331 | errdefer mod.gpa.free(name); | 4345 | errdefer mod.gpa.free(name); |
| 4332 | const namespace = scope_decl.namespace; | | |
| 4333 | const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node); | 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); | 4349 | new_decl.name = name; |
| 4337 | | | |
| 4338 | decl_arena_state.* = decl_arena.state; | | |
| 4339 | new_decl.ty = typed_value.ty; | 4350 | new_decl.ty = typed_value.ty; |
| 4340 | new_decl.val = typed_value.val; | 4351 | new_decl.val = typed_value.val; |
| 4341 | new_decl.has_tv = true; | 4352 | new_decl.has_tv = true; |