| ... | @@ -285,8 +285,7 @@ pub const Decl = struct { | ... | @@ -285,8 +285,7 @@ pub const Decl = struct { |
| 285 | log.debug("destroy Decl {*} ({s})", .{ decl, decl.name }); | 285 | log.debug("destroy Decl {*} ({s})", .{ decl, decl.name }); |
| 286 | decl.clearName(gpa); | 286 | decl.clearName(gpa); |
| 287 | if (decl.has_tv) { | 287 | if (decl.has_tv) { |
| 288 | if (decl.val.castTag(.function)) |payload| { | 288 | if (decl.getFunction()) |func| { |
| 289 | const func = payload.data; | | |
| 290 | func.deinit(gpa); | 289 | func.deinit(gpa); |
| 291 | gpa.destroy(func); | 290 | gpa.destroy(func); |
| 292 | } else if (decl.val.getTypeNamespace()) |namespace| { | 291 | } else if (decl.val.getTypeNamespace()) |namespace| { |
| ... | @@ -308,6 +307,10 @@ pub const Decl = struct { | ... | @@ -308,6 +307,10 @@ pub const Decl = struct { |
| 308 | } | 307 | } |
| 309 | | 308 | |
| 310 | pub fn clearValues(decl: *Decl, gpa: *Allocator) void { | 309 | pub fn clearValues(decl: *Decl, gpa: *Allocator) void { |
| | 310 | if (decl.getFunction()) |func| { |
| | 311 | func.deinit(gpa); |
| | 312 | gpa.destroy(func); |
| | 313 | } |
| 311 | if (decl.value_arena) |arena_state| { | 314 | if (decl.value_arena) |arena_state| { |
| 312 | arena_state.promote(gpa).deinit(); | 315 | arena_state.promote(gpa).deinit(); |
| 313 | decl.value_arena = null; | 316 | decl.value_arena = null; |
| ... | @@ -348,7 +351,7 @@ pub const Decl = struct { | ... | @@ -348,7 +351,7 @@ pub const Decl = struct { |
| 348 | return contents_hash; | 351 | return contents_hash; |
| 349 | } | 352 | } |
| 350 | | 353 | |
| 351 | pub fn zirBlockIndex(decl: Decl) Zir.Inst.Index { | 354 | pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index { |
| 352 | assert(decl.zir_decl_index != 0); | 355 | assert(decl.zir_decl_index != 0); |
| 353 | const zir = decl.namespace.file_scope.zir; | 356 | const zir = decl.namespace.file_scope.zir; |
| 354 | return zir.extra[decl.zir_decl_index + 6]; | 357 | return zir.extra[decl.zir_decl_index + 6]; |
| ... | @@ -369,6 +372,13 @@ pub const Decl = struct { | ... | @@ -369,6 +372,13 @@ pub const Decl = struct { |
| 369 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | 372 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 370 | } | 373 | } |
| 371 | | 374 | |
| | 375 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| | 376 | pub fn isRoot(decl: *const Decl) bool { |
| | 377 | if (decl.namespace.parent != null) |
| | 378 | return false; |
| | 379 | return decl == decl.namespace.ty.getOwnerDecl(); |
| | 380 | } |
| | 381 | |
| 372 | pub fn relativeToLine(decl: Decl, offset: u32) u32 { | 382 | pub fn relativeToLine(decl: Decl, offset: u32) u32 { |
| 373 | return decl.src_line + offset; | 383 | return decl.src_line + offset; |
| 374 | } | 384 | } |
| ... | @@ -832,6 +842,14 @@ pub const Scope = struct { | ... | @@ -832,6 +842,14 @@ pub const Scope = struct { |
| 832 | /// Owned by its owner Decl Value. | 842 | /// Owned by its owner Decl Value. |
| 833 | namespace: *Namespace, | 843 | namespace: *Namespace, |
| 834 | | 844 | |
| | 845 | /// Used by change detection algorithm, after astgen, contains the |
| | 846 | /// set of decls that existed in the previous ZIR but not in the new one. |
| | 847 | deleted_decls: std.ArrayListUnmanaged(*Decl) = .{}, |
| | 848 | /// Used by change detection algorithm, after astgen, contains the |
| | 849 | /// set of decls that existed both in the previous ZIR and in the new one, |
| | 850 | /// but their source code has been modified. |
| | 851 | outdated_decls: std.ArrayListUnmanaged(*Decl) = .{}, |
| | 852 | |
| 835 | pub fn unload(file: *File, gpa: *Allocator) void { | 853 | pub fn unload(file: *File, gpa: *Allocator) void { |
| 836 | file.unloadTree(gpa); | 854 | file.unloadTree(gpa); |
| 837 | file.unloadSource(gpa); | 855 | file.unloadSource(gpa); |
| ... | @@ -862,6 +880,8 @@ pub const Scope = struct { | ... | @@ -862,6 +880,8 @@ pub const Scope = struct { |
| 862 | pub fn deinit(file: *File, mod: *Module) void { | 880 | pub fn deinit(file: *File, mod: *Module) void { |
| 863 | const gpa = mod.gpa; | 881 | const gpa = mod.gpa; |
| 864 | log.debug("deinit File {s}", .{file.sub_file_path}); | 882 | log.debug("deinit File {s}", .{file.sub_file_path}); |
| | 883 | file.deleted_decls.deinit(gpa); |
| | 884 | file.outdated_decls.deinit(gpa); |
| 865 | if (file.status == .success_air) { | 885 | if (file.status == .success_air) { |
| 866 | file.namespace.getDecl().destroy(mod); | 886 | file.namespace.getDecl().destroy(mod); |
| 867 | } | 887 | } |
| ... | @@ -2361,8 +2381,10 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node | ... | @@ -2361,8 +2381,10 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node |
| 2361 | // We do not need to hold any locks at this time because all the Decl and Namespace | 2381 | // We do not need to hold any locks at this time because all the Decl and Namespace |
| 2362 | // objects being touched are specific to this File, and the only other concurrent | 2382 | // objects being touched are specific to this File, and the only other concurrent |
| 2363 | // tasks are touching other File objects. | 2383 | // tasks are touching other File objects. |
| 2364 | const change_list = try updateZirRefs(gpa, file, prev_zir); | 2384 | try updateZirRefs(gpa, file, prev_zir); |
| 2365 | @panic("TODO do something with change_list"); | 2385 | |
| | 2386 | // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, |
| | 2387 | // and semantic analysis will deal with them properly. |
| 2366 | } | 2388 | } |
| 2367 | | 2389 | |
| 2368 | // TODO don't report compile errors until Sema @importFile | 2390 | // TODO don't report compile errors until Sema @importFile |
| ... | @@ -2377,23 +2399,13 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node | ... | @@ -2377,23 +2399,13 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node |
| 2377 | } | 2399 | } |
| 2378 | } | 2400 | } |
| 2379 | | 2401 | |
| 2380 | const UpdateChangeList = struct { | | |
| 2381 | deleted: []*const Decl, | | |
| 2382 | outdated: []*const Decl, | | |
| 2383 | | | |
| 2384 | fn deinit(self: *UpdateChangeList, gpa: *Allocator) void { | | |
| 2385 | gpa.free(self.deleted); | | |
| 2386 | gpa.free(self.outdated); | | |
| 2387 | } | | |
| 2388 | }; | | |
| 2389 | | | |
| 2390 | /// Patch ups: | 2402 | /// Patch ups: |
| 2391 | /// * Struct.zir_index | 2403 | /// * Struct.zir_index |
| 2392 | /// * Fn.zir_body_inst | 2404 | /// * Fn.zir_body_inst |
| 2393 | /// * Decl.zir_decl_index | 2405 | /// * Decl.zir_decl_index |
| 2394 | /// * Decl.name | 2406 | /// * Decl.name |
| 2395 | /// * Namespace.decl keys | 2407 | /// * Namespace.decl keys |
| 2396 | fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChangeList { | 2408 | fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void { |
| 2397 | const new_zir = file.zir; | 2409 | const new_zir = file.zir; |
| 2398 | | 2410 | |
| 2399 | // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which | 2411 | // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which |
| ... | @@ -2419,7 +2431,8 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange | ... | @@ -2419,7 +2431,8 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange |
| 2419 | } | 2431 | } |
| 2420 | } | 2432 | } |
| 2421 | | 2433 | |
| 2422 | // Walk the Decl graph. | 2434 | // Walk the Decl graph, updating ZIR indexes, strings, and populating |
| | 2435 | // the deleted and outdated lists. |
| 2423 | | 2436 | |
| 2424 | var decl_stack: std.ArrayListUnmanaged(*Decl) = .{}; | 2437 | var decl_stack: std.ArrayListUnmanaged(*Decl) = .{}; |
| 2425 | defer decl_stack.deinit(gpa); | 2438 | defer decl_stack.deinit(gpa); |
| ... | @@ -2427,48 +2440,48 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange | ... | @@ -2427,48 +2440,48 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange |
| 2427 | const root_decl = file.namespace.getDecl(); | 2440 | const root_decl = file.namespace.getDecl(); |
| 2428 | try decl_stack.append(gpa, root_decl); | 2441 | try decl_stack.append(gpa, root_decl); |
| 2429 | | 2442 | |
| 2430 | var deleted_decls: std.ArrayListUnmanaged(*Decl) = .{}; | 2443 | file.deleted_decls.clearRetainingCapacity(); |
| 2431 | defer deleted_decls.deinit(gpa); | 2444 | file.outdated_decls.clearRetainingCapacity(); |
| 2432 | var outdated_decls: std.ArrayListUnmanaged(*Decl) = .{}; | 2445 | |
| 2433 | defer outdated_decls.deinit(gpa); | 2446 | // The root decl is always outdated; otherwise we would not have had |
| | 2447 | // to re-generate ZIR for the File. |
| | 2448 | try file.outdated_decls.append(gpa, root_decl); |
| 2434 | | 2449 | |
| 2435 | while (decl_stack.popOrNull()) |decl| { | 2450 | while (decl_stack.popOrNull()) |decl| { |
| 2436 | // Anonymous decls and the root decl have this set to 0. We still need | 2451 | // Anonymous decls and the root decl have this set to 0. We still need |
| 2437 | // to walk them but we do not need to modify this value. | 2452 | // to walk them but we do not need to modify this value. |
| | 2453 | // Anonymous decls should not be marked outdated. They will be re-generated |
| | 2454 | // if their owner decl is marked outdated. |
| 2438 | if (decl.zir_decl_index != 0) { | 2455 | if (decl.zir_decl_index != 0) { |
| 2439 | const old_hash = decl.contentsHashZir(old_zir); | 2456 | const old_hash = decl.contentsHashZir(old_zir); |
| 2440 | decl.zir_decl_index = extra_map.get(decl.zir_decl_index) orelse { | 2457 | decl.zir_decl_index = extra_map.get(decl.zir_decl_index) orelse { |
| 2441 | try deleted_decls.append(gpa, decl); | 2458 | try file.deleted_decls.append(gpa, decl); |
| 2442 | continue; | 2459 | continue; |
| 2443 | }; | 2460 | }; |
| 2444 | const new_name_index = string_table.get(mem.spanZ(decl.name)) orelse { | 2461 | const new_name_index = string_table.get(mem.spanZ(decl.name)) orelse { |
| 2445 | try deleted_decls.append(gpa, decl); | 2462 | try file.deleted_decls.append(gpa, decl); |
| 2446 | continue; | 2463 | continue; |
| 2447 | }; | 2464 | }; |
| 2448 | decl.name = new_zir.nullTerminatedString(new_name_index).ptr; | 2465 | decl.name = new_zir.nullTerminatedString(new_name_index).ptr; |
| 2449 | | 2466 | |
| 2450 | const new_hash = decl.contentsHashZir(new_zir); | 2467 | const new_hash = decl.contentsHashZir(new_zir); |
| 2451 | if (!std.zig.srcHashEql(old_hash, new_hash)) { | 2468 | if (!std.zig.srcHashEql(old_hash, new_hash)) { |
| 2452 | try outdated_decls.append(gpa, decl); | 2469 | try file.outdated_decls.append(gpa, decl); |
| 2453 | } | 2470 | } |
| 2454 | } else { | | |
| 2455 | // TODO all decls should probably store source hash. Without this, | | |
| 2456 | // we currently unnecessarily mark all anon decls outdated here. | | |
| 2457 | try outdated_decls.append(gpa, decl); | | |
| 2458 | } | 2471 | } |
| 2459 | | 2472 | |
| 2460 | if (!decl.has_tv) continue; | 2473 | if (!decl.has_tv) continue; |
| 2461 | | 2474 | |
| 2462 | if (decl.getStruct()) |struct_obj| { | 2475 | if (decl.getStruct()) |struct_obj| { |
| 2463 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { | 2476 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { |
| 2464 | try deleted_decls.append(gpa, decl); | 2477 | try file.deleted_decls.append(gpa, decl); |
| 2465 | continue; | 2478 | continue; |
| 2466 | }; | 2479 | }; |
| 2467 | } | 2480 | } |
| 2468 | | 2481 | |
| 2469 | if (decl.getFunction()) |func| { | 2482 | if (decl.getFunction()) |func| { |
| 2470 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { | 2483 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { |
| 2471 | try deleted_decls.append(gpa, decl); | 2484 | try file.deleted_decls.append(gpa, decl); |
| 2472 | continue; | 2485 | continue; |
| 2473 | }; | 2486 | }; |
| 2474 | } | 2487 | } |
| ... | @@ -2478,7 +2491,7 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange | ... | @@ -2478,7 +2491,7 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange |
| 2478 | const sub_decl = entry.value; | 2491 | const sub_decl = entry.value; |
| 2479 | if (sub_decl.zir_decl_index != 0) { | 2492 | if (sub_decl.zir_decl_index != 0) { |
| 2480 | const new_key_index = string_table.get(entry.key) orelse { | 2493 | const new_key_index = string_table.get(entry.key) orelse { |
| 2481 | try deleted_decls.append(gpa, sub_decl); | 2494 | try file.deleted_decls.append(gpa, sub_decl); |
| 2482 | continue; | 2495 | continue; |
| 2483 | }; | 2496 | }; |
| 2484 | entry.key = new_zir.nullTerminatedString(new_key_index); | 2497 | entry.key = new_zir.nullTerminatedString(new_key_index); |
| ... | @@ -2487,14 +2500,6 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange | ... | @@ -2487,14 +2500,6 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !UpdateChange |
| 2487 | } | 2500 | } |
| 2488 | } | 2501 | } |
| 2489 | } | 2502 | } |
| 2490 | | | |
| 2491 | const outdated_slice = outdated_decls.toOwnedSlice(gpa); | | |
| 2492 | const deleted_slice = deleted_decls.toOwnedSlice(gpa); | | |
| 2493 | | | |
| 2494 | return UpdateChangeList{ | | |
| 2495 | .outdated = outdated_slice, | | |
| 2496 | .deleted = deleted_slice, | | |
| 2497 | }; | | |
| 2498 | } | 2503 | } |
| 2499 | | 2504 | |
| 2500 | pub fn mapOldZirToNew( | 2505 | pub fn mapOldZirToNew( |
| ... | @@ -2512,10 +2517,8 @@ pub fn mapOldZirToNew( | ... | @@ -2512,10 +2517,8 @@ pub fn mapOldZirToNew( |
| 2512 | var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{}; | 2517 | var match_stack: std.ArrayListUnmanaged(MatchedZirDecl) = .{}; |
| 2513 | defer match_stack.deinit(gpa); | 2518 | defer match_stack.deinit(gpa); |
| 2514 | | 2519 | |
| 2515 | const old_main_struct_inst = old_zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] - | 2520 | const old_main_struct_inst = old_zir.getMainStruct(); |
| 2516 | @intCast(u32, Zir.Inst.Ref.typed_value_map.len); | 2521 | const new_main_struct_inst = new_zir.getMainStruct(); |
| 2517 | const new_main_struct_inst = new_zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] - | | |
| 2518 | @intCast(u32, Zir.Inst.Ref.typed_value_map.len); | | |
| 2519 | | 2522 | |
| 2520 | try match_stack.append(gpa, .{ | 2523 | try match_stack.append(gpa, .{ |
| 2521 | .old_inst = old_main_struct_inst, | 2524 | .old_inst = old_main_struct_inst, |
| ... | @@ -2579,7 +2582,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void { | ... | @@ -2579,7 +2582,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void { |
| 2579 | .complete => return, | 2582 | .complete => return, |
| 2580 | | 2583 | |
| 2581 | .outdated => blk: { | 2584 | .outdated => blk: { |
| 2582 | log.debug("re-analyzing {s}", .{decl.name}); | 2585 | log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); |
| 2583 | | 2586 | |
| 2584 | // The exports this Decl performs will be re-discovered, so we remove them here | 2587 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 2585 | // prior to re-analysis. | 2588 | // prior to re-analysis. |
| ... | @@ -2667,8 +2670,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { | ... | @@ -2667,8 +2670,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 2667 | } | 2670 | } |
| 2668 | | 2671 | |
| 2669 | assert(file.zir_loaded); | 2672 | assert(file.zir_loaded); |
| 2670 | const main_struct_inst = file.zir.extra[@enumToInt(Zir.ExtraIndex.main_struct)] - | 2673 | const main_struct_inst = file.zir.getMainStruct(); |
| 2671 | @intCast(u32, Zir.Inst.Ref.typed_value_map.len); | | |
| 2672 | | 2674 | |
| 2673 | const gpa = mod.gpa; | 2675 | const gpa = mod.gpa; |
| 2674 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 2676 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); |
| ... | @@ -2745,14 +2747,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2745,14 +2747,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2745 | defer tracy.end(); | 2747 | defer tracy.end(); |
| 2746 | | 2748 | |
| 2747 | const gpa = mod.gpa; | 2749 | const gpa = mod.gpa; |
| | 2750 | const zir = decl.namespace.file_scope.zir; |
| | 2751 | const zir_datas = zir.instructions.items(.data); |
| 2748 | | 2752 | |
| 2749 | decl.analysis = .in_progress; | 2753 | decl.analysis = .in_progress; |
| 2750 | | 2754 | |
| 2751 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | 2755 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 2752 | defer analysis_arena.deinit(); | 2756 | defer analysis_arena.deinit(); |
| 2753 | | 2757 | |
| 2754 | const zir = decl.namespace.file_scope.zir; | | |
| 2755 | | | |
| 2756 | var sema: Sema = .{ | 2758 | var sema: Sema = .{ |
| 2757 | .mod = mod, | 2759 | .mod = mod, |
| 2758 | .gpa = gpa, | 2760 | .gpa = gpa, |
| ... | @@ -2765,6 +2767,19 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2765,6 +2767,19 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2765 | .owner_func = null, | 2767 | .owner_func = null, |
| 2766 | .param_inst_list = &.{}, | 2768 | .param_inst_list = &.{}, |
| 2767 | }; | 2769 | }; |
| | 2770 | |
| | 2771 | if (decl.isRoot()) { |
| | 2772 | log.debug("semaDecl root {*} ({s})", .{decl, decl.name}); |
| | 2773 | const main_struct_inst = zir.getMainStruct(); |
| | 2774 | const struct_obj = decl.getStruct().?; |
| | 2775 | try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj); |
| | 2776 | assert(decl.namespace.file_scope.status == .success_zir); |
| | 2777 | decl.namespace.file_scope.status = .success_air; |
| | 2778 | decl.analysis = .complete; |
| | 2779 | decl.generation = mod.generation; |
| | 2780 | return false; |
| | 2781 | } |
| | 2782 | |
| 2768 | var block_scope: Scope.Block = .{ | 2783 | var block_scope: Scope.Block = .{ |
| 2769 | .parent = null, | 2784 | .parent = null, |
| 2770 | .sema = &sema, | 2785 | .sema = &sema, |
| ... | @@ -2775,25 +2790,23 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2775,25 +2790,23 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2775 | }; | 2790 | }; |
| 2776 | defer block_scope.instructions.deinit(gpa); | 2791 | defer block_scope.instructions.deinit(gpa); |
| 2777 | | 2792 | |
| 2778 | const zir_datas = zir.instructions.items(.data); | | |
| 2779 | const zir_tags = zir.instructions.items(.tag); | | |
| 2780 | | | |
| 2781 | const zir_block_index = decl.zirBlockIndex(); | 2793 | const zir_block_index = decl.zirBlockIndex(); |
| 2782 | const inst_data = zir_datas[zir_block_index].pl_node; | 2794 | const inst_data = zir_datas[zir_block_index].pl_node; |
| 2783 | const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); | 2795 | const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 2784 | const body = zir.extra[extra.end..][0..extra.data.body_len]; | 2796 | const body = zir.extra[extra.end..][0..extra.data.body_len]; |
| 2785 | const break_index = try sema.analyzeBody(&block_scope, body); | 2797 | const break_index = try sema.analyzeBody(&block_scope, body); |
| 2786 | const result_ref = zir_datas[break_index].@"break".operand; | 2798 | const result_ref = zir_datas[break_index].@"break".operand; |
| 2787 | const decl_tv = try sema.resolveInstConst(&block_scope, inst_data.src(), result_ref); | 2799 | const src = inst_data.src(); |
| | 2800 | const decl_tv = try sema.resolveInstConst(&block_scope, src, result_ref); |
| 2788 | const align_val = blk: { | 2801 | const align_val = blk: { |
| 2789 | const align_ref = decl.zirAlignRef(); | 2802 | const align_ref = decl.zirAlignRef(); |
| 2790 | if (align_ref == .none) break :blk Value.initTag(.null_value); | 2803 | if (align_ref == .none) break :blk Value.initTag(.null_value); |
| 2791 | break :blk (try sema.resolveInstConst(&block_scope, inst_data.src(), align_ref)).val; | 2804 | break :blk (try sema.resolveInstConst(&block_scope, src, align_ref)).val; |
| 2792 | }; | 2805 | }; |
| 2793 | const linksection_val = blk: { | 2806 | const linksection_val = blk: { |
| 2794 | const linksection_ref = decl.zirLinksectionRef(); | 2807 | const linksection_ref = decl.zirLinksectionRef(); |
| 2795 | if (linksection_ref == .none) break :blk Value.initTag(.null_value); | 2808 | if (linksection_ref == .none) break :blk Value.initTag(.null_value); |
| 2796 | break :blk (try sema.resolveInstConst(&block_scope, inst_data.src(), linksection_ref)).val; | 2809 | break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val; |
| 2797 | }; | 2810 | }; |
| 2798 | | 2811 | |
| 2799 | // We need the memory for the Type to go into the arena for the Decl | 2812 | // We need the memory for the Type to go into the arena for the Decl |
| ... | @@ -2842,7 +2855,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2842,7 +2855,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2842 | } | 2855 | } |
| 2843 | | 2856 | |
| 2844 | if (decl.is_exported) { | 2857 | if (decl.is_exported) { |
| 2845 | const export_src = inst_data.src(); // TODO make this point at `export` token | 2858 | const export_src = src; // TODO make this point at `export` token |
| 2846 | if (is_inline) { | 2859 | if (is_inline) { |
| 2847 | return mod.fail(&block_scope.base, export_src, "export of inline function", .{}); | 2860 | return mod.fail(&block_scope.base, export_src, "export of inline function", .{}); |
| 2848 | } | 2861 | } |
| ... | @@ -2859,7 +2872,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2859,7 +2872,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2859 | if (is_mutable and !decl_tv.ty.isValidVarType(is_extern)) { | 2872 | if (is_mutable and !decl_tv.ty.isValidVarType(is_extern)) { |
| 2860 | return mod.fail( | 2873 | return mod.fail( |
| 2861 | &block_scope.base, | 2874 | &block_scope.base, |
| 2862 | inst_data.src(), // TODO point at the mut token | 2875 | src, // TODO point at the mut token |
| 2863 | "variable of type '{}' must be const", | 2876 | "variable of type '{}' must be const", |
| 2864 | .{decl_tv.ty}, | 2877 | .{decl_tv.ty}, |
| 2865 | ); | 2878 | ); |
| ... | @@ -2891,7 +2904,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2891,7 +2904,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2891 | decl.generation = mod.generation; | 2904 | decl.generation = mod.generation; |
| 2892 | | 2905 | |
| 2893 | if (decl.is_exported) { | 2906 | if (decl.is_exported) { |
| 2894 | const export_src = inst_data.src(); // TODO point to the export token | 2907 | const export_src = src; // TODO point to the export token |
| 2895 | // The scope needs to have the decl in it. | 2908 | // The scope needs to have the decl in it. |
| 2896 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); | 2909 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); |
| 2897 | } | 2910 | } |
| ... | @@ -3047,26 +3060,6 @@ pub fn scanNamespace( | ... | @@ -3047,26 +3060,6 @@ pub fn scanNamespace( |
| 3047 | try mod.comp.work_queue.ensureUnusedCapacity(decls_len); | 3060 | try mod.comp.work_queue.ensureUnusedCapacity(decls_len); |
| 3048 | try namespace.decls.ensureCapacity(gpa, decls_len); | 3061 | try namespace.decls.ensureCapacity(gpa, decls_len); |
| 3049 | | 3062 | |
| 3050 | // Keep track of the decls that we expect to see in this namespace so that | | |
| 3051 | // we know which ones have been deleted. | | |
| 3052 | var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(gpa); | | |
| 3053 | defer deleted_decls.deinit(); | | |
| 3054 | { | | |
| 3055 | const namespace_decls = namespace.decls.items(); | | |
| 3056 | try deleted_decls.ensureCapacity(namespace_decls.len); | | |
| 3057 | for (namespace_decls) |entry| { | | |
| 3058 | deleted_decls.putAssumeCapacityNoClobber(entry.value, {}); | | |
| 3059 | } | | |
| 3060 | } | | |
| 3061 | | | |
| 3062 | // Keep track of decls that are invalidated from the update. Ultimately, | | |
| 3063 | // the goal is to queue up `analyze_decl` tasks in the work queue for | | |
| 3064 | // the outdated decls, but we cannot queue up the tasks until after | | |
| 3065 | // we find out which ones have been deleted, otherwise there would be | | |
| 3066 | // deleted Decl pointers in the work queue. | | |
| 3067 | var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(gpa); | | |
| 3068 | defer outdated_decls.deinit(); | | |
| 3069 | | | |
| 3070 | const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; | 3063 | const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; |
| 3071 | var extra_index = extra_start + bit_bags_count; | 3064 | var extra_index = extra_start + bit_bags_count; |
| 3072 | var bit_bag_index: usize = extra_start; | 3065 | var bit_bag_index: usize = extra_start; |
| ... | @@ -3075,8 +3068,6 @@ pub fn scanNamespace( | ... | @@ -3075,8 +3068,6 @@ pub fn scanNamespace( |
| 3075 | var scan_decl_iter: ScanDeclIter = .{ | 3068 | var scan_decl_iter: ScanDeclIter = .{ |
| 3076 | .module = mod, | 3069 | .module = mod, |
| 3077 | .namespace = namespace, | 3070 | .namespace = namespace, |
| 3078 | .deleted_decls = &deleted_decls, | | |
| 3079 | .outdated_decls = &outdated_decls, | | |
| 3080 | .parent_decl = parent_decl, | 3071 | .parent_decl = parent_decl, |
| 3081 | }; | 3072 | }; |
| 3082 | while (decl_i < decls_len) : (decl_i += 1) { | 3073 | while (decl_i < decls_len) : (decl_i += 1) { |
| ... | @@ -3094,36 +3085,12 @@ pub fn scanNamespace( | ... | @@ -3094,36 +3085,12 @@ pub fn scanNamespace( |
| 3094 | | 3085 | |
| 3095 | try scanDecl(&scan_decl_iter, decl_sub_index, flags); | 3086 | try scanDecl(&scan_decl_iter, decl_sub_index, flags); |
| 3096 | } | 3087 | } |
| 3097 | // Handle explicitly deleted decls from the source code. This is one of two | | |
| 3098 | // places that Decl deletions happen. The other is in `Compilation`, after | | |
| 3099 | // `performAllTheWork`, where we iterate over `Module.deletion_set` and | | |
| 3100 | // delete Decls which are no longer referenced. | | |
| 3101 | // If a Decl is explicitly deleted from source, and also no longer referenced, | | |
| 3102 | // it may be both in this `deleted_decls` set, as well as in the | | |
| 3103 | // `Module.deletion_set`. To avoid deleting it twice, we remove it from the | | |
| 3104 | // deletion set at this time. | | |
| 3105 | for (deleted_decls.items()) |entry| { | | |
| 3106 | const decl = entry.key; | | |
| 3107 | log.debug("'{s}' deleted from source", .{decl.name}); | | |
| 3108 | if (decl.deletion_flag) { | | |
| 3109 | log.debug("'{s}' redundantly in deletion set; removing", .{decl.name}); | | |
| 3110 | mod.deletion_set.removeAssertDiscard(decl); | | |
| 3111 | } | | |
| 3112 | try mod.deleteDecl(decl, &outdated_decls); | | |
| 3113 | } | | |
| 3114 | // Finally we can queue up re-analysis tasks after we have processed | | |
| 3115 | // the deleted decls. | | |
| 3116 | for (outdated_decls.items()) |entry| { | | |
| 3117 | try mod.markOutdatedDecl(entry.key); | | |
| 3118 | } | | |
| 3119 | return extra_index; | 3088 | return extra_index; |
| 3120 | } | 3089 | } |
| 3121 | | 3090 | |
| 3122 | const ScanDeclIter = struct { | 3091 | const ScanDeclIter = struct { |
| 3123 | module: *Module, | 3092 | module: *Module, |
| 3124 | namespace: *Scope.Namespace, | 3093 | namespace: *Scope.Namespace, |
| 3125 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), | | |
| 3126 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), | | |
| 3127 | parent_decl: *Decl, | 3094 | parent_decl: *Decl, |
| 3128 | usingnamespace_index: usize = 0, | 3095 | usingnamespace_index: usize = 0, |
| 3129 | comptime_index: usize = 0, | 3096 | comptime_index: usize = 0, |
| ... | @@ -3211,37 +3178,16 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo | ... | @@ -3211,37 +3178,16 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo |
| 3211 | decl.src_node = decl_node; | 3178 | decl.src_node = decl_node; |
| 3212 | decl.src_line = line; | 3179 | decl.src_line = line; |
| 3213 | | 3180 | |
| | 3181 | decl.clearName(gpa); |
| | 3182 | decl.name = decl_name; |
| | 3183 | |
| 3214 | decl.is_pub = is_pub; | 3184 | decl.is_pub = is_pub; |
| 3215 | decl.is_exported = is_exported; | 3185 | decl.is_exported = is_exported; |
| 3216 | decl.has_align = has_align; | 3186 | decl.has_align = has_align; |
| 3217 | decl.has_linksection = has_linksection; | 3187 | decl.has_linksection = has_linksection; |
| 3218 | decl.zir_decl_index = @intCast(u32, decl_sub_index); | 3188 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| 3219 | if (iter.deleted_decls.swapRemove(decl) == null) { | 3189 | if (decl.getFunction()) |func| { |
| 3220 | if (true) { | 3190 | switch (mod.comp.bin_file.tag) { |
| 3221 | @panic("TODO I think this code path is unreachable; should be caught by AstGen."); | | |
| 3222 | } | | |
| 3223 | decl.analysis = .sema_failure; | | |
| 3224 | const msg = try ErrorMsg.create(gpa, .{ | | |
| 3225 | .file_scope = namespace.file_scope, | | |
| 3226 | .parent_decl_node = 0, | | |
| 3227 | .lazy = .{ .token_abs = name_token }, | | |
| 3228 | }, "redeclaration of '{s}'", .{decl.name}); | | |
| 3229 | errdefer msg.destroy(gpa); | | |
| 3230 | const other_src_loc: SrcLoc = .{ | | |
| 3231 | .file_scope = namespace.file_scope, | | |
| 3232 | .parent_decl_node = 0, | | |
| 3233 | .lazy = .{ .node_abs = prev_src_node }, | | |
| 3234 | }; | | |
| 3235 | try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); | | |
| 3236 | try mod.failed_decls.putNoClobber(gpa, decl, msg); | | |
| 3237 | } else { | | |
| 3238 | if (true) { | | |
| 3239 | @panic("TODO reimplement scanDecl with regards to incremental compilation."); | | |
| 3240 | } | | |
| 3241 | if (!std.zig.srcHashEql(decl.contents_hash, contents_hash)) { | | |
| 3242 | try iter.outdated_decls.put(decl, {}); | | |
| 3243 | decl.contents_hash = contents_hash; | | |
| 3244 | } else if (try decl.isFunction()) switch (mod.comp.bin_file.tag) { | | |
| 3245 | .coff => { | 3191 | .coff => { |
| 3246 | // TODO Implement for COFF | 3192 | // TODO Implement for COFF |
| 3247 | }, | 3193 | }, |
| ... | @@ -3256,7 +3202,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo | ... | @@ -3256,7 +3202,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo |
| 3256 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); | 3202 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); |
| 3257 | }, | 3203 | }, |
| 3258 | .c, .wasm, .spirv => {}, | 3204 | .c, .wasm, .spirv => {}, |
| 3259 | }; | 3205 | } |
| 3260 | } | 3206 | } |
| 3261 | } | 3207 | } |
| 3262 | | 3208 | |
| ... | @@ -3277,8 +3223,7 @@ pub fn deleteDecl( | ... | @@ -3277,8 +3223,7 @@ pub fn deleteDecl( |
| 3277 | try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() + | 3223 | try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() + |
| 3278 | decl.dependencies.count()); | 3224 | decl.dependencies.count()); |
| 3279 | | 3225 | |
| 3280 | // Remove from the namespace it resides in. In the case of an anonymous Decl it will | 3226 | // Remove from the namespace it resides in. |
| 3281 | // not be present in the set, and this does nothing. | | |
| 3282 | decl.namespace.removeDecl(decl); | 3227 | decl.namespace.removeDecl(decl); |
| 3283 | | 3228 | |
| 3284 | // Remove itself from its dependencies, because we are about to destroy the decl pointer. | 3229 | // Remove itself from its dependencies, because we are about to destroy the decl pointer. |
| ... | @@ -3430,7 +3375,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -3430,7 +3375,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void { |
| 3430 | } | 3375 | } |
| 3431 | | 3376 | |
| 3432 | fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { | 3377 | fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { |
| 3433 | log.debug("mark {s} outdated", .{decl.name}); | 3378 | log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); |
| 3434 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl }); | 3379 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl }); |
| 3435 | if (mod.failed_decls.swapRemove(decl)) |entry| { | 3380 | if (mod.failed_decls.swapRemove(decl)) |entry| { |
| 3436 | entry.value.destroy(mod.gpa); | 3381 | entry.value.destroy(mod.gpa); |
| ... | @@ -4471,3 +4416,43 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError! | ... | @@ -4471,3 +4416,43 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Module.Struct) InnerError! |
| 4471 | } | 4416 | } |
| 4472 | } | 4417 | } |
| 4473 | } | 4418 | } |
| | 4419 | |
| | 4420 | /// Called from `performAllTheWork`, after all AstGen workers have finished, |
| | 4421 | /// and before the main semantic analysis loop begins. |
| | 4422 | pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
| | 4423 | // Ultimately, the goal is to queue up `analyze_decl` tasks in the work queue |
| | 4424 | // for the outdated decls, but we cannot queue up the tasks until after |
| | 4425 | // we find out which ones have been deleted, otherwise there would be |
| | 4426 | // deleted Decl pointers in the work queue. |
| | 4427 | var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa); |
| | 4428 | defer outdated_decls.deinit(); |
| | 4429 | for (mod.import_table.items()) |import_table_entry| { |
| | 4430 | const file = import_table_entry.value; |
| | 4431 | |
| | 4432 | try outdated_decls.ensureUnusedCapacity(file.outdated_decls.items.len); |
| | 4433 | for (file.outdated_decls.items) |decl| { |
| | 4434 | outdated_decls.putAssumeCapacity(decl, {}); |
| | 4435 | } |
| | 4436 | // Handle explicitly deleted decls from the source code. This is one of two |
| | 4437 | // places that Decl deletions happen. The other is in `Compilation`, after |
| | 4438 | // `performAllTheWork`, where we iterate over `Module.deletion_set` and |
| | 4439 | // delete Decls which are no longer referenced. |
| | 4440 | // If a Decl is explicitly deleted from source, and also no longer referenced, |
| | 4441 | // it may be both in this `deleted_decls` set, as well as in the |
| | 4442 | // `Module.deletion_set`. To avoid deleting it twice, we remove it from the |
| | 4443 | // deletion set at this time. |
| | 4444 | for (file.deleted_decls.items) |decl| { |
| | 4445 | log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); |
| | 4446 | if (decl.deletion_flag) { |
| | 4447 | log.debug("{*} ({s}) redundantly in deletion set; removing", .{ decl, decl.name }); |
| | 4448 | mod.deletion_set.removeAssertDiscard(decl); |
| | 4449 | } |
| | 4450 | try mod.deleteDecl(decl, &outdated_decls); |
| | 4451 | } |
| | 4452 | } |
| | 4453 | // Finally we can queue up re-analysis tasks after we have processed |
| | 4454 | // the deleted decls. |
| | 4455 | for (outdated_decls.items()) |entry| { |
| | 4456 | try mod.markOutdatedDecl(entry.key); |
| | 4457 | } |
| | 4458 | } |