| ... | ... | @@ -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 | 2999 | /// This ensures that the Decl will have an up-to-date Type and Value populated. |
| 2991 | 3000 | /// However the resolution status of the Type may not be fully resolved. |
| 2992 | 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 | 3017 | // dependencies are all up-to-date. |
| 3009 | 3018 | |
| 3010 | 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 | 3021 | mod.potentially_outdated.swapRemove(decl_as_depender); |
| 3013 | 3022 | |
| 3014 | | if (was_outdated) { |
| 3023 | if (decl_was_outdated) { |
| 3015 | 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 | 3029 | switch (decl.analysis) { |
| 3019 | 3030 | .in_progress => unreachable, |
| 3020 | 3031 | |
| ... | ... | @@ -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 | 3072 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { |
| 3054 | 3073 | error.AnalysisFail => { |
| 3055 | 3074 | if (decl.analysis == .in_progress) { |
| ... | ... | @@ -3078,7 +3097,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3078 | 3097 | }; |
| 3079 | 3098 | |
| 3080 | 3099 | // TODO: we do not yet have separate dependencies for decl values vs types. |
| 3081 | | if (was_outdated) { |
| 3100 | if (decl_was_outdated) { |
| 3082 | 3101 | if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) { |
| 3083 | 3102 | // This dependency was marked as PO, meaning dependees were waiting |
| 3084 | 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 | 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 |
| 3363 | | /// can track dependencies and re-analyze when the file becomes outdated. |
| 3364 | | pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3381 | /// Re-analyze the root Decl of a file on an incremental update. |
| 3382 | /// If `type_outdated`, the struct type itself is considered outdated and is |
| 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 | 3441 | const tracy = trace(@src()); |
| 3366 | 3442 | defer tracy.end(); |
| 3367 | 3443 | |
| 3368 | | if (file.root_decl != .none) return; |
| 3444 | assert(file.root_decl == .none); |
| 3369 | 3445 | |
| 3370 | 3446 | const gpa = mod.gpa; |
| 3371 | 3447 | log.debug("semaFile mod={s} sub_file_path={s}", .{ |
| ... | ... | @@ -3432,9 +3508,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3432 | 3508 | }, |
| 3433 | 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 | 3513 | const SemaDeclResult = packed struct { |
| ... | ... | @@ -3455,11 +3528,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3455 | 3528 | return error.AnalysisFail; |
| 3456 | 3529 | } |
| 3457 | 3530 | |
| 3458 | | if (mod.declIsRoot(decl_index)) { |
| 3459 | | // This comes from an `analyze_decl` job on an incremental update where |
| 3460 | | // this file changed. |
| 3461 | | @panic("TODO: update root Decl of modified file"); |
| 3462 | | } else if (decl.owns_tv) { |
| 3531 | assert(!mod.declIsRoot(decl_index)); |
| 3532 | |
| 3533 | if (decl.owns_tv) { |
| 3463 | 3534 | // We are re-analyzing an owner Decl (for a function or a namespace type). |
| 3464 | 3535 | @panic("TODO: update owner Decl"); |
| 3465 | 3536 | } |