Build the hosted catalog from the platform header's hosted section - #10828
Merged
Conversation
A platform header's hosted section is the complete list of functions the host supplies, and it is what gives each one its linker symbol and its host dispatch slot. Three stages nevertheless built their own hosted catalog by scanning every hosted declaration in scope and then asserting that the scan agreed with the checked hosted binding table, so a platform whose section did not line up with its declarations aborted the compiler instead of reporting the section. A declaration the section leaves out aborted post-check lowering with `platform hosted binding count 1 disagrees with hosted catalog size 2`; a section naming one declaration twice aborted the same way with the counts reversed, and aborted the `roc <app>` path and `--specialize=no` lowering through their own copies of the same assertion. All three now build from the bindings, so the section decides how many dispatch slots exist and which declaration occupies each one. Naming one declaration twice is two slots, which is what the header asked for and what checking reports as a duplicate. Lowering without specialization reads those bindings too, in place of re-deriving the section by matching declaration names against the header's text. A declaration the section leaves out then has no catalog entry, which is right—it has no symbol to call and no slot to occupy—but a program that called one went on to abort with `hosted procedure template was not output in the hosted catalog`. The checked-modules-to-LIR entrance now refuses a program that still carries such a declaration. Checking already reports it against the section it is missing from, so the compile has failed by the time lowering starts and refusing costs no diagnostic. Compile-time finalization lowers a module whose own checking has not finished, and such a module has no bindings yet, so that entrance reads nothing into their absence there. For that refusal to be sound, checking has to report every declaration it covers. A section entry names its target through an import, so no entry can reach a declaration written in the platform root itself, and checking walked only the modules the root owns—leaving a hosted declaration in `main.roc` unreported, accepted by `roc check`, and stopped later with nothing to say. The root is now checked against the section alongside the modules it owns. Glue reads the same section to name each hosted function's symbol and aborted with `hosted function 'Host.unlisted' has no platform hosted symbol` for the same input. It renders the platform's diagnostics already and now stops on them, because a platform checking rejected has no declared surface for glue to emit.
rtfeldman
force-pushed
the
issue-10809/hosted-catalog-from-section
branch
from
August 16, 2026 22:28
3370f93 to
1f3b43a
Compare
rtfeldman
marked this pull request as ready for review
August 17, 2026 01:09
Contributor
Greptile SummaryThe PR makes the checked platform header’s hosted bindings authoritative for hosted catalogs and prevents lowering or glue generation from consuming unbound hosted declarations.
Confidence Score: 5/5The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking defect established in the changed behavior. The hosted catalogs consistently derive their entries, symbols, and dispatch order from checked bindings, while invalid omitted or duplicate declarations are reported and stopped before unsupported lowering or glue output proceeds.
|
| Filename | Overview |
|---|---|
| src/check/Check.zig | Refactors hosted-declaration collection and includes the platform root when checking declarations against the hosted section. |
| src/lir/checked_pipeline.zig | Adds the checked-to-LIR guard that rejects hosted procedures absent from the visible platform binding table. |
| src/postcheck/boxy/lower.zig | Rebuilds the boxy hosted catalog from checked bindings rather than reconciling a declaration scan with header text. |
| src/postcheck/monotype/lower.zig | Rebuilds the monotype hosted catalog in binding order, preserving each binding’s symbol and dispatch slot. |
| src/cli/main.zig | Applies checked bindings by replacing the scanned CLI hosted catalog and propagates the new lowering error. |
| src/glue/glue.zig | Stops glue generation after platform checking errors and handles unbound-hosted lowering failures without panicking. |
| src/eval/compile_time_finalization.zig | Preserves compile-time finalization behavior by lowering with the checking-finalization state and treating unexpected binding rejection as an invariant failure. |
| src/cli/test/parallel_cli_runner.zig | Adds regression coverage for omitted declarations, duplicate entries, platform-root declarations, run/no-specialize paths, and glue diagnostics. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Platform hosted section] --> B[Checker resolves HostedBindingTable]
B --> C{Checking diagnostics?}
C -->|Errors| D[Stop build or glue]
C -->|Valid| E[Checked-to-LIR boundary]
E --> F{Every hosted procedure bound?}
F -->|No| G[HostedFunctionNotBound]
F -->|Yes| H[Build catalog in binding order]
H --> I[Assign linker symbols and dispatch slots]
I --> J[Boxy, monotype, or CLI lowering]
Reviews (1): Last reviewed commit: "Build the hosted catalog from the platfo..." | Re-trigger Greptile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A platform header's
hostedsection is the complete list of functions the host supplies, and it is what gives each one its linker symbol and its host dispatch slot. Three stages nevertheless built their own hosted catalog by scanning every hosted declaration in scope and then asserting that the scan agreed with the checked hosted binding table, so any platform whose section did not line up with its declarations aborted the compiler rather than reporting the section. A declaration the section omits aborted post-check lowering withplatform hosted binding count 1 disagrees with hosted catalog size 2; a section naming one declaration twice aborted the same way with the counts reversed, and aborted theroc <app>run path and--specialize=nolowering through their own copies of that assertion. All three now build from the bindings, so the section decides how many dispatch slots exist and which declaration occupies each one — naming one declaration twice is two slots, which is what the header asked for and what checking already reports as a duplicate. Lowering without specialization consumes those bindings too, rather than re-deriving the section by matching declaration names against the header's text.A declaration the section omits then has no catalog entry at all, which is right, since it has no symbol to call and no slot to occupy. A program that called one went on to abort with
hosted procedure template was not output in the hosted catalog, so the checked-modules-to-LIR entrance now refuses a program that still carries such a declaration; checking already reports it, so the compile has failed by the time lowering starts and refusing there costs no diagnostic. Compile-time finalization lowers a module whose own checking has not finished, and such a module has no bindings yet, so that entrance reads nothing into their absence there.That refusal is only sound if checking reports every declaration it covers, and one shape went unreported: a section entry names its target through an import, so no entry can reach a declaration written in the platform root itself, yet checking walked only the modules the root owns. A hosted declaration in
main.roctherefore passedroc checkcleanly and was stopped later with nothing to say. The root is now checked against the section alongside the modules it owns. Glue reads the same section to name each hosted function's symbol and aborted on the same input; it renders the platform's diagnostics already and now stops on them, because a platform checking rejected has no declared surface for glue to emit.