implements PLN-0008
This commit is contained in:
parent
d28916578b
commit
b75b2a5825
@ -1,9 +1,9 @@
|
|||||||
{"type":"meta","next_id":{"DSC":9,"AGD":9,"DEC":7,"PLN":8,"LSN":24,"CLSN":1}}
|
{"type":"meta","next_id":{"DSC":9,"AGD":9,"DEC":7,"PLN":9,"LSN":24,"CLSN":1}}
|
||||||
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
||||||
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"palette-management-in-studio","title":"Palette Management in Studio","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","legacy-import","palette-management","tile-bank","packer-boundary"],"agendas":[{"id":"AGD-0002","file":"AGD-0002-palette-management-in-studio.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"palette-management-in-studio","title":"Palette Management in Studio","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","legacy-import","palette-management","tile-bank","packer-boundary"],"agendas":[{"id":"AGD-0002","file":"AGD-0002-palette-management-in-studio.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0003","status":"done","ticket":"packer-docs-import","title":"Import docs/packer into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0009","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0009-mental-model-packer-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0010","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0010-asset-identity-and-runtime-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0011","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0011-foundations-workspace-runtime-and-build-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0012","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0012-runtime-ownership-and-studio-boundary-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0013","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0013-metadata-convergence-and-runtime-sink-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0014","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0014-pack-wizard-summary-validation-and-pack-execution-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0015","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0017","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0017-packer-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
{"type":"discussion","id":"DSC-0003","status":"done","ticket":"packer-docs-import","title":"Import docs/packer into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0009","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0009-mental-model-packer-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0010","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0010-asset-identity-and-runtime-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0011","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0011-foundations-workspace-runtime-and-build-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0012","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0012-runtime-ownership-and-studio-boundary-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0013","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0013-metadata-convergence-and-runtime-sink-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0014","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0014-pack-wizard-summary-validation-and-pack-execution-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0015","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0017","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0017-packer-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
|
||||||
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"tilemap-and-metatile-runtime-binary-layout","title":"Tilemap and Metatile Runtime Binary Layout","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","legacy-import","tilemap","metatile","runtime-layout"],"agendas":[{"id":"AGD-0004","file":"AGD-0004-tilemap-and-metatile-runtime-binary-layout.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"tilemap-and-metatile-runtime-binary-layout","title":"Tilemap and Metatile Runtime Binary Layout","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","legacy-import","tilemap","metatile","runtime-layout"],"agendas":[{"id":"AGD-0004","file":"AGD-0004-tilemap-and-metatile-runtime-binary-layout.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"variable-tile-bank-palette-serialization","title":"Variable Tile Bank Palette Serialization","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","legacy-import","tile-bank","palette-serialization","versioning"],"agendas":[{"id":"AGD-0005","file":"AGD-0005-variable-tile-bank-palette-serialization.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"variable-tile-bank-palette-serialization","title":"Variable Tile Bank Palette Serialization","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","legacy-import","tile-bank","palette-serialization","versioning"],"agendas":[{"id":"AGD-0005","file":"AGD-0005-variable-tile-bank-palette-serialization.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"pbs-game-facing-asset-refs-and-call-result-discard","title":"PBS Game-Facing Asset References and Ignored Call Result Lowering","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","ergonomics","lowering","runtime","asset-identity","expression-statements"],"agendas":[{"id":"AGD-0006","file":"AGD-0006-pbs-game-facing-asset-refs-and-call-result-discard.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[{"id":"DEC-0005","file":"DEC-0005-pbs-asset-address-surface-and-be-lowering.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-03-27","ref_agenda":"AGD-0006"},{"id":"DEC-0006","file":"DEC-0006-pbs-ignored-values-lowering-and-warning.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-03-27","ref_agenda":"AGD-0006"}],"plans":[{"id":"PLN-0005","file":"PLN-0005-pbs-asset-address-surface-spec-propagation.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0005"]},{"id":"PLN-0006","file":"PLN-0006-pbs-asset-address-surface-implementation.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0005"]},{"id":"PLN-0007","file":"PLN-0007-pbs-ignored-values-warning-implementation.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0006"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"pbs-game-facing-asset-refs-and-call-result-discard","title":"PBS Game-Facing Asset References and Ignored Call Result Lowering","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","ergonomics","lowering","runtime","asset-identity","expression-statements"],"agendas":[{"id":"AGD-0006","file":"AGD-0006-pbs-game-facing-asset-refs-and-call-result-discard.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[{"id":"DEC-0005","file":"DEC-0005-pbs-asset-address-surface-and-be-lowering.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-03-27","ref_agenda":"AGD-0006"},{"id":"DEC-0006","file":"DEC-0006-pbs-ignored-values-lowering-and-warning.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-03-27","ref_agenda":"AGD-0006"}],"plans":[{"id":"PLN-0005","file":"PLN-0005-pbs-asset-address-surface-spec-propagation.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0005"]},{"id":"PLN-0006","file":"PLN-0006-pbs-asset-address-surface-implementation.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0005"]},{"id":"PLN-0007","file":"PLN-0007-pbs-ignored-values-warning-implementation.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0006"]},{"id":"PLN-0008","file":"PLN-0008-pbs-assetlowering-host-metadata-and-callsite-rewrite.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27","ref_decisions":["DEC-0005"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0007","status":"done","ticket":"pbs-learn-to-discussion-lessons-migration","title":"Migrate PBS Learn Documents into Discussion Lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","migration","discussion-framework","lessons","learn-prune"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0018","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0018-pbs-ast-and-parser-contract-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0019","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0019-pbs-name-resolution-and-linking-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0020","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0020-pbs-runtime-values-identity-memory-boundaries-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0021","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0021-pbs-diagnostics-and-conformance-governance-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0022","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0022-pbs-globals-lifecycle-and-published-entrypoint-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
{"type":"discussion","id":"DSC-0007","status":"done","ticket":"pbs-learn-to-discussion-lessons-migration","title":"Migrate PBS Learn Documents into Discussion Lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","migration","discussion-framework","lessons","learn-prune"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0018","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0018-pbs-ast-and-parser-contract-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0019","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0019-pbs-name-resolution-and-linking-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0020","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0020-pbs-runtime-values-identity-memory-boundaries-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0021","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0021-pbs-diagnostics-and-conformance-governance-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0022","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0022-pbs-globals-lifecycle-and-published-entrypoint-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||||
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||||
|
|||||||
@ -0,0 +1,196 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0008
|
||||||
|
ticket: pbs-game-facing-asset-refs-and-call-result-discard
|
||||||
|
title: Implement Mandatory AssetLowering Host Metadata and Backend Callsite Rewrite
|
||||||
|
status: done
|
||||||
|
created: 2026-03-27
|
||||||
|
completed: 2026-03-27
|
||||||
|
tags: [compiler, pbs, implementation, assetlowering, host-metadata, backend-lowering, correction]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Complete the missing normative part of `DEC-0005` by implementing mandatory host-backed `AssetLowering` metadata and using it to rewrite `Addressable` arguments into runtime-facing `asset_id` at backend callsite lowering time.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
`DEC-0005` did not only require:
|
||||||
|
|
||||||
|
- `FESurfaceContext = List<Addressable(address, asset_id)>`,
|
||||||
|
- symbolic `assets...` semantics,
|
||||||
|
- and backend ownership of final validation.
|
||||||
|
|
||||||
|
It also normatively locked a second requirement:
|
||||||
|
|
||||||
|
- asset-aware lowering metadata must live on the host-backed declaration surface;
|
||||||
|
- the backend must use that metadata to identify which host parameter is asset-facing;
|
||||||
|
- and host-backed lowering must rewrite the `Addressable` argument to operational `asset_id` before the final `LowAssets` path.
|
||||||
|
|
||||||
|
`PLN-0006` implemented the symbolic surface and direct symbolic-to-`asset_id` expression lowering, but it did not implement:
|
||||||
|
|
||||||
|
- reserved attribute `[AssetLowering(param = N)]`,
|
||||||
|
- reserved-metadata propagation for host bindings,
|
||||||
|
- host-signature validation for asset-lowered parameters,
|
||||||
|
- or host-callsite rewriting driven by parameter metadata.
|
||||||
|
|
||||||
|
This plan exists to correct that gap without reinterpreting `DEC-0005`.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
### Included
|
||||||
|
- Add `AssetLowering(param = N)` as a PBS reserved attribute on host-backed signatures.
|
||||||
|
- Validate the attribute shape and its admissible target surface.
|
||||||
|
- Extend backend host-binding metadata to carry asset-lowering parameter information.
|
||||||
|
- Rewrite host call lowering so asset-facing parameters consume symbolic `Addressable` values and lower them to `asset_id` according to host metadata.
|
||||||
|
- Align tests and specs so the normative path is explicit and covered.
|
||||||
|
- Correct any now-misleading tests or implementation shortcuts introduced by `PLN-0006`.
|
||||||
|
|
||||||
|
### Excluded
|
||||||
|
- Redesign of `DEC-0005`.
|
||||||
|
- Changes to the `LowAssets` ABI already fixed by `DEC-0004`.
|
||||||
|
- Generalization to non-asset metadata families beyond the exact `AssetLowering` rule.
|
||||||
|
- Runtime-dynamic asset lookup exceptions.
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
### Step 1 - Add Reserved Attribute Surface For AssetLowering
|
||||||
|
|
||||||
|
**What:**
|
||||||
|
Introduce `[AssetLowering(param = N)]` as a normative reserved attribute on host-backed callable surfaces.
|
||||||
|
|
||||||
|
**How:**
|
||||||
|
Extend the PBS reserved attribute extractor and declaration validation so:
|
||||||
|
|
||||||
|
- `AssetLowering` is recognized as reserved metadata;
|
||||||
|
- it is admitted only on supported host-backed callable declarations;
|
||||||
|
- `param` is mandatory and must be a valid zero-based parameter index;
|
||||||
|
- the targeted parameter must match the `Addressable` author-facing contract required by `DEC-0005`;
|
||||||
|
- duplicate or malformed declarations fail deterministically.
|
||||||
|
|
||||||
|
**File(s):**
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsReservedMetadataExtractor.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsDeclarationSemanticsValidator.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsSemanticsErrors.java`
|
||||||
|
- tests under `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/`
|
||||||
|
|
||||||
|
### Step 2 - Propagate AssetLowering Through Reserved Metadata
|
||||||
|
|
||||||
|
**What:**
|
||||||
|
Make host binding metadata carry the asset-lowering contract instead of relying on implicit expression-level lowering.
|
||||||
|
|
||||||
|
**How:**
|
||||||
|
Extend `IRReservedMetadata.HostMethodBinding` or the equivalent host-binding metadata shape so each binding can expose:
|
||||||
|
|
||||||
|
- whether asset lowering is required;
|
||||||
|
- which parameter index is asset-facing.
|
||||||
|
|
||||||
|
Update metadata construction, merging, indexing, and any downstream readers so the information survives all backend-facing frontend phases.
|
||||||
|
|
||||||
|
**File(s):**
|
||||||
|
- `prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models/IRReservedMetadata.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsReservedMetadataExtractor.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableLoweringModels.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableMetadataIndexFactory.java`
|
||||||
|
- metadata conformance tests under `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/`
|
||||||
|
|
||||||
|
### Step 3 - Rewrite Host Calls Using AssetLowering Metadata
|
||||||
|
|
||||||
|
**What:**
|
||||||
|
Move final `Addressable -> asset_id` host-argument rewriting into the backend-owned host call path mandated by `DEC-0005`.
|
||||||
|
|
||||||
|
**How:**
|
||||||
|
Update executable lowering so:
|
||||||
|
|
||||||
|
- host callsites inspect `AssetLowering(param = N)` metadata from the resolved host binding;
|
||||||
|
- the backend validates that the selected argument is a terminal backend-known `Addressable`;
|
||||||
|
- the selected argument is lowered to operational `asset_id`;
|
||||||
|
- non-asset-facing arguments are lowered normally;
|
||||||
|
- the final emitted host call matches the already accepted `LowAssets` runtime path.
|
||||||
|
|
||||||
|
This step must remove reliance on the current shortcut where symbolic asset references are lowered generically without host-parameter ownership.
|
||||||
|
|
||||||
|
**File(s):**
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableBodyLowerer.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableCallsiteEmitter.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/PbsExecutableLoweringContext.java`
|
||||||
|
- related lowering metadata/index files
|
||||||
|
- targeted lowering tests under `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/`
|
||||||
|
|
||||||
|
### Step 4 - Realign Symbolic Expression Lowering With The Host-Metadata Contract
|
||||||
|
|
||||||
|
**What:**
|
||||||
|
Correct the partial implementation from `PLN-0006` so symbolic asset expressions support the normative host-metadata path instead of bypassing it.
|
||||||
|
|
||||||
|
**How:**
|
||||||
|
Review the current direct lowering of `assets...` expressions and keep only the behavior that remains valid under `DEC-0005`.
|
||||||
|
|
||||||
|
At minimum:
|
||||||
|
|
||||||
|
- standalone symbolic `Addressable` semantics must remain correct;
|
||||||
|
- host-backed `AssetLowering` callsites must no longer depend on an implicit generic shortcut;
|
||||||
|
- tests that previously “passed” through direct expression lowering must be updated to assert the host-metadata path explicitly.
|
||||||
|
|
||||||
|
If any `PLN-0006` behavior contradicts `DEC-0005`, correct the code and the tests rather than preserving the shortcut.
|
||||||
|
|
||||||
|
**File(s):**
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/lowering/`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsFrontendCompilerTest.java`
|
||||||
|
- `prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java`
|
||||||
|
|
||||||
|
### Step 5 - Propagate And Pin The Contract In Specs And Tests
|
||||||
|
|
||||||
|
**What:**
|
||||||
|
Ensure the normative wording and regression coverage now match the corrected implementation.
|
||||||
|
|
||||||
|
**How:**
|
||||||
|
Update specs and tests so they explicitly cover:
|
||||||
|
|
||||||
|
- `AssetLowering(param = N)` as mandatory host-backed metadata for asset-aware lowering;
|
||||||
|
- the backend-owned rewrite from symbolic `Addressable` to operational `asset_id`;
|
||||||
|
- rejection of malformed attribute usage and invalid parameter targeting;
|
||||||
|
- a representative `LowAssets`-aligned host call path using the metadata-bearing surface.
|
||||||
|
|
||||||
|
**File(s):**
|
||||||
|
- `docs/specs/compiler-languages/pbs/4. Static Semantics Specification.md`
|
||||||
|
- `docs/specs/compiler-languages/pbs/12. Diagnostics Specification.md`
|
||||||
|
- `docs/specs/compiler-languages/pbs/13. Lowering IRBackend Specification.md`
|
||||||
|
- `docs/specs/compiler/20. IRBackend to IRVM Lowering Specification.md`
|
||||||
|
- targeted PBS frontend/compiler tests
|
||||||
|
|
||||||
|
## Test Requirements
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
- Reserved-attribute tests for valid and invalid `AssetLowering(param = N)` usage.
|
||||||
|
- Metadata tests proving host bindings preserve the asset-lowering parameter index.
|
||||||
|
- Negative tests for duplicate, malformed, or out-of-range `AssetLowering` declarations.
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
- End-to-end PBS frontend compilation tests where a host-backed asset API uses `Addressable` plus `[AssetLowering(param = N)]`.
|
||||||
|
- Lowering tests proving the backend rewrites the marked argument to `asset_id` before the final host call.
|
||||||
|
- Regression tests proving `LowAssets`-aligned callsites still lower correctly after removing the shortcut path.
|
||||||
|
|
||||||
|
### Manual Verification
|
||||||
|
- Inspect extracted reserved metadata and verify `AssetLowering` is carried on the host binding.
|
||||||
|
- Inspect lowered instruction streams for an asset-aware host call and verify the asset-facing argument becomes `asset_id`.
|
||||||
|
- Confirm malformed host metadata fails with deterministic source-facing diagnostics.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] PBS supports `[AssetLowering(param = N)]` as a validated reserved attribute on the correct host-backed surface.
|
||||||
|
- [ ] Host binding metadata preserves the asset-lowering parameter contract through backend lowering preparation.
|
||||||
|
- [ ] Backend host-call lowering uses the metadata to rewrite the selected `Addressable` argument into runtime-facing `asset_id`.
|
||||||
|
- [ ] The final asset-aware host path remains aligned with `LowAssets` and no longer depends on a generic shortcut that bypasses host metadata.
|
||||||
|
- [ ] Tests and specs explicitly cover the normative `AssetLowering` path from `DEC-0005`.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- `DEC-0005-pbs-asset-address-surface-and-be-lowering`
|
||||||
|
- `DEC-0004` low-level `LowAssets` contract
|
||||||
|
- existing `PLN-0006` implementation as the correction baseline
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
|
||||||
|
- The current direct symbolic lowering path may overlap with the normative host-metadata path and require careful removal or restriction.
|
||||||
|
- Extending host metadata may require synchronized updates across multiple compiler layers, increasing the chance of partial propagation if done carelessly.
|
||||||
|
- If tests keep asserting the shortcut path instead of the normative path, the repository may regress into the same discrepancy again.
|
||||||
@ -207,6 +207,13 @@ At minimum, the PBS diagnostics baseline must cover:
|
|||||||
- a stable warning when a materialized value is produced and then ignored,
|
- a stable warning when a materialized value is produced and then ignored,
|
||||||
- and no warning for unit-like expression statements.
|
- and no warning for unit-like expression statements.
|
||||||
|
|
||||||
|
Reserved-attribute diagnostics for host-backed asset lowering must also cover:
|
||||||
|
|
||||||
|
- duplicate `AssetLowering` declarations on the same host signature,
|
||||||
|
- missing or malformed `AssetLowering(param = N)` arguments,
|
||||||
|
- out-of-range `AssetLowering.param` indexes,
|
||||||
|
- and `AssetLowering` targets whose selected parameter is not statically typed as `Addressable`.
|
||||||
|
|
||||||
At minimum, host-admission diagnostics must cover missing or malformed host capability metadata and unknown or undeclared capability names.
|
At minimum, host-admission diagnostics must cover missing or malformed host capability metadata and unknown or undeclared capability names.
|
||||||
|
|
||||||
Only backend-originated failures that remain source-attributable and user-actionable belong to the PBS-facing diagnostics contract.
|
Only backend-originated failures that remain source-attributable and user-actionable belong to the PBS-facing diagnostics contract.
|
||||||
|
|||||||
@ -185,6 +185,7 @@ When available at this boundary, declared host ABI shape (`arg_slots`, `ret_slot
|
|||||||
When a host-backed callsite also depends on backend-owned symbolic asset lowering:
|
When a host-backed callsite also depends on backend-owned symbolic asset lowering:
|
||||||
|
|
||||||
- the frontend boundary MUST preserve which callsite argument is asset-facing;
|
- the frontend boundary MUST preserve which callsite argument is asset-facing;
|
||||||
|
- for PBS v1 this asset-facing designation is carried by reserved host metadata `[AssetLowering(param = N)]`;
|
||||||
- the preserved symbolic operand MUST remain attributable to a backend-provided `Addressable` identity;
|
- the preserved symbolic operand MUST remain attributable to a backend-provided `Addressable` identity;
|
||||||
- backend stages MUST be able to rewrite that symbolic operand into runtime-facing `asset_id` before the final low-level host path is emitted.
|
- backend stages MUST be able to rewrite that symbolic operand into runtime-facing `asset_id` before the final low-level host path is emitted.
|
||||||
|
|
||||||
|
|||||||
@ -80,14 +80,19 @@ Rules:
|
|||||||
- Attributes are not first-class values and are not reflectable in v1 core.
|
- Attributes are not first-class values and are not reflectable in v1 core.
|
||||||
- Attributes do not automatically survive into runtime or bytecode artifacts.
|
- Attributes do not automatically survive into runtime or bytecode artifacts.
|
||||||
- An attribute affects runtime artifacts only when another specification defines an explicit lowering for its semantic effect.
|
- An attribute affects runtime artifacts only when another specification defines an explicit lowering for its semantic effect.
|
||||||
- In v1 core, the normative reserved attributes are `Host`, `Capability`, `BuiltinType`, `BuiltinConst`, `IntrinsicCall`, `Init`, `Frame`, and `InitAllowed`.
|
- In v1 core, the normative reserved attributes are `Host`, `Capability`, `AssetLowering`, `BuiltinType`, `BuiltinConst`, `IntrinsicCall`, `Init`, `Frame`, and `InitAllowed`.
|
||||||
- `Host` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
- `Host` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
||||||
- `Capability` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
- `Capability` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
||||||
|
- `AssetLowering` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
||||||
- `Init` is valid only on a top-level userland `fn` declaration with lifecycle-admissible signature.
|
- `Init` is valid only on a top-level userland `fn` declaration with lifecycle-admissible signature.
|
||||||
- `Frame` is valid only on a top-level userland `fn` declaration with lifecycle-admissible signature.
|
- `Frame` is valid only on a top-level userland `fn` declaration with lifecycle-admissible signature.
|
||||||
- `InitAllowed` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
- `InitAllowed` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
||||||
- `Host` is invalid on ordinary user-authored modules, top-level `fn`, struct methods, service methods, callbacks, contracts, and constants.
|
- `Host` is invalid on ordinary user-authored modules, top-level `fn`, struct methods, service methods, callbacks, contracts, and constants.
|
||||||
- `Host` metadata is consumed by the compiler during host-binding lowering.
|
- `Host` metadata is consumed by the compiler during host-binding lowering.
|
||||||
|
- `AssetLowering` MUST declare exactly the named argument `param`.
|
||||||
|
- `AssetLowering.param` MUST be a zero-based integer literal that names a valid host parameter position.
|
||||||
|
- The parameter targeted by `AssetLowering.param` MUST be statically typed as `Addressable`.
|
||||||
|
- `AssetLowering` metadata is consumed by backend-owned host-call lowering to rewrite the targeted symbolic `Addressable` operand into runtime-facing `asset_id`.
|
||||||
- The `Host` attribute syntax itself is not exported as runtime metadata; instead, its canonical identity participates in PBX host-binding emission as defined by the Host ABI Binding specification.
|
- The `Host` attribute syntax itself is not exported as runtime metadata; instead, its canonical identity participates in PBX host-binding emission as defined by the Host ABI Binding specification.
|
||||||
- `BuiltinType` is valid only on a reserved top-level `declare builtin type` declaration.
|
- `BuiltinType` is valid only on a reserved top-level `declare builtin type` declaration.
|
||||||
- `BuiltinConst` is valid only on a reserved top-level `declare const` declaration that omits an initializer.
|
- `BuiltinConst` is valid only on a reserved top-level `declare const` declaration that omits an initializer.
|
||||||
|
|||||||
@ -143,7 +143,8 @@ For example, the PBS-facing declaration:
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -155,6 +156,8 @@ maps to the canonical runtime identity:
|
|||||||
|
|
||||||
The loader MUST NOT derive runtime identity from the source owner spelling `LowAssets`.
|
The loader MUST NOT derive runtime identity from the source owner spelling `LowAssets`.
|
||||||
|
|
||||||
|
At the PBS-facing declaration layer, `AssetLowering(param = 0)` marks the author-facing `Addressable` parameter as the backend-owned symbolic operand that must be rewritten to operational `asset_id` before the final low-level host path is emitted.
|
||||||
|
|
||||||
## 7. PBX Host Binding Section
|
## 7. PBX Host Binding Section
|
||||||
|
|
||||||
### 7.1 Temporary section contract
|
### 7.1 Temporary section contract
|
||||||
|
|||||||
@ -214,7 +214,8 @@ or:
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -228,8 +229,8 @@ Rules:
|
|||||||
- stdlib line `1` MUST expose the low-level asset interface module at `@sdk:asset`,
|
- stdlib line `1` MUST expose the low-level asset interface module at `@sdk:asset`,
|
||||||
- that module MUST declare `LowAssets`,
|
- that module MUST declare `LowAssets`,
|
||||||
- that module MUST use runtime module `asset` and capability `asset`,
|
- that module MUST use runtime module `asset` and capability `asset`,
|
||||||
- that module MUST use the runtime-aligned signatures:
|
- that module MUST use the runtime-aligned signatures and reserved lowering metadata:
|
||||||
- `load(asset_id: int, slot: int) -> (status: int, loading_handle: int)`
|
- `load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int)` together with `[AssetLowering(param = 0)]`
|
||||||
- `status(loading_handle: int) -> int`
|
- `status(loading_handle: int) -> int`
|
||||||
- `commit(loading_handle: int) -> int`
|
- `commit(loading_handle: int) -> int`
|
||||||
- `cancel(loading_handle: int) -> int`
|
- `cancel(loading_handle: int) -> int`
|
||||||
|
|||||||
@ -150,6 +150,8 @@ Before bytecode emission, backend must run structural pre-verification on lowere
|
|||||||
7. and structural validity of host/intrinsic call forms.
|
7. and structural validity of host/intrinsic call forms.
|
||||||
8. and structural validity of backend-owned symbolic-to-operational rewrites such as `Addressable -> asset_id`.
|
8. and structural validity of backend-owned symbolic-to-operational rewrites such as `Addressable -> asset_id`.
|
||||||
|
|
||||||
|
For PBS host-backed asset calls in v1, this validation includes the rewrite selected by preserved host metadata such as `[AssetLowering(param = N)]`.
|
||||||
|
|
||||||
This pre-verification does not replace runtime verifier authority.
|
This pre-verification does not replace runtime verifier authority.
|
||||||
|
|
||||||
## 11. Deterministic Rejection Policy
|
## 11. Deterministic Rejection Policy
|
||||||
|
|||||||
@ -15,6 +15,7 @@ public final class PbsReservedMetadataExtractor {
|
|||||||
private static final String ATTR_BUILTIN_TYPE = "BuiltinType";
|
private static final String ATTR_BUILTIN_TYPE = "BuiltinType";
|
||||||
private static final String ATTR_INTRINSIC_CALL = "IntrinsicCall";
|
private static final String ATTR_INTRINSIC_CALL = "IntrinsicCall";
|
||||||
private static final String ATTR_BUILTIN_CONST = "BuiltinConst";
|
private static final String ATTR_BUILTIN_CONST = "BuiltinConst";
|
||||||
|
private static final String ATTR_ASSET_LOWERING = "AssetLowering";
|
||||||
|
|
||||||
public IRReservedMetadata extract(
|
public IRReservedMetadata extract(
|
||||||
final PbsAst.File ast,
|
final PbsAst.File ast,
|
||||||
@ -68,6 +69,7 @@ public final class PbsReservedMetadataExtractor {
|
|||||||
final var capability = capabilityAttribute
|
final var capability = capabilityAttribute
|
||||||
.flatMap(attr -> stringArgument(attr, "name"))
|
.flatMap(attr -> stringArgument(attr, "name"))
|
||||||
.orElse("");
|
.orElse("");
|
||||||
|
final var assetLoweringAttribute = firstAttributeNamed(signature.attributes(), ATTR_ASSET_LOWERING);
|
||||||
hostMethodBindings.add(new IRReservedMetadata.HostMethodBinding(
|
hostMethodBindings.add(new IRReservedMetadata.HostMethodBinding(
|
||||||
hostDecl.name(),
|
hostDecl.name(),
|
||||||
signature.name(),
|
signature.name(),
|
||||||
@ -78,6 +80,9 @@ public final class PbsReservedMetadataExtractor {
|
|||||||
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
||||||
case PLAIN, RESULT -> 1;
|
case PLAIN, RESULT -> 1;
|
||||||
},
|
},
|
||||||
|
assetLoweringAttribute.isPresent()
|
||||||
|
? safeToInteger(longArgument(assetLoweringAttribute.get(), "param").orElse(-1L))
|
||||||
|
: null,
|
||||||
capabilityAttribute.isPresent(),
|
capabilityAttribute.isPresent(),
|
||||||
capability,
|
capability,
|
||||||
signature.span()));
|
signature.span()));
|
||||||
@ -261,4 +266,11 @@ public final class PbsReservedMetadataExtractor {
|
|||||||
}
|
}
|
||||||
return ReadOnlyList.wrap(required.stream().toList());
|
return ReadOnlyList.wrap(required.stream().toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Integer safeToInteger(final long value) {
|
||||||
|
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (int) value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -415,10 +415,28 @@ final class PbsExecutableBodyLowerer {
|
|||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
lowerCallsiteReceiver(callExpr.callee(), context);
|
lowerCallsiteReceiver(callExpr.callee(), context);
|
||||||
lowerExpressionList(callExpr.arguments(), context);
|
lowerCallArguments(callExpr, context);
|
||||||
callsiteEmitter.emitCallsite(callExpr, context);
|
callsiteEmitter.emitCallsite(callExpr, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void lowerCallArguments(
|
||||||
|
final PbsAst.CallExpr callExpr,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var hostBinding = callsiteEmitter.resolveUniqueHostBinding(callExpr, context);
|
||||||
|
if (hostBinding == null || hostBinding.assetLoweringParam() == null) {
|
||||||
|
lowerExpressionList(callExpr.arguments(), context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < callExpr.arguments().size(); i++) {
|
||||||
|
final var argument = callExpr.arguments().get(i);
|
||||||
|
if (i == hostBinding.assetLoweringParam()) {
|
||||||
|
lowerAssetFacingArgument(argument, hostBinding, context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lowerExpression(argument, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void lowerExpressionList(
|
private void lowerExpressionList(
|
||||||
final ReadOnlyList<PbsAst.Expression> expressions,
|
final ReadOnlyList<PbsAst.Expression> expressions,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
@ -461,6 +479,26 @@ final class PbsExecutableBodyLowerer {
|
|||||||
lowerExpression(memberExpr.receiver(), context);
|
lowerExpression(memberExpr.receiver(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void lowerAssetFacingArgument(
|
||||||
|
final PbsAst.Expression expression,
|
||||||
|
final p.studio.compiler.models.IRReservedMetadata.HostMethodBinding hostBinding,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var assetReference = flattenAssetReference(expression);
|
||||||
|
if (assetReference == null) {
|
||||||
|
lowerExpression(expression, context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final var assetId = context.resolveAssetId(assetReference);
|
||||||
|
if (assetId == null) {
|
||||||
|
reportUnsupportedLowering(
|
||||||
|
"asset-facing host parameter does not resolve in backend-owned surface: " + assetReference,
|
||||||
|
expression.span(),
|
||||||
|
context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitPushI32(assetId, expression.span(), context);
|
||||||
|
}
|
||||||
|
|
||||||
private void lowerIfExpression(
|
private void lowerIfExpression(
|
||||||
final PbsAst.IfExpr ifExpr,
|
final PbsAst.IfExpr ifExpr,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
|
|||||||
@ -16,6 +16,23 @@ import java.util.Map;
|
|||||||
import static p.studio.compiler.pbs.lowering.PbsExecutableLoweringModels.*;
|
import static p.studio.compiler.pbs.lowering.PbsExecutableLoweringModels.*;
|
||||||
|
|
||||||
final class PbsExecutableCallsiteEmitter {
|
final class PbsExecutableCallsiteEmitter {
|
||||||
|
IRReservedMetadata.HostMethodBinding resolveUniqueHostBinding(
|
||||||
|
final PbsAst.CallExpr callExpr,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var calleeIdentity = resolveCalleeIdentity(callExpr.callee(), context.nameTable());
|
||||||
|
if (calleeIdentity == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final var candidates = resolveCallsiteCandidates(callExpr, calleeIdentity, context);
|
||||||
|
if (!candidates.callableCandidates().isEmpty() || !candidates.intrinsicCandidates().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (candidates.hostCandidates().size() != 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return candidates.hostCandidates().getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
int returnSlotsOf(
|
int returnSlotsOf(
|
||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
|
|||||||
@ -18,6 +18,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
private static final String ATTR_BUILTIN_CONST = "BuiltinConst";
|
private static final String ATTR_BUILTIN_CONST = "BuiltinConst";
|
||||||
private static final String ATTR_INTRINSIC_CALL = "IntrinsicCall";
|
private static final String ATTR_INTRINSIC_CALL = "IntrinsicCall";
|
||||||
private static final String ATTR_INIT_ALLOWED = "InitAllowed";
|
private static final String ATTR_INIT_ALLOWED = "InitAllowed";
|
||||||
|
private static final String ATTR_ASSET_LOWERING = "AssetLowering";
|
||||||
|
|
||||||
private static final Set<String> RESERVED_ATTRIBUTES = Set.of(
|
private static final Set<String> RESERVED_ATTRIBUTES = Set.of(
|
||||||
ATTR_HOST,
|
ATTR_HOST,
|
||||||
@ -25,7 +26,8 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
ATTR_BUILTIN_TYPE,
|
ATTR_BUILTIN_TYPE,
|
||||||
ATTR_BUILTIN_CONST,
|
ATTR_BUILTIN_CONST,
|
||||||
ATTR_INTRINSIC_CALL,
|
ATTR_INTRINSIC_CALL,
|
||||||
ATTR_INIT_ALLOWED);
|
ATTR_INIT_ALLOWED,
|
||||||
|
ATTR_ASSET_LOWERING);
|
||||||
|
|
||||||
private final NameTable nameTable;
|
private final NameTable nameTable;
|
||||||
private final PbsConstSemanticsValidator constSemanticsValidator = new PbsConstSemanticsValidator();
|
private final PbsConstSemanticsValidator constSemanticsValidator = new PbsConstSemanticsValidator();
|
||||||
@ -403,13 +405,15 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
final DiagnosticSink diagnostics) {
|
final DiagnosticSink diagnostics) {
|
||||||
final var hostAttributes = attributesNamed(signature.attributes(), ATTR_HOST);
|
final var hostAttributes = attributesNamed(signature.attributes(), ATTR_HOST);
|
||||||
final var initAllowedAttributes = attributesNamed(signature.attributes(), ATTR_INIT_ALLOWED);
|
final var initAllowedAttributes = attributesNamed(signature.attributes(), ATTR_INIT_ALLOWED);
|
||||||
|
final var assetLoweringAttributes = attributesNamed(signature.attributes(), ATTR_ASSET_LOWERING);
|
||||||
for (final var attribute : signature.attributes()) {
|
for (final var attribute : signature.attributes()) {
|
||||||
if (!isReservedAttribute(attribute.name())) {
|
if (!isReservedAttribute(attribute.name())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ATTR_HOST.equals(attribute.name())
|
if (ATTR_HOST.equals(attribute.name())
|
||||||
|| ATTR_CAPABILITY.equals(attribute.name())
|
|| ATTR_CAPABILITY.equals(attribute.name())
|
||||||
|| ATTR_INIT_ALLOWED.equals(attribute.name())) {
|
|| ATTR_INIT_ALLOWED.equals(attribute.name())
|
||||||
|
|| ATTR_ASSET_LOWERING.equals(attribute.name())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
reportInvalidReservedAttributeTarget(
|
reportInvalidReservedAttributeTarget(
|
||||||
@ -438,10 +442,19 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (assetLoweringAttributes.size() > 1) {
|
||||||
|
for (int i = 1; i < assetLoweringAttributes.size(); i++) {
|
||||||
|
reportDuplicateReservedAttribute(assetLoweringAttributes.get(i), ATTR_ASSET_LOWERING, diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validateHostAttributeShape(hostAttributes.getFirst(), diagnostics);
|
validateHostAttributeShape(hostAttributes.getFirst(), diagnostics);
|
||||||
if (!initAllowedAttributes.isEmpty()) {
|
if (!initAllowedAttributes.isEmpty()) {
|
||||||
validateInitAllowedAttributeShape(initAllowedAttributes.getFirst(), diagnostics);
|
validateInitAllowedAttributeShape(initAllowedAttributes.getFirst(), diagnostics);
|
||||||
}
|
}
|
||||||
|
if (!assetLoweringAttributes.isEmpty()) {
|
||||||
|
validateAssetLoweringAttributeShape(assetLoweringAttributes.getFirst(), signature, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateBuiltinTypeAttribute(
|
private void validateBuiltinTypeAttribute(
|
||||||
@ -587,6 +600,39 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateAssetLoweringAttributeShape(
|
||||||
|
final PbsAst.Attribute attribute,
|
||||||
|
final PbsAst.FunctionSignature signature,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
final var args = validateNamedArguments(attribute, Set.of("param"), Set.of(), diagnostics);
|
||||||
|
if (args == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
validateRequiredIntArgument(attribute, args, "param", false, diagnostics);
|
||||||
|
final var value = args.get("param");
|
||||||
|
if (!(value instanceof PbsAst.AttributeIntValue intValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final var paramIndex = intValue.value();
|
||||||
|
if (paramIndex < 0 || paramIndex >= signature.parameters().size()) {
|
||||||
|
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||||
|
PbsSemanticsErrors.E_SEM_MALFORMED_RESERVED_ATTRIBUTE.name(),
|
||||||
|
"AssetLowering param index %d is out of range for host signature '%s'".formatted(paramIndex, signature.name()),
|
||||||
|
attribute.span());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final var parameter = signature.parameters().get((int) paramIndex);
|
||||||
|
final var parameterType = unwrapGroup(parameter.typeRef());
|
||||||
|
if (parameterType == null
|
||||||
|
|| parameterType.kind() != PbsAst.TypeRefKind.SIMPLE
|
||||||
|
|| !"Addressable".equals(parameterType.name())) {
|
||||||
|
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||||
|
PbsSemanticsErrors.E_SEM_MALFORMED_RESERVED_ATTRIBUTE.name(),
|
||||||
|
"AssetLowering target parameter '%s' must have Addressable type".formatted(parameter.name()),
|
||||||
|
attribute.span());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, PbsAst.AttributeValue> validateNamedArguments(
|
private Map<String, PbsAst.AttributeValue> validateNamedArguments(
|
||||||
final PbsAst.Attribute attribute,
|
final PbsAst.Attribute attribute,
|
||||||
final Set<String> requiredNames,
|
final Set<String> requiredNames,
|
||||||
@ -690,6 +736,13 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
return trimmed.isEmpty();
|
return trimmed.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PbsAst.TypeRef unwrapGroup(final PbsAst.TypeRef typeRef) {
|
||||||
|
if (typeRef == null || typeRef.kind() != PbsAst.TypeRefKind.GROUP) {
|
||||||
|
return typeRef;
|
||||||
|
}
|
||||||
|
return unwrapGroup(typeRef.inner());
|
||||||
|
}
|
||||||
|
|
||||||
private List<PbsAst.Attribute> attributesNamed(
|
private List<PbsAst.Attribute> attributesNamed(
|
||||||
final ReadOnlyList<PbsAst.Attribute> attributes,
|
final ReadOnlyList<PbsAst.Attribute> attributes,
|
||||||
final String name) {
|
final String name) {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
|
|
||||||
[Host(module = "asset", name = "status", version = 1)]
|
[Host(module = "asset", name = "status", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
|
|||||||
@ -9,12 +9,18 @@ import p.studio.compiler.models.IRGlobalVisibility;
|
|||||||
import p.studio.compiler.models.IRSyntheticCallableKind;
|
import p.studio.compiler.models.IRSyntheticCallableKind;
|
||||||
import p.studio.compiler.models.SourceKind;
|
import p.studio.compiler.models.SourceKind;
|
||||||
import p.studio.compiler.pbs.lexer.LexErrors;
|
import p.studio.compiler.pbs.lexer.LexErrors;
|
||||||
|
import p.studio.compiler.pbs.lexer.PbsLexer;
|
||||||
|
import p.studio.compiler.pbs.parser.PbsParser;
|
||||||
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
|
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
|
||||||
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.compiler.source.identifiers.ModuleId;
|
||||||
|
import p.studio.compiler.source.tables.NameTable;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@ -433,7 +439,8 @@ class PbsFrontendCompilerTest {
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
|
|
||||||
[Host(module = "asset", name = "status", version = 1)]
|
[Host(module = "asset", name = "status", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
@ -462,7 +469,8 @@ class PbsFrontendCompilerTest {
|
|||||||
.anyMatch(h -> h.ownerName().equals("LowAssets")
|
.anyMatch(h -> h.ownerName().equals("LowAssets")
|
||||||
&& h.abiModule().equals("asset")
|
&& h.abiModule().equals("asset")
|
||||||
&& h.abiMethod().equals("load")
|
&& h.abiMethod().equals("load")
|
||||||
&& h.abiVersion() == 1));
|
&& h.abiVersion() == 1
|
||||||
|
&& java.util.Objects.equals(h.assetLoweringParam(), 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -493,6 +501,61 @@ class PbsFrontendCompilerTest {
|
|||||||
&& "37".equals(i.label())));
|
&& "37".equals(i.label())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRewriteAssetLoweringHostParameterToAssetId() {
|
||||||
|
final var interfaceSource = """
|
||||||
|
declare host LowAssets {
|
||||||
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
|
[Capability(name = "asset")]
|
||||||
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var source = """
|
||||||
|
fn boot() -> (status: int, loading_handle: int) {
|
||||||
|
return LowAssets.load(assets.ui.panel, 2);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
final var compiler = new PbsFrontendCompiler();
|
||||||
|
final var interfaceBackend = compiler.compileFile(new FileId(16), interfaceSource, diagnostics, SourceKind.SDK_INTERFACE);
|
||||||
|
final var sourceFileId = new FileId(17);
|
||||||
|
final var sourceTokens = PbsLexer.lex(source, sourceFileId, diagnostics);
|
||||||
|
final var sourceAst = PbsParser.parse(sourceTokens, sourceFileId, diagnostics);
|
||||||
|
final var interfaceTokens = PbsLexer.lex(interfaceSource, new FileId(18), diagnostics);
|
||||||
|
final var interfaceAst = PbsParser.parse(interfaceTokens, new FileId(18), diagnostics, PbsParser.ParseMode.INTERFACE_MODULE);
|
||||||
|
final var fileBackend = compiler.compileParsedFile(
|
||||||
|
sourceFileId,
|
||||||
|
sourceAst,
|
||||||
|
diagnostics,
|
||||||
|
SourceKind.PROJECT,
|
||||||
|
ModuleId.none(),
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
HostAdmissionContext.permissiveDefault(),
|
||||||
|
new FESurfaceContext(ReadOnlyList.from(new Addressable("assets.ui.panel", 55))),
|
||||||
|
new NameTable(),
|
||||||
|
interfaceAst.topDecls(),
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
interfaceBackend.reservedMetadata(),
|
||||||
|
Map.of());
|
||||||
|
|
||||||
|
assertEquals(0, diagnostics.errorCount(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||||
|
final var executableBoot = fileBackend.executableFunctions().stream()
|
||||||
|
.filter(fn -> fn.callableName().equals("boot"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
assertTrue(executableBoot.instructions().stream().anyMatch(i ->
|
||||||
|
i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.PUSH_I32
|
||||||
|
&& "55".equals(i.label())));
|
||||||
|
assertTrue(executableBoot.instructions().stream().anyMatch(i ->
|
||||||
|
i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_HOST
|
||||||
|
&& i.hostCall() != null
|
||||||
|
&& "asset".equals(i.hostCall().module())
|
||||||
|
&& "load".equals(i.hostCall().name())));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRejectUnresolvedBackendOwnedAssetReference() {
|
void shouldRejectUnresolvedBackendOwnedAssetReference() {
|
||||||
final var source = """
|
final var source = """
|
||||||
|
|||||||
@ -332,7 +332,8 @@ class PbsGateUSdkInterfaceConformanceTest {
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
|
|
||||||
[Host(module = "asset", name = "status", version = 1)]
|
[Host(module = "asset", name = "status", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
@ -361,8 +362,9 @@ class PbsGateUSdkInterfaceConformanceTest {
|
|||||||
assertEquals("asset", backend.reservedMetadata().requiredCapabilities().getFirst());
|
assertEquals("asset", backend.reservedMetadata().requiredCapabilities().getFirst());
|
||||||
assertTrue(backend.reservedMetadata().hostMethodBindings().stream()
|
assertTrue(backend.reservedMetadata().hostMethodBindings().stream()
|
||||||
.anyMatch(h -> h.ownerName().equals("LowAssets")
|
.anyMatch(h -> h.ownerName().equals("LowAssets")
|
||||||
|
&& java.util.Objects.equals(h.assetLoweringParam(), 0)
|
||||||
&& h.abiModule().equals("asset")
|
&& h.abiModule().equals("asset")
|
||||||
&& h.abiMethod().equals("cancel")
|
&& h.abiMethod().equals("load")
|
||||||
&& h.abiVersion() == 1));
|
&& h.abiVersion() == 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -126,7 +126,8 @@ class PbsInterfaceModuleSemanticsTest {
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
|
|
||||||
[Host(module = "asset", name = "status", version = 1)]
|
[Host(module = "asset", name = "status", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
@ -140,6 +141,24 @@ class PbsInterfaceModuleSemanticsTest {
|
|||||||
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRejectMalformedAssetLoweringOnHostSurface() {
|
||||||
|
final var source = """
|
||||||
|
declare host LowAssets {
|
||||||
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
|
[Capability(name = "asset")]
|
||||||
|
[AssetLowering(param = 1)]
|
||||||
|
fn load(addressable: Addressable) -> int;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(5), source, diagnostics, SourceKind.SDK_INTERFACE);
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_MALFORMED_RESERVED_ATTRIBUTE.name())));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRejectBuiltinFieldWithNonAdmissibleLayoutType() {
|
void shouldRejectBuiltinFieldWithNonAdmissibleLayoutType() {
|
||||||
final var source = """
|
final var source = """
|
||||||
|
|||||||
@ -69,7 +69,8 @@ class InterfaceModuleLoaderTest {
|
|||||||
declare host LowAssets {
|
declare host LowAssets {
|
||||||
[Host(module = "asset", name = "load", version = 1)]
|
[Host(module = "asset", name = "load", version = 1)]
|
||||||
[Capability(name = "asset")]
|
[Capability(name = "asset")]
|
||||||
fn load(asset_id: int, slot: int) -> (status: int, loading_handle: int);
|
[AssetLowering(param = 0)]
|
||||||
|
fn load(addressable: Addressable, slot: int) -> (status: int, loading_handle: int);
|
||||||
}
|
}
|
||||||
"""))),
|
"""))),
|
||||||
"pub host LowAssets;");
|
"pub host LowAssets;");
|
||||||
|
|||||||
@ -950,7 +950,8 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
assertTrue(irBackend.getReservedMetadata().hostMethodBindings().stream()
|
assertTrue(irBackend.getReservedMetadata().hostMethodBindings().stream()
|
||||||
.anyMatch(h -> h.ownerName().equals("LowAssets")
|
.anyMatch(h -> h.ownerName().equals("LowAssets")
|
||||||
&& h.sourceMethodName().equals("load")
|
&& h.sourceMethodName().equals("load")
|
||||||
&& h.abiModule().equals("asset")));
|
&& h.abiModule().equals("asset")
|
||||||
|
&& java.util.Objects.equals(h.assetLoweringParam(), 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -33,6 +33,7 @@ public record IRReservedMetadata(
|
|||||||
String abiMethod,
|
String abiMethod,
|
||||||
long abiVersion,
|
long abiVersion,
|
||||||
int retSlots,
|
int retSlots,
|
||||||
|
Integer assetLoweringParam,
|
||||||
boolean capabilityDeclared,
|
boolean capabilityDeclared,
|
||||||
String requiredCapability,
|
String requiredCapability,
|
||||||
Span span) {
|
Span span) {
|
||||||
@ -44,6 +45,9 @@ public record IRReservedMetadata(
|
|||||||
if (retSlots < 0) {
|
if (retSlots < 0) {
|
||||||
throw new IllegalArgumentException("host retSlots must be non-negative");
|
throw new IllegalArgumentException("host retSlots must be non-negative");
|
||||||
}
|
}
|
||||||
|
if (assetLoweringParam != null && assetLoweringParam < 0) {
|
||||||
|
throw new IllegalArgumentException("assetLoweringParam must be non-negative");
|
||||||
|
}
|
||||||
requiredCapability = requiredCapability == null ? "" : requiredCapability;
|
requiredCapability = requiredCapability == null ? "" : requiredCapability;
|
||||||
span = Objects.requireNonNull(span, "span");
|
span = Objects.requireNonNull(span, "span");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user