blob bdf20649 (234527B) - Raw
1 //! Compilation of all Zig source code is represented by one `Module`. 2 //! Each `Compilation` has exactly one or zero `Module`, depending on whether 3 //! there is or is not any zig source code, respectively. 4 5 const std = @import("std"); 6 const builtin = @import("builtin"); 7 const mem = std.mem; 8 const Allocator = std.mem.Allocator; 9 const ArrayListUnmanaged = std.ArrayListUnmanaged; 10 const assert = std.debug.assert; 11 const log = std.log.scoped(.module); 12 const BigIntConst = std.math.big.int.Const; 13 const BigIntMutable = std.math.big.int.Mutable; 14 const Target = std.Target; 15 const Ast = std.zig.Ast; 16 17 const Module = @This(); 18 const Compilation = @import("Compilation.zig"); 19 const Cache = @import("Cache.zig"); 20 const Value = @import("value.zig").Value; 21 const Type = @import("type.zig").Type; 22 const TypedValue = @import("TypedValue.zig"); 23 const Package = @import("Package.zig"); 24 const link = @import("link.zig"); 25 const Air = @import("Air.zig"); 26 const Zir = @import("Zir.zig"); 27 const trace = @import("tracy.zig").trace; 28 const AstGen = @import("AstGen.zig"); 29 const Sema = @import("Sema.zig"); 30 const target_util = @import("target.zig"); 31 const build_options = @import("build_options"); 32 const Liveness = @import("Liveness.zig"); 33 34 /// General-purpose allocator. Used for both temporary and long-term storage. 35 gpa: Allocator, 36 comp: *Compilation, 37 38 /// Where build artifacts and incremental compilation metadata serialization go. 39 zig_cache_artifact_directory: Compilation.Directory, 40 /// Pointer to externally managed resource. 41 root_pkg: *Package, 42 /// Normally, `main_pkg` and `root_pkg` are the same. The exception is `zig test`, in which 43 /// `root_pkg` is the test runner, and `main_pkg` is the user's source file which has the tests. 44 main_pkg: *Package, 45 sema_prog_node: std.Progress.Node = undefined, 46 47 /// Used by AstGen worker to load and store ZIR cache. 48 global_zir_cache: Compilation.Directory, 49 /// Used by AstGen worker to load and store ZIR cache. 50 local_zir_cache: Compilation.Directory, 51 /// It's rare for a decl to be exported, so we save memory by having a sparse 52 /// map of Decl indexes to details about them being exported. 53 /// The Export memory is owned by the `export_owners` table; the slice itself 54 /// is owned by this table. The slice is guaranteed to not be empty. 55 decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, []*Export) = .{}, 56 /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl 57 /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that 58 /// is performing the export of another Decl. 59 /// This table owns the Export memory. 60 export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, []*Export) = .{}, 61 /// The set of all the Zig source files in the Module. We keep track of this in order 62 /// to iterate over it and check which source files have been modified on the file system when 63 /// an update is requested, as well as to cache `@import` results. 64 /// Keys are fully resolved file paths. This table owns the keys and values. 65 import_table: std.StringArrayHashMapUnmanaged(*File) = .{}, 66 /// The set of all the files which have been loaded with `@embedFile` in the Module. 67 /// We keep track of this in order to iterate over it and check which files have been 68 /// modified on the file system when an update is requested, as well as to cache 69 /// `@embedFile` results. 70 /// Keys are fully resolved file paths. This table owns the keys and values. 71 embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{}, 72 73 /// This is a temporary addition to stage2 in order to match stage1 behavior, 74 /// however the end-game once the lang spec is settled will be to use a global 75 /// InternPool for comptime memoized objects, making this behavior consistent across all types, 76 /// not only string literals. Or, we might decide to not guarantee string literals 77 /// to have equal comptime pointers, in which case this field can be deleted (perhaps 78 /// the commit that introduced it can simply be reverted). 79 /// This table uses an optional index so that when a Decl is destroyed, the string literal 80 /// is still reclaimable by a future Decl. 81 string_literal_table: std.HashMapUnmanaged(StringLiteralContext.Key, Decl.OptionalIndex, StringLiteralContext, std.hash_map.default_max_load_percentage) = .{}, 82 string_literal_bytes: std.ArrayListUnmanaged(u8) = .{}, 83 84 /// The set of all the generic function instantiations. This is used so that when a generic 85 /// function is called twice with the same comptime parameter arguments, both calls dispatch 86 /// to the same function. 87 /// TODO: remove functions from this set when they are destroyed. 88 monomorphed_funcs: MonomorphedFuncsSet = .{}, 89 /// The set of all comptime function calls that have been cached so that future calls 90 /// with the same parameters will get the same return value. 91 memoized_calls: MemoizedCallSet = .{}, 92 /// Contains the values from `@setAlignStack`. A sparse table is used here 93 /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while 94 /// functions are many. 95 /// TODO: remove functions from this set when they are destroyed. 96 align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{}, 97 98 /// We optimize memory usage for a compilation with no compile errors by storing the 99 /// error messages and mapping outside of `Decl`. 100 /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator. 101 /// Note that a Decl can succeed but the Fn it represents can fail. In this case, 102 /// a Decl can have a failed_decls entry but have analysis status of success. 103 failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{}, 104 /// Keep track of one `@compileLog` callsite per owner Decl. 105 /// The value is the AST node index offset from the Decl. 106 compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, i32) = .{}, 107 /// Using a map here for consistency with the other fields here. 108 /// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator. 109 failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{}, 110 /// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator. 111 failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{}, 112 /// Using a map here for consistency with the other fields here. 113 /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. 114 failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, 115 116 /// Candidates for deletion. After a semantic analysis update completes, this list 117 /// contains Decls that need to be deleted if they end up having no references to them. 118 deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 119 120 /// Error tags and their values, tag names are duped with mod.gpa. 121 /// Corresponds with `error_name_list`. 122 global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, 123 124 /// ErrorInt -> []const u8 for fast lookups for @intToError at comptime 125 /// Corresponds with `global_error_set`. 126 error_name_list: ArrayListUnmanaged([]const u8), 127 128 /// Incrementing integer used to compare against the corresponding Decl 129 /// field to determine whether a Decl's status applies to an ongoing update, or a 130 /// previous analysis. 131 generation: u32 = 0, 132 133 stage1_flags: packed struct { 134 have_winmain: bool = false, 135 have_wwinmain: bool = false, 136 have_winmain_crt_startup: bool = false, 137 have_wwinmain_crt_startup: bool = false, 138 have_dllmain_crt_startup: bool = false, 139 have_c_main: bool = false, 140 reserved: u2 = 0, 141 } = .{}, 142 143 job_queued_update_builtin_zig: bool = true, 144 /// This makes it so that we can run `zig test` on the standard library. 145 /// Otherwise, the logic for scanning test decls skips all of them because 146 /// `main_pkg != std_pkg`. 147 main_pkg_in_std: bool, 148 149 compile_log_text: ArrayListUnmanaged(u8) = .{}, 150 151 emit_h: ?*GlobalEmitH, 152 153 test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 154 155 /// Rather than allocating Decl objects with an Allocator, we instead allocate 156 /// them with this SegmentedList. This provides four advantages: 157 /// * Stable memory so that one thread can access a Decl object while another 158 /// thread allocates additional Decl objects from this list. 159 /// * It allows us to use u32 indexes to reference Decl objects rather than 160 /// pointers, saving memory in Type, Value, and dependency sets. 161 /// * Using integers to reference Decl objects rather than pointers makes 162 /// serialization trivial. 163 /// * It provides a unique integer to be used for anonymous symbol names, avoiding 164 /// multi-threaded contention on an atomic counter. 165 allocated_decls: std.SegmentedList(Decl, 0) = .{}, 166 /// When a Decl object is freed from `allocated_decls`, it is pushed into this stack. 167 decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{}, 168 169 global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, 170 171 pub const StringLiteralContext = struct { 172 bytes: *std.ArrayListUnmanaged(u8), 173 174 pub const Key = struct { 175 index: u32, 176 len: u32, 177 }; 178 179 pub fn eql(self: @This(), a: Key, b: Key) bool { 180 _ = self; 181 return a.index == b.index and a.len == b.len; 182 } 183 184 pub fn hash(self: @This(), x: Key) u64 { 185 const x_slice = self.bytes.items[x.index..][0..x.len]; 186 return std.hash_map.hashString(x_slice); 187 } 188 }; 189 190 pub const StringLiteralAdapter = struct { 191 bytes: *std.ArrayListUnmanaged(u8), 192 193 pub fn eql(self: @This(), a_slice: []const u8, b: StringLiteralContext.Key) bool { 194 const b_slice = self.bytes.items[b.index..][0..b.len]; 195 return mem.eql(u8, a_slice, b_slice); 196 } 197 198 pub fn hash(self: @This(), adapted_key: []const u8) u64 { 199 _ = self; 200 return std.hash_map.hashString(adapted_key); 201 } 202 }; 203 204 const MonomorphedFuncsSet = std.HashMapUnmanaged( 205 *Fn, 206 void, 207 MonomorphedFuncsContext, 208 std.hash_map.default_max_load_percentage, 209 ); 210 211 const MonomorphedFuncsContext = struct { 212 pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool { 213 _ = ctx; 214 return a == b; 215 } 216 217 /// Must match `Sema.GenericCallAdapter.hash`. 218 pub fn hash(ctx: @This(), key: *Fn) u64 { 219 _ = ctx; 220 return key.hash; 221 } 222 }; 223 224 pub const WipAnalysis = struct { 225 sema: *Sema, 226 block: *Sema.Block, 227 src: Module.LazySrcLoc, 228 }; 229 230 pub const MemoizedCallSet = std.HashMapUnmanaged( 231 MemoizedCall.Key, 232 MemoizedCall.Result, 233 MemoizedCall, 234 std.hash_map.default_max_load_percentage, 235 ); 236 237 pub const MemoizedCall = struct { 238 module: *Module, 239 240 pub const Key = struct { 241 func: *Fn, 242 args: []TypedValue, 243 }; 244 245 pub const Result = struct { 246 val: Value, 247 arena: std.heap.ArenaAllocator.State, 248 }; 249 250 pub fn eql(ctx: @This(), a: Key, b: Key) bool { 251 if (a.func != b.func) return false; 252 253 assert(a.args.len == b.args.len); 254 for (a.args) |a_arg, arg_i| { 255 const b_arg = b.args[arg_i]; 256 if (!a_arg.eql(b_arg, ctx.module)) { 257 return false; 258 } 259 } 260 261 return true; 262 } 263 264 /// Must match `Sema.GenericCallAdapter.hash`. 265 pub fn hash(ctx: @This(), key: Key) u64 { 266 var hasher = std.hash.Wyhash.init(0); 267 268 // The generic function Decl is guaranteed to be the first dependency 269 // of each of its instantiations. 270 std.hash.autoHash(&hasher, key.func); 271 272 // This logic must be kept in sync with the logic in `analyzeCall` that 273 // computes the hash. 274 for (key.args) |arg| { 275 arg.hash(&hasher, ctx.module); 276 } 277 278 return hasher.final(); 279 } 280 }; 281 282 pub const SetAlignStack = struct { 283 alignment: u32, 284 /// TODO: This needs to store a non-lazy source location for the case of an inline function 285 /// which does `@setAlignStack` (applying it to the caller). 286 src: LazySrcLoc, 287 }; 288 289 /// A `Module` has zero or one of these depending on whether `-femit-h` is enabled. 290 pub const GlobalEmitH = struct { 291 /// Where to put the output. 292 loc: Compilation.EmitLoc, 293 /// When emit_h is non-null, each Decl gets one more compile error slot for 294 /// emit-h failing for that Decl. This table is also how we tell if a Decl has 295 /// failed emit-h or succeeded. 296 failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{}, 297 /// Tracks all decls in order to iterate over them and emit .h code for them. 298 decl_table: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 299 /// Similar to the allocated_decls field of Module, this is where `EmitH` objects 300 /// are allocated. There will be exactly one EmitH object per Decl object, with 301 /// identical indexes. 302 allocated_emit_h: std.SegmentedList(EmitH, 0) = .{}, 303 304 pub fn declPtr(global_emit_h: *GlobalEmitH, decl_index: Decl.Index) *EmitH { 305 return global_emit_h.allocated_emit_h.at(@enumToInt(decl_index)); 306 } 307 }; 308 309 pub const ErrorInt = u32; 310 311 pub const Export = struct { 312 options: std.builtin.ExportOptions, 313 src: LazySrcLoc, 314 /// Represents the position of the export, if any, in the output file. 315 link: link.File.Export, 316 /// The Decl that performs the export. Note that this is *not* the Decl being exported. 317 owner_decl: Decl.Index, 318 /// The Decl containing the export statement. Inline function calls 319 /// may cause this to be different from the owner_decl. 320 src_decl: Decl.Index, 321 /// The Decl being exported. Note this is *not* the Decl performing the export. 322 exported_decl: Decl.Index, 323 status: enum { 324 in_progress, 325 failed, 326 /// Indicates that the failure was due to a temporary issue, such as an I/O error 327 /// when writing to the output file. Retrying the export may succeed. 328 failed_retryable, 329 complete, 330 }, 331 332 pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc { 333 const src_decl = mod.declPtr(exp.src_decl); 334 return .{ 335 .file_scope = src_decl.getFileScope(), 336 .parent_decl_node = src_decl.src_node, 337 .lazy = exp.src, 338 }; 339 } 340 }; 341 342 pub const CaptureScope = struct { 343 parent: ?*CaptureScope, 344 345 /// Values from this decl's evaluation that will be closed over in 346 /// child decls. Values stored in the value_arena of the linked decl. 347 /// During sema, this map is backed by the gpa. Once sema completes, 348 /// it is reallocated using the value_arena. 349 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{}, 350 }; 351 352 pub const WipCaptureScope = struct { 353 scope: *CaptureScope, 354 finalized: bool, 355 gpa: Allocator, 356 perm_arena: Allocator, 357 358 pub fn init(gpa: Allocator, perm_arena: Allocator, parent: ?*CaptureScope) !@This() { 359 const scope = try perm_arena.create(CaptureScope); 360 scope.* = .{ .parent = parent }; 361 return @This(){ 362 .scope = scope, 363 .finalized = false, 364 .gpa = gpa, 365 .perm_arena = perm_arena, 366 }; 367 } 368 369 pub fn finalize(noalias self: *@This()) !void { 370 assert(!self.finalized); 371 // use a temp to avoid unintentional aliasing due to RLS 372 const tmp = try self.scope.captures.clone(self.perm_arena); 373 self.scope.captures.deinit(self.gpa); 374 self.scope.captures = tmp; 375 self.finalized = true; 376 } 377 378 pub fn reset(noalias self: *@This(), parent: ?*CaptureScope) !void { 379 if (!self.finalized) try self.finalize(); 380 self.scope = try self.perm_arena.create(CaptureScope); 381 self.scope.* = .{ .parent = parent }; 382 self.finalized = false; 383 } 384 385 pub fn deinit(noalias self: *@This()) void { 386 if (!self.finalized) { 387 self.scope.captures.deinit(self.gpa); 388 } 389 self.* = undefined; 390 } 391 }; 392 393 pub const Decl = struct { 394 /// Allocated with Module's allocator; outlives the ZIR code. 395 name: [*:0]const u8, 396 /// The most recent Type of the Decl after a successful semantic analysis. 397 /// Populated when `has_tv`. 398 ty: Type, 399 /// The most recent Value of the Decl after a successful semantic analysis. 400 /// Populated when `has_tv`. 401 val: Value, 402 /// Populated when `has_tv`. 403 /// Points to memory inside value_arena. 404 @"linksection": ?[*:0]const u8, 405 /// Populated when `has_tv`. 406 @"align": u32, 407 /// Populated when `has_tv`. 408 @"addrspace": std.builtin.AddressSpace, 409 /// The memory for ty, val, align, linksection, and captures. 410 /// If this is `null` then there is no memory management needed. 411 value_arena: ?*std.heap.ArenaAllocator.State = null, 412 /// The direct parent namespace of the Decl. 413 /// Reference to externally owned memory. 414 /// In the case of the Decl corresponding to a file, this is 415 /// the namespace of the struct, since there is no parent. 416 src_namespace: *Namespace, 417 418 /// The scope which lexically contains this decl. A decl must depend 419 /// on its lexical parent, in order to ensure that this pointer is valid. 420 /// This scope is allocated out of the arena of the parent decl. 421 src_scope: ?*CaptureScope, 422 423 /// An integer that can be checked against the corresponding incrementing 424 /// generation field of Module. This is used to determine whether `complete` status 425 /// represents pre- or post- re-analysis. 426 generation: u32, 427 /// The AST node index of this declaration. 428 /// Must be recomputed when the corresponding source file is modified. 429 src_node: Ast.Node.Index, 430 /// Line number corresponding to `src_node`. Stored separately so that source files 431 /// do not need to be loaded into memory in order to compute debug line numbers. 432 /// This value is absolute. 433 src_line: u32, 434 /// Index to ZIR `extra` array to the entry in the parent's decl structure 435 /// (the part that says "for every decls_len"). The first item at this index is 436 /// the contents hash, followed by line, name, etc. 437 /// For anonymous decls and also the root Decl for a File, this is 0. 438 zir_decl_index: Zir.Inst.Index, 439 440 /// Represents the "shallow" analysis status. For example, for decls that are functions, 441 /// the function type is analyzed with this set to `in_progress`, however, the semantic 442 /// analysis of the function body is performed with this value set to `success`. Functions 443 /// have their own analysis status field. 444 analysis: enum { 445 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore 446 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced. 447 unreferenced, 448 /// Semantic analysis for this Decl is running right now. 449 /// This state detects dependency loops. 450 in_progress, 451 /// The file corresponding to this Decl had a parse error or ZIR error. 452 /// There will be a corresponding ErrorMsg in Module.failed_files. 453 file_failure, 454 /// This Decl might be OK but it depends on another one which did not successfully complete 455 /// semantic analysis. 456 dependency_failure, 457 /// Semantic analysis failure. 458 /// There will be a corresponding ErrorMsg in Module.failed_decls. 459 sema_failure, 460 /// There will be a corresponding ErrorMsg in Module.failed_decls. 461 /// This indicates the failure was something like running out of disk space, 462 /// and attempting semantic analysis again may succeed. 463 sema_failure_retryable, 464 /// There will be a corresponding ErrorMsg in Module.failed_decls. 465 codegen_failure, 466 /// There will be a corresponding ErrorMsg in Module.failed_decls. 467 /// This indicates the failure was something like running out of disk space, 468 /// and attempting codegen again may succeed. 469 codegen_failure_retryable, 470 /// Everything is done. During an update, this Decl may be out of date, depending 471 /// on its dependencies. The `generation` field can be used to determine if this 472 /// completion status occurred before or after a given update. 473 complete, 474 /// A Module update is in progress, and this Decl has been flagged as being known 475 /// to require re-analysis. 476 outdated, 477 }, 478 /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated. 479 has_tv: bool, 480 /// If `true` it means the `Decl` is the resource owner of the type/value associated 481 /// with it. That means when `Decl` is destroyed, the cleanup code should additionally 482 /// check if the value owns a `Namespace`, and destroy that too. 483 owns_tv: bool, 484 /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared 485 /// when removed. 486 deletion_flag: bool, 487 /// Whether the corresponding AST decl has a `pub` keyword. 488 is_pub: bool, 489 /// Whether the corresponding AST decl has a `export` keyword. 490 is_exported: bool, 491 /// Whether the ZIR code provides an align instruction. 492 has_align: bool, 493 /// Whether the ZIR code provides a linksection and address space instruction. 494 has_linksection_or_addrspace: bool, 495 /// Flag used by garbage collection to mark and sweep. 496 /// Decls which correspond to an AST node always have this field set to `true`. 497 /// Anonymous Decls are initialized with this field set to `false` and then it 498 /// is the responsibility of machine code backends to mark it `true` whenever 499 /// a `decl_ref` Value is encountered that points to this Decl. 500 /// When the `codegen_decl` job is encountered in the main work queue, if the 501 /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it 502 /// deletes the Decl on the spot. 503 alive: bool, 504 /// Whether the Decl is a `usingnamespace` declaration. 505 is_usingnamespace: bool, 506 507 /// Represents the position of the code in the output file. 508 /// This is populated regardless of semantic analysis and code generation. 509 link: link.File.LinkBlock, 510 511 /// Represents the function in the linked output file, if the `Decl` is a function. 512 /// This is stored here and not in `Fn` because `Decl` survives across updates but 513 /// `Fn` does not. 514 /// TODO Look into making `Fn` a longer lived structure and moving this field there 515 /// to save on memory usage. 516 fn_link: link.File.LinkFn, 517 518 /// The shallow set of other decls whose typed_value could possibly change if this Decl's 519 /// typed_value is modified. 520 dependants: DepsTable = .{}, 521 /// The shallow set of other decls whose typed_value changing indicates that this Decl's 522 /// typed_value may need to be regenerated. 523 dependencies: DepsTable = .{}, 524 525 pub const Index = enum(u32) { 526 _, 527 528 pub fn toOptional(i: Index) OptionalIndex { 529 return @intToEnum(OptionalIndex, @enumToInt(i)); 530 } 531 }; 532 533 pub const OptionalIndex = enum(u32) { 534 none = std.math.maxInt(u32), 535 _, 536 537 pub fn init(oi: ?Index) OptionalIndex { 538 return oi orelse .none; 539 } 540 541 pub fn unwrap(oi: OptionalIndex) ?Index { 542 if (oi == .none) return null; 543 return @intToEnum(Index, @enumToInt(oi)); 544 } 545 }; 546 547 pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, void); 548 549 pub fn clearName(decl: *Decl, gpa: Allocator) void { 550 gpa.free(mem.sliceTo(decl.name, 0)); 551 decl.name = undefined; 552 } 553 554 pub fn clearValues(decl: *Decl, mod: *Module) void { 555 const gpa = mod.gpa; 556 if (decl.getExternFn()) |extern_fn| { 557 extern_fn.deinit(gpa); 558 gpa.destroy(extern_fn); 559 } 560 if (decl.getFunction()) |func| { 561 func.deinit(gpa); 562 gpa.destroy(func); 563 } 564 if (decl.getVariable()) |variable| { 565 variable.deinit(gpa); 566 gpa.destroy(variable); 567 } 568 if (decl.value_arena) |arena_state| { 569 if (decl.owns_tv) { 570 if (decl.val.castTag(.str_lit)) |str_lit| { 571 mod.string_literal_table.getPtrContext(str_lit.data, .{ 572 .bytes = &mod.string_literal_bytes, 573 }).?.* = .none; 574 } 575 } 576 arena_state.promote(gpa).deinit(); 577 decl.value_arena = null; 578 decl.has_tv = false; 579 decl.owns_tv = false; 580 } 581 } 582 583 pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void { 584 assert(decl.value_arena == null); 585 const arena_state = try arena.allocator().create(std.heap.ArenaAllocator.State); 586 arena_state.* = arena.state; 587 decl.value_arena = arena_state; 588 } 589 590 /// This name is relative to the containing namespace of the decl. 591 /// The memory is owned by the containing File ZIR. 592 pub fn getName(decl: Decl) ?[:0]const u8 { 593 const zir = decl.getFileScope().zir; 594 return decl.getNameZir(zir); 595 } 596 597 pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 { 598 assert(decl.zir_decl_index != 0); 599 const name_index = zir.extra[decl.zir_decl_index + 5]; 600 if (name_index <= 1) return null; 601 return zir.nullTerminatedString(name_index); 602 } 603 604 pub fn contentsHash(decl: Decl) std.zig.SrcHash { 605 const zir = decl.getFileScope().zir; 606 return decl.contentsHashZir(zir); 607 } 608 609 pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash { 610 assert(decl.zir_decl_index != 0); 611 const hash_u32s = zir.extra[decl.zir_decl_index..][0..4]; 612 const contents_hash = @bitCast(std.zig.SrcHash, hash_u32s.*); 613 return contents_hash; 614 } 615 616 pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index { 617 assert(decl.zir_decl_index != 0); 618 const zir = decl.getFileScope().zir; 619 return zir.extra[decl.zir_decl_index + 6]; 620 } 621 622 pub fn zirAlignRef(decl: Decl) Zir.Inst.Ref { 623 if (!decl.has_align) return .none; 624 assert(decl.zir_decl_index != 0); 625 const zir = decl.getFileScope().zir; 626 return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 8]); 627 } 628 629 pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref { 630 if (!decl.has_linksection_or_addrspace) return .none; 631 assert(decl.zir_decl_index != 0); 632 const zir = decl.getFileScope().zir; 633 const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align); 634 return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 635 } 636 637 pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref { 638 if (!decl.has_linksection_or_addrspace) return .none; 639 assert(decl.zir_decl_index != 0); 640 const zir = decl.getFileScope().zir; 641 const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align) + 1; 642 return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); 643 } 644 645 pub fn relativeToLine(decl: Decl, offset: u32) u32 { 646 return decl.src_line + offset; 647 } 648 649 pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index { 650 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, decl.src_node)); 651 } 652 653 pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 { 654 return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node); 655 } 656 657 pub fn tokSrcLoc(decl: Decl, token_index: Ast.TokenIndex) LazySrcLoc { 658 return .{ .token_offset = token_index - decl.srcToken() }; 659 } 660 661 pub fn nodeSrcLoc(decl: Decl, node_index: Ast.Node.Index) LazySrcLoc { 662 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); 663 } 664 665 pub fn srcLoc(decl: Decl) SrcLoc { 666 return decl.nodeOffsetSrcLoc(0); 667 } 668 669 pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32) SrcLoc { 670 return .{ 671 .file_scope = decl.getFileScope(), 672 .parent_decl_node = decl.src_node, 673 .lazy = LazySrcLoc.nodeOffset(node_offset), 674 }; 675 } 676 677 pub fn srcToken(decl: Decl) Ast.TokenIndex { 678 const tree = &decl.getFileScope().tree; 679 return tree.firstToken(decl.src_node); 680 } 681 682 pub fn srcByteOffset(decl: Decl) u32 { 683 const tree = &decl.getFileScope().tree; 684 return tree.tokens.items(.start)[decl.srcToken()]; 685 } 686 687 pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { 688 const unqualified_name = mem.sliceTo(decl.name, 0); 689 return decl.src_namespace.renderFullyQualifiedName(mod, unqualified_name, writer); 690 } 691 692 pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { 693 const unqualified_name = mem.sliceTo(decl.name, 0); 694 return decl.src_namespace.renderFullyQualifiedDebugName(mod, unqualified_name, writer); 695 } 696 697 pub fn getFullyQualifiedName(decl: Decl, mod: *Module) ![:0]u8 { 698 var buffer = std.ArrayList(u8).init(mod.gpa); 699 defer buffer.deinit(); 700 try decl.renderFullyQualifiedName(mod, buffer.writer()); 701 return buffer.toOwnedSliceSentinel(0); 702 } 703 704 pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { 705 if (!decl.has_tv) return error.AnalysisFail; 706 return TypedValue{ 707 .ty = decl.ty, 708 .val = decl.val, 709 }; 710 } 711 712 pub fn value(decl: *Decl) error{AnalysisFail}!Value { 713 return (try decl.typedValue()).val; 714 } 715 716 pub fn isFunction(decl: Decl) !bool { 717 const tv = try decl.typedValue(); 718 return tv.ty.zigTypeTag() == .Fn; 719 } 720 721 /// If the Decl has a value and it is a struct, return it, 722 /// otherwise null. 723 pub fn getStruct(decl: *Decl) ?*Struct { 724 if (!decl.owns_tv) return null; 725 const ty = (decl.val.castTag(.ty) orelse return null).data; 726 const struct_obj = (ty.castTag(.@"struct") orelse return null).data; 727 return struct_obj; 728 } 729 730 /// If the Decl has a value and it is a union, return it, 731 /// otherwise null. 732 pub fn getUnion(decl: *Decl) ?*Union { 733 if (!decl.owns_tv) return null; 734 const ty = (decl.val.castTag(.ty) orelse return null).data; 735 const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; 736 return union_obj; 737 } 738 739 /// If the Decl has a value and it is a function, return it, 740 /// otherwise null. 741 pub fn getFunction(decl: *const Decl) ?*Fn { 742 if (!decl.owns_tv) return null; 743 const func = (decl.val.castTag(.function) orelse return null).data; 744 return func; 745 } 746 747 /// If the Decl has a value and it is an extern function, returns it, 748 /// otherwise null. 749 pub fn getExternFn(decl: *const Decl) ?*ExternFn { 750 if (!decl.owns_tv) return null; 751 const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data; 752 return extern_fn; 753 } 754 755 /// If the Decl has a value and it is a variable, returns it, 756 /// otherwise null. 757 pub fn getVariable(decl: *const Decl) ?*Var { 758 if (!decl.owns_tv) return null; 759 const variable = (decl.val.castTag(.variable) orelse return null).data; 760 return variable; 761 } 762 763 /// Gets the namespace that this Decl creates by being a struct, union, 764 /// enum, or opaque. 765 /// Only returns it if the Decl is the owner. 766 pub fn getInnerNamespace(decl: *Decl) ?*Namespace { 767 if (!decl.owns_tv) return null; 768 const ty = (decl.val.castTag(.ty) orelse return null).data; 769 switch (ty.tag()) { 770 .@"struct" => { 771 const struct_obj = ty.castTag(.@"struct").?.data; 772 return &struct_obj.namespace; 773 }, 774 .enum_full, .enum_nonexhaustive => { 775 const enum_obj = ty.cast(Type.Payload.EnumFull).?.data; 776 return &enum_obj.namespace; 777 }, 778 .empty_struct => { 779 return ty.castTag(.empty_struct).?.data; 780 }, 781 .@"opaque" => { 782 const opaque_obj = ty.cast(Type.Payload.Opaque).?.data; 783 return &opaque_obj.namespace; 784 }, 785 .@"union", .union_tagged => { 786 const union_obj = ty.cast(Type.Payload.Union).?.data; 787 return &union_obj.namespace; 788 }, 789 790 else => return null, 791 } 792 } 793 794 pub fn dump(decl: *Decl) void { 795 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); 796 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{ 797 decl.scope.sub_file_path, 798 loc.line + 1, 799 loc.column + 1, 800 mem.sliceTo(decl.name, 0), 801 @tagName(decl.analysis), 802 }); 803 if (decl.has_tv) { 804 std.debug.print(" ty={} val={}", .{ decl.ty, decl.val }); 805 } 806 std.debug.print("\n", .{}); 807 } 808 809 pub fn getFileScope(decl: Decl) *File { 810 return decl.src_namespace.file_scope; 811 } 812 813 pub fn removeDependant(decl: *Decl, other: Decl.Index) void { 814 assert(decl.dependants.swapRemove(other)); 815 } 816 817 pub fn removeDependency(decl: *Decl, other: Decl.Index) void { 818 assert(decl.dependencies.swapRemove(other)); 819 } 820 821 pub fn isExtern(decl: Decl) bool { 822 assert(decl.has_tv); 823 return switch (decl.val.tag()) { 824 .extern_fn => true, 825 .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value, 826 else => false, 827 }; 828 } 829 830 pub fn getAlignment(decl: Decl, target: Target) u32 { 831 assert(decl.has_tv); 832 if (decl.@"align" != 0) { 833 // Explicit alignment. 834 return decl.@"align"; 835 } else { 836 // Natural alignment. 837 return decl.ty.abiAlignment(target); 838 } 839 } 840 }; 841 842 /// This state is attached to every Decl when Module emit_h is non-null. 843 pub const EmitH = struct { 844 fwd_decl: ArrayListUnmanaged(u8) = .{}, 845 }; 846 847 /// Represents the data that an explicit error set syntax provides. 848 pub const ErrorSet = struct { 849 /// The Decl that corresponds to the error set itself. 850 owner_decl: Decl.Index, 851 /// Offset from Decl node index, points to the error set AST node. 852 node_offset: i32, 853 /// The string bytes are stored in the owner Decl arena. 854 /// These must be in sorted order. See sortNames. 855 names: NameMap, 856 857 pub const NameMap = std.StringArrayHashMapUnmanaged(void); 858 859 pub fn srcLoc(self: ErrorSet, mod: *Module) SrcLoc { 860 const owner_decl = mod.declPtr(self.owner_decl); 861 return .{ 862 .file_scope = owner_decl.getFileScope(), 863 .parent_decl_node = owner_decl.src_node, 864 .lazy = LazySrcLoc.nodeOffset(self.node_offset), 865 }; 866 } 867 868 /// sort the NameMap. This should be called whenever the map is modified. 869 /// alloc should be the allocator used for the NameMap data. 870 pub fn sortNames(names: *NameMap) void { 871 const Context = struct { 872 keys: [][]const u8, 873 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { 874 return std.mem.lessThan(u8, ctx.keys[a_index], ctx.keys[b_index]); 875 } 876 }; 877 names.sort(Context{ .keys = names.keys() }); 878 } 879 }; 880 881 pub const PropertyBoolean = enum { no, yes, unknown, wip }; 882 883 /// Represents the data that a struct declaration provides. 884 pub const Struct = struct { 885 /// Set of field names in declaration order. 886 fields: Fields, 887 /// Represents the declarations inside this struct. 888 namespace: Namespace, 889 /// The Decl that corresponds to the struct itself. 890 owner_decl: Decl.Index, 891 /// Offset from `owner_decl`, points to the struct AST node. 892 node_offset: i32, 893 /// Index of the struct_decl ZIR instruction. 894 zir_index: Zir.Inst.Index, 895 896 layout: std.builtin.Type.ContainerLayout, 897 status: enum { 898 none, 899 field_types_wip, 900 have_field_types, 901 layout_wip, 902 have_layout, 903 fully_resolved_wip, 904 // The types and all its fields have had their layout resolved. Even through pointer, 905 // which `have_layout` does not ensure. 906 fully_resolved, 907 }, 908 /// If true, has more than one possible value. However it may still be non-runtime type 909 /// if it is a comptime-only type. 910 /// If false, resolving the fields is necessary to determine whether the type has only 911 /// one possible value. 912 known_non_opv: bool, 913 requires_comptime: PropertyBoolean = .unknown, 914 915 pub const Fields = std.StringArrayHashMapUnmanaged(Field); 916 917 /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. 918 pub const Field = struct { 919 /// Uses `noreturn` to indicate `anytype`. 920 /// undefined until `status` is `have_field_types` or `have_layout`. 921 ty: Type, 922 /// Uses `unreachable_value` to indicate no default. 923 default_val: Value, 924 /// Zero means to use the ABI alignment of the type. 925 abi_align: u32, 926 /// undefined until `status` is `have_layout`. 927 offset: u32, 928 /// If true then `default_val` is the comptime field value. 929 is_comptime: bool, 930 931 /// Returns the field alignment, assuming the struct is not packed. 932 pub fn normalAlignment(field: Field, target: Target) u32 { 933 if (field.abi_align == 0) { 934 return field.ty.abiAlignment(target); 935 } else { 936 return field.abi_align; 937 } 938 } 939 }; 940 941 pub fn getFullyQualifiedName(s: *Struct, mod: *Module) ![:0]u8 { 942 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); 943 } 944 945 pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { 946 const owner_decl = mod.declPtr(s.owner_decl); 947 return .{ 948 .file_scope = owner_decl.getFileScope(), 949 .parent_decl_node = owner_decl.src_node, 950 .lazy = LazySrcLoc.nodeOffset(s.node_offset), 951 }; 952 } 953 954 pub fn fieldSrcLoc(s: Struct, mod: *Module, query: FieldSrcQuery) SrcLoc { 955 @setCold(true); 956 const owner_decl = mod.declPtr(s.owner_decl); 957 const file = owner_decl.getFileScope(); 958 const tree = file.getTree(mod.gpa) catch |err| { 959 // In this case we emit a warning + a less precise source location. 960 log.warn("unable to load {s}: {s}", .{ 961 file.sub_file_path, @errorName(err), 962 }); 963 return s.srcLoc(mod); 964 }; 965 const node = owner_decl.relativeToNodeIndex(s.node_offset); 966 const node_tags = tree.nodes.items(.tag); 967 switch (node_tags[node]) { 968 .container_decl, 969 .container_decl_trailing, 970 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)), 971 .container_decl_two, .container_decl_two_trailing => { 972 var buffer: [2]Ast.Node.Index = undefined; 973 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node)); 974 }, 975 .container_decl_arg, 976 .container_decl_arg_trailing, 977 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)), 978 979 .tagged_union, 980 .tagged_union_trailing, 981 => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)), 982 .tagged_union_two, .tagged_union_two_trailing => { 983 var buffer: [2]Ast.Node.Index = undefined; 984 return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node)); 985 }, 986 .tagged_union_enum_tag, 987 .tagged_union_enum_tag_trailing, 988 => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)), 989 990 .root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()), 991 992 else => unreachable, 993 } 994 } 995 996 pub fn haveFieldTypes(s: Struct) bool { 997 return switch (s.status) { 998 .none, 999 .field_types_wip, 1000 => false, 1001 .have_field_types, 1002 .layout_wip, 1003 .have_layout, 1004 .fully_resolved_wip, 1005 .fully_resolved, 1006 => true, 1007 }; 1008 } 1009 1010 pub fn haveLayout(s: Struct) bool { 1011 return switch (s.status) { 1012 .none, 1013 .field_types_wip, 1014 .have_field_types, 1015 .layout_wip, 1016 => false, 1017 .have_layout, 1018 .fully_resolved_wip, 1019 .fully_resolved, 1020 => true, 1021 }; 1022 } 1023 1024 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 { 1025 assert(s.layout == .Packed); 1026 assert(s.haveFieldTypes()); 1027 var bit_sum: u64 = 0; 1028 for (s.fields.values()) |field, i| { 1029 if (i == index) { 1030 return @intCast(u16, bit_sum); 1031 } 1032 bit_sum += field.ty.bitSize(target); 1033 } 1034 return @intCast(u16, bit_sum); 1035 } 1036 1037 pub fn packedIntegerBits(s: Struct, target: Target) u16 { 1038 return s.packedFieldBitOffset(target, s.fields.count()); 1039 } 1040 1041 pub fn packedIntegerType(s: Struct, target: Target, buf: *Type.Payload.Bits) Type { 1042 buf.* = .{ 1043 .base = .{ .tag = .int_unsigned }, 1044 .data = s.packedIntegerBits(target), 1045 }; 1046 return Type.initPayload(&buf.base); 1047 } 1048 }; 1049 1050 /// Represents the data that an enum declaration provides, when the fields 1051 /// are auto-numbered, and there are no declarations. The integer tag type 1052 /// is inferred to be the smallest power of two unsigned int that fits 1053 /// the number of fields. 1054 pub const EnumSimple = struct { 1055 /// The Decl that corresponds to the enum itself. 1056 owner_decl: Decl.Index, 1057 /// Offset from `owner_decl`, points to the enum decl AST node. 1058 node_offset: i32, 1059 /// Set of field names in declaration order. 1060 fields: NameMap, 1061 1062 pub const NameMap = EnumFull.NameMap; 1063 1064 pub fn srcLoc(self: EnumSimple, mod: *Module) SrcLoc { 1065 const owner_decl = mod.declPtr(self.owner_decl); 1066 return .{ 1067 .file_scope = owner_decl.getFileScope(), 1068 .parent_decl_node = owner_decl.src_node, 1069 .lazy = LazySrcLoc.nodeOffset(self.node_offset), 1070 }; 1071 } 1072 }; 1073 1074 /// Represents the data that an enum declaration provides, when there are no 1075 /// declarations. However an integer tag type is provided, and the enum tag values 1076 /// are explicitly provided. 1077 pub const EnumNumbered = struct { 1078 /// The Decl that corresponds to the enum itself. 1079 owner_decl: Decl.Index, 1080 /// Offset from `owner_decl`, points to the enum decl AST node. 1081 node_offset: i32, 1082 /// An integer type which is used for the numerical value of the enum. 1083 /// Whether zig chooses this type or the user specifies it, it is stored here. 1084 tag_ty: Type, 1085 /// Set of field names in declaration order. 1086 fields: NameMap, 1087 /// Maps integer tag value to field index. 1088 /// Entries are in declaration order, same as `fields`. 1089 /// If this hash map is empty, it means the enum tags are auto-numbered. 1090 values: ValueMap, 1091 1092 pub const NameMap = EnumFull.NameMap; 1093 pub const ValueMap = EnumFull.ValueMap; 1094 1095 pub fn srcLoc(self: EnumNumbered, mod: *Module) SrcLoc { 1096 const owner_decl = mod.declPtr(self.owner_decl); 1097 return .{ 1098 .file_scope = owner_decl.getFileScope(), 1099 .parent_decl_node = owner_decl.src_node, 1100 .lazy = LazySrcLoc.nodeOffset(self.node_offset), 1101 }; 1102 } 1103 }; 1104 1105 /// Represents the data that an enum declaration provides, when there is 1106 /// at least one tag value explicitly specified, or at least one declaration. 1107 pub const EnumFull = struct { 1108 /// The Decl that corresponds to the enum itself. 1109 owner_decl: Decl.Index, 1110 /// Offset from `owner_decl`, points to the enum decl AST node. 1111 node_offset: i32, 1112 /// An integer type which is used for the numerical value of the enum. 1113 /// Whether zig chooses this type or the user specifies it, it is stored here. 1114 tag_ty: Type, 1115 /// Set of field names in declaration order. 1116 fields: NameMap, 1117 /// Maps integer tag value to field index. 1118 /// Entries are in declaration order, same as `fields`. 1119 /// If this hash map is empty, it means the enum tags are auto-numbered. 1120 values: ValueMap, 1121 /// Represents the declarations inside this enum. 1122 namespace: Namespace, 1123 /// true if zig inferred this tag type, false if user specified it 1124 tag_ty_inferred: bool, 1125 1126 pub const NameMap = std.StringArrayHashMapUnmanaged(void); 1127 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false); 1128 1129 pub fn srcLoc(self: EnumFull, mod: *Module) SrcLoc { 1130 const owner_decl = mod.declPtr(self.owner_decl); 1131 return .{ 1132 .file_scope = owner_decl.getFileScope(), 1133 .parent_decl_node = owner_decl.src_node, 1134 .lazy = LazySrcLoc.nodeOffset(self.node_offset), 1135 }; 1136 } 1137 }; 1138 1139 pub const Union = struct { 1140 /// An enum type which is used for the tag of the union. 1141 /// This type is created even for untagged unions, even when the memory 1142 /// layout does not store the tag. 1143 /// Whether zig chooses this type or the user specifies it, it is stored here. 1144 /// This will be set to the null type until status is `have_field_types`. 1145 tag_ty: Type, 1146 /// Set of field names in declaration order. 1147 fields: Fields, 1148 /// Represents the declarations inside this union. 1149 namespace: Namespace, 1150 /// The Decl that corresponds to the union itself. 1151 owner_decl: Decl.Index, 1152 /// Offset from `owner_decl`, points to the union decl AST node. 1153 node_offset: i32, 1154 /// Index of the union_decl ZIR instruction. 1155 zir_index: Zir.Inst.Index, 1156 1157 layout: std.builtin.Type.ContainerLayout, 1158 status: enum { 1159 none, 1160 field_types_wip, 1161 have_field_types, 1162 layout_wip, 1163 have_layout, 1164 fully_resolved_wip, 1165 // The types and all its fields have had their layout resolved. Even through pointer, 1166 // which `have_layout` does not ensure. 1167 fully_resolved, 1168 }, 1169 requires_comptime: PropertyBoolean = .unknown, 1170 1171 pub const Field = struct { 1172 /// undefined until `status` is `have_field_types` or `have_layout`. 1173 ty: Type, 1174 /// 0 means the ABI alignment of the type. 1175 abi_align: u32, 1176 1177 /// Returns the field alignment, assuming the union is not packed. 1178 /// Keep implementation in sync with `Sema.unionFieldAlignment`. 1179 /// Prefer to call that function instead of this one during Sema. 1180 pub fn normalAlignment(field: Field, target: Target) u32 { 1181 if (field.abi_align == 0) { 1182 return field.ty.abiAlignment(target); 1183 } else { 1184 return field.abi_align; 1185 } 1186 } 1187 }; 1188 1189 pub const Fields = std.StringArrayHashMapUnmanaged(Field); 1190 1191 pub fn getFullyQualifiedName(s: *Union, mod: *Module) ![:0]u8 { 1192 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); 1193 } 1194 1195 pub fn srcLoc(self: Union, mod: *Module) SrcLoc { 1196 const owner_decl = mod.declPtr(self.owner_decl); 1197 return .{ 1198 .file_scope = owner_decl.getFileScope(), 1199 .parent_decl_node = owner_decl.src_node, 1200 .lazy = LazySrcLoc.nodeOffset(self.node_offset), 1201 }; 1202 } 1203 1204 pub fn fieldSrcLoc(u: Union, mod: *Module, query: FieldSrcQuery) SrcLoc { 1205 @setCold(true); 1206 const owner_decl = mod.declPtr(u.owner_decl); 1207 const file = owner_decl.getFileScope(); 1208 const tree = file.getTree(mod.gpa) catch |err| { 1209 // In this case we emit a warning + a less precise source location. 1210 log.warn("unable to load {s}: {s}", .{ 1211 file.sub_file_path, @errorName(err), 1212 }); 1213 return u.srcLoc(mod); 1214 }; 1215 const node = owner_decl.relativeToNodeIndex(u.node_offset); 1216 const node_tags = tree.nodes.items(.tag); 1217 switch (node_tags[node]) { 1218 .container_decl, 1219 .container_decl_trailing, 1220 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)), 1221 .container_decl_two, .container_decl_two_trailing => { 1222 var buffer: [2]Ast.Node.Index = undefined; 1223 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node)); 1224 }, 1225 .container_decl_arg, 1226 .container_decl_arg_trailing, 1227 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)), 1228 else => unreachable, 1229 } 1230 } 1231 1232 pub fn haveFieldTypes(u: Union) bool { 1233 return switch (u.status) { 1234 .none, 1235 .field_types_wip, 1236 => false, 1237 .have_field_types, 1238 .layout_wip, 1239 .have_layout, 1240 .fully_resolved_wip, 1241 .fully_resolved, 1242 => true, 1243 }; 1244 } 1245 1246 pub fn hasAllZeroBitFieldTypes(u: Union) bool { 1247 assert(u.haveFieldTypes()); 1248 for (u.fields.values()) |field| { 1249 if (field.ty.hasRuntimeBits()) return false; 1250 } 1251 return true; 1252 } 1253 1254 pub fn mostAlignedField(u: Union, target: Target) u32 { 1255 assert(u.haveFieldTypes()); 1256 var most_alignment: u32 = 0; 1257 var most_index: usize = undefined; 1258 for (u.fields.values()) |field, i| { 1259 if (!field.ty.hasRuntimeBits()) continue; 1260 1261 const field_align = field.normalAlignment(target); 1262 if (field_align > most_alignment) { 1263 most_alignment = field_align; 1264 most_index = i; 1265 } 1266 } 1267 return @intCast(u32, most_index); 1268 } 1269 1270 /// Returns 0 if the union is represented with 0 bits at runtime. 1271 pub fn abiAlignment(u: Union, target: Target, have_tag: bool) u32 { 1272 var max_align: u32 = 0; 1273 if (have_tag) max_align = u.tag_ty.abiAlignment(target); 1274 for (u.fields.values()) |field| { 1275 if (!field.ty.hasRuntimeBits()) continue; 1276 1277 const field_align = field.normalAlignment(target); 1278 max_align = @maximum(max_align, field_align); 1279 } 1280 return max_align; 1281 } 1282 1283 pub fn abiSize(u: Union, target: Target, have_tag: bool) u64 { 1284 return u.getLayout(target, have_tag).abi_size; 1285 } 1286 1287 pub const Layout = struct { 1288 abi_size: u64, 1289 abi_align: u32, 1290 most_aligned_field: u32, 1291 most_aligned_field_size: u64, 1292 biggest_field: u32, 1293 payload_size: u64, 1294 payload_align: u32, 1295 tag_align: u32, 1296 tag_size: u64, 1297 padding: u32, 1298 }; 1299 1300 pub fn haveLayout(u: Union) bool { 1301 return switch (u.status) { 1302 .none, 1303 .field_types_wip, 1304 .have_field_types, 1305 .layout_wip, 1306 => false, 1307 .have_layout, 1308 .fully_resolved_wip, 1309 .fully_resolved, 1310 => true, 1311 }; 1312 } 1313 1314 pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout { 1315 assert(u.haveLayout()); 1316 var most_aligned_field: u32 = undefined; 1317 var most_aligned_field_size: u64 = undefined; 1318 var biggest_field: u32 = undefined; 1319 var payload_size: u64 = 0; 1320 var payload_align: u32 = 0; 1321 const fields = u.fields.values(); 1322 for (fields) |field, i| { 1323 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; 1324 1325 const field_align = a: { 1326 if (field.abi_align == 0) { 1327 break :a field.ty.abiAlignment(target); 1328 } else { 1329 break :a field.abi_align; 1330 } 1331 }; 1332 const field_size = field.ty.abiSize(target); 1333 if (field_size > payload_size) { 1334 payload_size = field_size; 1335 biggest_field = @intCast(u32, i); 1336 } 1337 if (field_align > payload_align) { 1338 payload_align = field_align; 1339 most_aligned_field = @intCast(u32, i); 1340 most_aligned_field_size = field_size; 1341 } 1342 } 1343 payload_align = @maximum(payload_align, 1); 1344 if (!have_tag or fields.len <= 1) return .{ 1345 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align), 1346 .abi_align = payload_align, 1347 .most_aligned_field = most_aligned_field, 1348 .most_aligned_field_size = most_aligned_field_size, 1349 .biggest_field = biggest_field, 1350 .payload_size = payload_size, 1351 .payload_align = payload_align, 1352 .tag_align = 0, 1353 .tag_size = 0, 1354 .padding = 0, 1355 }; 1356 // Put the tag before or after the payload depending on which one's 1357 // alignment is greater. 1358 const tag_size = u.tag_ty.abiSize(target); 1359 const tag_align = @maximum(1, u.tag_ty.abiAlignment(target)); 1360 var size: u64 = 0; 1361 var padding: u32 = undefined; 1362 if (tag_align >= payload_align) { 1363 // {Tag, Payload} 1364 size += tag_size; 1365 size = std.mem.alignForwardGeneric(u64, size, payload_align); 1366 size += payload_size; 1367 const prev_size = size; 1368 size = std.mem.alignForwardGeneric(u64, size, tag_align); 1369 padding = @intCast(u32, size - prev_size); 1370 } else { 1371 // {Payload, Tag} 1372 size += payload_size; 1373 size = std.mem.alignForwardGeneric(u64, size, tag_align); 1374 size += tag_size; 1375 const prev_size = size; 1376 size = std.mem.alignForwardGeneric(u64, size, payload_align); 1377 padding = @intCast(u32, size - prev_size); 1378 } 1379 return .{ 1380 .abi_size = size, 1381 .abi_align = @maximum(tag_align, payload_align), 1382 .most_aligned_field = most_aligned_field, 1383 .most_aligned_field_size = most_aligned_field_size, 1384 .biggest_field = biggest_field, 1385 .payload_size = payload_size, 1386 .payload_align = payload_align, 1387 .tag_align = tag_align, 1388 .tag_size = tag_size, 1389 .padding = padding, 1390 }; 1391 } 1392 }; 1393 1394 pub const Opaque = struct { 1395 /// The Decl that corresponds to the opaque itself. 1396 owner_decl: Decl.Index, 1397 /// Offset from `owner_decl`, points to the opaque decl AST node. 1398 node_offset: i32, 1399 /// Represents the declarations inside this opaque. 1400 namespace: Namespace, 1401 1402 pub fn srcLoc(self: Opaque, mod: *Module) SrcLoc { 1403 const owner_decl = mod.declPtr(self.owner_decl); 1404 return .{ 1405 .file_scope = owner_decl.getFileScope(), 1406 .parent_decl_node = owner_decl.src_node, 1407 .lazy = LazySrcLoc.nodeOffset(self.node_offset), 1408 }; 1409 } 1410 1411 pub fn getFullyQualifiedName(s: *Opaque, mod: *Module) ![:0]u8 { 1412 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); 1413 } 1414 }; 1415 1416 /// Some extern function struct memory is owned by the Decl's TypedValue.Managed 1417 /// arena allocator. 1418 pub const ExternFn = struct { 1419 /// The Decl that corresponds to the function itself. 1420 owner_decl: Decl.Index, 1421 /// Library name if specified. 1422 /// For example `extern "c" fn write(...) usize` would have 'c' as library name. 1423 /// Allocated with Module's allocator; outlives the ZIR code. 1424 lib_name: ?[*:0]const u8, 1425 1426 pub fn deinit(extern_fn: *ExternFn, gpa: Allocator) void { 1427 if (extern_fn.lib_name) |lib_name| { 1428 gpa.free(mem.sliceTo(lib_name, 0)); 1429 } 1430 } 1431 }; 1432 1433 /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. 1434 /// Extern functions do not have this data structure; they are represented by `ExternFn` 1435 /// instead. 1436 pub const Fn = struct { 1437 /// The Decl that corresponds to the function itself. 1438 owner_decl: Decl.Index, 1439 /// The ZIR instruction that is a function instruction. Use this to find 1440 /// the body. We store this rather than the body directly so that when ZIR 1441 /// is regenerated on update(), we can map this to the new corresponding 1442 /// ZIR instruction. 1443 zir_body_inst: Zir.Inst.Index, 1444 /// If this is not null, this function is a generic function instantiation, and 1445 /// there is a `TypedValue` here for each parameter of the function. 1446 /// Non-comptime parameters are marked with a `generic_poison` for the value. 1447 /// Non-anytype parameters are marked with a `generic_poison` for the type. 1448 /// These never have .generic_poison for the Type 1449 /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments 1450 /// into the inst_map when analyzing the body of a generic function instantiation. 1451 /// Instead, the is_anytype knowledge is communicated via `anytype_args`. 1452 comptime_args: ?[*]TypedValue, 1453 /// When comptime_args is null, this is undefined. Otherwise, this flags each 1454 /// parameter and tells whether it is anytype. 1455 /// TODO apply the same enhancement for param_names below to this field. 1456 anytype_args: [*]bool, 1457 1458 /// Prefer to use `getParamName` to access this because of the future improvement 1459 /// we want to do mentioned in the TODO below. 1460 /// Stored in gpa. 1461 /// TODO: change param ZIR instructions to be embedded inside the function 1462 /// ZIR instruction instead of before it, so that `zir_body_inst` can be used to 1463 /// determine param names rather than redundantly storing them here. 1464 param_names: []const [:0]const u8, 1465 1466 /// Precomputed hash for monomorphed_funcs. 1467 /// This is important because it may be accessed when resizing monomorphed_funcs 1468 /// while this Fn has already been added to the set, but does not have the 1469 /// owner_decl, comptime_args, or other fields populated yet. 1470 hash: u64, 1471 1472 /// Relative to owner Decl. 1473 lbrace_line: u32, 1474 /// Relative to owner Decl. 1475 rbrace_line: u32, 1476 lbrace_column: u16, 1477 rbrace_column: u16, 1478 1479 /// When a generic function is instantiated, this value is inherited from the 1480 /// active Sema context. Importantly, this value is also updated when an existing 1481 /// generic function instantiation is found and called. 1482 branch_quota: u32, 1483 state: Analysis, 1484 is_cold: bool = false, 1485 is_noinline: bool = false, 1486 calls_or_awaits_errorable_fn: bool = false, 1487 1488 /// Any inferred error sets that this function owns, both its own inferred error set and 1489 /// inferred error sets of any inline/comptime functions called. Not to be confused 1490 /// with inferred error sets of generic instantiations of this function, which are 1491 /// *not* tracked here - they are tracked in the new `Fn` object created for the 1492 /// instantiations. 1493 inferred_error_sets: InferredErrorSetList = .{}, 1494 1495 pub const Analysis = enum { 1496 queued, 1497 /// This function intentionally only has ZIR generated because it is marked 1498 /// inline, which means no runtime version of the function will be generated. 1499 inline_only, 1500 in_progress, 1501 /// There will be a corresponding ErrorMsg in Module.failed_decls 1502 sema_failure, 1503 /// This Fn might be OK but it depends on another Decl which did not 1504 /// successfully complete semantic analysis. 1505 dependency_failure, 1506 success, 1507 }; 1508 1509 /// This struct is used to keep track of any dependencies related to functions instances 1510 /// that return inferred error sets. Note that a function may be associated to 1511 /// multiple different error sets, for example an inferred error set which 1512 /// this function returns, but also any inferred error sets of called inline 1513 /// or comptime functions. 1514 pub const InferredErrorSet = struct { 1515 /// The function from which this error set originates. 1516 func: *Fn, 1517 1518 /// All currently known errors that this error set contains. This includes 1519 /// direct additions via `return error.Foo;`, and possibly also errors that 1520 /// are returned from any dependent functions. When the inferred error set is 1521 /// fully resolved, this map contains all the errors that the function might return. 1522 errors: ErrorSet.NameMap = .{}, 1523 1524 /// Other inferred error sets which this inferred error set should include. 1525 inferred_error_sets: std.AutoHashMapUnmanaged(*InferredErrorSet, void) = .{}, 1526 1527 /// Whether the function returned anyerror. This is true if either of 1528 /// the dependent functions returns anyerror. 1529 is_anyerror: bool = false, 1530 1531 /// Whether this error set is already fully resolved. If true, resolving 1532 /// can skip resolving any dependents of this inferred error set. 1533 is_resolved: bool = false, 1534 1535 pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void { 1536 switch (err_set_ty.tag()) { 1537 .error_set => { 1538 const names = err_set_ty.castTag(.error_set).?.data.names.keys(); 1539 for (names) |name| { 1540 try self.errors.put(gpa, name, {}); 1541 } 1542 }, 1543 .error_set_single => { 1544 const name = err_set_ty.castTag(.error_set_single).?.data; 1545 try self.errors.put(gpa, name, {}); 1546 }, 1547 .error_set_inferred => { 1548 const ies = err_set_ty.castTag(.error_set_inferred).?.data; 1549 try self.inferred_error_sets.put(gpa, ies, {}); 1550 }, 1551 .error_set_merged => { 1552 const names = err_set_ty.castTag(.error_set_merged).?.data.keys(); 1553 for (names) |name| { 1554 try self.errors.put(gpa, name, {}); 1555 } 1556 }, 1557 .anyerror => { 1558 self.is_anyerror = true; 1559 }, 1560 else => unreachable, 1561 } 1562 } 1563 }; 1564 1565 pub const InferredErrorSetList = std.SinglyLinkedList(InferredErrorSet); 1566 pub const InferredErrorSetListNode = InferredErrorSetList.Node; 1567 1568 pub fn deinit(func: *Fn, gpa: Allocator) void { 1569 var it = func.inferred_error_sets.first; 1570 while (it) |node| { 1571 const next = node.next; 1572 node.data.errors.deinit(gpa); 1573 node.data.inferred_error_sets.deinit(gpa); 1574 gpa.destroy(node); 1575 it = next; 1576 } 1577 1578 for (func.param_names) |param_name| { 1579 gpa.free(param_name); 1580 } 1581 gpa.free(func.param_names); 1582 } 1583 1584 pub fn getParamName(func: Fn, index: u32) [:0]const u8 { 1585 // TODO rework ZIR of parameters so that this function looks up 1586 // param names in ZIR instead of redundantly saving them into Fn. 1587 // const zir = func.owner_decl.getFileScope().zir; 1588 return func.param_names[index]; 1589 } 1590 1591 pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool { 1592 const owner_decl = mod.declPtr(func.owner_decl); 1593 const zir = owner_decl.getFileScope().zir; 1594 const zir_tags = zir.instructions.items(.tag); 1595 switch (zir_tags[func.zir_body_inst]) { 1596 .func => return false, 1597 .func_inferred => return true, 1598 .func_fancy => { 1599 const inst_data = zir.instructions.items(.data)[func.zir_body_inst].pl_node; 1600 const extra = zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); 1601 return extra.data.bits.is_inferred_error; 1602 }, 1603 else => unreachable, 1604 } 1605 } 1606 }; 1607 1608 pub const Var = struct { 1609 /// if is_extern == true this is undefined 1610 init: Value, 1611 owner_decl: Decl.Index, 1612 1613 /// Library name if specified. 1614 /// For example `extern "c" var stderrp = ...` would have 'c' as library name. 1615 /// Allocated with Module's allocator; outlives the ZIR code. 1616 lib_name: ?[*:0]const u8, 1617 1618 is_extern: bool, 1619 is_mutable: bool, 1620 is_threadlocal: bool, 1621 is_weak_linkage: bool, 1622 1623 pub fn deinit(variable: *Var, gpa: Allocator) void { 1624 if (variable.lib_name) |lib_name| { 1625 gpa.free(mem.sliceTo(lib_name, 0)); 1626 } 1627 } 1628 }; 1629 1630 pub const DeclAdapter = struct { 1631 mod: *Module, 1632 1633 pub fn hash(self: @This(), s: []const u8) u32 { 1634 _ = self; 1635 return @truncate(u32, std.hash.Wyhash.hash(0, s)); 1636 } 1637 1638 pub fn eql(self: @This(), a: []const u8, b_decl_index: Decl.Index, b_index: usize) bool { 1639 _ = b_index; 1640 const b_decl = self.mod.declPtr(b_decl_index); 1641 return mem.eql(u8, a, mem.sliceTo(b_decl.name, 0)); 1642 } 1643 }; 1644 1645 /// The container that structs, enums, unions, and opaques have. 1646 pub const Namespace = struct { 1647 parent: ?*Namespace, 1648 file_scope: *File, 1649 /// Will be a struct, enum, union, or opaque. 1650 ty: Type, 1651 /// Direct children of the namespace. Used during an update to detect 1652 /// which decls have been added/removed from source. 1653 /// Declaration order is preserved via entry order. 1654 /// Key memory is owned by `decl.name`. 1655 /// Anonymous decls are not stored here; they are kept in `anon_decls` instead. 1656 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{}, 1657 1658 anon_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, 1659 1660 /// Key is usingnamespace Decl itself. To find the namespace being included, 1661 /// the Decl Value has to be resolved as a Type which has a Namespace. 1662 /// Value is whether the usingnamespace decl is marked `pub`. 1663 usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{}, 1664 1665 const DeclContext = struct { 1666 module: *Module, 1667 1668 pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { 1669 const decl = ctx.module.declPtr(decl_index); 1670 return @truncate(u32, std.hash.Wyhash.hash(0, mem.sliceTo(decl.name, 0))); 1671 } 1672 1673 pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool { 1674 _ = b_index; 1675 const a_decl = ctx.module.declPtr(a_decl_index); 1676 const b_decl = ctx.module.declPtr(b_decl_index); 1677 const a_name = mem.sliceTo(a_decl.name, 0); 1678 const b_name = mem.sliceTo(b_decl.name, 0); 1679 return mem.eql(u8, a_name, b_name); 1680 } 1681 }; 1682 1683 pub fn deinit(ns: *Namespace, mod: *Module) void { 1684 ns.destroyDecls(mod); 1685 ns.* = undefined; 1686 } 1687 1688 pub fn destroyDecls(ns: *Namespace, mod: *Module) void { 1689 const gpa = mod.gpa; 1690 1691 log.debug("destroyDecls {*}", .{ns}); 1692 1693 var decls = ns.decls; 1694 ns.decls = .{}; 1695 1696 var anon_decls = ns.anon_decls; 1697 ns.anon_decls = .{}; 1698 1699 for (decls.keys()) |decl_index| { 1700 mod.destroyDecl(decl_index); 1701 } 1702 decls.deinit(gpa); 1703 1704 for (anon_decls.keys()) |key| { 1705 mod.destroyDecl(key); 1706 } 1707 anon_decls.deinit(gpa); 1708 ns.usingnamespace_set.deinit(gpa); 1709 } 1710 1711 pub fn deleteAllDecls( 1712 ns: *Namespace, 1713 mod: *Module, 1714 outdated_decls: ?*std.AutoArrayHashMap(Decl.Index, void), 1715 ) !void { 1716 const gpa = mod.gpa; 1717 1718 log.debug("deleteAllDecls {*}", .{ns}); 1719 1720 var decls = ns.decls; 1721 ns.decls = .{}; 1722 1723 var anon_decls = ns.anon_decls; 1724 ns.anon_decls = .{}; 1725 1726 // TODO rework this code to not panic on OOM. 1727 // (might want to coordinate with the clearDecl function) 1728 1729 for (decls.keys()) |child_decl| { 1730 mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory"); 1731 mod.destroyDecl(child_decl); 1732 } 1733 decls.deinit(gpa); 1734 1735 for (anon_decls.keys()) |child_decl| { 1736 mod.clearDecl(child_decl, outdated_decls) catch @panic("out of memory"); 1737 mod.destroyDecl(child_decl); 1738 } 1739 anon_decls.deinit(gpa); 1740 1741 ns.usingnamespace_set.deinit(gpa); 1742 } 1743 1744 // This renders e.g. "std.fs.Dir.OpenOptions" 1745 pub fn renderFullyQualifiedName( 1746 ns: Namespace, 1747 mod: *Module, 1748 name: []const u8, 1749 writer: anytype, 1750 ) @TypeOf(writer).Error!void { 1751 if (ns.parent) |parent| { 1752 const decl_index = ns.getDeclIndex(); 1753 const decl = mod.declPtr(decl_index); 1754 try parent.renderFullyQualifiedName(mod, mem.sliceTo(decl.name, 0), writer); 1755 } else { 1756 try ns.file_scope.renderFullyQualifiedName(writer); 1757 } 1758 if (name.len != 0) { 1759 try writer.writeAll("."); 1760 try writer.writeAll(name); 1761 } 1762 } 1763 1764 /// This renders e.g. "std/fs.zig:Dir.OpenOptions" 1765 pub fn renderFullyQualifiedDebugName( 1766 ns: Namespace, 1767 mod: *Module, 1768 name: []const u8, 1769 writer: anytype, 1770 ) @TypeOf(writer).Error!void { 1771 var separator_char: u8 = '.'; 1772 if (ns.parent) |parent| { 1773 const decl_index = ns.getDeclIndex(); 1774 const decl = mod.declPtr(decl_index); 1775 try parent.renderFullyQualifiedDebugName(mod, mem.sliceTo(decl.name, 0), writer); 1776 } else { 1777 try ns.file_scope.renderFullyQualifiedDebugName(writer); 1778 separator_char = ':'; 1779 } 1780 if (name.len != 0) { 1781 try writer.writeByte(separator_char); 1782 try writer.writeAll(name); 1783 } 1784 } 1785 1786 pub fn getDeclIndex(ns: Namespace) Decl.Index { 1787 return ns.ty.getOwnerDecl(); 1788 } 1789 }; 1790 1791 pub const File = struct { 1792 /// The Decl of the struct that represents this File. 1793 root_decl: Decl.OptionalIndex, 1794 status: enum { 1795 never_loaded, 1796 retryable_failure, 1797 parse_failure, 1798 astgen_failure, 1799 success_zir, 1800 }, 1801 source_loaded: bool, 1802 tree_loaded: bool, 1803 zir_loaded: bool, 1804 /// Relative to the owning package's root_src_dir. 1805 /// Memory is stored in gpa, owned by File. 1806 sub_file_path: []const u8, 1807 /// Whether this is populated depends on `source_loaded`. 1808 source: [:0]const u8, 1809 /// Whether this is populated depends on `status`. 1810 stat: Cache.File.Stat, 1811 /// Whether this is populated or not depends on `tree_loaded`. 1812 tree: Ast, 1813 /// Whether this is populated or not depends on `zir_loaded`. 1814 zir: Zir, 1815 /// Package that this file is a part of, managed externally. 1816 pkg: *Package, 1817 1818 /// Used by change detection algorithm, after astgen, contains the 1819 /// set of decls that existed in the previous ZIR but not in the new one. 1820 deleted_decls: std.ArrayListUnmanaged(Decl.Index) = .{}, 1821 /// Used by change detection algorithm, after astgen, contains the 1822 /// set of decls that existed both in the previous ZIR and in the new one, 1823 /// but their source code has been modified. 1824 outdated_decls: std.ArrayListUnmanaged(Decl.Index) = .{}, 1825 1826 /// The most recent successful ZIR for this file, with no errors. 1827 /// This is only populated when a previously successful ZIR 1828 /// newly introduces compile errors during an update. When ZIR is 1829 /// successful, this field is unloaded. 1830 prev_zir: ?*Zir = null, 1831 1832 pub fn unload(file: *File, gpa: Allocator) void { 1833 file.unloadTree(gpa); 1834 file.unloadSource(gpa); 1835 file.unloadZir(gpa); 1836 } 1837 1838 pub fn unloadTree(file: *File, gpa: Allocator) void { 1839 if (file.tree_loaded) { 1840 file.tree_loaded = false; 1841 file.tree.deinit(gpa); 1842 } 1843 } 1844 1845 pub fn unloadSource(file: *File, gpa: Allocator) void { 1846 if (file.source_loaded) { 1847 file.source_loaded = false; 1848 gpa.free(file.source); 1849 } 1850 } 1851 1852 pub fn unloadZir(file: *File, gpa: Allocator) void { 1853 if (file.zir_loaded) { 1854 file.zir_loaded = false; 1855 file.zir.deinit(gpa); 1856 } 1857 } 1858 1859 pub fn deinit(file: *File, mod: *Module) void { 1860 const gpa = mod.gpa; 1861 log.debug("deinit File {s}", .{file.sub_file_path}); 1862 file.deleted_decls.deinit(gpa); 1863 file.outdated_decls.deinit(gpa); 1864 if (file.root_decl.unwrap()) |root_decl| { 1865 mod.destroyDecl(root_decl); 1866 } 1867 gpa.free(file.sub_file_path); 1868 file.unload(gpa); 1869 if (file.prev_zir) |prev_zir| { 1870 prev_zir.deinit(gpa); 1871 gpa.destroy(prev_zir); 1872 } 1873 file.* = undefined; 1874 } 1875 1876 pub const Source = struct { 1877 bytes: [:0]const u8, 1878 stat: Cache.File.Stat, 1879 }; 1880 1881 pub fn getSource(file: *File, gpa: Allocator) !Source { 1882 if (file.source_loaded) return Source{ 1883 .bytes = file.source, 1884 .stat = file.stat, 1885 }; 1886 1887 const root_dir_path = file.pkg.root_src_directory.path orelse "."; 1888 log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{ 1889 root_dir_path, file.sub_file_path, 1890 }); 1891 1892 // Keep track of inode, file size, mtime, hash so we can detect which files 1893 // have been modified when an incremental update is requested. 1894 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); 1895 defer f.close(); 1896 1897 const stat = try f.stat(); 1898 1899 if (stat.size > std.math.maxInt(u32)) 1900 return error.FileTooBig; 1901 1902 const source = try gpa.allocSentinel(u8, @intCast(usize, stat.size), 0); 1903 defer if (!file.source_loaded) gpa.free(source); 1904 const amt = try f.readAll(source); 1905 if (amt != stat.size) 1906 return error.UnexpectedEndOfFile; 1907 1908 // Here we do not modify stat fields because this function is the one 1909 // used for error reporting. We need to keep the stat fields stale so that 1910 // astGenFile can know to regenerate ZIR. 1911 1912 file.source = source; 1913 file.source_loaded = true; 1914 return Source{ 1915 .bytes = source, 1916 .stat = .{ 1917 .size = stat.size, 1918 .inode = stat.inode, 1919 .mtime = stat.mtime, 1920 }, 1921 }; 1922 } 1923 1924 pub fn getTree(file: *File, gpa: Allocator) !*const Ast { 1925 if (file.tree_loaded) return &file.tree; 1926 1927 const source = try file.getSource(gpa); 1928 file.tree = try std.zig.parse(gpa, source.bytes); 1929 file.tree_loaded = true; 1930 return &file.tree; 1931 } 1932 1933 pub fn destroy(file: *File, mod: *Module) void { 1934 const gpa = mod.gpa; 1935 file.deinit(mod); 1936 gpa.destroy(file); 1937 } 1938 1939 pub fn renderFullyQualifiedName(file: File, writer: anytype) !void { 1940 // Convert all the slashes into dots and truncate the extension. 1941 const ext = std.fs.path.extension(file.sub_file_path); 1942 const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; 1943 for (noext) |byte| switch (byte) { 1944 '/', '\\' => try writer.writeByte('.'), 1945 else => try writer.writeByte(byte), 1946 }; 1947 } 1948 1949 pub fn renderFullyQualifiedDebugName(file: File, writer: anytype) !void { 1950 for (file.sub_file_path) |byte| switch (byte) { 1951 '/', '\\' => try writer.writeByte('/'), 1952 else => try writer.writeByte(byte), 1953 }; 1954 } 1955 1956 pub fn fullyQualifiedNameZ(file: File, gpa: Allocator) ![:0]u8 { 1957 var buf = std.ArrayList(u8).init(gpa); 1958 defer buf.deinit(); 1959 try file.renderFullyQualifiedName(buf.writer()); 1960 return buf.toOwnedSliceSentinel(0); 1961 } 1962 1963 /// Returns the full path to this file relative to its package. 1964 pub fn fullPath(file: File, ally: Allocator) ![]u8 { 1965 return file.pkg.root_src_directory.join(ally, &[_][]const u8{file.sub_file_path}); 1966 } 1967 1968 /// Returns the full path to this file relative to its package. 1969 pub fn fullPathZ(file: File, ally: Allocator) ![:0]u8 { 1970 return file.pkg.root_src_directory.joinZ(ally, &[_][]const u8{file.sub_file_path}); 1971 } 1972 1973 pub fn dumpSrc(file: *File, src: LazySrcLoc) void { 1974 const loc = std.zig.findLineColumn(file.source.bytes, src); 1975 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 }); 1976 } 1977 1978 pub fn okToReportErrors(file: File) bool { 1979 return switch (file.status) { 1980 .parse_failure, .astgen_failure => false, 1981 else => true, 1982 }; 1983 } 1984 }; 1985 1986 /// Represents the contents of a file loaded with `@embedFile`. 1987 pub const EmbedFile = struct { 1988 /// Relative to the owning package's root_src_dir. 1989 /// Memory is stored in gpa, owned by EmbedFile. 1990 sub_file_path: []const u8, 1991 bytes: [:0]const u8, 1992 stat: Cache.File.Stat, 1993 /// Package that this file is a part of, managed externally. 1994 pkg: *Package, 1995 /// The Decl that was created from the `@embedFile` to own this resource. 1996 /// This is how zig knows what other Decl objects to invalidate if the file 1997 /// changes on disk. 1998 owner_decl: Decl.Index, 1999 2000 fn destroy(embed_file: *EmbedFile, mod: *Module) void { 2001 const gpa = mod.gpa; 2002 gpa.free(embed_file.sub_file_path); 2003 gpa.free(embed_file.bytes); 2004 gpa.destroy(embed_file); 2005 } 2006 }; 2007 2008 /// This struct holds data necessary to construct API-facing `AllErrors.Message`. 2009 /// Its memory is managed with the general purpose allocator so that they 2010 /// can be created and destroyed in response to incremental updates. 2011 /// In some cases, the File could have been inferred from where the ErrorMsg 2012 /// is stored. For example, if it is stored in Module.failed_decls, then the File 2013 /// would be determined by the Decl Scope. However, the data structure contains the field 2014 /// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different 2015 /// file than the parent error message. It also simplifies processing of error messages. 2016 pub const ErrorMsg = struct { 2017 src_loc: SrcLoc, 2018 msg: []const u8, 2019 notes: []ErrorMsg = &.{}, 2020 2021 pub fn create( 2022 gpa: Allocator, 2023 src_loc: SrcLoc, 2024 comptime format: []const u8, 2025 args: anytype, 2026 ) !*ErrorMsg { 2027 const err_msg = try gpa.create(ErrorMsg); 2028 errdefer gpa.destroy(err_msg); 2029 err_msg.* = try init(gpa, src_loc, format, args); 2030 return err_msg; 2031 } 2032 2033 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`, 2034 /// as well as all notes. 2035 pub fn destroy(err_msg: *ErrorMsg, gpa: Allocator) void { 2036 err_msg.deinit(gpa); 2037 gpa.destroy(err_msg); 2038 } 2039 2040 pub fn init( 2041 gpa: Allocator, 2042 src_loc: SrcLoc, 2043 comptime format: []const u8, 2044 args: anytype, 2045 ) !ErrorMsg { 2046 return ErrorMsg{ 2047 .src_loc = src_loc, 2048 .msg = try std.fmt.allocPrint(gpa, format, args), 2049 }; 2050 } 2051 2052 pub fn deinit(err_msg: *ErrorMsg, gpa: Allocator) void { 2053 for (err_msg.notes) |*note| { 2054 note.deinit(gpa); 2055 } 2056 gpa.free(err_msg.notes); 2057 gpa.free(err_msg.msg); 2058 err_msg.* = undefined; 2059 } 2060 }; 2061 2062 /// Canonical reference to a position within a source file. 2063 pub const SrcLoc = struct { 2064 file_scope: *File, 2065 /// Might be 0 depending on tag of `lazy`. 2066 parent_decl_node: Ast.Node.Index, 2067 /// Relative to `parent_decl_node`. 2068 lazy: LazySrcLoc, 2069 2070 pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex { 2071 const tree = src_loc.file_scope.tree; 2072 return tree.firstToken(src_loc.parent_decl_node); 2073 } 2074 2075 pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.TokenIndex { 2076 return @bitCast(Ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node)); 2077 } 2078 2079 pub fn byteOffset(src_loc: SrcLoc, gpa: Allocator) !u32 { 2080 switch (src_loc.lazy) { 2081 .unneeded => unreachable, 2082 .entire_file => return 0, 2083 2084 .byte_abs => |byte_index| return byte_index, 2085 2086 .token_abs => |tok_index| { 2087 const tree = try src_loc.file_scope.getTree(gpa); 2088 const token_starts = tree.tokens.items(.start); 2089 return token_starts[tok_index]; 2090 }, 2091 .node_abs => |node| { 2092 const tree = try src_loc.file_scope.getTree(gpa); 2093 const token_starts = tree.tokens.items(.start); 2094 const tok_index = tree.firstToken(node); 2095 return token_starts[tok_index]; 2096 }, 2097 .byte_offset => |byte_off| { 2098 const tree = try src_loc.file_scope.getTree(gpa); 2099 const token_starts = tree.tokens.items(.start); 2100 return token_starts[src_loc.declSrcToken()] + byte_off; 2101 }, 2102 .token_offset => |tok_off| { 2103 const tree = try src_loc.file_scope.getTree(gpa); 2104 const tok_index = src_loc.declSrcToken() + tok_off; 2105 const token_starts = tree.tokens.items(.start); 2106 return token_starts[tok_index]; 2107 }, 2108 .node_offset => |traced_off| { 2109 const node_off = traced_off.x; 2110 const tree = try src_loc.file_scope.getTree(gpa); 2111 const node = src_loc.declRelativeToNodeIndex(node_off); 2112 assert(src_loc.file_scope.tree_loaded); 2113 const main_tokens = tree.nodes.items(.main_token); 2114 const tok_index = main_tokens[node]; 2115 const token_starts = tree.tokens.items(.start); 2116 return token_starts[tok_index]; 2117 }, 2118 .node_offset_bin_op => |node_off| { 2119 const tree = try src_loc.file_scope.getTree(gpa); 2120 const node = src_loc.declRelativeToNodeIndex(node_off); 2121 assert(src_loc.file_scope.tree_loaded); 2122 const main_tokens = tree.nodes.items(.main_token); 2123 const tok_index = main_tokens[node]; 2124 const token_starts = tree.tokens.items(.start); 2125 return token_starts[tok_index]; 2126 }, 2127 .node_offset_back2tok => |node_off| { 2128 const tree = try src_loc.file_scope.getTree(gpa); 2129 const node = src_loc.declRelativeToNodeIndex(node_off); 2130 const tok_index = tree.firstToken(node) - 2; 2131 const token_starts = tree.tokens.items(.start); 2132 return token_starts[tok_index]; 2133 }, 2134 .node_offset_var_decl_ty => |node_off| { 2135 const tree = try src_loc.file_scope.getTree(gpa); 2136 const node = src_loc.declRelativeToNodeIndex(node_off); 2137 const node_tags = tree.nodes.items(.tag); 2138 const full = switch (node_tags[node]) { 2139 .global_var_decl => tree.globalVarDecl(node), 2140 .local_var_decl => tree.localVarDecl(node), 2141 .simple_var_decl => tree.simpleVarDecl(node), 2142 .aligned_var_decl => tree.alignedVarDecl(node), 2143 else => unreachable, 2144 }; 2145 const tok_index = if (full.ast.type_node != 0) blk: { 2146 const main_tokens = tree.nodes.items(.main_token); 2147 break :blk main_tokens[full.ast.type_node]; 2148 } else blk: { 2149 break :blk full.ast.mut_token + 1; // the name token 2150 }; 2151 const token_starts = tree.tokens.items(.start); 2152 return token_starts[tok_index]; 2153 }, 2154 .node_offset_builtin_call_arg0 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 0), 2155 .node_offset_builtin_call_arg1 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 1), 2156 .node_offset_builtin_call_arg2 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 2), 2157 .node_offset_builtin_call_arg3 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 3), 2158 .node_offset_builtin_call_arg4 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 4), 2159 .node_offset_builtin_call_arg5 => |n| return src_loc.byteOffsetBuiltinCallArg(gpa, n, 5), 2160 .node_offset_array_access_index => |node_off| { 2161 const tree = try src_loc.file_scope.getTree(gpa); 2162 const node_datas = tree.nodes.items(.data); 2163 const node = src_loc.declRelativeToNodeIndex(node_off); 2164 const main_tokens = tree.nodes.items(.main_token); 2165 const tok_index = main_tokens[node_datas[node].rhs]; 2166 const token_starts = tree.tokens.items(.start); 2167 return token_starts[tok_index]; 2168 }, 2169 .node_offset_slice_sentinel => |node_off| { 2170 const tree = try src_loc.file_scope.getTree(gpa); 2171 const node_tags = tree.nodes.items(.tag); 2172 const node = src_loc.declRelativeToNodeIndex(node_off); 2173 const full = switch (node_tags[node]) { 2174 .slice_open => tree.sliceOpen(node), 2175 .slice => tree.slice(node), 2176 .slice_sentinel => tree.sliceSentinel(node), 2177 else => unreachable, 2178 }; 2179 const main_tokens = tree.nodes.items(.main_token); 2180 const tok_index = main_tokens[full.ast.sentinel]; 2181 const token_starts = tree.tokens.items(.start); 2182 return token_starts[tok_index]; 2183 }, 2184 .node_offset_call_func => |node_off| { 2185 const tree = try src_loc.file_scope.getTree(gpa); 2186 const node_tags = tree.nodes.items(.tag); 2187 const node = src_loc.declRelativeToNodeIndex(node_off); 2188 var params: [1]Ast.Node.Index = undefined; 2189 const full = switch (node_tags[node]) { 2190 .call_one, 2191 .call_one_comma, 2192 .async_call_one, 2193 .async_call_one_comma, 2194 => tree.callOne(¶ms, node), 2195 2196 .call, 2197 .call_comma, 2198 .async_call, 2199 .async_call_comma, 2200 => tree.callFull(node), 2201 2202 else => unreachable, 2203 }; 2204 const main_tokens = tree.nodes.items(.main_token); 2205 const tok_index = main_tokens[full.ast.fn_expr]; 2206 const token_starts = tree.tokens.items(.start); 2207 return token_starts[tok_index]; 2208 }, 2209 .node_offset_field_name => |node_off| { 2210 const tree = try src_loc.file_scope.getTree(gpa); 2211 const node_datas = tree.nodes.items(.data); 2212 const node_tags = tree.nodes.items(.tag); 2213 const node = src_loc.declRelativeToNodeIndex(node_off); 2214 const tok_index = switch (node_tags[node]) { 2215 .field_access => node_datas[node].rhs, 2216 else => tree.firstToken(node) - 2, 2217 }; 2218 const token_starts = tree.tokens.items(.start); 2219 return token_starts[tok_index]; 2220 }, 2221 .node_offset_deref_ptr => |node_off| { 2222 const tree = try src_loc.file_scope.getTree(gpa); 2223 const node_datas = tree.nodes.items(.data); 2224 const node = src_loc.declRelativeToNodeIndex(node_off); 2225 const tok_index = node_datas[node].lhs; 2226 const token_starts = tree.tokens.items(.start); 2227 return token_starts[tok_index]; 2228 }, 2229 .node_offset_asm_source => |node_off| { 2230 const tree = try src_loc.file_scope.getTree(gpa); 2231 const node_tags = tree.nodes.items(.tag); 2232 const node = src_loc.declRelativeToNodeIndex(node_off); 2233 const full = switch (node_tags[node]) { 2234 .asm_simple => tree.asmSimple(node), 2235 .@"asm" => tree.asmFull(node), 2236 else => unreachable, 2237 }; 2238 const main_tokens = tree.nodes.items(.main_token); 2239 const tok_index = main_tokens[full.ast.template]; 2240 const token_starts = tree.tokens.items(.start); 2241 return token_starts[tok_index]; 2242 }, 2243 .node_offset_asm_ret_ty => |node_off| { 2244 const tree = try src_loc.file_scope.getTree(gpa); 2245 const node_tags = tree.nodes.items(.tag); 2246 const node = src_loc.declRelativeToNodeIndex(node_off); 2247 const full = switch (node_tags[node]) { 2248 .asm_simple => tree.asmSimple(node), 2249 .@"asm" => tree.asmFull(node), 2250 else => unreachable, 2251 }; 2252 const asm_output = full.outputs[0]; 2253 const node_datas = tree.nodes.items(.data); 2254 const ret_ty_node = node_datas[asm_output].lhs; 2255 const main_tokens = tree.nodes.items(.main_token); 2256 const tok_index = main_tokens[ret_ty_node]; 2257 const token_starts = tree.tokens.items(.start); 2258 return token_starts[tok_index]; 2259 }, 2260 2261 .node_offset_for_cond, .node_offset_if_cond => |node_off| { 2262 const tree = try src_loc.file_scope.getTree(gpa); 2263 const node = src_loc.declRelativeToNodeIndex(node_off); 2264 const node_tags = tree.nodes.items(.tag); 2265 const src_node = switch (node_tags[node]) { 2266 .if_simple => tree.ifSimple(node).ast.cond_expr, 2267 .@"if" => tree.ifFull(node).ast.cond_expr, 2268 .while_simple => tree.whileSimple(node).ast.cond_expr, 2269 .while_cont => tree.whileCont(node).ast.cond_expr, 2270 .@"while" => tree.whileFull(node).ast.cond_expr, 2271 .for_simple => tree.forSimple(node).ast.cond_expr, 2272 .@"for" => tree.forFull(node).ast.cond_expr, 2273 else => unreachable, 2274 }; 2275 const main_tokens = tree.nodes.items(.main_token); 2276 const tok_index = main_tokens[src_node]; 2277 const token_starts = tree.tokens.items(.start); 2278 return token_starts[tok_index]; 2279 }, 2280 .node_offset_bin_lhs => |node_off| { 2281 const tree = try src_loc.file_scope.getTree(gpa); 2282 const node = src_loc.declRelativeToNodeIndex(node_off); 2283 const node_datas = tree.nodes.items(.data); 2284 const src_node = node_datas[node].lhs; 2285 const main_tokens = tree.nodes.items(.main_token); 2286 const tok_index = main_tokens[src_node]; 2287 const token_starts = tree.tokens.items(.start); 2288 return token_starts[tok_index]; 2289 }, 2290 .node_offset_bin_rhs => |node_off| { 2291 const tree = try src_loc.file_scope.getTree(gpa); 2292 const node = src_loc.declRelativeToNodeIndex(node_off); 2293 const node_datas = tree.nodes.items(.data); 2294 const src_node = node_datas[node].rhs; 2295 const main_tokens = tree.nodes.items(.main_token); 2296 const tok_index = main_tokens[src_node]; 2297 const token_starts = tree.tokens.items(.start); 2298 return token_starts[tok_index]; 2299 }, 2300 2301 .node_offset_switch_operand => |node_off| { 2302 const tree = try src_loc.file_scope.getTree(gpa); 2303 const node = src_loc.declRelativeToNodeIndex(node_off); 2304 const node_datas = tree.nodes.items(.data); 2305 const src_node = node_datas[node].lhs; 2306 const main_tokens = tree.nodes.items(.main_token); 2307 const tok_index = main_tokens[src_node]; 2308 const token_starts = tree.tokens.items(.start); 2309 return token_starts[tok_index]; 2310 }, 2311 2312 .node_offset_switch_special_prong => |node_off| { 2313 const tree = try src_loc.file_scope.getTree(gpa); 2314 const switch_node = src_loc.declRelativeToNodeIndex(node_off); 2315 const node_datas = tree.nodes.items(.data); 2316 const node_tags = tree.nodes.items(.tag); 2317 const main_tokens = tree.nodes.items(.main_token); 2318 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 2319 const case_nodes = tree.extra_data[extra.start..extra.end]; 2320 for (case_nodes) |case_node| { 2321 const case = switch (node_tags[case_node]) { 2322 .switch_case_one => tree.switchCaseOne(case_node), 2323 .switch_case => tree.switchCase(case_node), 2324 else => unreachable, 2325 }; 2326 const is_special = (case.ast.values.len == 0) or 2327 (case.ast.values.len == 1 and 2328 node_tags[case.ast.values[0]] == .identifier and 2329 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")); 2330 if (!is_special) continue; 2331 2332 const tok_index = main_tokens[case_node]; 2333 const token_starts = tree.tokens.items(.start); 2334 return token_starts[tok_index]; 2335 } else unreachable; 2336 }, 2337 2338 .node_offset_switch_range => |node_off| { 2339 const tree = try src_loc.file_scope.getTree(gpa); 2340 const switch_node = src_loc.declRelativeToNodeIndex(node_off); 2341 const node_datas = tree.nodes.items(.data); 2342 const node_tags = tree.nodes.items(.tag); 2343 const main_tokens = tree.nodes.items(.main_token); 2344 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 2345 const case_nodes = tree.extra_data[extra.start..extra.end]; 2346 for (case_nodes) |case_node| { 2347 const case = switch (node_tags[case_node]) { 2348 .switch_case_one => tree.switchCaseOne(case_node), 2349 .switch_case => tree.switchCase(case_node), 2350 else => unreachable, 2351 }; 2352 const is_special = (case.ast.values.len == 0) or 2353 (case.ast.values.len == 1 and 2354 node_tags[case.ast.values[0]] == .identifier and 2355 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")); 2356 if (is_special) continue; 2357 2358 for (case.ast.values) |item_node| { 2359 if (node_tags[item_node] == .switch_range) { 2360 const tok_index = main_tokens[item_node]; 2361 const token_starts = tree.tokens.items(.start); 2362 return token_starts[tok_index]; 2363 } 2364 } 2365 } else unreachable; 2366 }, 2367 2368 .node_offset_fn_type_cc => |node_off| { 2369 const tree = try src_loc.file_scope.getTree(gpa); 2370 const node_datas = tree.nodes.items(.data); 2371 const node_tags = tree.nodes.items(.tag); 2372 const node = src_loc.declRelativeToNodeIndex(node_off); 2373 var params: [1]Ast.Node.Index = undefined; 2374 const full = switch (node_tags[node]) { 2375 .fn_proto_simple => tree.fnProtoSimple(¶ms, node), 2376 .fn_proto_multi => tree.fnProtoMulti(node), 2377 .fn_proto_one => tree.fnProtoOne(¶ms, node), 2378 .fn_proto => tree.fnProto(node), 2379 .fn_decl => switch (node_tags[node_datas[node].lhs]) { 2380 .fn_proto_simple => tree.fnProtoSimple(¶ms, node_datas[node].lhs), 2381 .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs), 2382 .fn_proto_one => tree.fnProtoOne(¶ms, node_datas[node].lhs), 2383 .fn_proto => tree.fnProto(node_datas[node].lhs), 2384 else => unreachable, 2385 }, 2386 else => unreachable, 2387 }; 2388 const main_tokens = tree.nodes.items(.main_token); 2389 const tok_index = main_tokens[full.ast.callconv_expr]; 2390 const token_starts = tree.tokens.items(.start); 2391 return token_starts[tok_index]; 2392 }, 2393 2394 .node_offset_fn_type_ret_ty => |node_off| { 2395 const tree = try src_loc.file_scope.getTree(gpa); 2396 const node_tags = tree.nodes.items(.tag); 2397 const node = src_loc.declRelativeToNodeIndex(node_off); 2398 var params: [1]Ast.Node.Index = undefined; 2399 const full = switch (node_tags[node]) { 2400 .fn_proto_simple => tree.fnProtoSimple(¶ms, node), 2401 .fn_proto_multi => tree.fnProtoMulti(node), 2402 .fn_proto_one => tree.fnProtoOne(¶ms, node), 2403 .fn_proto => tree.fnProto(node), 2404 else => unreachable, 2405 }; 2406 const main_tokens = tree.nodes.items(.main_token); 2407 const tok_index = main_tokens[full.ast.return_type]; 2408 const token_starts = tree.tokens.items(.start); 2409 return token_starts[tok_index]; 2410 }, 2411 2412 .node_offset_anyframe_type => |node_off| { 2413 const tree = try src_loc.file_scope.getTree(gpa); 2414 const node_datas = tree.nodes.items(.data); 2415 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2416 const node = node_datas[parent_node].rhs; 2417 const main_tokens = tree.nodes.items(.main_token); 2418 const tok_index = main_tokens[node]; 2419 const token_starts = tree.tokens.items(.start); 2420 return token_starts[tok_index]; 2421 }, 2422 2423 .node_offset_lib_name => |node_off| { 2424 const tree = try src_loc.file_scope.getTree(gpa); 2425 const node_datas = tree.nodes.items(.data); 2426 const node_tags = tree.nodes.items(.tag); 2427 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2428 var params: [1]Ast.Node.Index = undefined; 2429 const full = switch (node_tags[parent_node]) { 2430 .fn_proto_simple => tree.fnProtoSimple(¶ms, parent_node), 2431 .fn_proto_multi => tree.fnProtoMulti(parent_node), 2432 .fn_proto_one => tree.fnProtoOne(¶ms, parent_node), 2433 .fn_proto => tree.fnProto(parent_node), 2434 .fn_decl => blk: { 2435 const fn_proto = node_datas[parent_node].lhs; 2436 break :blk switch (node_tags[fn_proto]) { 2437 .fn_proto_simple => tree.fnProtoSimple(¶ms, fn_proto), 2438 .fn_proto_multi => tree.fnProtoMulti(fn_proto), 2439 .fn_proto_one => tree.fnProtoOne(¶ms, fn_proto), 2440 .fn_proto => tree.fnProto(fn_proto), 2441 else => unreachable, 2442 }; 2443 }, 2444 else => unreachable, 2445 }; 2446 const tok_index = full.lib_name.?; 2447 const token_starts = tree.tokens.items(.start); 2448 return token_starts[tok_index]; 2449 }, 2450 2451 .node_offset_array_type_len => |node_off| { 2452 const tree = try src_loc.file_scope.getTree(gpa); 2453 const node_tags = tree.nodes.items(.tag); 2454 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2455 2456 const full: Ast.full.ArrayType = switch (node_tags[parent_node]) { 2457 .array_type => tree.arrayType(parent_node), 2458 .array_type_sentinel => tree.arrayTypeSentinel(parent_node), 2459 else => unreachable, 2460 }; 2461 const node = full.ast.elem_count; 2462 const main_tokens = tree.nodes.items(.main_token); 2463 const tok_index = main_tokens[node]; 2464 const token_starts = tree.tokens.items(.start); 2465 return token_starts[tok_index]; 2466 }, 2467 .node_offset_array_type_sentinel => |node_off| { 2468 const tree = try src_loc.file_scope.getTree(gpa); 2469 const node_tags = tree.nodes.items(.tag); 2470 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2471 2472 const full: Ast.full.ArrayType = switch (node_tags[parent_node]) { 2473 .array_type => tree.arrayType(parent_node), 2474 .array_type_sentinel => tree.arrayTypeSentinel(parent_node), 2475 else => unreachable, 2476 }; 2477 const node = full.ast.sentinel; 2478 const main_tokens = tree.nodes.items(.main_token); 2479 const tok_index = main_tokens[node]; 2480 const token_starts = tree.tokens.items(.start); 2481 return token_starts[tok_index]; 2482 }, 2483 .node_offset_array_type_elem => |node_off| { 2484 const tree = try src_loc.file_scope.getTree(gpa); 2485 const node_tags = tree.nodes.items(.tag); 2486 const parent_node = src_loc.declRelativeToNodeIndex(node_off); 2487 2488 const full: Ast.full.ArrayType = switch (node_tags[parent_node]) { 2489 .array_type => tree.arrayType(parent_node), 2490 .array_type_sentinel => tree.arrayTypeSentinel(parent_node), 2491 else => unreachable, 2492 }; 2493 const node = full.ast.elem_type; 2494 const main_tokens = tree.nodes.items(.main_token); 2495 const tok_index = main_tokens[node]; 2496 const token_starts = tree.tokens.items(.start); 2497 return token_starts[tok_index]; 2498 }, 2499 } 2500 } 2501 2502 pub fn byteOffsetBuiltinCallArg( 2503 src_loc: SrcLoc, 2504 gpa: Allocator, 2505 node_off: i32, 2506 arg_index: u32, 2507 ) !u32 { 2508 const tree = try src_loc.file_scope.getTree(gpa); 2509 const node_datas = tree.nodes.items(.data); 2510 const node_tags = tree.nodes.items(.tag); 2511 const node = src_loc.declRelativeToNodeIndex(node_off); 2512 const param = switch (node_tags[node]) { 2513 .builtin_call_two, .builtin_call_two_comma => switch (arg_index) { 2514 0 => node_datas[node].lhs, 2515 1 => node_datas[node].rhs, 2516 else => unreachable, 2517 }, 2518 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + arg_index], 2519 else => unreachable, 2520 }; 2521 const main_tokens = tree.nodes.items(.main_token); 2522 const tok_index = main_tokens[param]; 2523 const token_starts = tree.tokens.items(.start); 2524 return token_starts[tok_index]; 2525 } 2526 }; 2527 2528 /// This wraps a simple integer in debug builds so that later on we can find out 2529 /// where in semantic analysis the value got set. 2530 const TracedOffset = struct { 2531 x: i32, 2532 trace: std.debug.Trace = .{}, 2533 2534 const want_tracing = build_options.value_tracing; 2535 }; 2536 2537 /// Resolving a source location into a byte offset may require doing work 2538 /// that we would rather not do unless the error actually occurs. 2539 /// Therefore we need a data structure that contains the information necessary 2540 /// to lazily produce a `SrcLoc` as required. 2541 /// Most of the offsets in this data structure are relative to the containing Decl. 2542 /// This makes the source location resolve properly even when a Decl gets 2543 /// shifted up or down in the file, as long as the Decl's contents itself 2544 /// do not change. 2545 pub const LazySrcLoc = union(enum) { 2546 /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting 2547 /// that all code paths which would need to resolve the source location are 2548 /// unreachable. If you are debugging this tag incorrectly being this value, 2549 /// look into using reverse-continue with a memory watchpoint to see where the 2550 /// value is being set to this tag. 2551 unneeded, 2552 /// Means the source location points to an entire file; not any particular 2553 /// location within the file. `file_scope` union field will be active. 2554 entire_file, 2555 /// The source location points to a byte offset within a source file, 2556 /// offset from 0. The source file is determined contextually. 2557 /// Inside a `SrcLoc`, the `file_scope` union field will be active. 2558 byte_abs: u32, 2559 /// The source location points to a token within a source file, 2560 /// offset from 0. The source file is determined contextually. 2561 /// Inside a `SrcLoc`, the `file_scope` union field will be active. 2562 token_abs: u32, 2563 /// The source location points to an AST node within a source file, 2564 /// offset from 0. The source file is determined contextually. 2565 /// Inside a `SrcLoc`, the `file_scope` union field will be active. 2566 node_abs: u32, 2567 /// The source location points to a byte offset within a source file, 2568 /// offset from the byte offset of the Decl within the file. 2569 /// The Decl is determined contextually. 2570 byte_offset: u32, 2571 /// This data is the offset into the token list from the Decl token. 2572 /// The Decl is determined contextually. 2573 token_offset: u32, 2574 /// The source location points to an AST node, which is this value offset 2575 /// from its containing Decl node AST index. 2576 /// The Decl is determined contextually. 2577 node_offset: TracedOffset, 2578 /// The source location points to two tokens left of the first token of an AST node, 2579 /// which is this value offset from its containing Decl node AST index. 2580 /// The Decl is determined contextually. 2581 node_offset_back2tok: i32, 2582 /// The source location points to a variable declaration type expression, 2583 /// found by taking this AST node index offset from the containing 2584 /// Decl AST node, which points to a variable declaration AST node. Next, navigate 2585 /// to the type expression. 2586 /// The Decl is determined contextually. 2587 node_offset_var_decl_ty: i32, 2588 /// The source location points to a for loop condition expression, 2589 /// found by taking this AST node index offset from the containing 2590 /// Decl AST node, which points to a for loop AST node. Next, navigate 2591 /// to the condition expression. 2592 /// The Decl is determined contextually. 2593 node_offset_for_cond: i32, 2594 /// The source location points to the first parameter of a builtin 2595 /// function call, found by taking this AST node index offset from the containing 2596 /// Decl AST node, which points to a builtin call AST node. Next, navigate 2597 /// to the first parameter. 2598 /// The Decl is determined contextually. 2599 node_offset_builtin_call_arg0: i32, 2600 /// Same as `node_offset_builtin_call_arg0` except arg index 1. 2601 node_offset_builtin_call_arg1: i32, 2602 node_offset_builtin_call_arg2: i32, 2603 node_offset_builtin_call_arg3: i32, 2604 node_offset_builtin_call_arg4: i32, 2605 node_offset_builtin_call_arg5: i32, 2606 /// The source location points to the index expression of an array access 2607 /// expression, found by taking this AST node index offset from the containing 2608 /// Decl AST node, which points to an array access AST node. Next, navigate 2609 /// to the index expression. 2610 /// The Decl is determined contextually. 2611 node_offset_array_access_index: i32, 2612 /// The source location points to the sentinel expression of a slice 2613 /// expression, found by taking this AST node index offset from the containing 2614 /// Decl AST node, which points to a slice AST node. Next, navigate 2615 /// to the sentinel expression. 2616 /// The Decl is determined contextually. 2617 node_offset_slice_sentinel: i32, 2618 /// The source location points to the callee expression of a function 2619 /// call expression, found by taking this AST node index offset from the containing 2620 /// Decl AST node, which points to a function call AST node. Next, navigate 2621 /// to the callee expression. 2622 /// The Decl is determined contextually. 2623 node_offset_call_func: i32, 2624 /// The payload is offset from the containing Decl AST node. 2625 /// The source location points to the field name of: 2626 /// * a field access expression (`a.b`), or 2627 /// * the operand ("b" node) of a field initialization expression (`.a = b`) 2628 /// The Decl is determined contextually. 2629 node_offset_field_name: i32, 2630 /// The source location points to the pointer of a pointer deref expression, 2631 /// found by taking this AST node index offset from the containing 2632 /// Decl AST node, which points to a pointer deref AST node. Next, navigate 2633 /// to the pointer expression. 2634 /// The Decl is determined contextually. 2635 node_offset_deref_ptr: i32, 2636 /// The source location points to the assembly source code of an inline assembly 2637 /// expression, found by taking this AST node index offset from the containing 2638 /// Decl AST node, which points to inline assembly AST node. Next, navigate 2639 /// to the asm template source code. 2640 /// The Decl is determined contextually. 2641 node_offset_asm_source: i32, 2642 /// The source location points to the return type of an inline assembly 2643 /// expression, found by taking this AST node index offset from the containing 2644 /// Decl AST node, which points to inline assembly AST node. Next, navigate 2645 /// to the return type expression. 2646 /// The Decl is determined contextually. 2647 node_offset_asm_ret_ty: i32, 2648 /// The source location points to the condition expression of an if 2649 /// expression, found by taking this AST node index offset from the containing 2650 /// Decl AST node, which points to an if expression AST node. Next, navigate 2651 /// to the condition expression. 2652 /// The Decl is determined contextually. 2653 node_offset_if_cond: i32, 2654 /// The source location points to a binary expression, such as `a + b`, found 2655 /// by taking this AST node index offset from the containing Decl AST node. 2656 /// The Decl is determined contextually. 2657 node_offset_bin_op: i32, 2658 /// The source location points to the LHS of a binary expression, found 2659 /// by taking this AST node index offset from the containing Decl AST node, 2660 /// which points to a binary expression AST node. Next, navigate to the LHS. 2661 /// The Decl is determined contextually. 2662 node_offset_bin_lhs: i32, 2663 /// The source location points to the RHS of a binary expression, found 2664 /// by taking this AST node index offset from the containing Decl AST node, 2665 /// which points to a binary expression AST node. Next, navigate to the RHS. 2666 /// The Decl is determined contextually. 2667 node_offset_bin_rhs: i32, 2668 /// The source location points to the operand of a switch expression, found 2669 /// by taking this AST node index offset from the containing Decl AST node, 2670 /// which points to a switch expression AST node. Next, navigate to the operand. 2671 /// The Decl is determined contextually. 2672 node_offset_switch_operand: i32, 2673 /// The source location points to the else/`_` prong of a switch expression, found 2674 /// by taking this AST node index offset from the containing Decl AST node, 2675 /// which points to a switch expression AST node. Next, navigate to the else/`_` prong. 2676 /// The Decl is determined contextually. 2677 node_offset_switch_special_prong: i32, 2678 /// The source location points to all the ranges of a switch expression, found 2679 /// by taking this AST node index offset from the containing Decl AST node, 2680 /// which points to a switch expression AST node. Next, navigate to any of the 2681 /// range nodes. The error applies to all of them. 2682 /// The Decl is determined contextually. 2683 node_offset_switch_range: i32, 2684 /// The source location points to the calling convention of a function type 2685 /// expression, found by taking this AST node index offset from the containing 2686 /// Decl AST node, which points to a function type AST node. Next, navigate to 2687 /// the calling convention node. 2688 /// The Decl is determined contextually. 2689 node_offset_fn_type_cc: i32, 2690 /// The source location points to the return type of a function type 2691 /// expression, found by taking this AST node index offset from the containing 2692 /// Decl AST node, which points to a function type AST node. Next, navigate to 2693 /// the return type node. 2694 /// The Decl is determined contextually. 2695 node_offset_fn_type_ret_ty: i32, 2696 /// The source location points to the type expression of an `anyframe->T` 2697 /// expression, found by taking this AST node index offset from the containing 2698 /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate 2699 /// to the type expression. 2700 /// The Decl is determined contextually. 2701 node_offset_anyframe_type: i32, 2702 /// The source location points to the string literal of `extern "foo"`, found 2703 /// by taking this AST node index offset from the containing 2704 /// Decl AST node, which points to a function prototype or variable declaration 2705 /// expression AST node. Next, navigate to the string literal of the `extern "foo"`. 2706 /// The Decl is determined contextually. 2707 node_offset_lib_name: i32, 2708 /// The source location points to the len expression of an `[N:S]T` 2709 /// expression, found by taking this AST node index offset from the containing 2710 /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate 2711 /// to the len expression. 2712 /// The Decl is determined contextually. 2713 node_offset_array_type_len: i32, 2714 /// The source location points to the sentinel expression of an `[N:S]T` 2715 /// expression, found by taking this AST node index offset from the containing 2716 /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate 2717 /// to the sentinel expression. 2718 /// The Decl is determined contextually. 2719 node_offset_array_type_sentinel: i32, 2720 /// The source location points to the elem expression of an `[N:S]T` 2721 /// expression, found by taking this AST node index offset from the containing 2722 /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate 2723 /// to the elem expression. 2724 /// The Decl is determined contextually. 2725 node_offset_array_type_elem: i32, 2726 2727 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; 2728 2729 noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc { 2730 var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } }; 2731 result.node_offset.trace.addAddr(@returnAddress(), "init"); 2732 return result; 2733 } 2734 2735 fn nodeOffsetRelease(node_offset: i32) LazySrcLoc { 2736 return .{ .node_offset = .{ .x = node_offset } }; 2737 } 2738 2739 /// Upgrade to a `SrcLoc` based on the `Decl` provided. 2740 pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl) SrcLoc { 2741 return switch (lazy) { 2742 .unneeded, 2743 .entire_file, 2744 .byte_abs, 2745 .token_abs, 2746 .node_abs, 2747 => .{ 2748 .file_scope = decl.getFileScope(), 2749 .parent_decl_node = 0, 2750 .lazy = lazy, 2751 }, 2752 2753 .byte_offset, 2754 .token_offset, 2755 .node_offset, 2756 .node_offset_back2tok, 2757 .node_offset_var_decl_ty, 2758 .node_offset_for_cond, 2759 .node_offset_builtin_call_arg0, 2760 .node_offset_builtin_call_arg1, 2761 .node_offset_builtin_call_arg2, 2762 .node_offset_builtin_call_arg3, 2763 .node_offset_builtin_call_arg4, 2764 .node_offset_builtin_call_arg5, 2765 .node_offset_array_access_index, 2766 .node_offset_slice_sentinel, 2767 .node_offset_call_func, 2768 .node_offset_field_name, 2769 .node_offset_deref_ptr, 2770 .node_offset_asm_source, 2771 .node_offset_asm_ret_ty, 2772 .node_offset_if_cond, 2773 .node_offset_bin_op, 2774 .node_offset_bin_lhs, 2775 .node_offset_bin_rhs, 2776 .node_offset_switch_operand, 2777 .node_offset_switch_special_prong, 2778 .node_offset_switch_range, 2779 .node_offset_fn_type_cc, 2780 .node_offset_fn_type_ret_ty, 2781 .node_offset_anyframe_type, 2782 .node_offset_lib_name, 2783 .node_offset_array_type_len, 2784 .node_offset_array_type_sentinel, 2785 .node_offset_array_type_elem, 2786 => .{ 2787 .file_scope = decl.getFileScope(), 2788 .parent_decl_node = decl.src_node, 2789 .lazy = lazy, 2790 }, 2791 }; 2792 } 2793 }; 2794 2795 pub const SemaError = error{ OutOfMemory, AnalysisFail }; 2796 pub const CompileError = error{ 2797 OutOfMemory, 2798 /// When this is returned, the compile error for the failure has already been recorded. 2799 AnalysisFail, 2800 /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set 2801 /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that 2802 /// somewhere up the call stack, the operation will be retried after doing expensive work 2803 /// to compute a source location. 2804 NeededSourceLocation, 2805 /// A Type or Value was needed to be used during semantic analysis, but it was not available 2806 /// because the function is generic. This is only seen when analyzing the body of a param 2807 /// instruction. 2808 GenericPoison, 2809 /// In a comptime scope, a return instruction was encountered. This error is only seen when 2810 /// doing a comptime function call. 2811 ComptimeReturn, 2812 /// In a comptime scope, a break instruction was encountered. This error is only seen when 2813 /// evaluating a comptime block. 2814 ComptimeBreak, 2815 }; 2816 2817 pub fn deinit(mod: *Module) void { 2818 const gpa = mod.gpa; 2819 2820 for (mod.import_table.keys()) |key| { 2821 gpa.free(key); 2822 } 2823 for (mod.import_table.values()) |value| { 2824 value.destroy(mod); 2825 } 2826 mod.import_table.deinit(gpa); 2827 2828 { 2829 var it = mod.embed_table.iterator(); 2830 while (it.next()) |entry| { 2831 gpa.free(entry.key_ptr.*); 2832 entry.value_ptr.*.destroy(mod); 2833 } 2834 mod.embed_table.deinit(gpa); 2835 } 2836 2837 mod.deletion_set.deinit(gpa); 2838 2839 // The callsite of `Compilation.create` owns the `main_pkg`, however 2840 // Module owns the builtin and std packages that it adds. 2841 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| { 2842 gpa.free(kv.key); 2843 kv.value.destroy(gpa); 2844 } 2845 if (mod.main_pkg.table.fetchRemove("std")) |kv| { 2846 gpa.free(kv.key); 2847 kv.value.destroy(gpa); 2848 } 2849 if (mod.main_pkg.table.fetchRemove("root")) |kv| { 2850 gpa.free(kv.key); 2851 } 2852 if (mod.root_pkg != mod.main_pkg) { 2853 mod.root_pkg.destroy(gpa); 2854 } 2855 2856 mod.compile_log_text.deinit(gpa); 2857 2858 mod.zig_cache_artifact_directory.handle.close(); 2859 mod.local_zir_cache.handle.close(); 2860 mod.global_zir_cache.handle.close(); 2861 2862 for (mod.failed_decls.values()) |value| { 2863 value.destroy(gpa); 2864 } 2865 mod.failed_decls.deinit(gpa); 2866 2867 if (mod.emit_h) |emit_h| { 2868 for (emit_h.failed_decls.values()) |value| { 2869 value.destroy(gpa); 2870 } 2871 emit_h.failed_decls.deinit(gpa); 2872 emit_h.decl_table.deinit(gpa); 2873 emit_h.allocated_emit_h.deinit(gpa); 2874 gpa.destroy(emit_h); 2875 } 2876 2877 for (mod.failed_files.values()) |value| { 2878 if (value) |msg| msg.destroy(gpa); 2879 } 2880 mod.failed_files.deinit(gpa); 2881 2882 for (mod.failed_embed_files.values()) |msg| { 2883 msg.destroy(gpa); 2884 } 2885 mod.failed_embed_files.deinit(gpa); 2886 2887 for (mod.failed_exports.values()) |value| { 2888 value.destroy(gpa); 2889 } 2890 mod.failed_exports.deinit(gpa); 2891 2892 mod.compile_log_decls.deinit(gpa); 2893 2894 for (mod.decl_exports.values()) |export_list| { 2895 gpa.free(export_list); 2896 } 2897 mod.decl_exports.deinit(gpa); 2898 2899 for (mod.export_owners.values()) |value| { 2900 freeExportList(gpa, value); 2901 } 2902 mod.export_owners.deinit(gpa); 2903 2904 { 2905 var it = mod.global_error_set.keyIterator(); 2906 while (it.next()) |key| { 2907 gpa.free(key.*); 2908 } 2909 mod.global_error_set.deinit(gpa); 2910 } 2911 2912 mod.error_name_list.deinit(gpa); 2913 mod.test_functions.deinit(gpa); 2914 mod.align_stack_fns.deinit(gpa); 2915 mod.monomorphed_funcs.deinit(gpa); 2916 2917 { 2918 var it = mod.memoized_calls.iterator(); 2919 while (it.next()) |entry| { 2920 gpa.free(entry.key_ptr.args); 2921 entry.value_ptr.arena.promote(gpa).deinit(); 2922 } 2923 mod.memoized_calls.deinit(gpa); 2924 } 2925 2926 mod.decls_free_list.deinit(gpa); 2927 mod.allocated_decls.deinit(gpa); 2928 mod.global_assembly.deinit(gpa); 2929 2930 mod.string_literal_table.deinit(gpa); 2931 mod.string_literal_bytes.deinit(gpa); 2932 } 2933 2934 pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { 2935 const gpa = mod.gpa; 2936 { 2937 const decl = mod.declPtr(decl_index); 2938 log.debug("destroy {*} ({s})", .{ decl, decl.name }); 2939 _ = mod.test_functions.swapRemove(decl_index); 2940 if (decl.deletion_flag) { 2941 assert(mod.deletion_set.swapRemove(decl_index)); 2942 } 2943 if (mod.global_assembly.fetchRemove(decl_index)) |kv| { 2944 gpa.free(kv.value); 2945 } 2946 if (decl.has_tv) { 2947 if (decl.getInnerNamespace()) |namespace| { 2948 namespace.destroyDecls(mod); 2949 } 2950 decl.clearValues(mod); 2951 } 2952 decl.dependants.deinit(gpa); 2953 decl.dependencies.deinit(gpa); 2954 decl.clearName(gpa); 2955 decl.* = undefined; 2956 } 2957 mod.decls_free_list.append(gpa, decl_index) catch { 2958 // In order to keep `destroyDecl` a non-fallible function, we ignore memory 2959 // allocation failures here, instead leaking the Decl until garbage collection. 2960 }; 2961 if (mod.emit_h) |mod_emit_h| { 2962 const decl_emit_h = mod_emit_h.declPtr(decl_index); 2963 decl_emit_h.fwd_decl.deinit(gpa); 2964 decl_emit_h.* = undefined; 2965 } 2966 } 2967 2968 pub fn declPtr(mod: *Module, decl_index: Decl.Index) *Decl { 2969 return mod.allocated_decls.at(@enumToInt(decl_index)); 2970 } 2971 2972 /// Returns true if and only if the Decl is the top level struct associated with a File. 2973 pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { 2974 const decl = mod.declPtr(decl_index); 2975 if (decl.src_namespace.parent != null) 2976 return false; 2977 return decl_index == decl.src_namespace.getDeclIndex(); 2978 } 2979 2980 fn freeExportList(gpa: Allocator, export_list: []*Export) void { 2981 for (export_list) |exp| { 2982 gpa.free(exp.options.name); 2983 if (exp.options.section) |s| gpa.free(s); 2984 gpa.destroy(exp); 2985 } 2986 gpa.free(export_list); 2987 } 2988 2989 const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8; 2990 // TODO This is taking advantage of matching stage1 debug union layout. 2991 // We need a better language feature for initializing a union with 2992 // a runtime known tag. 2993 const Stage1DataLayout = extern struct { 2994 data: [8]u8 align(@alignOf(Zir.Inst.Data)), 2995 safety_tag: u8, 2996 }; 2997 comptime { 2998 if (data_has_safety_tag) { 2999 assert(@sizeOf(Stage1DataLayout) == @sizeOf(Zir.Inst.Data)); 3000 } 3001 } 3002 3003 pub fn astGenFile(mod: *Module, file: *File) !void { 3004 const tracy = trace(@src()); 3005 defer tracy.end(); 3006 3007 const comp = mod.comp; 3008 const gpa = mod.gpa; 3009 3010 // In any case we need to examine the stat of the file to determine the course of action. 3011 var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); 3012 defer source_file.close(); 3013 3014 const stat = try source_file.stat(); 3015 3016 const want_local_cache = file.pkg == mod.main_pkg; 3017 const digest = hash: { 3018 var path_hash: Cache.HashHelper = .{}; 3019 path_hash.addBytes(build_options.version); 3020 if (!want_local_cache) { 3021 path_hash.addOptionalBytes(file.pkg.root_src_directory.path); 3022 } 3023 path_hash.addBytes(file.sub_file_path); 3024 break :hash path_hash.final(); 3025 }; 3026 const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache; 3027 const zir_dir = cache_directory.handle; 3028 3029 var cache_file: ?std.fs.File = null; 3030 defer if (cache_file) |f| f.close(); 3031 3032 // Determine whether we need to reload the file from disk and redo parsing and AstGen. 3033 switch (file.status) { 3034 .never_loaded, .retryable_failure => cached: { 3035 // First, load the cached ZIR code, if any. 3036 log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{ 3037 file.sub_file_path, want_local_cache, &digest, 3038 }); 3039 3040 // We ask for a lock in order to coordinate with other zig processes. 3041 // If another process is already working on this file, we will get the cached 3042 // version. Likewise if we're working on AstGen and another process asks for 3043 // the cached file, they'll get it. 3044 cache_file = zir_dir.openFile(&digest, .{ .lock = .Shared }) catch |err| switch (err) { 3045 error.PathAlreadyExists => unreachable, // opening for reading 3046 error.NoSpaceLeft => unreachable, // opening for reading 3047 error.NotDir => unreachable, // no dir components 3048 error.InvalidUtf8 => unreachable, // it's a hex encoded name 3049 error.BadPathName => unreachable, // it's a hex encoded name 3050 error.NameTooLong => unreachable, // it's a fixed size name 3051 error.PipeBusy => unreachable, // it's not a pipe 3052 error.WouldBlock => unreachable, // not asking for non-blocking I/O 3053 3054 error.SymLinkLoop, 3055 error.FileNotFound, 3056 error.Unexpected, 3057 => break :cached, 3058 3059 else => |e| return e, // Retryable errors are handled at callsite. 3060 }; 3061 3062 // First we read the header to determine the lengths of arrays. 3063 const header = cache_file.?.reader().readStruct(Zir.Header) catch |err| switch (err) { 3064 // This can happen if Zig bails out of this function between creating 3065 // the cached file and writing it. 3066 error.EndOfStream => break :cached, 3067 else => |e| return e, 3068 }; 3069 const unchanged_metadata = 3070 stat.size == header.stat_size and 3071 stat.mtime == header.stat_mtime and 3072 stat.inode == header.stat_inode; 3073 3074 if (!unchanged_metadata) { 3075 log.debug("AstGen cache stale: {s}", .{file.sub_file_path}); 3076 break :cached; 3077 } 3078 log.debug("AstGen cache hit: {s} instructions_len={d}", .{ 3079 file.sub_file_path, header.instructions_len, 3080 }); 3081 3082 var instructions: std.MultiArrayList(Zir.Inst) = .{}; 3083 defer instructions.deinit(gpa); 3084 3085 try instructions.setCapacity(gpa, header.instructions_len); 3086 instructions.len = header.instructions_len; 3087 3088 var zir: Zir = .{ 3089 .instructions = instructions.toOwnedSlice(), 3090 .string_bytes = &.{}, 3091 .extra = &.{}, 3092 }; 3093 var keep_zir = false; 3094 defer if (!keep_zir) zir.deinit(gpa); 3095 3096 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); 3097 zir.extra = try gpa.alloc(u32, header.extra_len); 3098 3099 const safety_buffer = if (data_has_safety_tag) 3100 try gpa.alloc([8]u8, header.instructions_len) 3101 else 3102 undefined; 3103 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3104 3105 const data_ptr = if (data_has_safety_tag) 3106 @ptrCast([*]u8, safety_buffer.ptr) 3107 else 3108 @ptrCast([*]u8, zir.instructions.items(.data).ptr); 3109 3110 var iovecs = [_]std.os.iovec{ 3111 .{ 3112 .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr), 3113 .iov_len = header.instructions_len, 3114 }, 3115 .{ 3116 .iov_base = data_ptr, 3117 .iov_len = header.instructions_len * 8, 3118 }, 3119 .{ 3120 .iov_base = zir.string_bytes.ptr, 3121 .iov_len = header.string_bytes_len, 3122 }, 3123 .{ 3124 .iov_base = @ptrCast([*]u8, zir.extra.ptr), 3125 .iov_len = header.extra_len * 4, 3126 }, 3127 }; 3128 const amt_read = try cache_file.?.readvAll(&iovecs); 3129 const amt_expected = zir.instructions.len * 9 + 3130 zir.string_bytes.len + 3131 zir.extra.len * 4; 3132 if (amt_read != amt_expected) { 3133 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path}); 3134 break :cached; 3135 } 3136 if (data_has_safety_tag) { 3137 const tags = zir.instructions.items(.tag); 3138 for (zir.instructions.items(.data)) |*data, i| { 3139 const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])]; 3140 const as_struct = @ptrCast(*Stage1DataLayout, data); 3141 as_struct.* = .{ 3142 .safety_tag = @enumToInt(union_tag), 3143 .data = safety_buffer[i], 3144 }; 3145 } 3146 } 3147 3148 keep_zir = true; 3149 file.zir = zir; 3150 file.zir_loaded = true; 3151 file.stat = .{ 3152 .size = header.stat_size, 3153 .inode = header.stat_inode, 3154 .mtime = header.stat_mtime, 3155 }; 3156 file.status = .success_zir; 3157 log.debug("AstGen cached success: {s}", .{file.sub_file_path}); 3158 3159 // TODO don't report compile errors until Sema @importFile 3160 if (file.zir.hasCompileErrors()) { 3161 { 3162 comp.mutex.lock(); 3163 defer comp.mutex.unlock(); 3164 try mod.failed_files.putNoClobber(gpa, file, null); 3165 } 3166 file.status = .astgen_failure; 3167 return error.AnalysisFail; 3168 } 3169 return; 3170 }, 3171 .parse_failure, .astgen_failure, .success_zir => { 3172 const unchanged_metadata = 3173 stat.size == file.stat.size and 3174 stat.mtime == file.stat.mtime and 3175 stat.inode == file.stat.inode; 3176 3177 if (unchanged_metadata) { 3178 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path}); 3179 return; 3180 } 3181 3182 log.debug("metadata changed: {s}", .{file.sub_file_path}); 3183 }, 3184 } 3185 if (cache_file) |f| { 3186 f.close(); 3187 cache_file = null; 3188 } 3189 cache_file = zir_dir.createFile(&digest, .{ .lock = .Exclusive }) catch |err| switch (err) { 3190 error.NotDir => unreachable, // no dir components 3191 error.InvalidUtf8 => unreachable, // it's a hex encoded name 3192 error.BadPathName => unreachable, // it's a hex encoded name 3193 error.NameTooLong => unreachable, // it's a fixed size name 3194 error.PipeBusy => unreachable, // it's not a pipe 3195 error.WouldBlock => unreachable, // not asking for non-blocking I/O 3196 error.FileNotFound => unreachable, // no dir components 3197 3198 else => |e| { 3199 const pkg_path = file.pkg.root_src_directory.path orelse "."; 3200 const cache_path = cache_directory.path orelse "."; 3201 log.warn("unable to save cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{ 3202 pkg_path, file.sub_file_path, cache_path, &digest, @errorName(e), 3203 }); 3204 return; 3205 }, 3206 }; 3207 3208 mod.lockAndClearFileCompileError(file); 3209 3210 // If the previous ZIR does not have compile errors, keep it around 3211 // in case parsing or new ZIR fails. In case of successful ZIR update 3212 // at the end of this function we will free it. 3213 // We keep the previous ZIR loaded so that we can use it 3214 // for the update next time it does not have any compile errors. This avoids 3215 // needlessly tossing out semantic analysis work when an error is 3216 // temporarily introduced. 3217 if (file.zir_loaded and !file.zir.hasCompileErrors()) { 3218 assert(file.prev_zir == null); 3219 const prev_zir_ptr = try gpa.create(Zir); 3220 file.prev_zir = prev_zir_ptr; 3221 prev_zir_ptr.* = file.zir; 3222 file.zir = undefined; 3223 file.zir_loaded = false; 3224 } 3225 file.unload(gpa); 3226 3227 if (stat.size > std.math.maxInt(u32)) 3228 return error.FileTooBig; 3229 3230 const source = try gpa.allocSentinel(u8, @intCast(usize, stat.size), 0); 3231 defer if (!file.source_loaded) gpa.free(source); 3232 const amt = try source_file.readAll(source); 3233 if (amt != stat.size) 3234 return error.UnexpectedEndOfFile; 3235 3236 file.stat = .{ 3237 .size = stat.size, 3238 .inode = stat.inode, 3239 .mtime = stat.mtime, 3240 }; 3241 file.source = source; 3242 file.source_loaded = true; 3243 3244 file.tree = try std.zig.parse(gpa, source); 3245 defer if (!file.tree_loaded) file.tree.deinit(gpa); 3246 3247 if (file.tree.errors.len != 0) { 3248 const parse_err = file.tree.errors[0]; 3249 3250 var msg = std.ArrayList(u8).init(gpa); 3251 defer msg.deinit(); 3252 3253 const token_starts = file.tree.tokens.items(.start); 3254 const token_tags = file.tree.tokens.items(.tag); 3255 3256 const extra_offset = file.tree.errorOffset(parse_err); 3257 try file.tree.renderError(parse_err, msg.writer()); 3258 const err_msg = try gpa.create(ErrorMsg); 3259 err_msg.* = .{ 3260 .src_loc = .{ 3261 .file_scope = file, 3262 .parent_decl_node = 0, 3263 .lazy = .{ .byte_abs = token_starts[parse_err.token] + extra_offset }, 3264 }, 3265 .msg = msg.toOwnedSlice(), 3266 }; 3267 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) { 3268 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len); 3269 const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off; 3270 try mod.errNoteNonLazy(.{ 3271 .file_scope = file, 3272 .parent_decl_node = 0, 3273 .lazy = .{ .byte_abs = byte_abs }, 3274 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])}); 3275 } else if (parse_err.tag == .decl_between_fields) { 3276 try mod.errNoteNonLazy(.{ 3277 .file_scope = file, 3278 .parent_decl_node = 0, 3279 .lazy = .{ .byte_abs = token_starts[file.tree.errors[1].token] }, 3280 }, err_msg, "field before declarations here", .{}); 3281 try mod.errNoteNonLazy(.{ 3282 .file_scope = file, 3283 .parent_decl_node = 0, 3284 .lazy = .{ .byte_abs = token_starts[file.tree.errors[2].token] }, 3285 }, err_msg, "field after declarations here", .{}); 3286 } 3287 3288 { 3289 comp.mutex.lock(); 3290 defer comp.mutex.unlock(); 3291 try mod.failed_files.putNoClobber(gpa, file, err_msg); 3292 } 3293 file.status = .parse_failure; 3294 return error.AnalysisFail; 3295 } 3296 file.tree_loaded = true; 3297 3298 file.zir = try AstGen.generate(gpa, file.tree); 3299 file.zir_loaded = true; 3300 file.status = .success_zir; 3301 log.debug("AstGen fresh success: {s}", .{file.sub_file_path}); 3302 3303 const safety_buffer = if (data_has_safety_tag) 3304 try gpa.alloc([8]u8, file.zir.instructions.len) 3305 else 3306 undefined; 3307 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3308 const data_ptr = if (data_has_safety_tag) 3309 if (file.zir.instructions.len == 0) 3310 @as([*]const u8, undefined) 3311 else 3312 @ptrCast([*]const u8, safety_buffer.ptr) 3313 else 3314 @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr); 3315 if (data_has_safety_tag) { 3316 // The `Data` union has a safety tag but in the file format we store it without. 3317 for (file.zir.instructions.items(.data)) |*data, i| { 3318 const as_struct = @ptrCast(*const Stage1DataLayout, data); 3319 safety_buffer[i] = as_struct.data; 3320 } 3321 } 3322 3323 const header: Zir.Header = .{ 3324 .instructions_len = @intCast(u32, file.zir.instructions.len), 3325 .string_bytes_len = @intCast(u32, file.zir.string_bytes.len), 3326 .extra_len = @intCast(u32, file.zir.extra.len), 3327 3328 .stat_size = stat.size, 3329 .stat_inode = stat.inode, 3330 .stat_mtime = stat.mtime, 3331 }; 3332 var iovecs = [_]std.os.iovec_const{ 3333 .{ 3334 .iov_base = @ptrCast([*]const u8, &header), 3335 .iov_len = @sizeOf(Zir.Header), 3336 }, 3337 .{ 3338 .iov_base = @ptrCast([*]const u8, file.zir.instructions.items(.tag).ptr), 3339 .iov_len = file.zir.instructions.len, 3340 }, 3341 .{ 3342 .iov_base = data_ptr, 3343 .iov_len = file.zir.instructions.len * 8, 3344 }, 3345 .{ 3346 .iov_base = file.zir.string_bytes.ptr, 3347 .iov_len = file.zir.string_bytes.len, 3348 }, 3349 .{ 3350 .iov_base = @ptrCast([*]const u8, file.zir.extra.ptr), 3351 .iov_len = file.zir.extra.len * 4, 3352 }, 3353 }; 3354 cache_file.?.writevAll(&iovecs) catch |err| { 3355 const pkg_path = file.pkg.root_src_directory.path orelse "."; 3356 const cache_path = cache_directory.path orelse "."; 3357 log.warn("unable to write cached ZIR code for {s}/{s} to {s}/{s}: {s}", .{ 3358 pkg_path, file.sub_file_path, cache_path, &digest, @errorName(err), 3359 }); 3360 }; 3361 3362 if (file.zir.hasCompileErrors()) { 3363 { 3364 comp.mutex.lock(); 3365 defer comp.mutex.unlock(); 3366 try mod.failed_files.putNoClobber(gpa, file, null); 3367 } 3368 file.status = .astgen_failure; 3369 return error.AnalysisFail; 3370 } 3371 3372 if (file.prev_zir) |prev_zir| { 3373 // Iterate over all Namespace objects contained within this File, looking at the 3374 // previous and new ZIR together and update the references to point 3375 // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace 3376 // decl_table keys need to get updated to point to the new memory, even if the 3377 // underlying source code is unchanged. 3378 // We do not need to hold any locks at this time because all the Decl and Namespace 3379 // objects being touched are specific to this File, and the only other concurrent 3380 // tasks are touching other File objects. 3381 try updateZirRefs(mod, file, prev_zir.*); 3382 // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, 3383 // and semantic analysis will deal with them properly. 3384 // No need to keep previous ZIR. 3385 prev_zir.deinit(gpa); 3386 gpa.destroy(prev_zir); 3387 file.prev_zir = null; 3388 } else if (file.root_decl.unwrap()) |root_decl| { 3389 // This is an update, but it is the first time the File has succeeded 3390 // ZIR. We must mark it outdated since we have already tried to 3391 // semantically analyze it. 3392 try file.outdated_decls.resize(gpa, 1); 3393 file.outdated_decls.items[0] = root_decl; 3394 } 3395 } 3396 3397 /// Patch ups: 3398 /// * Struct.zir_index 3399 /// * Decl.zir_index 3400 /// * Fn.zir_body_inst 3401 /// * Decl.zir_decl_index 3402 fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { 3403 const gpa = mod.gpa; 3404 const new_zir = file.zir; 3405 3406 // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which 3407 // creates a namespace, gets mapped from old to new here. 3408 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}; 3409 defer inst_map.deinit(gpa); 3410 // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item. 3411 // e.g. the thing that Decl.zir_decl_index points to. 3412 var extra_map: std.AutoHashMapUnmanaged(u32, u32) = .{}; 3413 defer extra_map.deinit(gpa); 3414 3415 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map); 3416 3417 // Walk the Decl graph, updating ZIR indexes, strings, and populating 3418 // the deleted and outdated lists. 3419 3420 var decl_stack: std.ArrayListUnmanaged(Decl.Index) = .{}; 3421 defer decl_stack.deinit(gpa); 3422 3423 const root_decl = file.root_decl.unwrap().?; 3424 try decl_stack.append(gpa, root_decl); 3425 3426 file.deleted_decls.clearRetainingCapacity(); 3427 file.outdated_decls.clearRetainingCapacity(); 3428 3429 // The root decl is always outdated; otherwise we would not have had 3430 // to re-generate ZIR for the File. 3431 try file.outdated_decls.append(gpa, root_decl); 3432 3433 while (decl_stack.popOrNull()) |decl_index| { 3434 const decl = mod.declPtr(decl_index); 3435 // Anonymous decls and the root decl have this set to 0. We still need 3436 // to walk them but we do not need to modify this value. 3437 // Anonymous decls should not be marked outdated. They will be re-generated 3438 // if their owner decl is marked outdated. 3439 if (decl.zir_decl_index != 0) { 3440 const old_zir_decl_index = decl.zir_decl_index; 3441 const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { 3442 log.debug("updateZirRefs {s}: delete {*} ({s})", .{ 3443 file.sub_file_path, decl, decl.name, 3444 }); 3445 try file.deleted_decls.append(gpa, decl_index); 3446 continue; 3447 }; 3448 const old_hash = decl.contentsHashZir(old_zir); 3449 decl.zir_decl_index = new_zir_decl_index; 3450 const new_hash = decl.contentsHashZir(new_zir); 3451 if (!std.zig.srcHashEql(old_hash, new_hash)) { 3452 log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{ 3453 file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, 3454 }); 3455 try file.outdated_decls.append(gpa, decl_index); 3456 } else { 3457 log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{ 3458 file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, 3459 }); 3460 } 3461 } 3462 3463 if (!decl.owns_tv) continue; 3464 3465 if (decl.getStruct()) |struct_obj| { 3466 struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { 3467 try file.deleted_decls.append(gpa, decl_index); 3468 continue; 3469 }; 3470 } 3471 3472 if (decl.getUnion()) |union_obj| { 3473 union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse { 3474 try file.deleted_decls.append(gpa, decl_index); 3475 continue; 3476 }; 3477 } 3478 3479 if (decl.getFunction()) |func| { 3480 func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { 3481 try file.deleted_decls.append(gpa, decl_index); 3482 continue; 3483 }; 3484 } 3485 3486 if (decl.getInnerNamespace()) |namespace| { 3487 for (namespace.decls.keys()) |sub_decl| { 3488 try decl_stack.append(gpa, sub_decl); 3489 } 3490 for (namespace.anon_decls.keys()) |sub_decl| { 3491 try decl_stack.append(gpa, sub_decl); 3492 } 3493 } 3494 } 3495 } 3496 3497 pub fn populateBuiltinFile(mod: *Module) !void { 3498 const tracy = trace(@src()); 3499 defer tracy.end(); 3500 3501 const comp = mod.comp; 3502 const pkg_and_file = blk: { 3503 comp.mutex.lock(); 3504 defer comp.mutex.unlock(); 3505 3506 const builtin_pkg = mod.main_pkg.table.get("builtin").?; 3507 const result = try mod.importPkg(builtin_pkg); 3508 break :blk .{ 3509 .file = result.file, 3510 .pkg = builtin_pkg, 3511 }; 3512 }; 3513 const file = pkg_and_file.file; 3514 const builtin_pkg = pkg_and_file.pkg; 3515 const gpa = mod.gpa; 3516 file.source = try comp.generateBuiltinZigSource(gpa); 3517 file.source_loaded = true; 3518 3519 if (builtin_pkg.root_src_directory.handle.statFile(builtin_pkg.root_src_path)) |stat| { 3520 if (stat.size != file.source.len) { 3521 const full_path = try builtin_pkg.root_src_directory.join(gpa, &.{ 3522 builtin_pkg.root_src_path, 3523 }); 3524 defer gpa.free(full_path); 3525 3526 log.warn( 3527 "the cached file '{s}' had the wrong size. Expected {d}, found {d}. " ++ 3528 "Overwriting with correct file contents now", 3529 .{ full_path, file.source.len, stat.size }, 3530 ); 3531 3532 try writeBuiltinFile(file, builtin_pkg); 3533 } else { 3534 file.stat = .{ 3535 .size = stat.size, 3536 .inode = stat.inode, 3537 .mtime = stat.mtime, 3538 }; 3539 } 3540 } else |err| switch (err) { 3541 error.BadPathName => unreachable, // it's always "builtin.zig" 3542 error.NameTooLong => unreachable, // it's always "builtin.zig" 3543 error.PipeBusy => unreachable, // it's not a pipe 3544 error.WouldBlock => unreachable, // not asking for non-blocking I/O 3545 3546 error.FileNotFound => try writeBuiltinFile(file, builtin_pkg), 3547 3548 else => |e| return e, 3549 } 3550 3551 file.tree = try std.zig.parse(gpa, file.source); 3552 file.tree_loaded = true; 3553 assert(file.tree.errors.len == 0); // builtin.zig must parse 3554 3555 file.zir = try AstGen.generate(gpa, file.tree); 3556 file.zir_loaded = true; 3557 file.status = .success_zir; 3558 } 3559 3560 pub fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { 3561 var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{}); 3562 defer af.deinit(); 3563 try af.file.writeAll(file.source); 3564 try af.finish(); 3565 3566 file.stat = .{ 3567 .size = file.source.len, 3568 .inode = 0, // dummy value 3569 .mtime = 0, // dummy value 3570 }; 3571 } 3572 3573 pub fn mapOldZirToNew( 3574 gpa: Allocator, 3575 old_zir: Zir, 3576 new_zir: Zir, 3577 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), 3578 extra_map: *std.AutoHashMapUnmanaged(u32, u32), 3579 ) Allocator.Error!void { 3580 // Contain ZIR indexes of declaration instructions. 3581 const MatchedZirDecl = struct { 3582 old_inst: Zir.Inst.Index, 3583 new_inst: Zir.Inst.Index, 3584 }; 3585 var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{}; 3586 defer match_stack.deinit(gpa); 3587 3588 // Main struct inst is always the same 3589 try match_stack.append(gpa, .{ 3590 .old_inst = Zir.main_struct_inst, 3591 .new_inst = Zir.main_struct_inst, 3592 }); 3593 3594 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa); 3595 defer old_decls.deinit(); 3596 var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa); 3597 defer new_decls.deinit(); 3598 3599 while (match_stack.popOrNull()) |match_item| { 3600 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst); 3601 3602 // Maps name to extra index of decl sub item. 3603 var decl_map: std.StringHashMapUnmanaged(u32) = .{}; 3604 defer decl_map.deinit(gpa); 3605 3606 { 3607 var old_decl_it = old_zir.declIterator(match_item.old_inst); 3608 while (old_decl_it.next()) |old_decl| { 3609 try decl_map.put(gpa, old_decl.name, old_decl.sub_index); 3610 } 3611 } 3612 3613 var new_decl_it = new_zir.declIterator(match_item.new_inst); 3614 while (new_decl_it.next()) |new_decl| { 3615 const old_extra_index = decl_map.get(new_decl.name) orelse continue; 3616 const new_extra_index = new_decl.sub_index; 3617 try extra_map.put(gpa, old_extra_index, new_extra_index); 3618 3619 try old_zir.findDecls(&old_decls, old_extra_index); 3620 try new_zir.findDecls(&new_decls, new_extra_index); 3621 var i: usize = 0; 3622 while (true) : (i += 1) { 3623 if (i >= old_decls.items.len) break; 3624 if (i >= new_decls.items.len) break; 3625 try match_stack.append(gpa, .{ 3626 .old_inst = old_decls.items[i], 3627 .new_inst = new_decls.items[i], 3628 }); 3629 } 3630 } 3631 } 3632 } 3633 3634 /// This ensures that the Decl will have a Type and Value populated. 3635 /// However the resolution status of the Type may not be fully resolved. 3636 /// For example an inferred error set is not resolved until after `analyzeFnBody`. 3637 /// is called. 3638 pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { 3639 const tracy = trace(@src()); 3640 defer tracy.end(); 3641 3642 const decl = mod.declPtr(decl_index); 3643 3644 const subsequent_analysis = switch (decl.analysis) { 3645 .in_progress => unreachable, 3646 3647 .file_failure, 3648 .sema_failure, 3649 .sema_failure_retryable, 3650 .codegen_failure, 3651 .dependency_failure, 3652 .codegen_failure_retryable, 3653 => return error.AnalysisFail, 3654 3655 .complete => return, 3656 3657 .outdated => blk: { 3658 log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); 3659 3660 // The exports this Decl performs will be re-discovered, so we remove them here 3661 // prior to re-analysis. 3662 mod.deleteDeclExports(decl_index); 3663 // Dependencies will be re-discovered, so we remove them here prior to re-analysis. 3664 for (decl.dependencies.keys()) |dep_index| { 3665 const dep = mod.declPtr(dep_index); 3666 dep.removeDependant(decl_index); 3667 if (dep.dependants.count() == 0 and !dep.deletion_flag) { 3668 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ 3669 decl, decl.name, dep, dep.name, 3670 }); 3671 try mod.markDeclForDeletion(dep_index); 3672 } 3673 } 3674 decl.dependencies.clearRetainingCapacity(); 3675 3676 break :blk true; 3677 }, 3678 3679 .unreferenced => false, 3680 }; 3681 3682 var decl_prog_node = mod.sema_prog_node.start(mem.sliceTo(decl.name, 0), 0); 3683 decl_prog_node.activate(); 3684 defer decl_prog_node.end(); 3685 3686 const type_changed = mod.semaDecl(decl_index) catch |err| switch (err) { 3687 error.AnalysisFail => { 3688 if (decl.analysis == .in_progress) { 3689 // If this decl caused the compile error, the analysis field would 3690 // be changed to indicate it was this Decl's fault. Because this 3691 // did not happen, we infer here that it was a dependency failure. 3692 decl.analysis = .dependency_failure; 3693 } 3694 return error.AnalysisFail; 3695 }, 3696 error.NeededSourceLocation => unreachable, 3697 error.GenericPoison => unreachable, 3698 else => |e| { 3699 decl.analysis = .sema_failure_retryable; 3700 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); 3701 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( 3702 mod.gpa, 3703 decl.srcLoc(), 3704 "unable to analyze: {s}", 3705 .{@errorName(e)}, 3706 )); 3707 return error.AnalysisFail; 3708 }, 3709 }; 3710 3711 if (subsequent_analysis) { 3712 // We may need to chase the dependants and re-analyze them. 3713 // However, if the decl is a function, and the type is the same, we do not need to. 3714 if (type_changed or decl.ty.zigTypeTag() != .Fn) { 3715 for (decl.dependants.keys()) |dep_index| { 3716 const dep = mod.declPtr(dep_index); 3717 switch (dep.analysis) { 3718 .unreferenced => unreachable, 3719 .in_progress => continue, // already doing analysis, ok 3720 .outdated => continue, // already queued for update 3721 3722 .file_failure, 3723 .dependency_failure, 3724 .sema_failure, 3725 .sema_failure_retryable, 3726 .codegen_failure, 3727 .codegen_failure_retryable, 3728 .complete, 3729 => if (dep.generation != mod.generation) { 3730 try mod.markOutdatedDecl(dep_index); 3731 }, 3732 } 3733 } 3734 } 3735 } 3736 } 3737 3738 pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { 3739 const tracy = trace(@src()); 3740 defer tracy.end(); 3741 3742 const decl_index = func.owner_decl; 3743 const decl = mod.declPtr(decl_index); 3744 3745 switch (decl.analysis) { 3746 .unreferenced => unreachable, 3747 .in_progress => unreachable, 3748 .outdated => unreachable, 3749 3750 .file_failure, 3751 .sema_failure, 3752 .codegen_failure, 3753 .dependency_failure, 3754 .sema_failure_retryable, 3755 => return error.AnalysisFail, 3756 3757 .complete, .codegen_failure_retryable => { 3758 switch (func.state) { 3759 .sema_failure, .dependency_failure => return error.AnalysisFail, 3760 .queued => {}, 3761 .in_progress => unreachable, 3762 .inline_only => unreachable, // don't queue work for this 3763 .success => return, 3764 } 3765 3766 const gpa = mod.gpa; 3767 3768 var tmp_arena = std.heap.ArenaAllocator.init(gpa); 3769 defer tmp_arena.deinit(); 3770 const sema_arena = tmp_arena.allocator(); 3771 3772 var air = mod.analyzeFnBody(func, sema_arena) catch |err| switch (err) { 3773 error.AnalysisFail => { 3774 if (func.state == .in_progress) { 3775 // If this decl caused the compile error, the analysis field would 3776 // be changed to indicate it was this Decl's fault. Because this 3777 // did not happen, we infer here that it was a dependency failure. 3778 func.state = .dependency_failure; 3779 } 3780 return error.AnalysisFail; 3781 }, 3782 error.OutOfMemory => return error.OutOfMemory, 3783 }; 3784 defer air.deinit(gpa); 3785 3786 if (mod.comp.bin_file.options.emit == null) return; 3787 3788 log.debug("analyze liveness of {s}", .{decl.name}); 3789 var liveness = try Liveness.analyze(gpa, air); 3790 defer liveness.deinit(gpa); 3791 3792 if (builtin.mode == .Debug and mod.comp.verbose_air) { 3793 const fqn = try decl.getFullyQualifiedName(mod); 3794 defer mod.gpa.free(fqn); 3795 3796 std.debug.print("# Begin Function AIR: {s}:\n", .{fqn}); 3797 @import("print_air.zig").dump(mod, air, liveness); 3798 std.debug.print("# End Function AIR: {s}\n\n", .{fqn}); 3799 } 3800 3801 mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) { 3802 error.OutOfMemory => return error.OutOfMemory, 3803 error.AnalysisFail => { 3804 decl.analysis = .codegen_failure; 3805 return; 3806 }, 3807 else => { 3808 try mod.failed_decls.ensureUnusedCapacity(gpa, 1); 3809 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( 3810 gpa, 3811 decl.srcLoc(), 3812 "unable to codegen: {s}", 3813 .{@errorName(err)}, 3814 )); 3815 decl.analysis = .codegen_failure_retryable; 3816 return; 3817 }, 3818 }; 3819 return; 3820 }, 3821 } 3822 } 3823 3824 pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void { 3825 const tracy = trace(@src()); 3826 defer tracy.end(); 3827 3828 // TODO we can potentially relax this if we store some more information along 3829 // with decl dependency edges 3830 const owner_decl = mod.declPtr(embed_file.owner_decl); 3831 for (owner_decl.dependants.keys()) |dep_index| { 3832 const dep = mod.declPtr(dep_index); 3833 switch (dep.analysis) { 3834 .unreferenced => unreachable, 3835 .in_progress => continue, // already doing analysis, ok 3836 .outdated => continue, // already queued for update 3837 3838 .file_failure, 3839 .dependency_failure, 3840 .sema_failure, 3841 .sema_failure_retryable, 3842 .codegen_failure, 3843 .codegen_failure_retryable, 3844 .complete, 3845 => if (dep.generation != mod.generation) { 3846 try mod.markOutdatedDecl(dep_index); 3847 }, 3848 } 3849 } 3850 } 3851 3852 pub fn semaPkg(mod: *Module, pkg: *Package) !void { 3853 const file = (try mod.importPkg(pkg)).file; 3854 return mod.semaFile(file); 3855 } 3856 3857 /// Regardless of the file status, will create a `Decl` so that we 3858 /// can track dependencies and re-analyze when the file becomes outdated. 3859 pub fn semaFile(mod: *Module, file: *File) SemaError!void { 3860 const tracy = trace(@src()); 3861 defer tracy.end(); 3862 3863 if (file.root_decl != .none) return; 3864 3865 const gpa = mod.gpa; 3866 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 3867 errdefer new_decl_arena.deinit(); 3868 const new_decl_arena_allocator = new_decl_arena.allocator(); 3869 3870 const struct_obj = try new_decl_arena_allocator.create(Module.Struct); 3871 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); 3872 const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); 3873 const ty_ty = comptime Type.initTag(.type); 3874 struct_obj.* = .{ 3875 .owner_decl = undefined, // set below 3876 .fields = .{}, 3877 .node_offset = 0, // it's the struct for the root file 3878 .zir_index = undefined, // set below 3879 .layout = .Auto, 3880 .status = .none, 3881 .known_non_opv = undefined, 3882 .namespace = .{ 3883 .parent = null, 3884 .ty = struct_ty, 3885 .file_scope = file, 3886 }, 3887 }; 3888 const new_decl_index = try mod.allocateNewDecl(&struct_obj.namespace, 0, null); 3889 const new_decl = mod.declPtr(new_decl_index); 3890 file.root_decl = new_decl_index.toOptional(); 3891 struct_obj.owner_decl = new_decl_index; 3892 new_decl.name = try file.fullyQualifiedNameZ(gpa); 3893 new_decl.src_line = 0; 3894 new_decl.is_pub = true; 3895 new_decl.is_exported = false; 3896 new_decl.has_align = false; 3897 new_decl.has_linksection_or_addrspace = false; 3898 new_decl.ty = ty_ty; 3899 new_decl.val = struct_val; 3900 new_decl.has_tv = true; 3901 new_decl.owns_tv = true; 3902 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. 3903 new_decl.analysis = .in_progress; 3904 new_decl.generation = mod.generation; 3905 3906 if (file.status == .success_zir) { 3907 assert(file.zir_loaded); 3908 const main_struct_inst = Zir.main_struct_inst; 3909 struct_obj.zir_index = main_struct_inst; 3910 3911 var sema_arena = std.heap.ArenaAllocator.init(gpa); 3912 defer sema_arena.deinit(); 3913 const sema_arena_allocator = sema_arena.allocator(); 3914 3915 var sema: Sema = .{ 3916 .mod = mod, 3917 .gpa = gpa, 3918 .arena = sema_arena_allocator, 3919 .perm_arena = new_decl_arena_allocator, 3920 .code = file.zir, 3921 .owner_decl = new_decl, 3922 .owner_decl_index = new_decl_index, 3923 .func = null, 3924 .fn_ret_ty = Type.void, 3925 .owner_func = null, 3926 }; 3927 defer sema.deinit(); 3928 3929 var wip_captures = try WipCaptureScope.init(gpa, new_decl_arena_allocator, null); 3930 defer wip_captures.deinit(); 3931 3932 var block_scope: Sema.Block = .{ 3933 .parent = null, 3934 .sema = &sema, 3935 .src_decl = new_decl_index, 3936 .namespace = &struct_obj.namespace, 3937 .wip_capture_scope = wip_captures.scope, 3938 .instructions = .{}, 3939 .inlining = null, 3940 .is_comptime = true, 3941 }; 3942 defer block_scope.instructions.deinit(gpa); 3943 3944 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| { 3945 try wip_captures.finalize(); 3946 new_decl.analysis = .complete; 3947 } else |err| switch (err) { 3948 error.OutOfMemory => return error.OutOfMemory, 3949 error.AnalysisFail => {}, 3950 } 3951 3952 if (mod.comp.whole_cache_manifest) |man| { 3953 const source = file.getSource(gpa) catch |err| { 3954 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); 3955 return error.AnalysisFail; 3956 }; 3957 const resolved_path = try file.pkg.root_src_directory.join(gpa, &.{ 3958 file.sub_file_path, 3959 }); 3960 errdefer gpa.free(resolved_path); 3961 3962 try man.addFilePostContents(resolved_path, source.bytes, source.stat); 3963 } 3964 } else { 3965 new_decl.analysis = .file_failure; 3966 } 3967 3968 try new_decl.finalizeNewArena(&new_decl_arena); 3969 } 3970 3971 /// Returns `true` if the Decl type changed. 3972 /// Returns `true` if this is the first time analyzing the Decl. 3973 /// Returns `false` otherwise. 3974 fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { 3975 const tracy = trace(@src()); 3976 defer tracy.end(); 3977 3978 const decl = mod.declPtr(decl_index); 3979 3980 if (decl.getFileScope().status != .success_zir) { 3981 return error.AnalysisFail; 3982 } 3983 3984 const gpa = mod.gpa; 3985 const zir = decl.getFileScope().zir; 3986 const zir_datas = zir.instructions.items(.data); 3987 3988 decl.analysis = .in_progress; 3989 3990 // We need the memory for the Type to go into the arena for the Decl 3991 var decl_arena = std.heap.ArenaAllocator.init(gpa); 3992 errdefer decl_arena.deinit(); 3993 const decl_arena_allocator = decl_arena.allocator(); 3994 3995 var analysis_arena = std.heap.ArenaAllocator.init(gpa); 3996 defer analysis_arena.deinit(); 3997 const analysis_arena_allocator = analysis_arena.allocator(); 3998 3999 var sema: Sema = .{ 4000 .mod = mod, 4001 .gpa = gpa, 4002 .arena = analysis_arena_allocator, 4003 .perm_arena = decl_arena_allocator, 4004 .code = zir, 4005 .owner_decl = decl, 4006 .owner_decl_index = decl_index, 4007 .func = null, 4008 .fn_ret_ty = Type.void, 4009 .owner_func = null, 4010 }; 4011 defer sema.deinit(); 4012 4013 if (mod.declIsRoot(decl_index)) { 4014 log.debug("semaDecl root {*} ({s})", .{ decl, decl.name }); 4015 const main_struct_inst = Zir.main_struct_inst; 4016 const struct_obj = decl.getStruct().?; 4017 // This might not have gotten set in `semaFile` if the first time had 4018 // a ZIR failure, so we set it here in case. 4019 struct_obj.zir_index = main_struct_inst; 4020 try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj); 4021 decl.analysis = .complete; 4022 decl.generation = mod.generation; 4023 return false; 4024 } 4025 log.debug("semaDecl {*} ({s})", .{ decl, decl.name }); 4026 4027 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 4028 defer wip_captures.deinit(); 4029 4030 var block_scope: Sema.Block = .{ 4031 .parent = null, 4032 .sema = &sema, 4033 .src_decl = decl_index, 4034 .namespace = decl.src_namespace, 4035 .wip_capture_scope = wip_captures.scope, 4036 .instructions = .{}, 4037 .inlining = null, 4038 .is_comptime = true, 4039 }; 4040 defer { 4041 block_scope.instructions.deinit(gpa); 4042 block_scope.params.deinit(gpa); 4043 } 4044 4045 const zir_block_index = decl.zirBlockIndex(); 4046 const inst_data = zir_datas[zir_block_index].pl_node; 4047 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); 4048 const body = zir.extra[extra.end..][0..extra.data.body_len]; 4049 const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand; 4050 try wip_captures.finalize(); 4051 const src = LazySrcLoc.nodeOffset(0); 4052 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref); 4053 const decl_align: u32 = blk: { 4054 const align_ref = decl.zirAlignRef(); 4055 if (align_ref == .none) break :blk 0; 4056 break :blk try sema.resolveAlign(&block_scope, src, align_ref); 4057 }; 4058 const decl_linksection: ?[*:0]const u8 = blk: { 4059 const linksection_ref = decl.zirLinksectionRef(); 4060 if (linksection_ref == .none) break :blk null; 4061 const bytes = try sema.resolveConstString(&block_scope, src, linksection_ref); 4062 break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; 4063 }; 4064 const target = sema.mod.getTarget(); 4065 const address_space = blk: { 4066 const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { 4067 .function, .extern_fn => .function, 4068 .variable => .variable, 4069 else => .constant, 4070 }; 4071 4072 break :blk switch (decl.zirAddrspaceRef()) { 4073 .none => switch (addrspace_ctx) { 4074 .function => target_util.defaultAddressSpace(target, .function), 4075 .variable => target_util.defaultAddressSpace(target, .global_mutable), 4076 .constant => target_util.defaultAddressSpace(target, .global_constant), 4077 else => unreachable, 4078 }, 4079 else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx), 4080 }; 4081 }; 4082 4083 // Note this resolves the type of the Decl, not the value; if this Decl 4084 // is a struct, for example, this resolves `type` (which needs no resolution), 4085 // not the struct itself. 4086 try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty); 4087 4088 const decl_arena_state = try decl_arena_allocator.create(std.heap.ArenaAllocator.State); 4089 4090 if (decl.is_usingnamespace) { 4091 if (!decl_tv.ty.eql(Type.type, mod)) { 4092 return sema.fail(&block_scope, src, "expected type, found {}", .{ 4093 decl_tv.ty.fmt(mod), 4094 }); 4095 } 4096 var buffer: Value.ToTypeBuffer = undefined; 4097 const ty = try decl_tv.val.toType(&buffer).copy(decl_arena_allocator); 4098 if (ty.getNamespace() == null) { 4099 return sema.fail(&block_scope, src, "type {} has no namespace", .{ty.fmt(mod)}); 4100 } 4101 4102 decl.ty = Type.type; 4103 decl.val = try Value.Tag.ty.create(decl_arena_allocator, ty); 4104 decl.@"align" = 0; 4105 decl.@"linksection" = null; 4106 decl.has_tv = true; 4107 decl.owns_tv = false; 4108 decl_arena_state.* = decl_arena.state; 4109 decl.value_arena = decl_arena_state; 4110 decl.analysis = .complete; 4111 decl.generation = mod.generation; 4112 4113 return true; 4114 } 4115 4116 if (decl_tv.val.castTag(.function)) |fn_payload| { 4117 const func = fn_payload.data; 4118 const owns_tv = func.owner_decl == decl_index; 4119 if (owns_tv) { 4120 var prev_type_has_bits = false; 4121 var prev_is_inline = false; 4122 var type_changed = true; 4123 4124 if (decl.has_tv) { 4125 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(); 4126 type_changed = !decl.ty.eql(decl_tv.ty, mod); 4127 if (decl.getFunction()) |prev_func| { 4128 prev_is_inline = prev_func.state == .inline_only; 4129 } 4130 decl.clearValues(mod); 4131 } 4132 4133 decl.ty = try decl_tv.ty.copy(decl_arena_allocator); 4134 decl.val = try decl_tv.val.copy(decl_arena_allocator); 4135 decl.@"align" = decl_align; 4136 decl.@"linksection" = decl_linksection; 4137 decl.@"addrspace" = address_space; 4138 decl.has_tv = true; 4139 decl.owns_tv = owns_tv; 4140 decl_arena_state.* = decl_arena.state; 4141 decl.value_arena = decl_arena_state; 4142 decl.analysis = .complete; 4143 decl.generation = mod.generation; 4144 4145 const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty); 4146 4147 if (has_runtime_bits) { 4148 // We don't fully codegen the decl until later, but we do need to reserve a global 4149 // offset table index for it. This allows us to codegen decls out of dependency 4150 // order, increasing how many computations can be done in parallel. 4151 try mod.comp.bin_file.allocateDeclIndexes(decl_index); 4152 try mod.comp.work_queue.writeItem(.{ .codegen_func = func }); 4153 if (type_changed and mod.emit_h != null) { 4154 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); 4155 } 4156 } else if (!prev_is_inline and prev_type_has_bits) { 4157 mod.comp.bin_file.freeDecl(decl_index); 4158 } 4159 4160 const is_inline = decl.ty.fnCallingConvention() == .Inline; 4161 if (decl.is_exported) { 4162 const export_src = src; // TODO make this point at `export` token 4163 if (is_inline) { 4164 return sema.fail(&block_scope, export_src, "export of inline function", .{}); 4165 } 4166 // The scope needs to have the decl in it. 4167 const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; 4168 try sema.analyzeExport(&block_scope, export_src, options, decl_index); 4169 } 4170 return type_changed or is_inline != prev_is_inline; 4171 } 4172 } 4173 var type_changed = true; 4174 if (decl.has_tv) { 4175 type_changed = !decl.ty.eql(decl_tv.ty, mod); 4176 decl.clearValues(mod); 4177 } 4178 4179 decl.owns_tv = false; 4180 var queue_linker_work = false; 4181 var is_extern = false; 4182 switch (decl_tv.val.tag()) { 4183 .variable => { 4184 const variable = decl_tv.val.castTag(.variable).?.data; 4185 if (variable.owner_decl == decl_index) { 4186 decl.owns_tv = true; 4187 queue_linker_work = true; 4188 4189 const copied_init = try variable.init.copy(decl_arena_allocator); 4190 variable.init = copied_init; 4191 } 4192 }, 4193 .extern_fn => { 4194 const extern_fn = decl_tv.val.castTag(.extern_fn).?.data; 4195 if (extern_fn.owner_decl == decl_index) { 4196 decl.owns_tv = true; 4197 queue_linker_work = true; 4198 is_extern = true; 4199 } 4200 }, 4201 4202 .generic_poison => unreachable, 4203 .unreachable_value => unreachable, 4204 4205 .function => {}, 4206 4207 else => { 4208 log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); 4209 queue_linker_work = true; 4210 }, 4211 } 4212 4213 decl.ty = try decl_tv.ty.copy(decl_arena_allocator); 4214 decl.val = try decl_tv.val.copy(decl_arena_allocator); 4215 decl.@"align" = decl_align; 4216 decl.@"linksection" = decl_linksection; 4217 decl.@"addrspace" = address_space; 4218 decl.has_tv = true; 4219 decl_arena_state.* = decl_arena.state; 4220 decl.value_arena = decl_arena_state; 4221 decl.analysis = .complete; 4222 decl.generation = mod.generation; 4223 4224 const has_runtime_bits = is_extern or 4225 (queue_linker_work and try sema.typeHasRuntimeBits(&block_scope, src, decl.ty)); 4226 4227 if (has_runtime_bits) { 4228 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name }); 4229 4230 // Needed for codegen_decl which will call updateDecl and then the 4231 // codegen backend wants full access to the Decl Type. 4232 try sema.resolveTypeFully(&block_scope, src, decl.ty); 4233 4234 try mod.comp.bin_file.allocateDeclIndexes(decl_index); 4235 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); 4236 4237 if (type_changed and mod.emit_h != null) { 4238 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); 4239 } 4240 } 4241 4242 if (decl.is_exported) { 4243 const export_src = src; // TODO point to the export token 4244 // The scope needs to have the decl in it. 4245 const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; 4246 try sema.analyzeExport(&block_scope, export_src, options, decl_index); 4247 } 4248 4249 return type_changed; 4250 } 4251 4252 /// Returns the depender's index of the dependee. 4253 pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void { 4254 if (depender_index == dependee_index) return; 4255 4256 const depender = mod.declPtr(depender_index); 4257 const dependee = mod.declPtr(dependee_index); 4258 4259 log.debug("{*} ({s}) depends on {*} ({s})", .{ 4260 depender, depender.name, dependee, dependee.name, 4261 }); 4262 4263 try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1); 4264 try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1); 4265 4266 if (dependee.deletion_flag) { 4267 dependee.deletion_flag = false; 4268 assert(mod.deletion_set.swapRemove(dependee_index)); 4269 } 4270 4271 dependee.dependants.putAssumeCapacity(depender_index, {}); 4272 depender.dependencies.putAssumeCapacity(dependee_index, {}); 4273 } 4274 4275 pub const ImportFileResult = struct { 4276 file: *File, 4277 is_new: bool, 4278 }; 4279 4280 pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult { 4281 const gpa = mod.gpa; 4282 4283 // The resolved path is used as the key in the import table, to detect if 4284 // an import refers to the same as another, despite different relative paths 4285 // or differently mapped package names. 4286 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 4287 pkg.root_src_directory.path orelse ".", pkg.root_src_path, 4288 }); 4289 var keep_resolved_path = false; 4290 defer if (!keep_resolved_path) gpa.free(resolved_path); 4291 4292 const gop = try mod.import_table.getOrPut(gpa, resolved_path); 4293 errdefer _ = mod.import_table.pop(); 4294 if (gop.found_existing) return ImportFileResult{ 4295 .file = gop.value_ptr.*, 4296 .is_new = false, 4297 }; 4298 4299 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path); 4300 errdefer gpa.free(sub_file_path); 4301 4302 const new_file = try gpa.create(File); 4303 errdefer gpa.destroy(new_file); 4304 4305 keep_resolved_path = true; // It's now owned by import_table. 4306 gop.value_ptr.* = new_file; 4307 new_file.* = .{ 4308 .sub_file_path = sub_file_path, 4309 .source = undefined, 4310 .source_loaded = false, 4311 .tree_loaded = false, 4312 .zir_loaded = false, 4313 .stat = undefined, 4314 .tree = undefined, 4315 .zir = undefined, 4316 .status = .never_loaded, 4317 .pkg = pkg, 4318 .root_decl = .none, 4319 }; 4320 return ImportFileResult{ 4321 .file = new_file, 4322 .is_new = true, 4323 }; 4324 } 4325 4326 pub fn importFile( 4327 mod: *Module, 4328 cur_file: *File, 4329 import_string: []const u8, 4330 ) !ImportFileResult { 4331 if (cur_file.pkg.table.get(import_string)) |pkg| { 4332 return mod.importPkg(pkg); 4333 } 4334 if (!mem.endsWith(u8, import_string, ".zig")) { 4335 return error.PackageNotFound; 4336 } 4337 const gpa = mod.gpa; 4338 4339 // The resolved path is used as the key in the import table, to detect if 4340 // an import refers to the same as another, despite different relative paths 4341 // or differently mapped package names. 4342 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse "."; 4343 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 4344 cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string, 4345 }); 4346 var keep_resolved_path = false; 4347 defer if (!keep_resolved_path) gpa.free(resolved_path); 4348 4349 const gop = try mod.import_table.getOrPut(gpa, resolved_path); 4350 errdefer _ = mod.import_table.pop(); 4351 if (gop.found_existing) return ImportFileResult{ 4352 .file = gop.value_ptr.*, 4353 .is_new = false, 4354 }; 4355 4356 const new_file = try gpa.create(File); 4357 errdefer gpa.destroy(new_file); 4358 4359 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); 4360 defer gpa.free(resolved_root_path); 4361 4362 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) { 4363 return error.ImportOutsidePkgPath; 4364 } 4365 // +1 for the directory separator here. 4366 const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); 4367 errdefer gpa.free(sub_file_path); 4368 4369 log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{ 4370 resolved_root_path, resolved_path, sub_file_path, import_string, 4371 }); 4372 4373 keep_resolved_path = true; // It's now owned by import_table. 4374 gop.value_ptr.* = new_file; 4375 new_file.* = .{ 4376 .sub_file_path = sub_file_path, 4377 .source = undefined, 4378 .source_loaded = false, 4379 .tree_loaded = false, 4380 .zir_loaded = false, 4381 .stat = undefined, 4382 .tree = undefined, 4383 .zir = undefined, 4384 .status = .never_loaded, 4385 .pkg = cur_file.pkg, 4386 .root_decl = .none, 4387 }; 4388 return ImportFileResult{ 4389 .file = new_file, 4390 .is_new = true, 4391 }; 4392 } 4393 4394 pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*EmbedFile { 4395 const gpa = mod.gpa; 4396 4397 // The resolved path is used as the key in the table, to detect if 4398 // a file refers to the same as another, despite different relative paths. 4399 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse "."; 4400 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{ 4401 cur_pkg_dir_path, cur_file.sub_file_path, "..", rel_file_path, 4402 }); 4403 var keep_resolved_path = false; 4404 defer if (!keep_resolved_path) gpa.free(resolved_path); 4405 4406 const gop = try mod.embed_table.getOrPut(gpa, resolved_path); 4407 errdefer assert(mod.embed_table.remove(resolved_path)); 4408 if (gop.found_existing) return gop.value_ptr.*; 4409 4410 const new_file = try gpa.create(EmbedFile); 4411 errdefer gpa.destroy(new_file); 4412 4413 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); 4414 defer gpa.free(resolved_root_path); 4415 4416 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) { 4417 return error.ImportOutsidePkgPath; 4418 } 4419 // +1 for the directory separator here. 4420 const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]); 4421 errdefer gpa.free(sub_file_path); 4422 4423 var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{}); 4424 defer file.close(); 4425 4426 const actual_stat = try file.stat(); 4427 const stat: Cache.File.Stat = .{ 4428 .size = actual_stat.size, 4429 .inode = actual_stat.inode, 4430 .mtime = actual_stat.mtime, 4431 }; 4432 const size_usize = std.math.cast(usize, actual_stat.size) orelse return error.Overflow; 4433 const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0); 4434 errdefer gpa.free(bytes); 4435 4436 log.debug("new embedFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, rel_file_path={s}", .{ 4437 resolved_root_path, resolved_path, sub_file_path, rel_file_path, 4438 }); 4439 4440 if (mod.comp.whole_cache_manifest) |man| { 4441 const copied_resolved_path = try gpa.dupe(u8, resolved_path); 4442 errdefer gpa.free(copied_resolved_path); 4443 try man.addFilePostContents(copied_resolved_path, bytes, stat); 4444 } 4445 4446 keep_resolved_path = true; // It's now owned by embed_table. 4447 gop.value_ptr.* = new_file; 4448 new_file.* = .{ 4449 .sub_file_path = sub_file_path, 4450 .bytes = bytes, 4451 .stat = stat, 4452 .pkg = cur_file.pkg, 4453 .owner_decl = undefined, // Set by Sema immediately after this function returns. 4454 }; 4455 return new_file; 4456 } 4457 4458 pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { 4459 var file = try embed_file.pkg.root_src_directory.handle.openFile(embed_file.sub_file_path, .{}); 4460 defer file.close(); 4461 4462 const stat = try file.stat(); 4463 4464 const unchanged_metadata = 4465 stat.size == embed_file.stat.size and 4466 stat.mtime == embed_file.stat.mtime and 4467 stat.inode == embed_file.stat.inode; 4468 4469 if (unchanged_metadata) return; 4470 4471 const gpa = mod.gpa; 4472 const size_usize = std.math.cast(usize, stat.size) orelse return error.Overflow; 4473 const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0); 4474 gpa.free(embed_file.bytes); 4475 embed_file.bytes = bytes; 4476 embed_file.stat = .{ 4477 .size = stat.size, 4478 .mtime = stat.mtime, 4479 .inode = stat.inode, 4480 }; 4481 4482 mod.comp.mutex.lock(); 4483 defer mod.comp.mutex.unlock(); 4484 try mod.comp.work_queue.writeItem(.{ .update_embed_file = embed_file }); 4485 } 4486 4487 pub fn scanNamespace( 4488 mod: *Module, 4489 namespace: *Namespace, 4490 extra_start: usize, 4491 decls_len: u32, 4492 parent_decl: *Decl, 4493 ) SemaError!usize { 4494 const tracy = trace(@src()); 4495 defer tracy.end(); 4496 4497 const gpa = mod.gpa; 4498 const zir = namespace.file_scope.zir; 4499 4500 try mod.comp.work_queue.ensureUnusedCapacity(decls_len); 4501 try namespace.decls.ensureTotalCapacity(gpa, decls_len); 4502 4503 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; 4504 var extra_index = extra_start + bit_bags_count; 4505 var bit_bag_index: usize = extra_start; 4506 var cur_bit_bag: u32 = undefined; 4507 var decl_i: u32 = 0; 4508 var scan_decl_iter: ScanDeclIter = .{ 4509 .module = mod, 4510 .namespace = namespace, 4511 .parent_decl = parent_decl, 4512 }; 4513 while (decl_i < decls_len) : (decl_i += 1) { 4514 if (decl_i % 8 == 0) { 4515 cur_bit_bag = zir.extra[bit_bag_index]; 4516 bit_bag_index += 1; 4517 } 4518 const flags = @truncate(u4, cur_bit_bag); 4519 cur_bit_bag >>= 4; 4520 4521 const decl_sub_index = extra_index; 4522 extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1) 4523 extra_index += @truncate(u1, flags >> 2); // Align 4524 extra_index += @as(u2, @truncate(u1, flags >> 3)) * 2; // Link section or address space, consists of 2 Refs 4525 4526 try scanDecl(&scan_decl_iter, decl_sub_index, flags); 4527 } 4528 return extra_index; 4529 } 4530 4531 const ScanDeclIter = struct { 4532 module: *Module, 4533 namespace: *Namespace, 4534 parent_decl: *Decl, 4535 usingnamespace_index: usize = 0, 4536 comptime_index: usize = 0, 4537 unnamed_test_index: usize = 0, 4538 }; 4539 4540 fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!void { 4541 const tracy = trace(@src()); 4542 defer tracy.end(); 4543 4544 const mod = iter.module; 4545 const namespace = iter.namespace; 4546 const gpa = mod.gpa; 4547 const zir = namespace.file_scope.zir; 4548 4549 // zig fmt: off 4550 const is_pub = (flags & 0b0001) != 0; 4551 const export_bit = (flags & 0b0010) != 0; 4552 const has_align = (flags & 0b0100) != 0; 4553 const has_linksection_or_addrspace = (flags & 0b1000) != 0; 4554 // zig fmt: on 4555 4556 const line_off = zir.extra[decl_sub_index + 4]; 4557 const line = iter.parent_decl.relativeToLine(line_off); 4558 const decl_name_index = zir.extra[decl_sub_index + 5]; 4559 const decl_doccomment_index = zir.extra[decl_sub_index + 7]; 4560 const decl_zir_index = zir.extra[decl_sub_index + 6]; 4561 const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node; 4562 const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node); 4563 4564 // Every Decl needs a name. 4565 var is_named_test = false; 4566 const decl_name: [:0]const u8 = switch (decl_name_index) { 4567 0 => name: { 4568 if (export_bit) { 4569 const i = iter.usingnamespace_index; 4570 iter.usingnamespace_index += 1; 4571 break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); 4572 } else { 4573 const i = iter.comptime_index; 4574 iter.comptime_index += 1; 4575 break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); 4576 } 4577 }, 4578 1 => name: { 4579 const i = iter.unnamed_test_index; 4580 iter.unnamed_test_index += 1; 4581 break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); 4582 }, 4583 2 => name: { 4584 is_named_test = true; 4585 const test_name = zir.nullTerminatedString(decl_doccomment_index); 4586 break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); 4587 }, 4588 else => name: { 4589 const raw_name = zir.nullTerminatedString(decl_name_index); 4590 if (raw_name.len == 0) { 4591 is_named_test = true; 4592 const test_name = zir.nullTerminatedString(decl_name_index + 1); 4593 break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); 4594 } else { 4595 break :name try gpa.dupeZ(u8, raw_name); 4596 } 4597 }, 4598 }; 4599 const is_exported = export_bit and decl_name_index != 0; 4600 const is_usingnamespace = export_bit and decl_name_index == 0; 4601 if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); 4602 4603 // We create a Decl for it regardless of analysis status. 4604 const gop = try namespace.decls.getOrPutContextAdapted( 4605 gpa, 4606 @as([]const u8, mem.sliceTo(decl_name, 0)), 4607 DeclAdapter{ .mod = mod }, 4608 Namespace.DeclContext{ .module = mod }, 4609 ); 4610 const comp = mod.comp; 4611 if (!gop.found_existing) { 4612 const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); 4613 const new_decl = mod.declPtr(new_decl_index); 4614 new_decl.name = decl_name; 4615 if (is_usingnamespace) { 4616 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); 4617 } 4618 log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); 4619 new_decl.src_line = line; 4620 gop.key_ptr.* = new_decl_index; 4621 // Exported decls, comptime decls, usingnamespace decls, and 4622 // test decls if in test mode, get analyzed. 4623 const decl_pkg = namespace.file_scope.pkg; 4624 const want_analysis = is_exported or switch (decl_name_index) { 4625 0 => true, // comptime or usingnamespace decl 4626 1 => blk: { 4627 // test decl with no name. Skip the part where we check against 4628 // the test name filter. 4629 if (!comp.bin_file.options.is_test) break :blk false; 4630 if (decl_pkg != mod.main_pkg) { 4631 if (!mod.main_pkg_in_std) break :blk false; 4632 const std_pkg = mod.main_pkg.table.get("std").?; 4633 if (std_pkg != decl_pkg) break :blk false; 4634 } 4635 try mod.test_functions.put(gpa, new_decl_index, {}); 4636 break :blk true; 4637 }, 4638 else => blk: { 4639 if (!is_named_test) break :blk false; 4640 if (!comp.bin_file.options.is_test) break :blk false; 4641 if (decl_pkg != mod.main_pkg) { 4642 if (!mod.main_pkg_in_std) break :blk false; 4643 const std_pkg = mod.main_pkg.table.get("std").?; 4644 if (std_pkg != decl_pkg) break :blk false; 4645 } 4646 if (comp.test_filter) |test_filter| { 4647 if (mem.indexOf(u8, decl_name, test_filter) == null) { 4648 break :blk false; 4649 } 4650 } 4651 try mod.test_functions.put(gpa, new_decl_index, {}); 4652 break :blk true; 4653 }, 4654 }; 4655 if (want_analysis) { 4656 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index }); 4657 } 4658 new_decl.is_pub = is_pub; 4659 new_decl.is_exported = is_exported; 4660 new_decl.is_usingnamespace = is_usingnamespace; 4661 new_decl.has_align = has_align; 4662 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; 4663 new_decl.zir_decl_index = @intCast(u32, decl_sub_index); 4664 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive. 4665 return; 4666 } 4667 gpa.free(decl_name); 4668 const decl_index = gop.key_ptr.*; 4669 const decl = mod.declPtr(decl_index); 4670 log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace }); 4671 // Update the AST node of the decl; even if its contents are unchanged, it may 4672 // have been re-ordered. 4673 decl.src_node = decl_node; 4674 decl.src_line = line; 4675 4676 decl.is_pub = is_pub; 4677 decl.is_exported = is_exported; 4678 decl.is_usingnamespace = is_usingnamespace; 4679 decl.has_align = has_align; 4680 decl.has_linksection_or_addrspace = has_linksection_or_addrspace; 4681 decl.zir_decl_index = @intCast(u32, decl_sub_index); 4682 if (decl.getFunction()) |_| { 4683 switch (comp.bin_file.tag) { 4684 .coff => { 4685 // TODO Implement for COFF 4686 }, 4687 .elf => if (decl.fn_link.elf.len != 0) { 4688 // TODO Look into detecting when this would be unnecessary by storing enough state 4689 // in `Decl` to notice that the line number did not change. 4690 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); 4691 }, 4692 .macho => if (decl.fn_link.macho.len != 0) { 4693 // TODO Look into detecting when this would be unnecessary by storing enough state 4694 // in `Decl` to notice that the line number did not change. 4695 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); 4696 }, 4697 .plan9 => { 4698 // TODO Look into detecting when this would be unnecessary by storing enough state 4699 // in `Decl` to notice that the line number did not change. 4700 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); 4701 }, 4702 .c, .wasm, .spirv, .nvptx => {}, 4703 } 4704 } 4705 } 4706 4707 /// Make it as if the semantic analysis for this Decl never happened. 4708 pub fn clearDecl( 4709 mod: *Module, 4710 decl_index: Decl.Index, 4711 outdated_decls: ?*std.AutoArrayHashMap(Decl.Index, void), 4712 ) Allocator.Error!void { 4713 const tracy = trace(@src()); 4714 defer tracy.end(); 4715 4716 const decl = mod.declPtr(decl_index); 4717 log.debug("clearing {*} ({s})", .{ decl, decl.name }); 4718 4719 const gpa = mod.gpa; 4720 try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); 4721 4722 if (outdated_decls) |map| { 4723 _ = map.swapRemove(decl_index); 4724 try map.ensureUnusedCapacity(decl.dependants.count()); 4725 } 4726 4727 // Remove itself from its dependencies. 4728 for (decl.dependencies.keys()) |dep_index| { 4729 const dep = mod.declPtr(dep_index); 4730 dep.removeDependant(decl_index); 4731 if (dep.dependants.count() == 0 and !dep.deletion_flag) { 4732 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ 4733 decl, decl.name, dep, dep.name, 4734 }); 4735 // We don't recursively perform a deletion here, because during the update, 4736 // another reference to it may turn up. 4737 dep.deletion_flag = true; 4738 mod.deletion_set.putAssumeCapacity(dep_index, {}); 4739 } 4740 } 4741 decl.dependencies.clearRetainingCapacity(); 4742 4743 // Anything that depends on this deleted decl needs to be re-analyzed. 4744 for (decl.dependants.keys()) |dep_index| { 4745 const dep = mod.declPtr(dep_index); 4746 dep.removeDependency(decl_index); 4747 if (outdated_decls) |map| { 4748 map.putAssumeCapacity(dep_index, {}); 4749 } 4750 } 4751 decl.dependants.clearRetainingCapacity(); 4752 4753 if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { 4754 kv.value.destroy(gpa); 4755 } 4756 if (mod.emit_h) |emit_h| { 4757 if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { 4758 kv.value.destroy(gpa); 4759 } 4760 assert(emit_h.decl_table.swapRemove(decl_index)); 4761 } 4762 _ = mod.compile_log_decls.swapRemove(decl_index); 4763 mod.deleteDeclExports(decl_index); 4764 4765 if (decl.has_tv) { 4766 if (decl.ty.isFnOrHasRuntimeBits()) { 4767 mod.comp.bin_file.freeDecl(decl_index); 4768 4769 // TODO instead of a union, put this memory trailing Decl objects, 4770 // and allow it to be variably sized. 4771 decl.link = switch (mod.comp.bin_file.tag) { 4772 .coff => .{ .coff = link.File.Coff.TextBlock.empty }, 4773 .elf => .{ .elf = link.File.Elf.TextBlock.empty }, 4774 .macho => .{ .macho = link.File.MachO.TextBlock.empty }, 4775 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, 4776 .c => .{ .c = {} }, 4777 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, 4778 .spirv => .{ .spirv = {} }, 4779 .nvptx => .{ .nvptx = {} }, 4780 }; 4781 decl.fn_link = switch (mod.comp.bin_file.tag) { 4782 .coff => .{ .coff = {} }, 4783 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty }, 4784 .macho => .{ .macho = link.File.Dwarf.SrcFn.empty }, 4785 .plan9 => .{ .plan9 = {} }, 4786 .c => .{ .c = {} }, 4787 .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, 4788 .spirv => .{ .spirv = .{} }, 4789 .nvptx => .{ .nvptx = {} }, 4790 }; 4791 } 4792 if (decl.getInnerNamespace()) |namespace| { 4793 try namespace.deleteAllDecls(mod, outdated_decls); 4794 } 4795 decl.clearValues(mod); 4796 } 4797 4798 if (decl.deletion_flag) { 4799 decl.deletion_flag = false; 4800 assert(mod.deletion_set.swapRemove(decl_index)); 4801 } 4802 4803 decl.analysis = .unreferenced; 4804 } 4805 4806 /// This function is exclusively called for anonymous decls. 4807 pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { 4808 const decl = mod.declPtr(decl_index); 4809 log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name }); 4810 4811 // TODO: remove `allocateDeclIndexes` and make the API that the linker backends 4812 // are required to notice the first time `updateDecl` happens and keep track 4813 // of it themselves. However they can rely on getting a `freeDecl` call if any 4814 // `updateDecl` or `updateFunc` calls happen. This will allow us to avoid any call 4815 // into the linker backend here, since the linker backend will never have been told 4816 // about the Decl in the first place. 4817 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we 4818 // must call `freeDecl` in the linker backend now. 4819 switch (mod.comp.bin_file.tag) { 4820 .c => {}, // this linker backend has already migrated to the new API 4821 else => if (decl.has_tv) { 4822 if (decl.ty.isFnOrHasRuntimeBits()) { 4823 mod.comp.bin_file.freeDecl(decl_index); 4824 } 4825 }, 4826 } 4827 4828 assert(!mod.declIsRoot(decl_index)); 4829 assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); 4830 4831 const dependants = decl.dependants.keys(); 4832 for (dependants) |dep| { 4833 mod.declPtr(dep).removeDependency(decl_index); 4834 } 4835 4836 for (decl.dependencies.keys()) |dep| { 4837 mod.declPtr(dep).removeDependant(decl_index); 4838 } 4839 mod.destroyDecl(decl_index); 4840 } 4841 4842 /// We don't perform a deletion here, because this Decl or another one 4843 /// may end up referencing it before the update is complete. 4844 fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void { 4845 const decl = mod.declPtr(decl_index); 4846 decl.deletion_flag = true; 4847 try mod.deletion_set.put(mod.gpa, decl_index, {}); 4848 } 4849 4850 /// Cancel the creation of an anon decl and delete any references to it. 4851 /// If other decls depend on this decl, they must be aborted first. 4852 pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { 4853 const decl = mod.declPtr(decl_index); 4854 log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name }); 4855 4856 assert(!mod.declIsRoot(decl_index)); 4857 assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); 4858 4859 // An aborted decl must not have dependants -- they must have 4860 // been aborted first and removed from this list. 4861 assert(decl.dependants.count() == 0); 4862 4863 for (decl.dependencies.keys()) |dep_index| { 4864 const dep = mod.declPtr(dep_index); 4865 dep.removeDependant(decl_index); 4866 } 4867 4868 mod.destroyDecl(decl_index); 4869 } 4870 4871 /// Delete all the Export objects that are caused by this Decl. Re-analysis of 4872 /// this Decl will cause them to be re-created (or not). 4873 fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) void { 4874 const kv = mod.export_owners.fetchSwapRemove(decl_index) orelse return; 4875 4876 for (kv.value) |exp| { 4877 if (mod.decl_exports.getPtr(exp.exported_decl)) |value_ptr| { 4878 // Remove exports with owner_decl matching the regenerating decl. 4879 const list = value_ptr.*; 4880 var i: usize = 0; 4881 var new_len = list.len; 4882 while (i < new_len) { 4883 if (list[i].owner_decl == decl_index) { 4884 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]); 4885 new_len -= 1; 4886 } else { 4887 i += 1; 4888 } 4889 } 4890 value_ptr.* = mod.gpa.shrink(list, new_len); 4891 if (new_len == 0) { 4892 assert(mod.decl_exports.swapRemove(exp.exported_decl)); 4893 } 4894 } 4895 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| { 4896 elf.deleteExport(exp.link.elf); 4897 } 4898 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { 4899 macho.deleteExport(exp.link.macho); 4900 } 4901 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { 4902 wasm.deleteExport(exp.link.wasm); 4903 } 4904 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { 4905 failed_kv.value.destroy(mod.gpa); 4906 } 4907 mod.gpa.free(exp.options.name); 4908 mod.gpa.destroy(exp); 4909 } 4910 mod.gpa.free(kv.value); 4911 } 4912 4913 pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { 4914 const tracy = trace(@src()); 4915 defer tracy.end(); 4916 4917 const gpa = mod.gpa; 4918 const decl_index = func.owner_decl; 4919 const decl = mod.declPtr(decl_index); 4920 4921 // Use the Decl's arena for captured values. 4922 var decl_arena = decl.value_arena.?.promote(gpa); 4923 defer decl.value_arena.?.* = decl_arena.state; 4924 const decl_arena_allocator = decl_arena.allocator(); 4925 4926 var sema: Sema = .{ 4927 .mod = mod, 4928 .gpa = gpa, 4929 .arena = arena, 4930 .perm_arena = decl_arena_allocator, 4931 .code = decl.getFileScope().zir, 4932 .owner_decl = decl, 4933 .owner_decl_index = decl_index, 4934 .func = func, 4935 .fn_ret_ty = decl.ty.fnReturnType(), 4936 .owner_func = func, 4937 .branch_quota = @maximum(func.branch_quota, Sema.default_branch_quota), 4938 }; 4939 defer sema.deinit(); 4940 4941 // reset in case calls to errorable functions are removed. 4942 func.calls_or_awaits_errorable_fn = false; 4943 4944 // First few indexes of extra are reserved and set at the end. 4945 const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len; 4946 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); 4947 sema.air_extra.items.len += reserved_count; 4948 4949 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); 4950 defer wip_captures.deinit(); 4951 4952 var inner_block: Sema.Block = .{ 4953 .parent = null, 4954 .sema = &sema, 4955 .src_decl = decl_index, 4956 .namespace = decl.src_namespace, 4957 .wip_capture_scope = wip_captures.scope, 4958 .instructions = .{}, 4959 .inlining = null, 4960 .is_comptime = false, 4961 }; 4962 defer inner_block.instructions.deinit(gpa); 4963 4964 const fn_info = sema.code.getFnInfo(func.zir_body_inst); 4965 const zir_tags = sema.code.instructions.items(.tag); 4966 4967 // Here we are performing "runtime semantic analysis" for a function body, which means 4968 // we must map the parameter ZIR instructions to `arg` AIR instructions. 4969 // AIR requires the `arg` parameters to be the first N instructions. 4970 // This could be a generic function instantiation, however, in which case we need to 4971 // map the comptime parameters to constant values and only emit arg AIR instructions 4972 // for the runtime ones. 4973 const fn_ty = decl.ty; 4974 const fn_ty_info = fn_ty.fnInfo(); 4975 const runtime_params_len = @intCast(u32, fn_ty_info.param_types.len); 4976 try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len); 4977 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType` 4978 try sema.inst_map.ensureUnusedCapacity(gpa, fn_info.total_params_len); 4979 4980 var runtime_param_index: usize = 0; 4981 var total_param_index: usize = 0; 4982 for (fn_info.param_body) |inst| { 4983 const param: struct { name: u32, src: LazySrcLoc } = switch (zir_tags[inst]) { 4984 .param, .param_comptime => blk: { 4985 const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok; 4986 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index).data; 4987 break :blk .{ .name = extra.name, .src = pl_tok.src() }; 4988 }, 4989 4990 .param_anytype, .param_anytype_comptime => blk: { 4991 const str_tok = sema.code.instructions.items(.data)[inst].str_tok; 4992 break :blk .{ .name = str_tok.start, .src = str_tok.src() }; 4993 }, 4994 4995 else => continue, 4996 }; 4997 4998 const param_ty = if (func.comptime_args) |comptime_args| t: { 4999 const arg_tv = comptime_args[total_param_index]; 5000 5001 const arg_val = if (arg_tv.val.tag() != .generic_poison) 5002 arg_tv.val 5003 else if (arg_tv.ty.onePossibleValue()) |opv| 5004 opv 5005 else 5006 break :t arg_tv.ty; 5007 5008 const arg = try sema.addConstant(arg_tv.ty, arg_val); 5009 sema.inst_map.putAssumeCapacityNoClobber(inst, arg); 5010 total_param_index += 1; 5011 continue; 5012 } else fn_ty_info.param_types[runtime_param_index]; 5013 5014 const opt_opv = sema.typeHasOnePossibleValue(&inner_block, param.src, param_ty) catch |err| switch (err) { 5015 error.NeededSourceLocation => unreachable, 5016 error.GenericPoison => unreachable, 5017 error.ComptimeReturn => unreachable, 5018 error.ComptimeBreak => unreachable, 5019 else => |e| return e, 5020 }; 5021 if (opt_opv) |opv| { 5022 const arg = try sema.addConstant(param_ty, opv); 5023 sema.inst_map.putAssumeCapacityNoClobber(inst, arg); 5024 total_param_index += 1; 5025 runtime_param_index += 1; 5026 continue; 5027 } 5028 const arg_index = @intCast(u32, sema.air_instructions.len); 5029 inner_block.instructions.appendAssumeCapacity(arg_index); 5030 sema.air_instructions.appendAssumeCapacity(.{ 5031 .tag = .arg, 5032 .data = .{ .ty = param_ty }, 5033 }); 5034 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index)); 5035 total_param_index += 1; 5036 runtime_param_index += 1; 5037 } 5038 5039 func.state = .in_progress; 5040 log.debug("set {s} to in_progress", .{decl.name}); 5041 5042 const last_arg_index = inner_block.instructions.items.len; 5043 5044 sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) { 5045 // TODO make these unreachable instead of @panic 5046 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"), 5047 error.GenericPoison => @panic("zig compiler bug: GenericPoison"), 5048 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"), 5049 else => |e| return e, 5050 }; 5051 5052 // If we don't get an error return trace from a caller, create our own. 5053 if (func.calls_or_awaits_errorable_fn and 5054 mod.comp.bin_file.options.error_return_tracing and 5055 !sema.fn_ret_ty.isError()) 5056 { 5057 sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { 5058 // TODO make these unreachable instead of @panic 5059 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"), 5060 error.GenericPoison => @panic("zig compiler bug: GenericPoison"), 5061 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"), 5062 error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"), 5063 else => |e| return e, 5064 }; 5065 } 5066 5067 try wip_captures.finalize(); 5068 5069 // Copy the block into place and mark that as the main block. 5070 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + 5071 inner_block.instructions.items.len); 5072 const main_block_index = sema.addExtraAssumeCapacity(Air.Block{ 5073 .body_len = @intCast(u32, inner_block.instructions.items.len), 5074 }); 5075 sema.air_extra.appendSliceAssumeCapacity(inner_block.instructions.items); 5076 sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index; 5077 5078 func.state = .success; 5079 log.debug("set {s} to success", .{decl.name}); 5080 5081 // Finally we must resolve the return type and parameter types so that backends 5082 // have full access to type information. 5083 // Crucially, this happens *after* we set the function state to success above, 5084 // so that dependencies on the function body will now be satisfied rather than 5085 // result in circular dependency errors. 5086 const src = LazySrcLoc.nodeOffset(0); 5087 sema.resolveFnTypes(&inner_block, src, fn_ty_info) catch |err| switch (err) { 5088 error.NeededSourceLocation => unreachable, 5089 error.GenericPoison => unreachable, 5090 error.ComptimeReturn => unreachable, 5091 error.ComptimeBreak => unreachable, 5092 error.AnalysisFail => { 5093 // In this case our function depends on a type that had a compile error. 5094 // We should not try to lower this function. 5095 decl.analysis = .dependency_failure; 5096 return error.AnalysisFail; 5097 }, 5098 else => |e| return e, 5099 }; 5100 5101 // Similarly, resolve any queued up types that were requested to be resolved for 5102 // the backends. 5103 for (sema.types_to_resolve.items) |inst_ref| { 5104 const ty = sema.getTmpAir().getRefType(inst_ref); 5105 sema.resolveTypeFully(&inner_block, src, ty) catch |err| switch (err) { 5106 error.NeededSourceLocation => unreachable, 5107 error.GenericPoison => unreachable, 5108 error.ComptimeReturn => unreachable, 5109 error.ComptimeBreak => unreachable, 5110 error.AnalysisFail => { 5111 // In this case our function depends on a type that had a compile error. 5112 // We should not try to lower this function. 5113 decl.analysis = .dependency_failure; 5114 return error.AnalysisFail; 5115 }, 5116 else => |e| return e, 5117 }; 5118 } 5119 5120 return Air{ 5121 .instructions = sema.air_instructions.toOwnedSlice(), 5122 .extra = sema.air_extra.toOwnedSlice(gpa), 5123 .values = sema.air_values.toOwnedSlice(gpa), 5124 }; 5125 } 5126 5127 fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { 5128 const decl = mod.declPtr(decl_index); 5129 log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); 5130 try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index }); 5131 if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { 5132 kv.value.destroy(mod.gpa); 5133 } 5134 if (decl.has_tv and decl.owns_tv) { 5135 if (decl.val.castTag(.function)) |payload| { 5136 const func = payload.data; 5137 _ = mod.align_stack_fns.remove(func); 5138 } 5139 } 5140 if (mod.emit_h) |emit_h| { 5141 if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { 5142 kv.value.destroy(mod.gpa); 5143 } 5144 } 5145 _ = mod.compile_log_decls.swapRemove(decl_index); 5146 decl.analysis = .outdated; 5147 } 5148 5149 pub fn allocateNewDecl( 5150 mod: *Module, 5151 namespace: *Namespace, 5152 src_node: Ast.Node.Index, 5153 src_scope: ?*CaptureScope, 5154 ) !Decl.Index { 5155 const decl_and_index: struct { 5156 new_decl: *Decl, 5157 decl_index: Decl.Index, 5158 } = if (mod.decls_free_list.popOrNull()) |decl_index| d: { 5159 break :d .{ 5160 .new_decl = mod.declPtr(decl_index), 5161 .decl_index = decl_index, 5162 }; 5163 } else d: { 5164 const decl = try mod.allocated_decls.addOne(mod.gpa); 5165 errdefer mod.allocated_decls.shrinkRetainingCapacity(mod.allocated_decls.len - 1); 5166 if (mod.emit_h) |mod_emit_h| { 5167 const decl_emit_h = try mod_emit_h.allocated_emit_h.addOne(mod.gpa); 5168 decl_emit_h.* = .{}; 5169 } 5170 break :d .{ 5171 .new_decl = decl, 5172 .decl_index = @intToEnum(Decl.Index, mod.allocated_decls.len - 1), 5173 }; 5174 }; 5175 5176 decl_and_index.new_decl.* = .{ 5177 .name = undefined, 5178 .src_namespace = namespace, 5179 .src_node = src_node, 5180 .src_line = undefined, 5181 .has_tv = false, 5182 .owns_tv = false, 5183 .ty = undefined, 5184 .val = undefined, 5185 .@"align" = undefined, 5186 .@"linksection" = undefined, 5187 .@"addrspace" = .generic, 5188 .analysis = .unreferenced, 5189 .deletion_flag = false, 5190 .zir_decl_index = 0, 5191 .src_scope = src_scope, 5192 .link = switch (mod.comp.bin_file.tag) { 5193 .coff => .{ .coff = link.File.Coff.TextBlock.empty }, 5194 .elf => .{ .elf = link.File.Elf.TextBlock.empty }, 5195 .macho => .{ .macho = link.File.MachO.TextBlock.empty }, 5196 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty }, 5197 .c => .{ .c = {} }, 5198 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty }, 5199 .spirv => .{ .spirv = {} }, 5200 .nvptx => .{ .nvptx = {} }, 5201 }, 5202 .fn_link = switch (mod.comp.bin_file.tag) { 5203 .coff => .{ .coff = {} }, 5204 .elf => .{ .elf = link.File.Dwarf.SrcFn.empty }, 5205 .macho => .{ .macho = link.File.Dwarf.SrcFn.empty }, 5206 .plan9 => .{ .plan9 = {} }, 5207 .c => .{ .c = {} }, 5208 .wasm => .{ .wasm = link.File.Wasm.FnData.empty }, 5209 .spirv => .{ .spirv = .{} }, 5210 .nvptx => .{ .nvptx = {} }, 5211 }, 5212 .generation = 0, 5213 .is_pub = false, 5214 .is_exported = false, 5215 .has_linksection_or_addrspace = false, 5216 .has_align = false, 5217 .alive = false, 5218 .is_usingnamespace = false, 5219 }; 5220 5221 return decl_and_index.decl_index; 5222 } 5223 5224 /// Get error value for error tag `name`. 5225 pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).KV { 5226 const gop = try mod.global_error_set.getOrPut(mod.gpa, name); 5227 if (gop.found_existing) { 5228 return std.StringHashMapUnmanaged(ErrorInt).KV{ 5229 .key = gop.key_ptr.*, 5230 .value = gop.value_ptr.*, 5231 }; 5232 } 5233 5234 errdefer assert(mod.global_error_set.remove(name)); 5235 try mod.error_name_list.ensureUnusedCapacity(mod.gpa, 1); 5236 gop.key_ptr.* = try mod.gpa.dupe(u8, name); 5237 gop.value_ptr.* = @intCast(ErrorInt, mod.error_name_list.items.len); 5238 mod.error_name_list.appendAssumeCapacity(gop.key_ptr.*); 5239 return std.StringHashMapUnmanaged(ErrorInt).KV{ 5240 .key = gop.key_ptr.*, 5241 .value = gop.value_ptr.*, 5242 }; 5243 } 5244 5245 pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { 5246 const src_decl = mod.declPtr(block.src_decl); 5247 return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, block.wip_capture_scope, typed_value); 5248 } 5249 5250 pub fn createAnonymousDeclFromDecl( 5251 mod: *Module, 5252 src_decl: *Decl, 5253 namespace: *Namespace, 5254 src_scope: ?*CaptureScope, 5255 tv: TypedValue, 5256 ) !Decl.Index { 5257 const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); 5258 errdefer mod.destroyDecl(new_decl_index); 5259 const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ 5260 src_decl.name, @enumToInt(new_decl_index), 5261 }); 5262 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name); 5263 return new_decl_index; 5264 } 5265 5266 /// Takes ownership of `name` even if it returns an error. 5267 pub fn initNewAnonDecl( 5268 mod: *Module, 5269 new_decl_index: Decl.Index, 5270 src_line: u32, 5271 namespace: *Namespace, 5272 typed_value: TypedValue, 5273 name: [:0]u8, 5274 ) !void { 5275 errdefer mod.gpa.free(name); 5276 5277 const new_decl = mod.declPtr(new_decl_index); 5278 5279 new_decl.name = name; 5280 new_decl.src_line = src_line; 5281 new_decl.ty = typed_value.ty; 5282 new_decl.val = typed_value.val; 5283 new_decl.@"align" = 0; 5284 new_decl.@"linksection" = null; 5285 new_decl.has_tv = true; 5286 new_decl.analysis = .complete; 5287 new_decl.generation = mod.generation; 5288 5289 try namespace.anon_decls.putNoClobber(mod.gpa, new_decl_index, {}); 5290 5291 // The Decl starts off with alive=false and the codegen backend will set alive=true 5292 // if the Decl is referenced by an instruction or another constant. Otherwise, 5293 // the Decl will be garbage collected by the `codegen_decl` task instead of sent 5294 // to the linker. 5295 if (typed_value.ty.isFnOrHasRuntimeBits()) { 5296 try mod.comp.bin_file.allocateDeclIndexes(new_decl_index); 5297 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index }); 5298 } 5299 } 5300 5301 pub fn makeIntType(arena: Allocator, signedness: std.builtin.Signedness, bits: u16) !Type { 5302 const int_payload = try arena.create(Type.Payload.Bits); 5303 int_payload.* = .{ 5304 .base = .{ 5305 .tag = switch (signedness) { 5306 .signed => .int_signed, 5307 .unsigned => .int_unsigned, 5308 }, 5309 }, 5310 .data = bits, 5311 }; 5312 return Type.initPayload(&int_payload.base); 5313 } 5314 5315 pub fn errNoteNonLazy( 5316 mod: *Module, 5317 src_loc: SrcLoc, 5318 parent: *ErrorMsg, 5319 comptime format: []const u8, 5320 args: anytype, 5321 ) error{OutOfMemory}!void { 5322 const msg = try std.fmt.allocPrint(mod.gpa, format, args); 5323 errdefer mod.gpa.free(msg); 5324 5325 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1); 5326 parent.notes[parent.notes.len - 1] = .{ 5327 .src_loc = src_loc, 5328 .msg = msg, 5329 }; 5330 } 5331 5332 pub fn getTarget(mod: Module) Target { 5333 return mod.comp.bin_file.options.target; 5334 } 5335 5336 pub fn optimizeMode(mod: Module) std.builtin.Mode { 5337 return mod.comp.bin_file.options.optimize_mode; 5338 } 5339 5340 fn lockAndClearFileCompileError(mod: *Module, file: *File) void { 5341 switch (file.status) { 5342 .success_zir, .retryable_failure => {}, 5343 .never_loaded, .parse_failure, .astgen_failure => { 5344 mod.comp.mutex.lock(); 5345 defer mod.comp.mutex.unlock(); 5346 if (mod.failed_files.fetchSwapRemove(file)) |kv| { 5347 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message. 5348 } 5349 }, 5350 } 5351 } 5352 5353 pub const SwitchProngSrc = union(enum) { 5354 scalar: u32, 5355 multi: Multi, 5356 range: Multi, 5357 5358 pub const Multi = struct { 5359 prong: u32, 5360 item: u32, 5361 }; 5362 5363 pub const RangeExpand = enum { none, first, last }; 5364 5365 /// This function is intended to be called only when it is certain that we need 5366 /// the LazySrcLoc in order to emit a compile error. 5367 pub fn resolve( 5368 prong_src: SwitchProngSrc, 5369 gpa: Allocator, 5370 decl: *Decl, 5371 switch_node_offset: i32, 5372 range_expand: RangeExpand, 5373 ) LazySrcLoc { 5374 @setCold(true); 5375 const tree = decl.getFileScope().getTree(gpa) catch |err| { 5376 // In this case we emit a warning + a less precise source location. 5377 log.warn("unable to load {s}: {s}", .{ 5378 decl.getFileScope().sub_file_path, @errorName(err), 5379 }); 5380 return LazySrcLoc.nodeOffset(0); 5381 }; 5382 const switch_node = decl.relativeToNodeIndex(switch_node_offset); 5383 const main_tokens = tree.nodes.items(.main_token); 5384 const node_datas = tree.nodes.items(.data); 5385 const node_tags = tree.nodes.items(.tag); 5386 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 5387 const case_nodes = tree.extra_data[extra.start..extra.end]; 5388 5389 var multi_i: u32 = 0; 5390 var scalar_i: u32 = 0; 5391 for (case_nodes) |case_node| { 5392 const case = switch (node_tags[case_node]) { 5393 .switch_case_one => tree.switchCaseOne(case_node), 5394 .switch_case => tree.switchCase(case_node), 5395 else => unreachable, 5396 }; 5397 if (case.ast.values.len == 0) 5398 continue; 5399 if (case.ast.values.len == 1 and 5400 node_tags[case.ast.values[0]] == .identifier and 5401 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) 5402 { 5403 continue; 5404 } 5405 const is_multi = case.ast.values.len != 1 or 5406 node_tags[case.ast.values[0]] == .switch_range; 5407 5408 switch (prong_src) { 5409 .scalar => |i| if (!is_multi and i == scalar_i) return LazySrcLoc.nodeOffset( 5410 decl.nodeIndexToRelative(case.ast.values[0]), 5411 ), 5412 .multi => |s| if (is_multi and s.prong == multi_i) { 5413 var item_i: u32 = 0; 5414 for (case.ast.values) |item_node| { 5415 if (node_tags[item_node] == .switch_range) continue; 5416 5417 if (item_i == s.item) return LazySrcLoc.nodeOffset( 5418 decl.nodeIndexToRelative(item_node), 5419 ); 5420 item_i += 1; 5421 } else unreachable; 5422 }, 5423 .range => |s| if (is_multi and s.prong == multi_i) { 5424 var range_i: u32 = 0; 5425 for (case.ast.values) |range| { 5426 if (node_tags[range] != .switch_range) continue; 5427 5428 if (range_i == s.item) switch (range_expand) { 5429 .none => return LazySrcLoc.nodeOffset( 5430 decl.nodeIndexToRelative(range), 5431 ), 5432 .first => return LazySrcLoc.nodeOffset( 5433 decl.nodeIndexToRelative(node_datas[range].lhs), 5434 ), 5435 .last => return LazySrcLoc.nodeOffset( 5436 decl.nodeIndexToRelative(node_datas[range].rhs), 5437 ), 5438 }; 5439 range_i += 1; 5440 } else unreachable; 5441 }, 5442 } 5443 if (is_multi) { 5444 multi_i += 1; 5445 } else { 5446 scalar_i += 1; 5447 } 5448 } else unreachable; 5449 } 5450 }; 5451 5452 pub const PeerTypeCandidateSrc = union(enum) { 5453 /// Do not print out error notes for candidate sources 5454 none: void, 5455 /// When we want to know the the src of candidate i, look up at 5456 /// index i in this slice 5457 override: []LazySrcLoc, 5458 /// resolvePeerTypes originates from a @TypeOf(...) call 5459 typeof_builtin_call_node_offset: i32, 5460 5461 pub fn resolve( 5462 self: PeerTypeCandidateSrc, 5463 gpa: Allocator, 5464 decl: *Decl, 5465 candidate_i: usize, 5466 ) ?LazySrcLoc { 5467 @setCold(true); 5468 5469 switch (self) { 5470 .none => { 5471 return null; 5472 }, 5473 .override => |candidate_srcs| { 5474 return candidate_srcs[candidate_i]; 5475 }, 5476 .typeof_builtin_call_node_offset => |node_offset| { 5477 switch (candidate_i) { 5478 0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset }, 5479 1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset }, 5480 2 => return LazySrcLoc{ .node_offset_builtin_call_arg2 = node_offset }, 5481 3 => return LazySrcLoc{ .node_offset_builtin_call_arg3 = node_offset }, 5482 4 => return LazySrcLoc{ .node_offset_builtin_call_arg4 = node_offset }, 5483 5 => return LazySrcLoc{ .node_offset_builtin_call_arg5 = node_offset }, 5484 else => {}, 5485 } 5486 5487 const tree = decl.getFileScope().getTree(gpa) catch |err| { 5488 // In this case we emit a warning + a less precise source location. 5489 log.warn("unable to load {s}: {s}", .{ 5490 decl.getFileScope().sub_file_path, @errorName(err), 5491 }); 5492 return LazySrcLoc.nodeOffset(0); 5493 }; 5494 const node = decl.relativeToNodeIndex(node_offset); 5495 const node_datas = tree.nodes.items(.data); 5496 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 5497 5498 return LazySrcLoc{ .node_abs = params[candidate_i] }; 5499 }, 5500 } 5501 } 5502 }; 5503 5504 const FieldSrcQuery = struct { 5505 index: usize, 5506 range: enum { name, type, value, alignment }, 5507 }; 5508 5509 fn queryFieldSrc( 5510 tree: Ast, 5511 query: FieldSrcQuery, 5512 file_scope: *File, 5513 container_decl: Ast.full.ContainerDecl, 5514 ) SrcLoc { 5515 const node_tags = tree.nodes.items(.tag); 5516 var field_index: usize = 0; 5517 for (container_decl.ast.members) |member_node| { 5518 const field = switch (node_tags[member_node]) { 5519 .container_field_init => tree.containerFieldInit(member_node), 5520 .container_field_align => tree.containerFieldAlign(member_node), 5521 .container_field => tree.containerField(member_node), 5522 else => continue, 5523 }; 5524 if (field_index == query.index) { 5525 return switch (query.range) { 5526 .name => .{ 5527 .file_scope = file_scope, 5528 .parent_decl_node = 0, 5529 .lazy = .{ .token_abs = field.ast.name_token }, 5530 }, 5531 .type => .{ 5532 .file_scope = file_scope, 5533 .parent_decl_node = 0, 5534 .lazy = .{ .node_abs = field.ast.type_expr }, 5535 }, 5536 .value => .{ 5537 .file_scope = file_scope, 5538 .parent_decl_node = 0, 5539 .lazy = .{ .node_abs = field.ast.value_expr }, 5540 }, 5541 .alignment => .{ 5542 .file_scope = file_scope, 5543 .parent_decl_node = 0, 5544 .lazy = .{ .node_abs = field.ast.align_expr }, 5545 }, 5546 }; 5547 } 5548 field_index += 1; 5549 } 5550 unreachable; 5551 } 5552 5553 /// Called from `performAllTheWork`, after all AstGen workers have finished, 5554 /// and before the main semantic analysis loop begins. 5555 pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { 5556 // Ultimately, the goal is to queue up `analyze_decl` tasks in the work queue 5557 // for the outdated decls, but we cannot queue up the tasks until after 5558 // we find out which ones have been deleted, otherwise there would be 5559 // deleted Decl pointers in the work queue. 5560 var outdated_decls = std.AutoArrayHashMap(Decl.Index, void).init(mod.gpa); 5561 defer outdated_decls.deinit(); 5562 for (mod.import_table.values()) |file| { 5563 try outdated_decls.ensureUnusedCapacity(file.outdated_decls.items.len); 5564 for (file.outdated_decls.items) |decl_index| { 5565 outdated_decls.putAssumeCapacity(decl_index, {}); 5566 } 5567 file.outdated_decls.clearRetainingCapacity(); 5568 5569 // Handle explicitly deleted decls from the source code. This is one of two 5570 // places that Decl deletions happen. The other is in `Compilation`, after 5571 // `performAllTheWork`, where we iterate over `Module.deletion_set` and 5572 // delete Decls which are no longer referenced. 5573 // If a Decl is explicitly deleted from source, and also no longer referenced, 5574 // it may be both in this `deleted_decls` set, as well as in the 5575 // `Module.deletion_set`. To avoid deleting it twice, we remove it from the 5576 // deletion set at this time. 5577 for (file.deleted_decls.items) |decl_index| { 5578 const decl = mod.declPtr(decl_index); 5579 log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); 5580 5581 // Remove from the namespace it resides in, preserving declaration order. 5582 assert(decl.zir_decl_index != 0); 5583 _ = decl.src_namespace.decls.orderedRemoveAdapted(@as([]const u8, mem.sliceTo(decl.name, 0)), DeclAdapter{ .mod = mod }); 5584 5585 try mod.clearDecl(decl_index, &outdated_decls); 5586 mod.destroyDecl(decl_index); 5587 } 5588 file.deleted_decls.clearRetainingCapacity(); 5589 } 5590 // Finally we can queue up re-analysis tasks after we have processed 5591 // the deleted decls. 5592 for (outdated_decls.keys()) |key| { 5593 try mod.markOutdatedDecl(key); 5594 } 5595 } 5596 5597 /// Called from `Compilation.update`, after everything is done, just before 5598 /// reporting compile errors. In this function we emit exported symbol collision 5599 /// errors and communicate exported symbols to the linker backend. 5600 pub fn processExports(mod: *Module) !void { 5601 const gpa = mod.gpa; 5602 // Map symbol names to `Export` for name collision detection. 5603 var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}; 5604 defer symbol_exports.deinit(gpa); 5605 5606 var it = mod.decl_exports.iterator(); 5607 while (it.next()) |entry| { 5608 const exported_decl = entry.key_ptr.*; 5609 const exports = entry.value_ptr.*; 5610 for (exports) |new_export| { 5611 const gop = try symbol_exports.getOrPut(gpa, new_export.options.name); 5612 if (gop.found_existing) { 5613 new_export.status = .failed_retryable; 5614 try mod.failed_exports.ensureUnusedCapacity(gpa, 1); 5615 const src_loc = new_export.getSrcLoc(mod); 5616 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{ 5617 new_export.options.name, 5618 }); 5619 errdefer msg.destroy(gpa); 5620 const other_export = gop.value_ptr.*; 5621 const other_src_loc = other_export.getSrcLoc(mod); 5622 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{}); 5623 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); 5624 new_export.status = .failed; 5625 } else { 5626 gop.value_ptr.* = new_export; 5627 } 5628 } 5629 mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) { 5630 error.OutOfMemory => return error.OutOfMemory, 5631 else => { 5632 const new_export = exports[0]; 5633 new_export.status = .failed_retryable; 5634 try mod.failed_exports.ensureUnusedCapacity(gpa, 1); 5635 const src_loc = new_export.getSrcLoc(mod); 5636 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{ 5637 @errorName(err), 5638 }); 5639 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); 5640 }, 5641 }; 5642 } 5643 } 5644 5645 pub fn populateTestFunctions(mod: *Module) !void { 5646 const gpa = mod.gpa; 5647 const builtin_pkg = mod.main_pkg.table.get("builtin").?; 5648 const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; 5649 const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); 5650 const builtin_namespace = root_decl.src_namespace; 5651 const decl_index = builtin_namespace.decls.getKeyAdapted(@as([]const u8, "test_functions"), DeclAdapter{ .mod = mod }).?; 5652 const decl = mod.declPtr(decl_index); 5653 var buf: Type.SlicePtrFieldTypeBuffer = undefined; 5654 const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType(); 5655 5656 const array_decl_index = d: { 5657 // Add mod.test_functions to an array decl then make the test_functions 5658 // decl reference it as a slice. 5659 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 5660 errdefer new_decl_arena.deinit(); 5661 const arena = new_decl_arena.allocator(); 5662 5663 const test_fn_vals = try arena.alloc(Value, mod.test_functions.count()); 5664 const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ 5665 .ty = try Type.Tag.array.create(arena, .{ 5666 .len = test_fn_vals.len, 5667 .elem_type = try tmp_test_fn_ty.copy(arena), 5668 }), 5669 .val = try Value.Tag.aggregate.create(arena, test_fn_vals), 5670 }); 5671 const array_decl = mod.declPtr(array_decl_index); 5672 5673 // Add a dependency on each test name and function pointer. 5674 try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2); 5675 5676 for (mod.test_functions.keys()) |test_decl_index, i| { 5677 const test_decl = mod.declPtr(test_decl_index); 5678 const test_name_slice = mem.sliceTo(test_decl.name, 0); 5679 const test_name_decl_index = n: { 5680 var name_decl_arena = std.heap.ArenaAllocator.init(gpa); 5681 errdefer name_decl_arena.deinit(); 5682 const bytes = try name_decl_arena.allocator().dupe(u8, test_name_slice); 5683 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{ 5684 .ty = try Type.Tag.array_u8.create(name_decl_arena.allocator(), bytes.len), 5685 .val = try Value.Tag.bytes.create(name_decl_arena.allocator(), bytes), 5686 }); 5687 try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); 5688 break :n test_name_decl_index; 5689 }; 5690 array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, {}); 5691 array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, {}); 5692 try mod.linkerUpdateDecl(test_name_decl_index); 5693 5694 const field_vals = try arena.create([3]Value); 5695 field_vals.* = .{ 5696 try Value.Tag.slice.create(arena, .{ 5697 .ptr = try Value.Tag.decl_ref.create(arena, test_name_decl_index), 5698 .len = try Value.Tag.int_u64.create(arena, test_name_slice.len), 5699 }), // name 5700 try Value.Tag.decl_ref.create(arena, test_decl_index), // func 5701 Value.initTag(.null_value), // async_frame_size 5702 }; 5703 test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals); 5704 } 5705 5706 try array_decl.finalizeNewArena(&new_decl_arena); 5707 break :d array_decl_index; 5708 }; 5709 try mod.linkerUpdateDecl(array_decl_index); 5710 5711 { 5712 var new_decl_arena = std.heap.ArenaAllocator.init(gpa); 5713 errdefer new_decl_arena.deinit(); 5714 const arena = new_decl_arena.allocator(); 5715 5716 // This copy accesses the old Decl Type/Value so it must be done before `clearValues`. 5717 const new_ty = try Type.Tag.const_slice.create(arena, try tmp_test_fn_ty.copy(arena)); 5718 const new_val = try Value.Tag.slice.create(arena, .{ 5719 .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index), 5720 .len = try Value.Tag.int_u64.create(arena, mod.test_functions.count()), 5721 }); 5722 5723 // Since we are replacing the Decl's value we must perform cleanup on the 5724 // previous value. 5725 decl.clearValues(mod); 5726 decl.ty = new_ty; 5727 decl.val = new_val; 5728 decl.has_tv = true; 5729 5730 try decl.finalizeNewArena(&new_decl_arena); 5731 } 5732 try mod.linkerUpdateDecl(decl_index); 5733 } 5734 5735 pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { 5736 const comp = mod.comp; 5737 5738 if (comp.bin_file.options.emit == null) return; 5739 5740 const decl = mod.declPtr(decl_index); 5741 5742 comp.bin_file.updateDecl(mod, decl_index) catch |err| switch (err) { 5743 error.OutOfMemory => return error.OutOfMemory, 5744 error.AnalysisFail => { 5745 decl.analysis = .codegen_failure; 5746 return; 5747 }, 5748 else => { 5749 const gpa = mod.gpa; 5750 try mod.failed_decls.ensureUnusedCapacity(gpa, 1); 5751 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( 5752 gpa, 5753 decl.srcLoc(), 5754 "unable to codegen: {s}", 5755 .{@errorName(err)}, 5756 )); 5757 decl.analysis = .codegen_failure_retryable; 5758 return; 5759 }, 5760 }; 5761 } 5762 5763 fn reportRetryableFileError( 5764 mod: *Module, 5765 file: *File, 5766 comptime format: []const u8, 5767 args: anytype, 5768 ) error{OutOfMemory}!void { 5769 file.status = .retryable_failure; 5770 5771 const err_msg = try ErrorMsg.create( 5772 mod.gpa, 5773 .{ 5774 .file_scope = file, 5775 .parent_decl_node = 0, 5776 .lazy = .entire_file, 5777 }, 5778 format, 5779 args, 5780 ); 5781 errdefer err_msg.destroy(mod.gpa); 5782 5783 mod.comp.mutex.lock(); 5784 defer mod.comp.mutex.unlock(); 5785 5786 const gop = try mod.failed_files.getOrPut(mod.gpa, file); 5787 if (gop.found_existing) { 5788 if (gop.value_ptr.*) |old_err_msg| { 5789 old_err_msg.destroy(mod.gpa); 5790 } 5791 } 5792 gop.value_ptr.* = err_msg; 5793 } 5794 5795 pub fn markReferencedDeclsAlive(mod: *Module, val: Value) void { 5796 switch (val.tag()) { 5797 .decl_ref_mut => return mod.markDeclIndexAlive(val.castTag(.decl_ref_mut).?.data.decl_index), 5798 .extern_fn => return mod.markDeclIndexAlive(val.castTag(.extern_fn).?.data.owner_decl), 5799 .function => return mod.markDeclIndexAlive(val.castTag(.function).?.data.owner_decl), 5800 .variable => return mod.markDeclIndexAlive(val.castTag(.variable).?.data.owner_decl), 5801 .decl_ref => return mod.markDeclIndexAlive(val.cast(Value.Payload.Decl).?.data), 5802 5803 .repeated, 5804 .eu_payload, 5805 .opt_payload, 5806 .empty_array_sentinel, 5807 => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.SubValue).?.data), 5808 5809 .eu_payload_ptr, 5810 .opt_payload_ptr, 5811 => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.PayloadPtr).?.data.container_ptr), 5812 5813 .slice => { 5814 const slice = val.cast(Value.Payload.Slice).?.data; 5815 mod.markReferencedDeclsAlive(slice.ptr); 5816 mod.markReferencedDeclsAlive(slice.len); 5817 }, 5818 5819 .elem_ptr => { 5820 const elem_ptr = val.cast(Value.Payload.ElemPtr).?.data; 5821 return mod.markReferencedDeclsAlive(elem_ptr.array_ptr); 5822 }, 5823 .field_ptr => { 5824 const field_ptr = val.cast(Value.Payload.FieldPtr).?.data; 5825 return mod.markReferencedDeclsAlive(field_ptr.container_ptr); 5826 }, 5827 .aggregate => { 5828 for (val.castTag(.aggregate).?.data) |field_val| { 5829 mod.markReferencedDeclsAlive(field_val); 5830 } 5831 }, 5832 .@"union" => { 5833 const data = val.cast(Value.Payload.Union).?.data; 5834 mod.markReferencedDeclsAlive(data.tag); 5835 mod.markReferencedDeclsAlive(data.val); 5836 }, 5837 5838 else => {}, 5839 } 5840 } 5841 5842 pub fn markDeclAlive(mod: *Module, decl: *Decl) void { 5843 if (decl.alive) return; 5844 decl.alive = true; 5845 5846 // This is the first time we are marking this Decl alive. We must 5847 // therefore recurse into its value and mark any Decl it references 5848 // as also alive, so that any Decl referenced does not get garbage collected. 5849 mod.markReferencedDeclsAlive(decl.val); 5850 } 5851 5852 fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void { 5853 return mod.markDeclAlive(mod.declPtr(decl_index)); 5854 } 5855 5856 pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void { 5857 try mod.global_assembly.ensureUnusedCapacity(mod.gpa, 1); 5858 5859 const duped_source = try mod.gpa.dupe(u8, source); 5860 errdefer mod.gpa.free(duped_source); 5861 5862 mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source); 5863 }