| ... | @@ -2987,6 +2987,15 @@ pub fn mapOldZirToNew( | ... | @@ -2987,6 +2987,15 @@ pub fn mapOldZirToNew( |
| 2987 | } | 2987 | } |
| 2988 | } | 2988 | } |
| 2989 | | 2989 | |
| | 2990 | /// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl. |
| | 2991 | pub 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. |
| 3009 | | 3018 | |
| 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) or | 3020 | 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); |
| 3013 | | 3022 | |
| 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 | } |
| 3017 | | 3026 | |
| | 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, |
| 3020 | | 3031 | |
| ... | @@ -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 | } |
| 3052 | | 3063 | |
| | 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 | }; |
| 3079 | | 3098 | |
| 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 waiting | 3102 | // 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 | } |
| 3361 | | 3380 | |
| 3362 | /// Regardless of the file status, will create a `Decl` so that we | 3381 | /// 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 |
| 3364 | pub 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. |
| | 3385 | fn 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. |
| | 3440 | fn 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(); |
| 3367 | | 3443 | |
| 3368 | if (file.root_decl != .none) return; | 3444 | assert(file.root_decl == .none); |
| 3369 | | 3445 | |
| 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 | } |
| 3439 | | 3512 | |
| 3440 | const SemaDeclResult = packed struct { | 3513 | const 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 | } |
| 3457 | | 3530 | |
| 3458 | if (mod.declIsRoot(decl_index)) { | 3531 | assert(!mod.declIsRoot(decl_index)); |
| 3459 | // This comes from an `analyze_decl` job on an incremental update where | 3532 | |
| 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 | } |