implements PLN-0007
This commit is contained in:
parent
4a6cc35989
commit
d28916578b
@ -4,6 +4,6 @@
|
|||||||
{"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":"review","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"]}],"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"}]}
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
id: PLN-0007
|
id: PLN-0007
|
||||||
ticket: pbs-game-facing-asset-refs-and-call-result-discard
|
ticket: pbs-game-facing-asset-refs-and-call-result-discard
|
||||||
title: Implement DEC-0006 Ignored Values Lowering and Warning
|
title: Implement DEC-0006 Ignored Values Lowering and Warning
|
||||||
status: review
|
status: done
|
||||||
created: 2026-03-27
|
created: 2026-03-27
|
||||||
completed:
|
completed: 2026-03-27
|
||||||
tags: [compiler, pbs, implementation, diagnostics, lowering, expression-statements, warnings]
|
tags: [compiler, pbs, implementation, diagnostics, lowering, expression-statements, warnings]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -203,6 +203,9 @@ At minimum, the PBS diagnostics baseline must cover:
|
|||||||
- unresolved terminal asset reference,
|
- unresolved terminal asset reference,
|
||||||
- namespace-versus-terminal asset misuse,
|
- namespace-versus-terminal asset misuse,
|
||||||
- structurally invalid symbolic asset path admitted by source syntax but rejected by semantic surface rules.
|
- structurally invalid symbolic asset path admitted by source syntax but rejected by semantic surface rules.
|
||||||
|
10. ignored-value diagnostics for expression statements, including:
|
||||||
|
- a stable warning when a materialized value is produced and then ignored,
|
||||||
|
- and no warning for unit-like expression statements.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@ -229,7 +232,9 @@ When failures exist, implementations must still preserve deterministic diagnosti
|
|||||||
|
|
||||||
## 11. Cost Diagnostics and Warning Policy
|
## 11. Cost Diagnostics and Warning Policy
|
||||||
|
|
||||||
Warnings are supported and recommended in v1, but they are not part of the minimum mandatory conformance baseline.
|
Warnings are supported in v1, and one warning is mandatory for PBS core: ignored materialized values in expression statements.
|
||||||
|
|
||||||
|
The mandatory warning identity for this rule is `W_SEM_IGNORED_VALUE`.
|
||||||
|
|
||||||
Tooling may surface qualitative cost facts as warnings or notes, especially for:
|
Tooling may surface qualitative cost facts as warnings or notes, especially for:
|
||||||
|
|
||||||
|
|||||||
@ -188,6 +188,12 @@ When a host-backed callsite also depends on backend-owned symbolic asset lowerin
|
|||||||
- 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.
|
||||||
|
|
||||||
|
When an expression statement leaves a materialized runtime value on the stack:
|
||||||
|
|
||||||
|
- `IRBackend` lowering MUST emit explicit discard behavior rather than relying on implicit backend stack cleanup;
|
||||||
|
- for single-slot materialized values this discard is represented by `POP`;
|
||||||
|
- and the discard path MUST preserve stack-accounting validity for subsequent backend lowering stages.
|
||||||
|
|
||||||
### 12.4 VM-owned metadata obligations
|
### 12.4 VM-owned metadata obligations
|
||||||
|
|
||||||
VM-owned intrinsic callsites admitted at this boundary must preserve canonical intrinsic identity:
|
VM-owned intrinsic callsites admitted at this boundary must preserve canonical intrinsic identity:
|
||||||
|
|||||||
@ -238,6 +238,9 @@ Rules:
|
|||||||
- Symbolic asset references admitted by the frontend MUST resolve against the backend-provided `Addressable` surface rather than by direct packer queries.
|
- Symbolic asset references admitted by the frontend MUST resolve against the backend-provided `Addressable` surface rather than by direct packer queries.
|
||||||
- A valid symbolic asset reference MUST correspond to a terminal `Addressable` entry in the backend-provided surface.
|
- A valid symbolic asset reference MUST correspond to a terminal `Addressable` entry in the backend-provided surface.
|
||||||
- Intermediate `assets...` namespace nodes MUST NOT type-check as `Addressable` values.
|
- Intermediate `assets...` namespace nodes MUST NOT type-check as `Addressable` values.
|
||||||
|
- An expression statement MAY evaluate an expression that has a materialized value type.
|
||||||
|
- When an expression statement ignores a materialized value, PBS v1 MUST emit the ignored-value warning defined by the diagnostics specification.
|
||||||
|
- Unit-like expression statements MUST NOT emit the ignored-value warning.
|
||||||
|
|
||||||
### 3.4 Constant expressions
|
### 3.4 Constant expressions
|
||||||
|
|
||||||
|
|||||||
@ -143,6 +143,7 @@ final class PbsExecutableBodyLowerer {
|
|||||||
case PbsAst.WhileStatement whileStatement -> lowerWhileStatement(whileStatement, context);
|
case PbsAst.WhileStatement whileStatement -> lowerWhileStatement(whileStatement, context);
|
||||||
case PbsAst.ExpressionStatement expressionStatement -> {
|
case PbsAst.ExpressionStatement expressionStatement -> {
|
||||||
lowerExpression(expressionStatement.expression(), context);
|
lowerExpression(expressionStatement.expression(), context);
|
||||||
|
discardIgnoredValueSlots(expressionStatement.expression(), context);
|
||||||
yield false;
|
yield false;
|
||||||
}
|
}
|
||||||
case PbsAst.BreakStatement breakStatement -> lowerBreakStatement(breakStatement, context);
|
case PbsAst.BreakStatement breakStatement -> lowerBreakStatement(breakStatement, context);
|
||||||
@ -426,6 +427,21 @@ final class PbsExecutableBodyLowerer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void discardIgnoredValueSlots(
|
||||||
|
final PbsAst.Expression expression,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var slots = materializedValueSlots(expression, context);
|
||||||
|
for (int i = 0; i < slots; i++) {
|
||||||
|
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.POP,
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
expression == null ? p.studio.compiler.source.Span.none() : expression.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void lowerMemberExpression(
|
private void lowerMemberExpression(
|
||||||
final PbsAst.MemberExpr memberExpr,
|
final PbsAst.MemberExpr memberExpr,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
@ -508,6 +524,92 @@ final class PbsExecutableBodyLowerer {
|
|||||||
return receiverPath + "." + memberExpr.memberName();
|
return receiverPath + "." + memberExpr.memberName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int materializedValueSlots(
|
||||||
|
final PbsAst.Expression expression,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
if (expression == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return switch (expression) {
|
||||||
|
case PbsAst.CallExpr callExpr -> callsiteEmitter.returnSlotsOf(callExpr, context);
|
||||||
|
case PbsAst.ApplyExpr ignored -> 0;
|
||||||
|
case PbsAst.BinaryExpr ignored -> 1;
|
||||||
|
case PbsAst.UnaryExpr ignored -> 1;
|
||||||
|
case PbsAst.ElseExpr elseExpr ->
|
||||||
|
Math.max(
|
||||||
|
materializedValueSlots(elseExpr.optionalExpression(), context),
|
||||||
|
materializedValueSlots(elseExpr.fallbackExpression(), context));
|
||||||
|
case PbsAst.IfExpr ifExpr ->
|
||||||
|
Math.max(
|
||||||
|
blockValueSlots(ifExpr.thenBlock(), context),
|
||||||
|
materializedValueSlots(ifExpr.elseExpression(), context));
|
||||||
|
case PbsAst.SwitchExpr ignored -> 0;
|
||||||
|
case PbsAst.HandleExpr ignored -> 0;
|
||||||
|
case PbsAst.AsExpr asExpr -> materializedValueSlots(asExpr.expression(), context);
|
||||||
|
case PbsAst.MemberExpr memberExpr -> {
|
||||||
|
final var assetReference = flattenAssetReference(memberExpr);
|
||||||
|
if (assetReference != null && context.resolveAssetId(assetReference) != null) {
|
||||||
|
yield 1;
|
||||||
|
}
|
||||||
|
yield materializedValueSlots(memberExpr.receiver(), context);
|
||||||
|
}
|
||||||
|
case PbsAst.PropagateExpr propagateExpr -> materializedValueSlots(propagateExpr.expression(), context);
|
||||||
|
case PbsAst.GroupExpr groupExpr -> materializedValueSlots(groupExpr.expression(), context);
|
||||||
|
case PbsAst.NewExpr newExpr -> expressionListValueSlots(newExpr.arguments(), context);
|
||||||
|
case PbsAst.BindExpr bindExpr -> materializedValueSlots(bindExpr.contextExpression(), context);
|
||||||
|
case PbsAst.SomeExpr someExpr -> materializedValueSlots(someExpr.value(), context);
|
||||||
|
case PbsAst.OkExpr okExpr -> materializedValueSlots(okExpr.value(), context);
|
||||||
|
case PbsAst.TupleExpr tupleExpr -> {
|
||||||
|
var slots = 0;
|
||||||
|
for (final var item : tupleExpr.items()) {
|
||||||
|
slots += materializedValueSlots(item.expression(), context);
|
||||||
|
}
|
||||||
|
yield slots;
|
||||||
|
}
|
||||||
|
case PbsAst.BlockExpr blockExpr -> blockValueSlots(blockExpr.block(), context);
|
||||||
|
case PbsAst.IdentifierExpr identifierExpr -> producesIdentifierValue(identifierExpr, context) ? 1 : 0;
|
||||||
|
case PbsAst.IntLiteralExpr ignored -> 1;
|
||||||
|
case PbsAst.StringLiteralExpr ignoredString -> 1;
|
||||||
|
case PbsAst.BoolLiteralExpr ignoredBool -> 1;
|
||||||
|
case PbsAst.FloatLiteralExpr ignoredFloat -> 0;
|
||||||
|
case PbsAst.BoundedLiteralExpr ignoredBounded -> 0;
|
||||||
|
case PbsAst.ThisExpr ignoredThis -> 0;
|
||||||
|
case PbsAst.NoneExpr ignoredNone -> 0;
|
||||||
|
case PbsAst.ErrExpr ignoredErr -> 0;
|
||||||
|
case PbsAst.UnitExpr ignoredUnit -> 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int blockValueSlots(
|
||||||
|
final PbsAst.Block block,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
if (block == null || block.tailExpression() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return materializedValueSlots(block.tailExpression(), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int expressionListValueSlots(
|
||||||
|
final ReadOnlyList<PbsAst.Expression> expressions,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
var slots = 0;
|
||||||
|
for (final var expression : expressions) {
|
||||||
|
slots += materializedValueSlots(expression, context);
|
||||||
|
}
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean producesIdentifierValue(
|
||||||
|
final PbsAst.IdentifierExpr identifierExpr,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
if ("assets".equals(identifierExpr.name())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return context.resolveLocalSlot(identifierExpr.name()) != null
|
||||||
|
|| context.resolveGlobalSlot(identifierExpr.name()) != null
|
||||||
|
|| context.resolveConstDecl(identifierExpr.name()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
private void lowerConstExpression(
|
private void lowerConstExpression(
|
||||||
final PbsAst.Expression expression,
|
final PbsAst.Expression expression,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
|
|||||||
@ -16,6 +16,29 @@ 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 {
|
||||||
|
int returnSlotsOf(
|
||||||
|
final PbsAst.CallExpr callExpr,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var calleeIdentity = resolveCalleeIdentity(callExpr.callee(), context.nameTable());
|
||||||
|
if (calleeIdentity == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
final var candidates = resolveCallsiteCandidates(callExpr, calleeIdentity, context);
|
||||||
|
final var resolvedCategory = resolveCallsiteCategory(candidates, callExpr, context);
|
||||||
|
if (resolvedCategory == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return switch (resolvedCategory) {
|
||||||
|
case HOST -> candidates.hostCandidates().getFirst().retSlots();
|
||||||
|
case INTRINSIC -> candidates.intrinsicCandidates().getFirst().retSlots();
|
||||||
|
case CALLABLE -> {
|
||||||
|
if (candidates.callableCandidates().size() != 1) {
|
||||||
|
yield 0;
|
||||||
|
}
|
||||||
|
yield context.returnSlotsByCallableId().getOrDefault(candidates.callableCandidates().getFirst(), 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void emitCallsite(
|
void emitCallsite(
|
||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
|
|||||||
@ -172,7 +172,7 @@ final class PbsFlowStatementAnalyzer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (statement instanceof PbsAst.ExpressionStatement expressionStatement) {
|
if (statement instanceof PbsAst.ExpressionStatement expressionStatement) {
|
||||||
expressionAnalyzer.analyzeExpression(
|
final var expressionType = expressionAnalyzer.analyzeExpression(
|
||||||
expressionStatement.expression(),
|
expressionStatement.expression(),
|
||||||
scope,
|
scope,
|
||||||
null,
|
null,
|
||||||
@ -183,7 +183,13 @@ final class PbsFlowStatementAnalyzer {
|
|||||||
diagnostics,
|
diagnostics,
|
||||||
ExprUse.VALUE,
|
ExprUse.VALUE,
|
||||||
false,
|
false,
|
||||||
this::analyzeNestedBlock);
|
this::analyzeNestedBlock).type();
|
||||||
|
if (typeOps.isMaterializedValue(expressionType)) {
|
||||||
|
Diagnostics.warning(diagnostics,
|
||||||
|
PbsSemanticsErrors.W_SEM_IGNORED_VALUE.name(),
|
||||||
|
"Ignored materialized value in expression statement",
|
||||||
|
expressionStatement.span());
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (statement instanceof PbsAst.AssignStatement assignStatement) {
|
if (statement instanceof PbsAst.AssignStatement assignStatement) {
|
||||||
|
|||||||
@ -139,6 +139,16 @@ final class PbsFlowTypeOps {
|
|||||||
return type.kind() == Kind.STR || type.kind() == Kind.UNKNOWN;
|
return type.kind() == Kind.STR || type.kind() == Kind.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isMaterializedValue(final TypeView type) {
|
||||||
|
if (type == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return switch (type.kind()) {
|
||||||
|
case UNKNOWN, UNIT, ASSET_NAMESPACE -> false;
|
||||||
|
default -> true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private boolean tupleCompatible(final TypeView actual, final TypeView expected) {
|
private boolean tupleCompatible(final TypeView actual, final TypeView expected) {
|
||||||
if (actual.tupleFields().size() != expected.tupleFields().size()) {
|
if (actual.tupleFields().size() != expected.tupleFields().size()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -69,4 +69,5 @@ public enum PbsSemanticsErrors {
|
|||||||
E_SEM_HANDLE_ERROR_MISMATCH,
|
E_SEM_HANDLE_ERROR_MISMATCH,
|
||||||
E_SEM_HANDLE_ARM_TERMINAL_INVALID,
|
E_SEM_HANDLE_ARM_TERMINAL_INVALID,
|
||||||
E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE,
|
E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE,
|
||||||
|
W_SEM_IGNORED_VALUE,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ 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.diagnostics.Severity;
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
@ -52,6 +53,28 @@ class PbsDiagnosticsContractTest {
|
|||||||
assertEquals(DiagnosticPhase.STATIC_SEMANTICS, diagnostic.getPhase());
|
assertEquals(DiagnosticPhase.STATIC_SEMANTICS, diagnostic.getPhase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldTagIgnoredValueWarningsWithStaticSemanticsPhase() {
|
||||||
|
final var source = """
|
||||||
|
fn pure() -> int { return 1; }
|
||||||
|
fn frame() -> void {
|
||||||
|
pure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(11), source, diagnostics);
|
||||||
|
|
||||||
|
final var diagnostic = diagnostics.stream()
|
||||||
|
.filter(d -> d.getCode().equals(PbsSemanticsErrors.W_SEM_IGNORED_VALUE.name()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
assertEquals(DiagnosticPhase.STATIC_SEMANTICS, diagnostic.getPhase());
|
||||||
|
assertEquals(Severity.Warning, diagnostic.getSeverity());
|
||||||
|
assertEquals(diagnostic.getCode(), diagnostic.getTemplateId());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldTagLinkingDiagnosticsAndExposeRelatedSpanForDuplicateBarrelEntry() {
|
void shouldTagLinkingDiagnosticsAndExposeRelatedSpanForDuplicateBarrelEntry() {
|
||||||
final var diagnostics = DiagnosticSink.empty();
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|||||||
@ -288,13 +288,17 @@ class PbsFrontendCompilerTest {
|
|||||||
final var compiler = new PbsFrontendCompiler();
|
final var compiler = new PbsFrontendCompiler();
|
||||||
final var fileBackend = compiler.compileFile(new FileId(99), source, diagnostics);
|
final var fileBackend = compiler.compileFile(new FileId(99), source, diagnostics);
|
||||||
|
|
||||||
assertTrue(diagnostics.isEmpty(), "Valid program should not report diagnostics");
|
assertEquals(0, diagnostics.errorCount(), "Valid program should not report errors");
|
||||||
|
assertEquals(2, diagnostics.warningCount());
|
||||||
final var executableA = fileBackend.executableFunctions().stream()
|
final var executableA = fileBackend.executableFunctions().stream()
|
||||||
.filter(fn -> fn.callableName().equals("a"))
|
.filter(fn -> fn.callableName().equals("a"))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
assertEquals("b", executableA.instructions().get(0).calleeCallableName());
|
final var callNames = executableA.instructions().stream()
|
||||||
assertEquals("c", executableA.instructions().get(1).calleeCallableName());
|
.filter(i -> i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
|
||||||
|
.map(p.studio.compiler.models.IRBackendExecutableFunction.Instruction::calleeCallableName)
|
||||||
|
.toList();
|
||||||
|
assertEquals(java.util.List.of("b", "c"), callNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -312,7 +316,8 @@ class PbsFrontendCompilerTest {
|
|||||||
final var compiler = new PbsFrontendCompiler();
|
final var compiler = new PbsFrontendCompiler();
|
||||||
final var fileBackend = compiler.compileFile(new FileId(100), source, diagnostics);
|
final var fileBackend = compiler.compileFile(new FileId(100), source, diagnostics);
|
||||||
|
|
||||||
assertTrue(diagnostics.isEmpty(), "Valid program should not report diagnostics");
|
assertEquals(0, diagnostics.errorCount(), "Valid program should not report errors");
|
||||||
|
assertEquals(1, diagnostics.warningCount());
|
||||||
final var executableMain = fileBackend.executableFunctions().stream()
|
final var executableMain = fileBackend.executableFunctions().stream()
|
||||||
.filter(fn -> fn.callableName().equals("main"))
|
.filter(fn -> fn.callableName().equals("main"))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -512,6 +517,61 @@ class PbsFrontendCompilerTest {
|
|||||||
assertEquals(0, fileBackend.executableFunctions().size());
|
assertEquals(0, fileBackend.executableFunctions().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldWarnAndDiscardIgnoredMaterializedExpressionStatements() {
|
||||||
|
final var source = """
|
||||||
|
fn pure() -> int { return 1; }
|
||||||
|
|
||||||
|
fn frame() -> void {
|
||||||
|
pure();
|
||||||
|
1 + 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
final var compiler = new PbsFrontendCompiler();
|
||||||
|
final var fileBackend = compiler.compileFile(new FileId(14), source, diagnostics);
|
||||||
|
|
||||||
|
assertEquals(2, diagnostics.warningCount());
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.W_SEM_IGNORED_VALUE.name())));
|
||||||
|
final var executableFrame = fileBackend.executableFunctions().stream()
|
||||||
|
.filter(fn -> fn.callableName().equals("frame"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
assertTrue(executableFrame.instructions().stream().anyMatch(i ->
|
||||||
|
i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC));
|
||||||
|
assertEquals(2, executableFrame.instructions().stream()
|
||||||
|
.filter(i -> i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.POP)
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotWarnOrDiscardUnitExpressionStatements() {
|
||||||
|
final var source = """
|
||||||
|
fn log() -> void { return; }
|
||||||
|
|
||||||
|
fn frame() -> void {
|
||||||
|
log();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
final var compiler = new PbsFrontendCompiler();
|
||||||
|
final var fileBackend = compiler.compileFile(new FileId(15), source, diagnostics);
|
||||||
|
|
||||||
|
assertEquals(0, diagnostics.warningCount());
|
||||||
|
final var executableFrame = fileBackend.executableFunctions().stream()
|
||||||
|
.filter(fn -> fn.callableName().equals("frame"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
assertEquals(0, executableFrame.instructions().stream()
|
||||||
|
.filter(i -> i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.POP)
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRejectHostBindingWithoutCapabilityAtHostAdmission() {
|
void shouldRejectHostBindingWithoutCapabilityAtHostAdmission() {
|
||||||
final var source = """
|
final var source = """
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
package p.studio.compiler.pbs.semantics;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class PbsIgnoredValueSemanticsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldWarnWhenExpressionStatementIgnoresMaterializedValue() {
|
||||||
|
final var source = """
|
||||||
|
fn pure() -> int { return 1; }
|
||||||
|
|
||||||
|
fn frame() -> void {
|
||||||
|
pure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
assertEquals(1, diagnostics.warningCount());
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.W_SEM_IGNORED_VALUE.name())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotWarnWhenExpressionStatementIsUnitLike() {
|
||||||
|
final var source = """
|
||||||
|
fn log() -> void { return; }
|
||||||
|
|
||||||
|
fn frame() -> void {
|
||||||
|
log();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(1), source, diagnostics);
|
||||||
|
|
||||||
|
assertEquals(0, diagnostics.warningCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -87,7 +87,8 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
LogAggregator.empty(),
|
LogAggregator.empty(),
|
||||||
BuildingIssueSink.empty());
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
assertEquals(0, diagnostics.errorCount(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||||
|
assertEquals(0, diagnostics.warningCount());
|
||||||
final var frameFn = irBackend.getExecutableFunctions().stream()
|
final var frameFn = irBackend.getExecutableFunctions().stream()
|
||||||
.filter(function -> "frame".equals(function.callableName()))
|
.filter(function -> "frame".equals(function.callableName()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -97,6 +98,62 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
&& "91".equals(instruction.label())));
|
&& "91".equals(instruction.label())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldKeepWarningsNonBlockingWhileLoweringExplicitDiscard() throws IOException {
|
||||||
|
final var projectRoot = tempDir.resolve("project-ignored-values");
|
||||||
|
final var sourceRoot = projectRoot.resolve("src");
|
||||||
|
final var modulePath = sourceRoot.resolve("main");
|
||||||
|
Files.createDirectories(modulePath);
|
||||||
|
|
||||||
|
final var sourceFile = modulePath.resolve("source.pbs");
|
||||||
|
final var modBarrel = modulePath.resolve("mod.barrel");
|
||||||
|
Files.writeString(sourceFile, """
|
||||||
|
fn pure() -> int { return 1; }
|
||||||
|
|
||||||
|
[Frame]
|
||||||
|
fn frame() -> void {
|
||||||
|
pure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
Files.writeString(modBarrel, "pub fn frame() -> void;");
|
||||||
|
|
||||||
|
final var projectTable = new ProjectTable();
|
||||||
|
final var fileTable = new FileTable(1);
|
||||||
|
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||||
|
.rootPath(projectRoot)
|
||||||
|
.name("core")
|
||||||
|
.version("1.0.0")
|
||||||
|
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||||
|
registerFile(projectId, projectRoot, modBarrel, fileTable);
|
||||||
|
|
||||||
|
final var ctx = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
new BuildStack(ReadOnlyList.wrap(List.of(projectId))));
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
final var irBackend = new PBSFrontendPhaseService().compile(
|
||||||
|
ctx,
|
||||||
|
diagnostics,
|
||||||
|
LogAggregator.empty(),
|
||||||
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
|
assertEquals(1, diagnostics.warningCount());
|
||||||
|
assertEquals(0, diagnostics.errorCount());
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.W_SEM_IGNORED_VALUE.name())));
|
||||||
|
final var frameFn = irBackend.getExecutableFunctions().stream()
|
||||||
|
.filter(function -> "frame".equals(function.callableName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
assertTrue(frameFn.instructions().stream().anyMatch(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.POP));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldReportInvalidBarrelFilename() throws IOException {
|
void shouldReportInvalidBarrelFilename() throws IOException {
|
||||||
final var projectRoot = tempDir.resolve("project");
|
final var projectRoot = tempDir.resolve("project");
|
||||||
@ -259,7 +316,8 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
LogAggregator.empty(),
|
LogAggregator.empty(),
|
||||||
BuildingIssueSink.empty());
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
assertEquals(0, diagnostics.errorCount(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||||
|
assertEquals(1, diagnostics.warningCount());
|
||||||
|
|
||||||
final var targetFn = irBackend.getExecutableFunctions().stream()
|
final var targetFn = irBackend.getExecutableFunctions().stream()
|
||||||
.filter(function -> "target".equals(function.callableName()))
|
.filter(function -> "target".equals(function.callableName()))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user