authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-08 23:59:56+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-14 07:40:07+00:00
log7ba8641d19b719c11c0f6177fb28fa098a769e1f
treec4ec6df6cb9205f15d6d0ef64eaa7e191725d60a
parent42fedb3f6c8f9c54da8faea35f424cbd3f72c386
signaturelock-open Commit is signed but in an unrecognized format.

Zcu: handle updates to file root struct


2 files changed, 88 insertions(+), 17 deletions(-)

src/Module.zig+86-15
...@@ -2987,6 +2987,15 @@ pub fn mapOldZirToNew(...@@ -2987,6 +2987,15 @@ pub fn mapOldZirToNew(
2987 }2987 }
2988}2988}
29892989
2990/// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.
2991pub fn ensureFileAnalyzed(zcu: *Zcu, file: *File) SemaError!void {
2992 if (file.root_decl == .none) {
2993 return zcu.semaFile(file);
2994 } else {
2995 return zcu.ensureDeclAnalyzed(file.root_decl);
2996 }
2997}
2998
2990/// This ensures that the Decl will have an up-to-date Type and Value populated.2999/// This ensures that the Decl will have an up-to-date Type and Value populated.
2991/// However the resolution status of the Type may not be fully resolved.3000/// However the resolution status of the Type may not be fully resolved.
2992/// For example an inferred error set is not resolved until after `analyzeFnBody`.3001/// For example an inferred error set is not resolved until after `analyzeFnBody`.
...@@ -3008,13 +3017,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3008,13 +3017,15 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3008 // dependencies are all up-to-date.3017 // dependencies are all up-to-date.
30093018
3010 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });3019 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
3011 const was_outdated = mod.outdated.swapRemove(decl_as_depender) or3020 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
3012 mod.potentially_outdated.swapRemove(decl_as_depender);3021 mod.potentially_outdated.swapRemove(decl_as_depender);
30133022
3014 if (was_outdated) {3023 if (decl_was_outdated) {
3015 _ = mod.outdated_ready.swapRemove(decl_as_depender);3024 _ = mod.outdated_ready.swapRemove(decl_as_depender);
3016 }3025 }
30173026
3027 const was_outdated = mod.outdated_file_root.swapRemove(decl_index) or decl_was_outdated;
3028
3018 switch (decl.analysis) {3029 switch (decl.analysis) {
3019 .in_progress => unreachable,3030 .in_progress => unreachable,
30203031
...@@ -3050,6 +3061,14 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3050,6 +3061,14 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3050 };3061 };
3051 }3062 }
30523063
3064 if (mod.declIsRoot(decl_index)) {
3065 const changed = try mod.semaFileUpdate(decl.getFileScope(mod), decl_was_outdated);
3066 break :blk .{
3067 .invalidate_decl_val = changed,
3068 .invalidate_decl_ref = changed,
3069 };
3070 }
3071
3053 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {3072 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
3054 error.AnalysisFail => {3073 error.AnalysisFail => {
3055 if (decl.analysis == .in_progress) {3074 if (decl.analysis == .in_progress) {
...@@ -3078,7 +3097,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3078,7 +3097,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3078 };3097 };
30793098
3080 // TODO: we do not yet have separate dependencies for decl values vs types.3099 // TODO: we do not yet have separate dependencies for decl values vs types.
3081 if (was_outdated) {3100 if (decl_was_outdated) {
3082 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {3101 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {
3083 // This dependency was marked as PO, meaning dependees were waiting3102 // This dependency was marked as PO, meaning dependees were waiting
3084 // on its analysis result, and it has turned out to be outdated.3103 // on its analysis result, and it has turned out to be outdated.
...@@ -3359,13 +3378,70 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa...@@ -3359,13 +3378,70 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
3359 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());3378 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
3360}3379}
33613380
3362/// Regardless of the file status, will create a `Decl` so that we3381/// Re-analyze the root Decl of a file on an incremental update.
3363/// can track dependencies and re-analyze when the file becomes outdated.3382/// If `type_outdated`, the struct type itself is considered outdated and is
3364pub fn semaFile(mod: *Module, file: *File) SemaError!void {3383/// reconstructed at a new InternPool index. Otherwise, the namespace is just
3384/// re-analyzed. Returns whether the decl's tyval was invalidated.
3385fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
3386 assert(file.root_decl != .none);
3387
3388 const decl = zcu.declPtr(file.root_decl);
3389
3390 if (file.status != .success_zir) {
3391 if (decl.analysis == .file_failure) {
3392 return false;
3393 } else {
3394 decl.analysis = .file_failure;
3395 return true;
3396 }
3397 }
3398
3399 if (decl.analysis == .file_failure) {
3400 // No struct type currently exists. Create one!
3401 _ = try zcu.getFileRootStruct(file.root_decl, decl.src_namespace, file);
3402 return true;
3403 }
3404
3405 assert(decl.has_tv);
3406 assert(decl.owns_tv);
3407
3408 if (type_outdated) {
3409 // Invalidate the existing type, reusing the decl and namespace.
3410 try zcu.intern_pool.remove(decl.val.toIntern());
3411 decl.val = undefined;
3412 _ = try zcu.getFileRootStruct(file.root_decl, decl.src_namespace, file);
3413 return true;
3414 }
3415
3416 // Only the struct's namespace is outdated.
3417 // Preserve the type - just scan the namespace again.
3418
3419 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
3420 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3421
3422 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3423 extra_index += @intFromEnum(small.has_fields_len);
3424 const decls_len = if (small.has_decls_len) blk: {
3425 const decls_len = file.zir.extra[extra_index];
3426 extra_index += 1;
3427 break :blk decls_len;
3428 } else 0;
3429 const decls = file.zir.bodySlice(extra_index, decls_len);
3430
3431 if (!type_outdated) {
3432 try zcu.scanNamespace(decl.src_namespace, decls, decl);
3433 }
3434
3435 return false;
3436}
3437
3438/// Regardless of the file status, will create a `Decl` if none exists so that we can track
3439/// dependencies and re-analyze when the file becomes outdated.
3440fn semaFile(mod: *Module, file: *File) SemaError!void {
3365 const tracy = trace(@src());3441 const tracy = trace(@src());
3366 defer tracy.end();3442 defer tracy.end();
33673443
3368 if (file.root_decl != .none) return;3444 assert(file.root_decl == .none);
33693445
3370 const gpa = mod.gpa;3446 const gpa = mod.gpa;
3371 log.debug("semaFile mod={s} sub_file_path={s}", .{3447 log.debug("semaFile mod={s} sub_file_path={s}", .{
...@@ -3432,9 +3508,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3432,9 +3508,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3432 },3508 },
3433 .incremental => {},3509 .incremental => {},
3434 }3510 }
3435
3436 // Since this is our first time analyzing this file, there can be no dependencies on
3437 // its root Decl. Thus, we do not need to invalidate any dependencies.
3438}3511}
34393512
3440const SemaDeclResult = packed struct {3513const SemaDeclResult = packed struct {
...@@ -3455,11 +3528,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3455,11 +3528,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3455 return error.AnalysisFail;3528 return error.AnalysisFail;
3456 }3529 }
34573530
3458 if (mod.declIsRoot(decl_index)) {3531 assert(!mod.declIsRoot(decl_index));
3459 // This comes from an `analyze_decl` job on an incremental update where3532
3460 // this file changed.3533 if (decl.owns_tv) {
3461 @panic("TODO: update root Decl of modified file");
3462 } else if (decl.owns_tv) {
3463 // We are re-analyzing an owner Decl (for a function or a namespace type).3534 // We are re-analyzing an owner Decl (for a function or a namespace type).
3464 @panic("TODO: update owner Decl");3535 @panic("TODO: update owner Decl");
3465 }3536 }
src/Sema.zig+2-2
...@@ -5883,7 +5883,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5883,7 +5883,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5883 mod.astGenFile(result.file) catch |err|5883 mod.astGenFile(result.file) catch |err|
5884 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});5884 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
58855885
5886 try mod.semaFile(result.file);5886 try mod.ensureFileAnalyzed(result.file);
5887 const file_root_decl_index = result.file.root_decl.unwrap().?;5887 const file_root_decl_index = result.file.root_decl.unwrap().?;
5888 return sema.analyzeDeclVal(parent_block, src, file_root_decl_index);5888 return sema.analyzeDeclVal(parent_block, src, file_root_decl_index);
5889}5889}
...@@ -13705,7 +13705,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13705,7 +13705,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13705 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });13705 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
13706 },13706 },
13707 };13707 };
13708 try mod.semaFile(result.file);13708 try mod.ensureFileAnalyzed(result.file);
13709 const file_root_decl_index = result.file.root_decl.unwrap().?;13709 const file_root_decl_index = result.file.root_decl.unwrap().?;
13710 return sema.analyzeDeclVal(block, operand_src, file_root_decl_index);13710 return sema.analyzeDeclVal(block, operand_src, file_root_decl_index);
13711}13711}