diff --git a/freak-conformance-audit.md b/freak-conformance-audit.md index f1008fd..7a438d2 100644 --- a/freak-conformance-audit.md +++ b/freak-conformance-audit.md @@ -96,14 +96,14 @@ Verdict legend: 🛠 code fix, 📖 amend bible, ✅ already aligned. |---|---|---|---| | `pilot x = value` declares variable, mutable by default | ✅ | ✅ | [freakc/parser.py:900-950](freakc/parser.py); confirmed by `tests/suite/test_variables.fk` | | `fixed pilot x = value` immutable | ✅ | ✅ | parsed and enforced | -| Type annotation optional / inferred | ✅ | ✅ | The shipping checker infers unannotated literals. In V4, task-local `pilot` and `fixed pilot` annotations—including tuple and fixed-array annotations used by tuple/list destructuring—are normalized with exact spans into HIR snapshot v4 facts, exposed/canonicalized by TY, and consumed by MIR build without re-reading their type tokens. MIR build still uses body tokens for patterns, initializer boundaries, places, and CFG; six unrelated type-text callers remain guarded, backend representation is unchanged, and symbol-valued annotated locals retain the existing phantom-local-IR limitation. | +| Type annotation optional / inferred | ✅ | ✅ | The shipping checker infers unannotated literals. In V4, task-local `pilot` and `fixed pilot` annotations—including tuple and fixed-array annotations used by tuple/list destructuring—are normalized with exact spans into HIR snapshot v5 facts, exposed/canonicalized by TY, and consumed by MIR build without re-reading their type tokens. MIR build still uses body tokens for patterns, initializer boundaries, places, and CFG; six unrelated type-text callers remain guarded, backend representation is unchanged, and symbol-valued annotated locals retain the existing phantom-local-IR limitation. | | `pilot mut x = ...` (Phase-1 BC) for explicit mutability under `--strict-borrow` | ✅ | 📖 | [src/compiler/v3/checker.fk](src/compiler/v3/checker.fk) — bible should mention this dual mode (default leak-everything vs `--strict-borrow`) | #### §1.2 Functions ([freak-full-bible.md:42-71](freak-full-bible.md)) | Contract | Status | Verdict | Notes | |---|---|---|---| -| `task name(...) -> type { ... }` | ✅ | ✅ | core feature | +| `task name(...) -> type { ... }` | ✅ | ✅ | Core feature. V4 stores ordinary top-level tasks as closed `explicit` / `implicit-block` / `arrow` HIR return-form facts; an explicit `-> T` carries normalized surface text and its exact span through HIR snapshot v5, and TY consumes that declared type/span without token reconstruction. Arrow inference, implicit block returns, impl/doctrine/extern signatures, MIR body lowering, and backend behavior retain their existing semantics and remain separately bounded. | | `give back` return keyword | ✅ | ✅ | | | `say` print keyword always available | ✅ | ✅ | | | String path interpolation `"{path}"` | ✅ | ✅ | Self-hosted V3 lowers resolved `IDENT(.IDENT)*` paths in every word-expression context on C and LLVM; non-path brace bodies remain literal. Executable evidence: [tests/v3_interpolation.py](tests/v3_interpolation.py) and [tests/v3_legacy_golden.py](tests/v3_legacy_golden.py). | diff --git a/freakc/auditor.py b/freakc/auditor.py index 16dc3ba..0ea590b 100644 --- a/freakc/auditor.py +++ b/freakc/auditor.py @@ -2867,6 +2867,103 @@ def add(label: str, ok: bool, detail: str = "") -> None: if unw_missing: failures.append("V4 unwinder-import diagnostic regressed: " + "; ".join(unw_missing)) + # Check 9b: V4 ordinary-task return facts belong to HIR. This is an + # ownership boundary, not a new return semantic. + v4_hir_task_return = repo / "src" / "compiler" / "v4" / "crates" / "freak_hir" / "src" / "lib.fk" + v4_ty_task_return = repo / "src" / "compiler" / "v4" / "crates" / "freak_ty" / "src" / "lib.fk" + v4_task_return_smoke = repo / "src" / "compiler" / "v4" / "tests" / "task_return_semantic_boundary_smoke.fk" + v4_task_return_harness = repo / "src" / "compiler" / "v4" / "check_v4.py" + v4_task_return_readme = repo / "src" / "compiler" / "v4" / "README.md" + task_return_boundary_missing: List[str] = [] + if v4_hir_task_return.exists(): + hir_src = v4_hir_task_return.read_text(encoding="utf-8") + for needle in ( + 'pilot v4_hir_snapshot_format = "freak-hir-snapshot-v5"', + 'pilot v4_hir_task_return_explicit = "explicit"', + 'pilot v4_hir_task_return_implicit_block = "implicit-block"', + 'pilot v4_hir_task_return_arrow = "arrow"', + "pilot v4_hir_task_return_items = 0", + "pilot v4_hir_task_return_forms = 0", + "pilot v4_hir_task_return_types = 0", + "pilot v4_hir_task_return_spans = 0", + "task v4_hir_task_return_form(", + "task v4_hir_task_return_type(", + "task v4_hir_task_return_span(", + 'pilot out = "hir-task-return"', + '"task-returns"', + "task v4_hir_snapshot_task_return_is_valid(", + "task v4_hir_snapshot_task_return_owner_is_valid(", + "task v4_hir_snapshot_task_return_slots_are_valid(", + ): + if needle not in hir_src: + task_return_boundary_missing.append(f"freak_hir: {needle}") + else: + task_return_boundary_missing.append("freak_hir/src/lib.fk missing") + if v4_ty_task_return.exists(): + ty_src = v4_ty_task_return.read_text(encoding="utf-8") + for needle in ( + "task v4_ty_signature_is_ordinary_hir_task(", + "task v4_ty_ordinary_task_explicit_return_from_hir(", + "task v4_ty_ordinary_task_explicit_return_span_from_hir(", + "task v4_ty_ordinary_task_arrow_return_fallback(", + "task v4_ty_nonordinary_signature_return_fallback(", + "task v4_ty_nonordinary_signature_return_span_fallback(", + "task v4_ty_nonordinary_hir_item_return_fallback(", + ): + if needle not in ty_src: + task_return_boundary_missing.append(f"freak_ty: {needle}") + else: + task_return_boundary_missing.append("freak_ty/src/lib.fk missing") + if not v4_task_return_smoke.exists(): + task_return_boundary_missing.append("smoke fixture: task_return_semantic_boundary_smoke.fk") + if v4_task_return_harness.exists(): + harness_src = v4_task_return_harness.read_text(encoding="utf-8") + for needle in ( + '"name": "task return semantic boundary"', + '"fixture": "task_return_semantic_boundary_smoke.fk"', + "def check_task_return_hir_boundary() -> None:", + "def task_return_explicit_call_closure_violations(ty_source: str) -> list[str]:", + "task return boundary guard self-test: helper-indirected fallback rejected", + "check_task_return_hir_boundary()", + ): + if needle not in harness_src: + task_return_boundary_missing.append(f"check_v4.py: {needle}") + else: + task_return_boundary_missing.append("check_v4.py harness missing") + for doc_path, needles in ( + ( + v4_task_return_readme, + ( + "The third bounded boundary covers declared returns on ordinary top-level tasks.", + "HIR snapshot v5 validates that vocabulary", + ), + ), + ( + audit_doc, + ( + "V4 stores ordinary top-level tasks as closed", + "TY consumes that declared type/span without token reconstruction", + ), + ), + ): + if not doc_path.exists(): + task_return_boundary_missing.append(f"documentation missing: {doc_path.name}") + continue + doc_src = doc_path.read_text(encoding="utf-8") + for needle in needles: + if needle not in doc_src: + task_return_boundary_missing.append(f"{doc_path.name}: {needle}") + add( + "V4 task return HIR boundary", + not task_return_boundary_missing, + "HIR v5 + TY adapters + smoke + docs wired" if not task_return_boundary_missing else f"{len(task_return_boundary_missing)} gap(s)", + ) + if task_return_boundary_missing: + failures.append( + "V4 ordinary-task return HIR boundary regressed: " + + "; ".join(task_return_boundary_missing) + ) + # ── Check 10: V4 contract-region source sets ── # Borrowed return signatures may select every parameter whose lifetime # outlives the return region. Require the set-valued TY/MIR/Meiya contract, diff --git a/src/compiler/v4/README.md b/src/compiler/v4/README.md index a0eb4f3..1049a2f 100644 --- a/src/compiler/v4/README.md +++ b/src/compiler/v4/README.md @@ -79,12 +79,20 @@ construction. Six unrelated `v4_ty_type_text` consumers remain allowlisted for method type arguments, raw-pointer instance methods, associated methods, shape/route constructor heads, and route-case expressions; the harness requires that exact set and prevents local declaration lowering from returning to it. -Task parameter and return types, shape/route fields, const annotations, -doctrine/extern types, the remaining MIR body families, and all other type -families remain explicit follow-up slices. These boundaries change fact -ownership, not language semantics or backend representation. Symbol-valued -annotated locals still retain the pre-existing phantom-local-IR limitation -described in the FFI section below. +The third bounded boundary covers declared returns on ordinary top-level tasks. +`freak_hir` stores one closed `explicit` / `implicit-block` / `arrow` record per +task, including normalized surface type and exact contained span only for an +explicit `-> T`; HIR snapshot v5 validates that vocabulary, task-only ownership, +canonical spans, contiguous slots, and declared counts before restore. TY reads +explicit return types and spans only through those HIR facts. Arrow inference, +implicit block returns, and non-ordinary impl/doctrine/extern signatures remain +separately named fallbacks and keep their existing semantics. Task parameter +types, shape/route fields, const annotations, non-ordinary signatures, the +remaining MIR body families, and all other type families remain explicit +follow-up slices. These boundaries change fact ownership, not language +semantics or backend representation. Symbol-valued annotated locals still +retain the pre-existing phantom-local-IR limitation described in the FFI +section below. Closures now form a complete first-pass frontend/query slice. The resilient parser records arrow and block forms as `ClosureExpr` trees and leaves `IncompleteNode` recovery facts for missing pipes, body markers, expressions, @@ -510,7 +518,7 @@ unit-section||| None: "local-annotation-mir-diagnostics=0", "local-annotation-borrow-status=clean", "local-annotation-borrow-diagnostics=0", - "hir-snapshot format=freak-hir-snapshot-v4 files=1 items=1 alias-targets=0 local-annotations=4 diagnostics=0", - "hir-snapshot-restore ok=1 files=1 items=1 local-annotations=4 diagnostics=0 skipped-other=0 live-files=1", + "hir-snapshot format=freak-hir-snapshot-v5 files=1 items=1 alias-targets=0 local-annotations=4 task-returns=1 diagnostics=0", + "hir-snapshot-restore ok=1 files=1 items=1 local-annotations=4 task-returns=1 diagnostics=0 skipped-other=0 live-files=1", "local-annotation-restored-count=4", "local-annotation-restored-fixed=char", "local-annotation-malformed-restore-rejected=true", @@ -9078,6 +9078,54 @@ def check_runner_retained_memory() -> None: "local-annotation-bad-stmt-span-stable=true", ], }, + { + "name": "task return semantic boundary", + "fixture": "task_return_semantic_boundary_smoke.fk", + "expect": [ + "task-return-parse-diagnostics=0", + "task-return-hir-records=3", + "task-return-explicit-form=explicit", + "task-return-explicit-surface=lend 'a maybe<[word;2]>", + "task-return-explicit-source=lend 'a maybe< [word; 2] >", + "task-return-explicit-span-contained=true", + "task-return-implicit-form=implicit-block", + "task-return-implicit-surface=", + "task-return-implicit-type=unknown", + "task-return-implicit-span-empty=true", + "task-return-arrow-form=arrow", + "task-return-arrow-type=bool", + "task-return-arrow-display=task arrow(...) -> bool", + "task-return-arrow-span-empty=true", + "task-return-ty-surface=lend 'a maybe<[word;2]>", + "task-return-ty-canonical=lend 'a maybe<[word;2]>", + "task-return-ty-display=task keep<'a>(...) -> lend 'a maybe<[word;2]>", + "task-return-mir-expected=lend 'a maybe<[word;2]>", + "task-return-mir-diagnostics=0", + "task-return-borrow-status=clean", + "ty-snapshot format=freak-ty-snapshot-v1 files=1 signatures=3 diagnostics=0", + "hir-snapshot format=freak-hir-snapshot-v5 files=1 items=3 alias-targets=0 local-annotations=0 task-returns=3 diagnostics=0", + "hir-snapshot-restore ok=1 files=1 items=3 local-annotations=0 task-returns=3 diagnostics=0 skipped-other=0 live-files=1", + "task-return-restored-form=explicit", + "task-return-restored-surface=lend 'a maybe<[word;2]>", + "task-return-schema-variants-rejected=true", + "task-return-schema-variants-atomic=true", + "task-return-editor-display=task keep<'a>(...) -> lend 'a maybe<[word;2]>", + "task-return-invalidation-edit-isolated=true", + "task-return-before-ty=int", + "task-return-before-mir=int", + "task-return-before-borrow=clean", + "task-return-before-editor=task changed(...) -> int", + "task-return-invalidation-hir=true", + "task-return-invalidation-ty=true", + "task-return-invalidation-mir=true", + "task-return-invalidation-borrowck=true", + "task-return-invalidation-editor=true", + "task-return-after-ty=num", + "task-return-after-mir=num", + "task-return-after-borrow=clean", + "task-return-after-editor=task changed(...) -> num", + ], + }, ] if str(ROOT) not in sys.path: @@ -9375,6 +9423,126 @@ def freak_tasks_containing(source: str, needle: str) -> set[str]: } +def freak_task_calls(source: str, body: str) -> set[str]: + task_names = set(re.findall(r"(?m)^task\s+([A-Za-z0-9_]+)\s*\(", source)) + return { + task_name + for task_name in task_names + if re.search(rf"\b{re.escape(task_name)}\s*\(", body) is not None + } + + +def freak_task_call_closure(source: str, roots: set[str]) -> set[str]: + task_names = set(re.findall(r"(?m)^task\s+([A-Za-z0-9_]+)\s*\(", source)) + pending = sorted(roots & task_names) + reached: set[str] = set() + while pending: + task_name = pending.pop() + if task_name in reached: + continue + reached.add(task_name) + body = freak_task_body(source, task_name) + if body is None: + continue + pending.extend(sorted(freak_task_calls(source, body) - reached)) + return reached + + +def freak_braced_arm(body: str, marker: str) -> str | None: + marker_index = body.find(marker) + if marker_index < 0: + return None + open_index = body.find("{", marker_index + len(marker)) + if open_index < 0: + return None + close_index = freak_matching_brace(body, open_index, len(body)) + if close_index is None: + return None + return body[open_index + 1 : close_index] + + +def task_return_explicit_call_closure_violations(ty_source: str) -> list[str]: + violations: list[str] = [] + explicit_roots = { + "v4_ty_ordinary_task_explicit_return_from_hir", + "v4_ty_ordinary_task_explicit_return_span_from_hir", + } + + surface_body = freak_task_body(ty_source, "v4_ty_signature_return_surface_type") + surface_arm = None if surface_body is None else freak_braced_arm( + surface_body, + "if v4_ty_signature_is_ordinary_hir_task(ty_id, sig_id)", + ) + if surface_arm is None or "v4_ty_task_return_from_hir" not in surface_arm: + violations.append("task return ordinary surface dispatch no longer enters the HIR return dispatcher") + elif "v4_ty_nonordinary_signature_return_fallback" in surface_arm: + violations.append("task return ordinary surface dispatch reaches the nonordinary fallback") + if surface_arm is not None: + explicit_roots.update( + freak_task_calls(ty_source, surface_arm) - {"v4_ty_task_return_from_hir"} + ) + + hir_dispatch_body = freak_task_body(ty_source, "v4_ty_task_return_from_hir") + explicit_arm = None if hir_dispatch_body is None else freak_braced_arm( + hir_dispatch_body, + "if form == v4_hir_task_return_explicit", + ) + if explicit_arm is None: + violations.append("task return HIR dispatcher has no bounded explicit-return arm") + else: + explicit_roots.update(freak_task_calls(ty_source, explicit_arm)) + + span_body = freak_task_body(ty_source, "v4_ty_signature_return_span") + span_arm = None if span_body is None else freak_braced_arm( + span_body, + "if v4_ty_signature_is_ordinary_hir_task(ty_id, sig_id)", + ) + if span_arm is None: + violations.append("task return signature span dispatcher has no bounded ordinary-task arm") + else: + explicit_roots.update(freak_task_calls(ty_source, span_arm)) + + reached = freak_task_call_closure(ty_source, explicit_roots) + forbidden_tasks = { + "v4_ty_nonordinary_signature_return_fallback", + "v4_ty_nonordinary_signature_return_span_fallback", + "v4_ty_nonordinary_hir_item_return_fallback", + "v4_ty_task_return_from_tokens", + "v4_ty_task_return_span_from_tokens", + } + reached_forbidden = sorted(reached & forbidden_tasks) + if reached_forbidden: + violations.append( + "task return explicit HIR call closure reaches forbidden fallback: " + + ", ".join(reached_forbidden) + ) + + forbidden_fragments = ( + "v4_ty_type_text", + "v4_lex_", + "v4_parse_", + "v4_expand_", + "_token", + "v4_ty_span_from_tokens", + ) + for task_name in sorted(reached): + body = freak_task_body(ty_source, task_name) or "" + for forbidden in forbidden_fragments: + if forbidden in body: + violations.append( + f"task return explicit HIR call closure reconstructs syntax: {task_name} uses {forbidden}" + ) + token_helpers = sorted( + call for call in freak_task_calls(ty_source, body) if "token" in call + ) + if token_helpers: + violations.append( + f"task return explicit HIR call closure reaches token helper from {task_name}: " + + ", ".join(token_helpers) + ) + return violations + + def check_alias_hir_boundary() -> None: expand_source = read_text(crate_path("freak_expand")) hir_source = read_text(crate_path("freak_hir")) @@ -9492,7 +9660,7 @@ def check_mir_local_annotation_boundary() -> None: violations: list[str] = [] for marker in ( - 'pilot v4_hir_snapshot_format = "freak-hir-snapshot-v4"', + 'pilot v4_hir_snapshot_format = "freak-hir-snapshot-v5"', "pilot v4_hir_local_annotation_items = 0", "pilot v4_hir_local_annotation_stmt_spans = 0", "pilot v4_hir_local_annotation_types = 0", @@ -9605,6 +9773,159 @@ def check_mir_local_annotation_boundary() -> None: print("semantic MIR local annotations: TY facts, six-task builder type-text allowlist") +def check_task_return_hir_boundary() -> None: + hir_source = read_text(crate_path("freak_hir")) + ty_source = read_text(crate_path("freak_ty")) + violations: list[str] = [] + + if 'pilot v4_ty_snapshot_format = "freak-ty-snapshot-v1"' not in ty_source: + violations.append("task return boundary unexpectedly changed the TY snapshot format") + + for marker in ( + 'pilot v4_hir_snapshot_format = "freak-hir-snapshot-v5"', + "pilot v4_hir_task_return_items = 0", + "pilot v4_hir_task_return_forms = 0", + "pilot v4_hir_task_return_types = 0", + "pilot v4_hir_task_return_spans = 0", + '"hir-task-return"', + '"task-returns"', + "v4_hir_task_return_explicit", + "v4_hir_task_return_implicit_block", + "v4_hir_task_return_arrow", + ): + if marker not in hir_source: + violations.append(f"task return HIR boundary missing: {marker}") + + hir_storage_accessors = ( + "v4_hir_task_return_record_id", + "v4_hir_task_return_form", + "v4_hir_task_return_type", + "v4_hir_task_return_span", + ) + for task_name in hir_storage_accessors: + body = freak_task_body(hir_source, task_name) + if body is None: + violations.append(f"task return HIR storage accessor missing: {task_name}") + continue + for forbidden in ( + "v4_parse_", + "v4_lex_", + "v4_expand_", + "_token", + "v4_hir_local_annotation_type_text", + ): + if forbidden in body: + violations.append( + f"task return HIR storage accessor reconstructs syntax: {task_name} uses {forbidden}" + ) + + ty_hir_contracts = { + "v4_ty_ordinary_task_explicit_return_from_hir": "v4_hir_task_return_type", + "v4_ty_ordinary_task_explicit_return_span_from_hir": "v4_hir_task_return_span", + } + for task_name, required in ty_hir_contracts.items(): + body = freak_task_body(ty_source, task_name) + if body is None: + violations.append(f"task return TY HIR adapter missing: {task_name}") + continue + if required not in body or "v4_hir_task_return_form" not in body: + violations.append(f"task return TY HIR adapter bypasses stored facts: {task_name}") + for forbidden in ( + "v4_parse_", + "v4_lex_", + "v4_expand_", + "_token", + "v4_ty_type_text", + "v4_ty_task_return_from_tokens", + "v4_ty_span_from_tokens", + ): + if forbidden in body: + violations.append( + f"task return TY HIR adapter reconstructs syntax: {task_name} uses {forbidden}" + ) + + surface_body = freak_task_body(ty_source, "v4_ty_signature_return_surface_type") + if surface_body is None: + violations.append("task return signature surface adapter missing") + else: + for required in ( + "v4_ty_signature_is_ordinary_hir_task", + "v4_ty_task_return_from_hir", + "v4_ty_nonordinary_signature_return_fallback", + ): + if required not in surface_body: + violations.append(f"task return signature dispatch missing: {required}") + if "v4_ty_task_return_from_tokens" in surface_body or "v4_ty_type_text" in surface_body: + violations.append("ordinary task return signature surface directly reconstructs token type text") + + span_body = freak_task_body(ty_source, "v4_ty_signature_return_span") + if span_body is None: + violations.append("task return signature span adapter missing") + else: + if "v4_ty_ordinary_task_explicit_return_span_from_hir" not in span_body or "v4_ty_nonordinary_signature_return_span_fallback" not in span_body: + violations.append("task return signature span dispatch does not separate HIR and nonordinary fallbacks") + if "v4_ty_task_return_span_from_tokens" in span_body or "v4_ty_span_from_tokens" in span_body: + violations.append("ordinary task return signature span directly reconstructs tokens") + + arrow_body = freak_task_body(ty_source, "v4_ty_ordinary_task_arrow_return_fallback") + if arrow_body is None or "v4_ty_infer_arrow_expr_return" not in arrow_body: + violations.append("arrow shorthand return fallback is not separately pinned") + + hir_dispatch_body = freak_task_body(ty_source, "v4_ty_task_return_from_hir") + if hir_dispatch_body is None or "v4_ty_nonordinary_hir_item_return_fallback" not in hir_dispatch_body: + violations.append("nonordinary HIR-item return fallback is not separately pinned") + + allowed_return_token_tasks = { + "v4_ty_display_for_hir_item", + "v4_ty_doctrine_method_return_surface_type", + "v4_ty_extern_member_return_surface_type", + "v4_ty_extern_member_return_type", + "v4_ty_impl_method_return_type", + "v4_ty_nonordinary_hir_item_return_fallback", + "v4_ty_nonordinary_signature_return_fallback", + } + actual_return_token_tasks = freak_tasks_containing(ty_source, "v4_ty_task_return_from_tokens(") + if actual_return_token_tasks != allowed_return_token_tasks: + missing = sorted(allowed_return_token_tasks - actual_return_token_tasks) + extra = sorted(actual_return_token_tasks - allowed_return_token_tasks) + if missing: + violations.append("task return token fallback allowlist missing expected tasks: " + ", ".join(missing)) + if extra: + violations.append("task return token fallback allowlist gained tasks: " + ", ".join(extra)) + + display_body = freak_task_body(ty_source, "v4_ty_display_for_hir_item") + if display_body is None or "v4_resolve_is_extern_member_def" not in display_body or "v4_ty_task_return_from_hir" not in display_body: + violations.append("task display does not isolate extern token fallback from ordinary HIR returns") + + violations.extend(task_return_explicit_call_closure_violations(ty_source)) + + explicit_adapter = "v4_ty_ordinary_task_explicit_return_from_hir" + explicit_body = freak_task_body(ty_source, explicit_adapter) + if explicit_body is None or "give back return_ty" not in explicit_body: + violations.append("task return boundary guard self-test could not locate explicit adapter return") + else: + mutated_body = explicit_body.replace( + "give back return_ty", + "give back v4_ty_nonordinary_signature_return_fallback(0, 0)", + 1, + ) + mutated_source = ty_source.replace(explicit_body, mutated_body, 1) + probe_violations = task_return_explicit_call_closure_violations(mutated_source) + if not any( + "v4_ty_nonordinary_signature_return_fallback" in violation + for violation in probe_violations + ): + violations.append("task return boundary guard self-test accepted helper-indirected fallback") + + if violations: + for violation in violations: + print(violation) + raise SystemExit(1) + + print("task return boundary guard self-test: helper-indirected fallback rejected") + print("no syntax past HIR: ordinary task declared return type and span") + + def check_tooling_interfaces() -> None: readme = read_text(V4_ROOT / "README.md") lsp_source = read_text(crate_path("freak_lsp")) @@ -11070,6 +11391,7 @@ def main(argv: list[str] | None = None) -> int: check_crate_boundaries() check_alias_hir_boundary() check_mir_local_annotation_boundary() + check_task_return_hir_boundary() check_tooling_interfaces() check_snapshot_inventories() base_source = check_flattened_crates() diff --git a/src/compiler/v4/crates/freak_hir/src/lib.fk b/src/compiler/v4/crates/freak_hir/src/lib.fk index dba16aa..77ebb1c 100644 --- a/src/compiler/v4/crates/freak_hir/src/lib.fk +++ b/src/compiler/v4/crates/freak_hir/src/lib.fk @@ -17,7 +17,10 @@ pilot v4_hir_import = "Import" pilot v4_hir_extern = "Extern" pilot v4_hir_attribute = "Attribute" pilot v4_hir_error = "Error" -pilot v4_hir_snapshot_format = "freak-hir-snapshot-v4" +pilot v4_hir_snapshot_format = "freak-hir-snapshot-v5" +pilot v4_hir_task_return_explicit = "explicit" +pilot v4_hir_task_return_implicit_block = "implicit-block" +pilot v4_hir_task_return_arrow = "arrow" pilot v4_hir_files = 0 pilot v4_hir_expansions = 0 @@ -36,6 +39,13 @@ pilot v4_hir_local_annotation_items = 0 pilot v4_hir_local_annotation_stmt_spans = 0 pilot v4_hir_local_annotation_types = 0 pilot v4_hir_local_annotation_type_spans = 0 +-- Every ordinary top-level task owns one closed return-form record. Explicit +-- declared return types are normalized here; implicit blocks and arrow +-- shorthand retain distinct form tags without inventing a declared type. +pilot v4_hir_task_return_items = 0 +pilot v4_hir_task_return_forms = 0 +pilot v4_hir_task_return_types = 0 +pilot v4_hir_task_return_spans = 0 pilot v4_hir_diags = 0 pilot v4_hir_file_len = 0 pilot v4_hir_ready = 0 @@ -55,6 +65,10 @@ task v4_hir_init() -> void { v4_hir_local_annotation_stmt_spans = array_new() v4_hir_local_annotation_types = array_new() v4_hir_local_annotation_type_spans = array_new() + v4_hir_task_return_items = array_new() + v4_hir_task_return_forms = array_new() + v4_hir_task_return_types = array_new() + v4_hir_task_return_spans = array_new() v4_hir_diags = array_new() v4_hir_file_len = 0 v4_hir_ready = 1 @@ -78,6 +92,10 @@ task v4_hir_file_new(file_id: int, expansion_id: int) -> int { array_push(v4_hir_local_annotation_stmt_spans, word_from_int(array_new())) array_push(v4_hir_local_annotation_types, word_from_int(array_new())) array_push(v4_hir_local_annotation_type_spans, word_from_int(array_new())) + array_push(v4_hir_task_return_items, word_from_int(array_new())) + array_push(v4_hir_task_return_forms, word_from_int(array_new())) + array_push(v4_hir_task_return_types, word_from_int(array_new())) + array_push(v4_hir_task_return_spans, word_from_int(array_new())) array_push(v4_hir_diags, word_from_int(array_new())) } array_set(v4_hir_files, hir_id, word_from_int(file_id)) @@ -93,6 +111,10 @@ task v4_hir_file_new(file_id: int, expansion_id: int) -> int { array_set(v4_hir_local_annotation_stmt_spans, hir_id, word_from_int(array_new())) array_set(v4_hir_local_annotation_types, hir_id, word_from_int(array_new())) array_set(v4_hir_local_annotation_type_spans, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_items, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_forms, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_types, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_spans, hir_id, word_from_int(array_new())) array_set(v4_hir_diags, hir_id, word_from_int(array_new())) v4_hir_file_len = hir_id + 1 give back hir_id @@ -142,6 +164,22 @@ task v4_hir_local_annotation_type_spans_handle(hir_id: int) -> int { give back word_to_int(array_get(v4_hir_local_annotation_type_spans, hir_id)) } +task v4_hir_task_return_items_handle(hir_id: int) -> int { + give back word_to_int(array_get(v4_hir_task_return_items, hir_id)) +} + +task v4_hir_task_return_forms_handle(hir_id: int) -> int { + give back word_to_int(array_get(v4_hir_task_return_forms, hir_id)) +} + +task v4_hir_task_return_types_handle(hir_id: int) -> int { + give back word_to_int(array_get(v4_hir_task_return_types, hir_id)) +} + +task v4_hir_task_return_spans_handle(hir_id: int) -> int { + give back word_to_int(array_get(v4_hir_task_return_spans, hir_id)) +} + task v4_hir_diags_handle(hir_id: int) -> int { give back word_to_int(array_get(v4_hir_diags, hir_id)) } @@ -532,6 +570,55 @@ task v4_hir_add_local_annotation(hir_id: int, item_id: int, stmt_span: word, typ give back record_id } +task v4_hir_task_return_record_count(hir_id: int) -> int { + give back array_len(v4_hir_task_return_items_handle(hir_id)) +} + +task v4_hir_task_return_record_id(hir_id: int, item_id: int) -> int { + pilot record_id = 0 + pilot record_count = v4_hir_task_return_record_count(hir_id) + repeat until record_id >= record_count { + if word_to_int(array_get(v4_hir_task_return_items_handle(hir_id), record_id)) == item_id { + give back record_id + } + record_id += 1 + } + give back 0 - 1 +} + +task v4_hir_task_return_form(hir_id: int, item_id: int) -> word { + pilot record_id = v4_hir_task_return_record_id(hir_id, item_id) + if record_id < 0 { + give back "" + } + give back array_get(v4_hir_task_return_forms_handle(hir_id), record_id) +} + +task v4_hir_task_return_type(hir_id: int, item_id: int) -> word { + pilot record_id = v4_hir_task_return_record_id(hir_id, item_id) + if record_id < 0 { + give back "" + } + give back array_get(v4_hir_task_return_types_handle(hir_id), record_id) +} + +task v4_hir_task_return_span(hir_id: int, item_id: int) -> word { + pilot record_id = v4_hir_task_return_record_id(hir_id, item_id) + if record_id < 0 { + give back V4_NO_SPAN + } + give back array_get(v4_hir_task_return_spans_handle(hir_id), record_id) +} + +task v4_hir_add_task_return(hir_id: int, item_id: int, form: word, type_text: word, type_span: word) -> int { + pilot record_id = v4_hir_task_return_record_count(hir_id) + array_push(v4_hir_task_return_items_handle(hir_id), word_from_int(item_id)) + array_push(v4_hir_task_return_forms_handle(hir_id), form) + array_push(v4_hir_task_return_types_handle(hir_id), type_text) + array_push(v4_hir_task_return_spans_handle(hir_id), type_span) + give back record_id +} + task v4_hir_first_token_at_or_after(stream_id: int, offset: int) -> int { pilot token_id = 0 pilot token_count = v4_lex_token_count(stream_id) @@ -704,6 +791,117 @@ task v4_hir_local_annotation_type_text(stream_id: int, start_token: int, end_tok give back out } +task v4_hir_task_param_open_token(stream_id: int, start_token: int, end_token: int) -> int { + pilot idx = start_token + pilot generic_depth = 0 + repeat until idx >= end_token { + if v4_lex_token_type(stream_id, idx) != v4_tok_trivia { + pilot value = v4_lex_token_value(stream_id, idx) + if value == "(" and generic_depth == 0 { + give back idx + } + if value == "<" { + generic_depth += 1 + } else if value == ">" and generic_depth > 0 { + generic_depth -= 1 + } + } + idx += 1 + } + give back 0 - 1 +} + +task v4_hir_task_param_close_token(stream_id: int, open_token: int, end_token: int) -> int { + if open_token < 0 { + give back 0 - 1 + } + pilot idx = open_token + pilot depth = 0 + repeat until idx >= end_token { + if v4_lex_token_type(stream_id, idx) != v4_tok_trivia { + pilot value = v4_lex_token_value(stream_id, idx) + if value == "(" { + depth += 1 + } else if value == ")" { + depth -= 1 + if depth == 0 { + give back idx + } + } + } + idx += 1 + } + give back 0 - 1 +} + +task v4_hir_task_return_type_end(stream_id: int, start_token: int, end_token: int) -> int { + pilot idx = start_token + pilot depth = 0 + repeat until idx >= end_token { + pilot token_type = v4_lex_token_type(stream_id, idx) + pilot value = v4_lex_token_value(stream_id, idx) + if token_type == v4_tok_trivia { + if value == "\n" and depth == 0 { + give back idx + } + } else { + if depth == 0 and (value == "{" or value == "=>") { + give back idx + } + if value == "(" or value == "[" or value == "<" { + depth += 1 + } else if value == ")" or value == "]" or value == ">" { + if depth > 0 { + depth -= 1 + } + } + } + idx += 1 + } + give back end_token +} + +task v4_hir_lower_task_return(hir_id: int, item_id: int) -> void { + if v4_hir_item_kind(hir_id, item_id) != v4_hir_task { + give back + } + pilot stream_id = v4_hir_item_stream_id(hir_id) + if stream_id < 0 { + give back + } + pilot item_span = v4_hir_item_span(hir_id, item_id) + pilot item_start = v4_hir_first_token_at_or_after(stream_id, v4_span_start(item_span)) + pilot item_end = v4_hir_first_token_at_or_after(stream_id, v4_span_end(item_span)) + pilot param_open = v4_hir_task_param_open_token(stream_id, item_start, item_end) + pilot param_close = v4_hir_task_param_close_token(stream_id, param_open, item_end) + if param_close < 0 { + pilot missing_params_record = v4_hir_add_task_return(hir_id, item_id, v4_hir_task_return_implicit_block, "", V4_NO_SPAN) + give back + } + pilot after_params = v4_hir_skip_trivia(stream_id, param_close + 1, item_end) + if after_params >= item_end { + pilot missing_body_record = v4_hir_add_task_return(hir_id, item_id, v4_hir_task_return_implicit_block, "", V4_NO_SPAN) + give back + } + + pilot marker = v4_lex_token_value(stream_id, after_params) + pilot no_span = V4_NO_SPAN + if marker == "->" { + pilot type_start = v4_hir_skip_trivia(stream_id, after_params + 1, item_end) + pilot type_end = v4_hir_task_return_type_end(stream_id, type_start, item_end) + pilot type_text = v4_hir_local_annotation_type_text(stream_id, type_start, type_end) + pilot type_span = v4_hir_span_from_tokens(stream_id, type_start, type_end) + if type_text != "" and type_span != no_span { + pilot explicit_record = v4_hir_add_task_return(hir_id, item_id, v4_hir_task_return_explicit, type_text, type_span) + give back + } + } else if marker == "=>" { + pilot arrow_record = v4_hir_add_task_return(hir_id, item_id, v4_hir_task_return_arrow, "", V4_NO_SPAN) + give back + } + pilot implicit_record = v4_hir_add_task_return(hir_id, item_id, v4_hir_task_return_implicit_block, "", V4_NO_SPAN) +} + task v4_hir_lower_local_annotations(hir_id: int, item_id: int) -> void { pilot item_kind = v4_hir_item_kind(hir_id, item_id) if item_kind != v4_hir_task and item_kind != v4_hir_impl and item_kind != v4_hir_doctrine { @@ -955,6 +1153,7 @@ task v4_hir_lower_expanded(file_id: int, expansion_id: int) -> int { pilot item_span = v4_expand_node_span(expansion_id, node_idx) pilot item_id = v4_hir_add_item(hir_id, hir_kind, item_name, item_span, node_idx) v4_hir_lower_alias_target_type(hir_id, item_id, expansion_id, node_idx) + v4_hir_lower_task_return(hir_id, item_id) v4_hir_lower_local_annotations(hir_id, item_id) } node_idx += 1 @@ -1050,6 +1249,17 @@ task v4_hir_snapshot_local_annotation_total() -> int { give back total } +task v4_hir_snapshot_task_return_total() -> int { + v4_hir_init() + pilot total = 0 + pilot hir_id = 0 + repeat until hir_id >= v4_hir_file_count() { + total += v4_hir_task_return_record_count(hir_id) + hir_id += 1 + } + give back total +} + task v4_hir_snapshot_diag_total() -> int { v4_hir_init() pilot total = 0 @@ -1068,6 +1278,7 @@ task v4_hir_snapshot_summary() -> word { summary = summary + " items=" + word_from_int(v4_hir_snapshot_item_total()) summary = summary + " alias-targets=" + word_from_int(v4_hir_snapshot_alias_target_total()) summary = summary + " local-annotations=" + word_from_int(v4_hir_snapshot_local_annotation_total()) + summary = summary + " task-returns=" + word_from_int(v4_hir_snapshot_task_return_total()) summary = summary + " diagnostics=" + word_from_int(v4_hir_snapshot_diag_total()) give back summary } @@ -1079,6 +1290,7 @@ task v4_hir_snapshot_header() -> word { out = out + "|items=" + word_from_int(v4_hir_snapshot_item_total()) out = out + "|alias-targets=" + word_from_int(v4_hir_snapshot_alias_target_total()) out = out + "|local-annotations=" + word_from_int(v4_hir_snapshot_local_annotation_total()) + out = out + "|task-returns=" + word_from_int(v4_hir_snapshot_task_return_total()) out = out + "|diagnostics=" + word_from_int(v4_hir_snapshot_diag_total()) give back out } @@ -1119,6 +1331,18 @@ task v4_hir_snapshot_local_annotation_line(hir_id: int, record_id: int) -> word give back out } +task v4_hir_snapshot_task_return_line(hir_id: int, record_id: int) -> word { + pilot out = "hir-task-return" + pilot item_id: word = array_get(v4_hir_task_return_items_handle(hir_id), record_id) + out = out + "|" + word_from_int(hir_id) + out = out + "|" + word_from_int(record_id) + out = out + "|" + item_id + out = out + "|" + v4_hir_snapshot_escape(array_get(v4_hir_task_return_forms_handle(hir_id), record_id)) + out = out + "|" + v4_hir_snapshot_escape(array_get(v4_hir_task_return_types_handle(hir_id), record_id)) + out = out + "|" + v4_hir_snapshot_escape(array_get(v4_hir_task_return_spans_handle(hir_id), record_id)) + give back out +} + task v4_hir_snapshot_diag_line(hir_id: int, diag_id: int) -> word { pilot out = "hir-diag" out = out + "|" + word_from_int(hir_id) @@ -1152,6 +1376,14 @@ task v4_hir_snapshot() -> word { local_annotation_id += 1 } + pilot task_return_id = 0 + pilot task_return_count = v4_hir_task_return_record_count(hir_id) + repeat until task_return_id >= task_return_count { + array_push(parts, "\n") + array_push(parts, v4_hir_snapshot_task_return_line(hir_id, task_return_id)) + task_return_id += 1 + } + pilot diag_id = 0 pilot diag_count = v4_hir_diag_count(hir_id) repeat until diag_id >= diag_count { @@ -1168,7 +1400,7 @@ task v4_hir_snapshot() -> word { task v4_hir_snapshot_record_expected_fields(kind: word) -> int { if kind == "hir-snapshot" { - give back 7 + give back 8 } if kind == "hir" { give back 6 @@ -1179,6 +1411,9 @@ task v4_hir_snapshot_record_expected_fields(kind: word) -> int { if kind == "hir-local-annotation" { give back 7 } + if kind == "hir-task-return" { + give back 7 + } if kind == "hir-diag" { give back 4 } @@ -1264,6 +1499,36 @@ task v4_hir_snapshot_local_annotation_is_valid(line: word) -> bool { give back v4_span_new(type_file, type_start, type_end) == type_span } +task v4_hir_snapshot_task_return_is_valid(line: word) -> bool { + if v4_hir_snapshot_nonnegative_int_is_valid(v4_hir_snapshot_field_raw(line, 1)) == false { + give back false + } + if v4_hir_snapshot_nonnegative_int_is_valid(v4_hir_snapshot_field_raw(line, 2)) == false { + give back false + } + if v4_hir_snapshot_nonnegative_int_is_valid(v4_hir_snapshot_field_raw(line, 3)) == false { + give back false + } + + pilot form = v4_hir_snapshot_field(line, 4) + pilot type_text = v4_hir_snapshot_field(line, 5) + pilot type_span = v4_hir_snapshot_field(line, 6) + pilot no_span = V4_NO_SPAN + if form == v4_hir_task_return_implicit_block or form == v4_hir_task_return_arrow { + give back type_text == "" and type_span == no_span + } + if form != v4_hir_task_return_explicit or type_text == "" or type_span == no_span { + give back false + } + pilot span_file = v4_span_file(type_span) + pilot span_start = v4_span_start(type_span) + pilot span_end = v4_span_end(type_span) + if span_file == V4_NO_FILE or span_end <= span_start { + give back false + } + give back v4_span_new(span_file, span_start, span_end) == type_span +} + task v4_hir_snapshot_file_for_hir(payload: word, wanted_hir_id: word) -> word { pilot found_file = V4_NO_FILE pilot matches = 0 @@ -1340,6 +1605,43 @@ task v4_hir_snapshot_local_annotation_owner_is_valid(payload: word, line: word) give back matches == 1 } +task v4_hir_snapshot_task_return_owner_is_valid(payload: word, line: word) -> bool { + pilot wanted_hir_id = v4_hir_snapshot_field_raw(line, 1) + pilot wanted_item_id = v4_hir_snapshot_field_raw(line, 3) + pilot snapshot_file = v4_hir_snapshot_file_for_hir(payload, wanted_hir_id) + pilot no_file = V4_NO_FILE + if snapshot_file == no_file { + give back false + } + + pilot matches = 0 + pilot line_id = 0 + pilot line_count = v4_hir_snapshot_line_count(payload) + repeat until line_id >= line_count { + pilot candidate = v4_hir_snapshot_line(payload, line_id) + if v4_hir_snapshot_field_raw(candidate, 0) == "hir-item" and v4_hir_snapshot_field_raw(candidate, 1) == wanted_hir_id and v4_hir_snapshot_field_raw(candidate, 2) == wanted_item_id { + if v4_hir_snapshot_field(candidate, 3) != v4_hir_task { + give back false + } + pilot item_span = v4_hir_snapshot_field(candidate, 6) + pilot item_start = v4_span_start(item_span) + pilot item_end = v4_span_end(item_span) + if item_span == V4_NO_SPAN or v4_span_file(item_span) != snapshot_file or item_end <= item_start or v4_span_new(snapshot_file, item_start, item_end) != item_span { + give back false + } + if v4_hir_snapshot_field(line, 4) == v4_hir_task_return_explicit { + pilot type_span = v4_hir_snapshot_field(line, 6) + if v4_span_file(type_span) != snapshot_file or v4_span_start(type_span) < item_start or v4_span_end(type_span) > item_end { + give back false + } + } + matches += 1 + } + line_id += 1 + } + give back matches == 1 +} + task v4_hir_snapshot_local_annotation_slots_are_valid(payload: word, hir_line: word) -> bool { pilot wanted_hir_id = v4_hir_snapshot_field_raw(hir_line, 1) pilot declared_items = word_to_int(v4_hir_snapshot_field_raw(hir_line, 4)) @@ -1377,6 +1679,66 @@ task v4_hir_snapshot_local_annotation_slots_are_valid(payload: word, hir_line: w give back true } +task v4_hir_snapshot_task_return_slots_are_valid(payload: word, hir_line: word) -> bool { + pilot wanted_hir_id = v4_hir_snapshot_field_raw(hir_line, 1) + pilot declared_items = word_to_int(v4_hir_snapshot_field_raw(hir_line, 4)) + pilot return_count = 0 + pilot line_id = 0 + pilot line_count = v4_hir_snapshot_line_count(payload) + repeat until line_id >= line_count { + pilot line = v4_hir_snapshot_line(payload, line_id) + if v4_hir_snapshot_field_raw(line, 0) == "hir-task-return" and v4_hir_snapshot_field_raw(line, 1) == wanted_hir_id { + return_count += 1 + } + line_id += 1 + } + + pilot expected_record = 0 + repeat until expected_record >= return_count { + pilot occurrences = 0 + line_id = 0 + repeat until line_id >= line_count { + pilot line = v4_hir_snapshot_line(payload, line_id) + if v4_hir_snapshot_field_raw(line, 0) == "hir-task-return" and v4_hir_snapshot_field_raw(line, 1) == wanted_hir_id and v4_hir_snapshot_field_raw(line, 2) == word_from_int(expected_record) { + pilot item_id = word_to_int(v4_hir_snapshot_field_raw(line, 3)) + if item_id < 0 or item_id >= declared_items { + give back false + } + occurrences += 1 + } + line_id += 1 + } + if occurrences != 1 { + give back false + } + expected_record += 1 + } + + pilot item_id = 0 + repeat until item_id >= declared_items { + pilot item_kind = "" + pilot owner_records = 0 + line_id = 0 + repeat until line_id >= line_count { + pilot line = v4_hir_snapshot_line(payload, line_id) + if v4_hir_snapshot_field_raw(line, 0) == "hir-item" and v4_hir_snapshot_field_raw(line, 1) == wanted_hir_id and v4_hir_snapshot_field_raw(line, 2) == word_from_int(item_id) { + item_kind = v4_hir_snapshot_field(line, 3) + } else if v4_hir_snapshot_field_raw(line, 0) == "hir-task-return" and v4_hir_snapshot_field_raw(line, 1) == wanted_hir_id and v4_hir_snapshot_field_raw(line, 3) == word_from_int(item_id) { + owner_records += 1 + } + line_id += 1 + } + if item_kind == v4_hir_task and owner_records != 1 { + give back false + } + if item_kind != v4_hir_task and owner_records != 0 { + give back false + } + item_id += 1 + } + give back true +} + task v4_hir_snapshot_child_slots_are_valid(payload: word, hir_line: word) -> bool { pilot wanted_hir_id = v4_hir_snapshot_field_raw(hir_line, 1) pilot declared_items_word = v4_hir_snapshot_field_raw(hir_line, 4) @@ -1480,6 +1842,9 @@ task v4_hir_snapshot_record_is_valid(line: word) -> bool { if kind == "hir-local-annotation" and v4_hir_snapshot_local_annotation_is_valid(line) == false { give back false } + if kind == "hir-task-return" and v4_hir_snapshot_task_return_is_valid(line) == false { + give back false + } give back true } @@ -1489,6 +1854,7 @@ task v4_hir_snapshot_validate(payload: word) -> word { pilot items = 0 pilot alias_targets = 0 pilot local_annotations = 0 + pilot task_returns = 0 pilot diagnostics = 0 pilot malformed = 0 pilot saw_header = 0 @@ -1498,6 +1864,7 @@ task v4_hir_snapshot_validate(payload: word) -> word { pilot declared_items = "" pilot declared_alias_targets = "" pilot declared_local_annotations = "" + pilot declared_task_returns = "" pilot declared_diagnostics = "" pilot no_file = V4_NO_FILE @@ -1515,6 +1882,7 @@ task v4_hir_snapshot_validate(payload: word) -> word { declared_items = v4_hir_snapshot_key_value(line, "items") declared_alias_targets = v4_hir_snapshot_key_value(line, "alias-targets") declared_local_annotations = v4_hir_snapshot_key_value(line, "local-annotations") + declared_task_returns = v4_hir_snapshot_key_value(line, "task-returns") declared_diagnostics = v4_hir_snapshot_key_value(line, "diagnostics") if format != v4_hir_snapshot_format { malformed += 1 @@ -1527,6 +1895,9 @@ task v4_hir_snapshot_validate(payload: word) -> word { if v4_hir_snapshot_local_annotation_slots_are_valid(payload, line) == false { malformed += 1 } + if v4_hir_snapshot_task_return_slots_are_valid(payload, line) == false { + malformed += 1 + } } else if kind == "hir-item" { items += 1 if v4_hir_snapshot_file_for_hir(payload, v4_hir_snapshot_field_raw(line, 1)) == no_file { @@ -1543,6 +1914,11 @@ task v4_hir_snapshot_validate(payload: word) -> word { if v4_hir_snapshot_local_annotation_owner_is_valid(payload, line) == false { malformed += 1 } + } else if kind == "hir-task-return" { + task_returns += 1 + if v4_hir_snapshot_task_return_owner_is_valid(payload, line) == false { + malformed += 1 + } } else if kind == "hir-diag" { diagnostics += 1 if v4_hir_snapshot_file_for_hir(payload, v4_hir_snapshot_field_raw(line, 1)) == no_file { @@ -1577,6 +1953,9 @@ task v4_hir_snapshot_validate(payload: word) -> word { if declared_local_annotations != word_from_int(local_annotations) { import_ok = 0 } + if declared_task_returns != word_from_int(task_returns) { + import_ok = 0 + } if v4_hir_snapshot_hir_slots_are_valid(payload, files) == false { import_ok = 0 } @@ -1591,6 +1970,8 @@ task v4_hir_snapshot_validate(payload: word) -> word { out = out + " declared-alias-targets=" + declared_alias_targets out = out + " local-annotations=" + word_from_int(local_annotations) out = out + " declared-local-annotations=" + declared_local_annotations + out = out + " task-returns=" + word_from_int(task_returns) + out = out + " declared-task-returns=" + declared_task_returns out = out + " diagnostics=" + word_from_int(diagnostics) out = out + " malformed=" + word_from_int(malformed) out = out + " headers=" + word_from_int(saw_header) @@ -1614,6 +1995,10 @@ task v4_hir_restore_file_slot(hir_id: int, file_id: int, expansion_id: int) -> i array_push(v4_hir_local_annotation_stmt_spans, word_from_int(array_new())) array_push(v4_hir_local_annotation_types, word_from_int(array_new())) array_push(v4_hir_local_annotation_type_spans, word_from_int(array_new())) + array_push(v4_hir_task_return_items, word_from_int(array_new())) + array_push(v4_hir_task_return_forms, word_from_int(array_new())) + array_push(v4_hir_task_return_types, word_from_int(array_new())) + array_push(v4_hir_task_return_spans, word_from_int(array_new())) array_push(v4_hir_diags, word_from_int(array_new())) } @@ -1630,6 +2015,10 @@ task v4_hir_restore_file_slot(hir_id: int, file_id: int, expansion_id: int) -> i array_set(v4_hir_local_annotation_stmt_spans, hir_id, word_from_int(array_new())) array_set(v4_hir_local_annotation_types, hir_id, word_from_int(array_new())) array_set(v4_hir_local_annotation_type_spans, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_items, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_forms, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_types, hir_id, word_from_int(array_new())) + array_set(v4_hir_task_return_spans, hir_id, word_from_int(array_new())) array_set(v4_hir_diags, hir_id, word_from_int(array_new())) if hir_id >= v4_hir_file_len { v4_hir_file_len = hir_id + 1 @@ -1737,6 +2126,39 @@ task v4_hir_snapshot_restore_local_annotation_line(line: word) -> int { give back v4_hir_restore_local_annotation_slot(hir_id, record_id, item_id, stmt_span, type_text, type_span) } +task v4_hir_restore_task_return_slot(hir_id: int, record_id: int, item_id: int, form: word, type_text: word, type_span: word) -> int { + if v4_hir_file_exists(hir_id) == false { + give back 0 + } + repeat until v4_hir_task_return_record_count(hir_id) > record_id { + array_push(v4_hir_task_return_items_handle(hir_id), word_from_int(0 - 1)) + array_push(v4_hir_task_return_forms_handle(hir_id), "") + array_push(v4_hir_task_return_types_handle(hir_id), "") + array_push(v4_hir_task_return_spans_handle(hir_id), V4_NO_SPAN) + } + array_set(v4_hir_task_return_items_handle(hir_id), record_id, word_from_int(item_id)) + array_set(v4_hir_task_return_forms_handle(hir_id), record_id, form) + array_set(v4_hir_task_return_types_handle(hir_id), record_id, type_text) + array_set(v4_hir_task_return_spans_handle(hir_id), record_id, type_span) + give back 1 +} + +task v4_hir_snapshot_restore_task_return_line(line: word) -> int { + if v4_hir_snapshot_record_is_valid(line) == false { + give back 0 + } + if v4_hir_snapshot_field_raw(line, 0) != "hir-task-return" { + give back 0 + } + pilot hir_id = word_to_int(v4_hir_snapshot_field_raw(line, 1)) + pilot record_id = word_to_int(v4_hir_snapshot_field_raw(line, 2)) + pilot item_id = word_to_int(v4_hir_snapshot_field_raw(line, 3)) + pilot form = v4_hir_snapshot_field(line, 4) + pilot type_text = v4_hir_snapshot_field(line, 5) + pilot type_span = v4_hir_snapshot_field(line, 6) + give back v4_hir_restore_task_return_slot(hir_id, record_id, item_id, form, type_text, type_span) +} + task v4_hir_snapshot_restore_diag_line(line: word) -> int { if v4_hir_snapshot_record_is_valid(line) == false { give back 0 @@ -1764,6 +2186,7 @@ task v4_hir_snapshot_restore(payload: word) -> word { pilot restored_files = 0 pilot restored_items = 0 pilot restored_local_annotations = 0 + pilot restored_task_returns = 0 pilot restored_diagnostics = 0 pilot skipped_other = 0 v4_hir_begin_snapshot_restore() @@ -1776,7 +2199,7 @@ task v4_hir_snapshot_restore(payload: word) -> word { pilot kind = v4_hir_snapshot_field_raw(line, 0) if kind == "hir" { restored_files += v4_hir_snapshot_restore_file_line(line) - } else if kind != "hir-item" and kind != "hir-local-annotation" and kind != "hir-diag" and kind != "hir-snapshot" and kind != "end" { + } else if kind != "hir-item" and kind != "hir-local-annotation" and kind != "hir-task-return" and kind != "hir-diag" and kind != "hir-snapshot" and kind != "end" { skipped_other += 1 } } @@ -1792,6 +2215,8 @@ task v4_hir_snapshot_restore(payload: word) -> word { restored_items += v4_hir_snapshot_restore_item_line(line) } else if kind == "hir-local-annotation" { restored_local_annotations += v4_hir_snapshot_restore_local_annotation_line(line) + } else if kind == "hir-task-return" { + restored_task_returns += v4_hir_snapshot_restore_task_return_line(line) } else if kind == "hir-diag" { restored_diagnostics += v4_hir_snapshot_restore_diag_line(line) } @@ -1803,6 +2228,7 @@ task v4_hir_snapshot_restore(payload: word) -> word { out = out + " files=" + word_from_int(restored_files) out = out + " items=" + word_from_int(restored_items) out = out + " local-annotations=" + word_from_int(restored_local_annotations) + out = out + " task-returns=" + word_from_int(restored_task_returns) out = out + " diagnostics=" + word_from_int(restored_diagnostics) out = out + " skipped-other=" + word_from_int(skipped_other) out = out + " live-files=" + word_from_int(v4_hir_file_count()) diff --git a/src/compiler/v4/crates/freak_ty/src/lib.fk b/src/compiler/v4/crates/freak_ty/src/lib.fk index 7fe23e0..479abae 100644 --- a/src/compiler/v4/crates/freak_ty/src/lib.fk +++ b/src/compiler/v4/crates/freak_ty/src/lib.fk @@ -5436,23 +5436,95 @@ task v4_ty_task_return_span_from_tokens(stream_id: int, start_token: int, end_to give back V4_NO_SPAN } -task v4_ty_signature_return_span(ty_id: int, sig_id: int) -> word { +task v4_ty_signature_is_ordinary_hir_task(ty_id: int, sig_id: int) -> bool { + if sig_id < 0 or sig_id >= v4_ty_signature_count(ty_id) or v4_ty_signature_kind(ty_id, sig_id) != v4_ty_task_sig or v4_ty_signature_extern_member_id(ty_id, sig_id) >= 0 { + give back false + } + pilot hir_id = v4_ty_signature_hir_id(ty_id) + pilot hir_item = v4_ty_signature_hir_item(ty_id, sig_id) + if hir_id < 0 or hir_item < 0 or hir_item >= v4_hir_item_count(hir_id) { + give back false + } + give back v4_hir_item_kind(hir_id, hir_item) == v4_hir_task +} + +task v4_ty_ordinary_task_explicit_return_from_hir(hir_id: int, hir_item: int) -> word { + if hir_id < 0 or hir_item < 0 or v4_hir_task_return_form(hir_id, hir_item) != v4_hir_task_return_explicit { + give back v4_ty_unknown + } + pilot return_ty = v4_hir_task_return_type(hir_id, hir_item) + if return_ty == "" { + give back v4_ty_unknown + } + give back return_ty +} + +task v4_ty_ordinary_task_explicit_return_span_from_hir(hir_id: int, hir_item: int) -> word { + if hir_id < 0 or hir_item < 0 or v4_hir_task_return_form(hir_id, hir_item) != v4_hir_task_return_explicit { + give back V4_NO_SPAN + } + give back v4_hir_task_return_span(hir_id, hir_item) +} + +task v4_ty_ordinary_task_arrow_return_fallback(hir_id: int, hir_item: int) -> word { + pilot stream_id = v4_hir_item_stream_id(hir_id) + pilot start_token = v4_ty_hir_item_start_token(hir_id, hir_item) + pilot end_token = v4_ty_hir_item_end_token(hir_id, hir_item) + pilot fat_arrow = v4_ty_find_token_value(stream_id, start_token, end_token, "=>") + if fat_arrow < 0 { + give back v4_ty_unknown + } + give back v4_ty_infer_arrow_expr_return(stream_id, fat_arrow + 1, end_token) +} + +task v4_ty_nonordinary_signature_return_fallback(ty_id: int, sig_id: int) -> word { + pilot stream_id = v4_ty_signature_stream_id(ty_id) + pilot start_token = v4_ty_signature_item_start_token(ty_id, sig_id) + pilot end_token = v4_ty_signature_item_end_token(ty_id, sig_id) + if stream_id < 0 or start_token < 0 or end_token <= start_token { + give back v4_ty_unknown + } + give back v4_ty_task_return_from_tokens(stream_id, start_token, end_token) +} + +task v4_ty_nonordinary_signature_return_span_fallback(ty_id: int, sig_id: int) -> word { pilot stream_id = v4_ty_signature_stream_id(ty_id) pilot start_token = v4_ty_signature_item_start_token(ty_id, sig_id) pilot end_token = v4_ty_signature_item_end_token(ty_id, sig_id) give back v4_ty_task_return_span_from_tokens(stream_id, start_token, end_token) } +task v4_ty_nonordinary_hir_item_return_fallback(hir_id: int, hir_item: int) -> word { + pilot stream_id = v4_hir_item_stream_id(hir_id) + pilot start_token = v4_ty_hir_item_start_token(hir_id, hir_item) + pilot end_token = v4_ty_hir_item_end_token(hir_id, hir_item) + give back v4_ty_task_return_from_tokens(stream_id, start_token, end_token) +} + +task v4_ty_signature_return_span(ty_id: int, sig_id: int) -> word { + if v4_ty_signature_is_ordinary_hir_task(ty_id, sig_id) { + give back v4_ty_ordinary_task_explicit_return_span_from_hir(v4_ty_signature_hir_id(ty_id), v4_ty_signature_hir_item(ty_id, sig_id)) + } + give back v4_ty_nonordinary_signature_return_span_fallback(ty_id, sig_id) +} + task v4_ty_task_return_from_hir(hir_id: int, hir_item: int) -> word { if hir_item < 0 { give back v4_ty_unknown } - - pilot tree_id = v4_hir_tree_id(hir_id) - pilot stream_id = v4_parse_stream_id(tree_id) - pilot start_token = v4_ty_hir_item_start_token(hir_id, hir_item) - pilot end_token = v4_ty_hir_item_end_token(hir_id, hir_item) - give back v4_ty_task_return_from_tokens(stream_id, start_token, end_token) + pilot form = v4_hir_task_return_form(hir_id, hir_item) + if form == v4_hir_task_return_explicit { + give back v4_ty_ordinary_task_explicit_return_from_hir(hir_id, hir_item) + } + if form == v4_hir_task_return_arrow { + give back v4_ty_ordinary_task_arrow_return_fallback(hir_id, hir_item) + } + if form == "" { + give back v4_ty_nonordinary_hir_item_return_fallback(hir_id, hir_item) + } + -- Implicit block tasks have no declared return fact. TY keeps its current + -- conservative unknown fallback until block return inference owns it. + give back v4_ty_unknown } task v4_ty_const_signature_id_for_name(ty_id: int, const_name: word) -> int { @@ -9305,13 +9377,10 @@ task v4_ty_signature_borrowed_return_source_param(ty_id: int, sig_id: int) -> in } task v4_ty_signature_return_surface_type(ty_id: int, sig_id: int) -> word { - pilot stream_id = v4_ty_signature_stream_id(ty_id) - pilot start_token = v4_ty_signature_item_start_token(ty_id, sig_id) - pilot end_token = v4_ty_signature_item_end_token(ty_id, sig_id) - if stream_id < 0 or start_token < 0 or end_token <= start_token { - give back v4_ty_unknown + if v4_ty_signature_is_ordinary_hir_task(ty_id, sig_id) { + give back v4_ty_task_return_from_hir(v4_ty_signature_hir_id(ty_id), v4_ty_signature_hir_item(ty_id, sig_id)) } - give back v4_ty_task_return_from_tokens(stream_id, start_token, end_token) + give back v4_ty_nonordinary_signature_return_fallback(ty_id, sig_id) } task v4_ty_shape_signature_id_for_name(ty_id: int, shape_name: word) -> int { diff --git a/src/compiler/v4/tests/task_return_semantic_boundary_smoke.fk b/src/compiler/v4/tests/task_return_semantic_boundary_smoke.fk new file mode 100644 index 0000000..95b1227 --- /dev/null +++ b/src/compiler/v4/tests/task_return_semantic_boundary_smoke.fk @@ -0,0 +1,242 @@ +-- V4 ordinary-task declared-return HIR ownership smoke fixture. +-- Verification prepends the V4 crates before this file. + +task v4_task_return_bool(value: bool) -> word { + if value { give back "true" } + give back "false" +} + +task v4_task_return_braces(inner: word) -> word { + give back "{" + inner + "}" +} + +task v4_task_return_find_symbol(doc_id: int, name: word) -> int { + pilot symbol_id = 0 + repeat until symbol_id >= v4_document_symbol_count(doc_id) { + if v4_document_symbol_name(doc_id, symbol_id) == name { + give back symbol_id + } + symbol_id += 1 + } + give back 0 - 1 +} + +task v4_task_return_symbol_display(path: word, source: word, name: word) -> word { + pilot symbols = v4_document_symbols_text_cached(path, source) + pilot symbol_id = v4_task_return_find_symbol(symbols, name) + give back v4_document_symbol_type(symbols, symbol_id) +} + +task v4_task_return_invalidation_positive(report: word, key: word) -> bool { + give back word_to_int(v4_unit_snapshot_key_value(report, key)) > 0 +} + +task v4_task_return_invalidation_probe() -> void { + pilot path = "task-return-invalidation.fk" + pilot prefix = "task changed() -> " + pilot suffix = " " + v4_task_return_braces(" give back 7 ") + "\n" + pilot before = prefix + "int" + suffix + pilot after = prefix + "num" + suffix + say "task-return-invalidation-edit-isolated=" + v4_task_return_bool(before == prefix + "int" + suffix and after == prefix + "num" + suffix and before.length() == after.length()) + + v4_lsp_open_document(path, before) + pilot before_hir = v4_hir_text_cached(path, before) + pilot before_ty = v4_ty_text_cached(path, before) + pilot before_mir = v4_mir_text_cached(path, before) + pilot before_borrow = v4_borrowck_text_cached(path, before) + pilot before_symbols = v4_document_symbols_text_cached(path, before) + pilot before_resolve = v4_ty_resolve_id(before_ty) + pilot before_def = v4_resolve_def_for_name(before_resolve, "changed") + pilot before_sig = v4_ty_lookup_signature(before_ty, before_def) + pilot before_body = v4_mir_lookup_body(before_mir, before_def) + pilot before_result = v4_borrowck_lookup_result(before_borrow, before_def) + pilot before_symbol = v4_task_return_find_symbol(before_symbols, "changed") + say "task-return-before-ty=" + v4_ty_signature_return_type(before_ty, before_sig) + say "task-return-before-mir=" + v4_mir_expected_return_type(before_mir, before_body) + say "task-return-before-borrow=" + v4_borrowck_result_status(before_borrow, before_result) + say "task-return-before-editor=" + v4_document_symbol_type(before_symbols, before_symbol) + + pilot change = v4_lsp_handle_text_request("textDocument/didChange", path, after, 0) + pilot report = v4_unit_snapshot_line(change, 2) + say "task-return-invalidation-hir=" + v4_task_return_bool(v4_task_return_invalidation_positive(report, "hir-invalidations-added")) + say "task-return-invalidation-ty=" + v4_task_return_bool(v4_task_return_invalidation_positive(report, "ty-invalidations-added")) + say "task-return-invalidation-mir=" + v4_task_return_bool(v4_task_return_invalidation_positive(report, "mir-invalidations-added")) + say "task-return-invalidation-borrowck=" + v4_task_return_bool(v4_task_return_invalidation_positive(report, "borrowck-invalidations-added")) + say "task-return-invalidation-editor=" + v4_task_return_bool(v4_task_return_invalidation_positive(report, "editor-invalidations-added")) + + pilot after_hir = v4_hir_text_cached(path, after) + pilot after_ty = v4_ty_text_cached(path, after) + pilot after_mir = v4_mir_text_cached(path, after) + pilot after_borrow = v4_borrowck_text_cached(path, after) + pilot after_symbols = v4_document_symbols_text_cached(path, after) + pilot after_resolve = v4_ty_resolve_id(after_ty) + pilot after_def = v4_resolve_def_for_name(after_resolve, "changed") + pilot after_sig = v4_ty_lookup_signature(after_ty, after_def) + pilot after_body = v4_mir_lookup_body(after_mir, after_def) + pilot after_result = v4_borrowck_lookup_result(after_borrow, after_def) + pilot after_symbol = v4_task_return_find_symbol(after_symbols, "changed") + say "task-return-after-ty=" + v4_ty_signature_return_type(after_ty, after_sig) + say "task-return-after-mir=" + v4_mir_expected_return_type(after_mir, after_body) + say "task-return-after-borrow=" + v4_borrowck_result_status(after_borrow, after_result) + say "task-return-after-editor=" + v4_document_symbol_type(after_symbols, after_symbol) +} + +task v4_task_return_source_text() -> word { + pilot src = "task keep<'a>(lend 'a value: maybe<[word;2]>) -> lend 'a maybe< [word; 2] > " + src = src + v4_task_return_braces("\n give back lend value\n") + "\n" + src = src + "task implicit() " + v4_task_return_braces(" give back 7 ") + "\n" + src = src + "task arrow() => true\n" + give back src +} + +task v4_task_return_snapshot_variant(payload: word, mode: word) -> word { + pilot wanted_hir = "" + pilot wanted_item = "" + pilot search_id = 0 + pilot search_count = v4_hir_snapshot_line_count(payload) + repeat until search_id >= search_count { + pilot candidate = v4_hir_snapshot_line(payload, search_id) + if wanted_hir == "" and v4_hir_snapshot_field_raw(candidate, 0) == "hir-task-return" { + wanted_hir = v4_hir_snapshot_field_raw(candidate, 1) + wanted_item = v4_hir_snapshot_field_raw(candidate, 3) + } + search_id += 1 + } + + pilot out = "" + pilot changed = 0 + pilot line_id = 0 + pilot line_count = v4_hir_snapshot_line_count(payload) + repeat until line_id >= line_count { + pilot line = v4_hir_snapshot_line(payload, line_id) + pilot kind = v4_hir_snapshot_field_raw(line, 0) + if kind == "hir-snapshot" and mode == "count" { + line = "hir-snapshot|format=" + v4_hir_snapshot_key_value(line, "format") + line = line + "|files=" + v4_hir_snapshot_key_value(v4_hir_snapshot_line(payload, line_id), "files") + line = line + "|items=" + v4_hir_snapshot_key_value(v4_hir_snapshot_line(payload, line_id), "items") + line = line + "|alias-targets=" + v4_hir_snapshot_key_value(v4_hir_snapshot_line(payload, line_id), "alias-targets") + line = line + "|local-annotations=" + v4_hir_snapshot_key_value(v4_hir_snapshot_line(payload, line_id), "local-annotations") + line = line + "|task-returns=" + word_from_int(word_to_int(v4_hir_snapshot_key_value(v4_hir_snapshot_line(payload, line_id), "task-returns")) + 1) + line = line + "|diagnostics=" + v4_hir_snapshot_key_value(v4_hir_snapshot_line(payload, line_id), "diagnostics") + } else if kind == "hir-item" and mode == "owner-kind" and changed == 0 and v4_hir_snapshot_field_raw(line, 1) == wanted_hir and v4_hir_snapshot_field_raw(line, 2) == wanted_item { + pilot rebuilt_item = "hir-item" + pilot item_field_id = 1 + repeat until item_field_id >= 10 { + if item_field_id == 3 { + rebuilt_item = rebuilt_item + "|" + v4_hir_snapshot_escape(v4_hir_shape) + } else { + rebuilt_item = rebuilt_item + "|" + v4_hir_snapshot_field_raw(line, item_field_id) + } + item_field_id += 1 + } + line = rebuilt_item + changed = 1 + } else if kind == "hir-task-return" and changed == 0 and mode != "count" { + pilot rebuilt = "hir-task-return" + pilot field_id = 1 + repeat until field_id >= 7 { + if field_id == 2 and mode == "slot" { + rebuilt = rebuilt + "|1" + } else if field_id == 4 and mode == "form" { + rebuilt = rebuilt + "|invented" + } else if field_id == 5 and mode == "type" { + rebuilt = rebuilt + "|" + } else if field_id == 6 and mode == "span" { + rebuilt = rebuilt + "|" + v4_hir_snapshot_escape(V4_NO_SPAN) + } else { + rebuilt = rebuilt + "|" + v4_hir_snapshot_field_raw(line, field_id) + } + field_id += 1 + } + line = rebuilt + changed = 1 + } + if line_id > 0 { + out = out + "\n" + } + out = out + line + line_id += 1 + } + give back out +} + +pilot v4_task_return_source = v4_task_return_source_text() +pilot v4_task_return_stream = v4_lex_text(0, v4_task_return_source) +pilot v4_task_return_tree = v4_parse_stream(0, v4_task_return_stream) +pilot v4_task_return_hir = v4_hir_lower_tree(0, v4_task_return_tree) +pilot v4_task_return_resolve = v4_resolve_lower_hir(0, v4_task_return_hir) +pilot v4_task_return_ty = v4_ty_lower_resolve(0, v4_task_return_resolve) +pilot v4_task_return_mir = v4_mir_lower_ty(0, v4_task_return_ty) +pilot v4_task_return_borrow = v4_borrowck_check_mir(0, v4_task_return_mir) + +pilot v4_task_return_keep_def = v4_resolve_def_for_name(v4_task_return_resolve, "keep") +pilot v4_task_return_implicit_def = v4_resolve_def_for_name(v4_task_return_resolve, "implicit") +pilot v4_task_return_arrow_def = v4_resolve_def_for_name(v4_task_return_resolve, "arrow") +pilot v4_task_return_keep_sig = v4_ty_lookup_signature(v4_task_return_ty, v4_task_return_keep_def) +pilot v4_task_return_implicit_sig = v4_ty_lookup_signature(v4_task_return_ty, v4_task_return_implicit_def) +pilot v4_task_return_arrow_sig = v4_ty_lookup_signature(v4_task_return_ty, v4_task_return_arrow_def) +pilot v4_task_return_keep_item = v4_ty_signature_hir_item(v4_task_return_ty, v4_task_return_keep_sig) +pilot v4_task_return_implicit_item = v4_ty_signature_hir_item(v4_task_return_ty, v4_task_return_implicit_sig) +pilot v4_task_return_arrow_item = v4_ty_signature_hir_item(v4_task_return_ty, v4_task_return_arrow_sig) +pilot v4_task_return_keep_span = v4_hir_task_return_span(v4_task_return_hir, v4_task_return_keep_item) +pilot v4_task_return_keep_body = v4_mir_lookup_body(v4_task_return_mir, v4_task_return_keep_def) +pilot v4_task_return_keep_result = v4_borrowck_lookup_result(v4_task_return_borrow, v4_task_return_keep_def) + +say "task-return-parse-diagnostics=" + word_from_int(v4_parse_diag_count(v4_task_return_tree)) +say "task-return-hir-records=" + word_from_int(v4_hir_task_return_record_count(v4_task_return_hir)) +say "task-return-explicit-form=" + v4_hir_task_return_form(v4_task_return_hir, v4_task_return_keep_item) +say "task-return-explicit-surface=" + v4_hir_task_return_type(v4_task_return_hir, v4_task_return_keep_item) +say "task-return-explicit-source=" + v4_slice(v4_task_return_source, v4_span_start(v4_task_return_keep_span), v4_span_end(v4_task_return_keep_span)) +say "task-return-explicit-span-contained=" + v4_task_return_bool(v4_span_start(v4_task_return_keep_span) >= v4_span_start(v4_hir_item_span(v4_task_return_hir, v4_task_return_keep_item)) and v4_span_end(v4_task_return_keep_span) <= v4_span_end(v4_hir_item_span(v4_task_return_hir, v4_task_return_keep_item))) +say "task-return-implicit-form=" + v4_hir_task_return_form(v4_task_return_hir, v4_task_return_implicit_item) +say "task-return-implicit-surface=" + v4_hir_task_return_type(v4_task_return_hir, v4_task_return_implicit_item) +say "task-return-implicit-type=" + v4_ty_signature_return_type(v4_task_return_ty, v4_task_return_implicit_sig) +say "task-return-implicit-span-empty=" + v4_task_return_bool(v4_hir_task_return_span(v4_task_return_hir, v4_task_return_implicit_item) == V4_NO_SPAN) +say "task-return-arrow-form=" + v4_hir_task_return_form(v4_task_return_hir, v4_task_return_arrow_item) +say "task-return-arrow-type=" + v4_ty_signature_return_type(v4_task_return_ty, v4_task_return_arrow_sig) +say "task-return-arrow-display=" + v4_ty_signature_of(v4_task_return_ty, v4_task_return_arrow_def) +say "task-return-arrow-span-empty=" + v4_task_return_bool(v4_hir_task_return_span(v4_task_return_hir, v4_task_return_arrow_item) == V4_NO_SPAN) +say "task-return-ty-surface=" + v4_ty_signature_return_surface_type(v4_task_return_ty, v4_task_return_keep_sig) +say "task-return-ty-canonical=" + v4_ty_signature_return_type(v4_task_return_ty, v4_task_return_keep_sig) +say "task-return-ty-display=" + v4_ty_signature_of(v4_task_return_ty, v4_task_return_keep_def) +say "task-return-mir-expected=" + v4_mir_expected_return_type(v4_task_return_mir, v4_task_return_keep_body) +say "task-return-mir-diagnostics=" + word_from_int(v4_mir_diag_count(v4_task_return_mir)) +say "task-return-borrow-status=" + v4_borrowck_result_status(v4_task_return_borrow, v4_task_return_keep_result) +say v4_ty_snapshot_summary() + +pilot v4_task_return_snapshot = v4_hir_snapshot() +say v4_hir_snapshot_summary() +say v4_hir_snapshot_restore(v4_task_return_snapshot) +say "task-return-restored-form=" + v4_hir_task_return_form(v4_task_return_hir, v4_task_return_keep_item) +say "task-return-restored-surface=" + v4_hir_task_return_type(v4_task_return_hir, v4_task_return_keep_item) + +pilot v4_task_return_before_bad_files = v4_hir_file_count() +pilot v4_task_return_before_bad_records = v4_hir_task_return_record_count(v4_task_return_hir) +pilot v4_task_return_schema_rejected = true +pilot v4_task_return_schema_atomic = true +pilot v4_task_return_modes = array_new() +array_push(v4_task_return_modes, "form") +array_push(v4_task_return_modes, "type") +array_push(v4_task_return_modes, "span") +array_push(v4_task_return_modes, "count") +array_push(v4_task_return_modes, "slot") +array_push(v4_task_return_modes, "owner-kind") +pilot v4_task_return_mode_id = 0 +repeat until v4_task_return_mode_id >= array_len(v4_task_return_modes) { + pilot v4_task_return_mode: word = array_get(v4_task_return_modes, v4_task_return_mode_id) + pilot v4_task_return_variant = v4_task_return_snapshot_variant(v4_task_return_snapshot, v4_task_return_mode) + pilot v4_task_return_validation = v4_hir_snapshot_validate(v4_task_return_variant) + pilot v4_task_return_restore = v4_hir_snapshot_restore(v4_task_return_variant) + if v4_task_return_validation.starts_with("hir-snapshot-import ok=0") == false or v4_task_return_restore.starts_with("hir-snapshot-restore ok=0 reason=validation-failed") == false { + v4_task_return_schema_rejected = false + } + if v4_hir_file_count() != v4_task_return_before_bad_files or v4_hir_task_return_record_count(v4_task_return_hir) != v4_task_return_before_bad_records or v4_hir_task_return_type(v4_task_return_hir, v4_task_return_keep_item) != "lend 'a maybe<[word;2]>" { + v4_task_return_schema_atomic = false + } + v4_task_return_mode_id += 1 +} +say "task-return-schema-variants-rejected=" + v4_task_return_bool(v4_task_return_schema_rejected) +say "task-return-schema-variants-atomic=" + v4_task_return_bool(v4_task_return_schema_atomic) + +say "task-return-editor-display=" + v4_task_return_symbol_display("task-return-boundary.fk", v4_task_return_source, "keep") +v4_task_return_invalidation_probe()