implements PR015
This commit is contained in:
parent
4f32913577
commit
8d8c3dc180
@ -1,44 +0,0 @@
|
|||||||
# PR-013 - PBS Unresolved Import Diagnostics
|
|
||||||
|
|
||||||
## Briefing
|
|
||||||
|
|
||||||
Import resolution currently ignores missing target modules in frontend linking validation. This PR enforces deterministic diagnostics for unresolved module imports and unresolved imported symbols.
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
Silent import misses break the diagnostics contract and defer user-actionable errors.
|
|
||||||
|
|
||||||
## Target
|
|
||||||
|
|
||||||
- Module import validation in `PbsModuleVisibilityValidator`.
|
|
||||||
- Linking diagnostic coverage for import failures.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Emit errors for missing target module references.
|
|
||||||
- Keep existing public-symbol checks.
|
|
||||||
- Preserve deterministic, source-first attribution.
|
|
||||||
|
|
||||||
## Method
|
|
||||||
|
|
||||||
- Extend import validation to detect absent target modules.
|
|
||||||
- Report diagnostics on the importing site.
|
|
||||||
- Keep related-span behavior where applicable.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- Importing a non-existent module always emits deterministic linking/import diagnostic.
|
|
||||||
- Importing a non-public symbol still emits existing diagnostic.
|
|
||||||
- Diagnostic attribution points to import site.
|
|
||||||
- No silent pass for unresolved imports remains.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
- Add tests for missing module import.
|
|
||||||
- Add tests for missing symbol import in existing module.
|
|
||||||
- Verify phase and diagnostic code stability.
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- Full manifest/dependency resolver redesign.
|
|
||||||
- Loader/runtime capability checks.
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
# PR-014 - PBS Switch Wildcard Rule Enforcement
|
|
||||||
|
|
||||||
## Briefing
|
|
||||||
|
|
||||||
Switch semantics do not currently enforce all wildcard constraints. This PR enforces: at most one wildcard arm, and rejection of mixed `default` and `_` in the same switch.
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
Wildcard ambiguity weakens deterministic static semantics and conformance.
|
|
||||||
|
|
||||||
## Target
|
|
||||||
|
|
||||||
- Switch expression semantic validation in flow analyzer.
|
|
||||||
- Required static diagnostics for wildcard rule violations.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Enforce wildcard-count and wildcard-mixing rules.
|
|
||||||
- Preserve existing selector/type compatibility checks.
|
|
||||||
|
|
||||||
## Method
|
|
||||||
|
|
||||||
- Track wildcard token form used per switch arm.
|
|
||||||
- Emit diagnostics for duplicate wildcard and mixed wildcard spellings.
|
|
||||||
- Keep existing exhaustiveness behavior.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- Two wildcard arms are rejected deterministically.
|
|
||||||
- `default` + `_` in one switch is rejected deterministically.
|
|
||||||
- Existing duplicate-pattern logic for non-wildcards remains unchanged.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
- Add tests for duplicate wildcard arms.
|
|
||||||
- Add tests for mixed `default`/`_` arms.
|
|
||||||
- Run semantic control-flow suite.
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- New switch syntax.
|
|
||||||
- Runtime switch lowering changes.
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
# PR-015 - PBS this/Self Context Validation
|
|
||||||
|
|
||||||
## Briefing
|
|
||||||
|
|
||||||
The frontend accepts `this` and `Self` outside allowed contexts without required diagnostics. This PR adds explicit static checks for invalid usage.
|
|
||||||
|
|
||||||
## Motivation
|
|
||||||
|
|
||||||
Context-free acceptance of `this`/`Self` is non-conformant and creates type ambiguity.
|
|
||||||
|
|
||||||
## Target
|
|
||||||
|
|
||||||
- `this` expression analysis.
|
|
||||||
- `Self` type-surface analysis in declarations.
|
|
||||||
- Error catalog and deterministic diagnostics.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
- Reject `this` outside struct method, service method, and ctor bodies.
|
|
||||||
- Reject `Self` outside struct/service method declarations and ctors.
|
|
||||||
|
|
||||||
## Method
|
|
||||||
|
|
||||||
- Add callable-context metadata into flow/type validation.
|
|
||||||
- Emit dedicated diagnostics for invalid `this` and invalid `Self` usage.
|
|
||||||
- Keep valid owner contexts unchanged.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
- Invalid `this` usage emits deterministic static diagnostic.
|
|
||||||
- Invalid `Self` usage emits deterministic static diagnostic.
|
|
||||||
- Valid struct/service/ctor contexts remain accepted.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
- Add positive tests for valid `this`/`Self` contexts.
|
|
||||||
- Add negative tests for top-level functions and unrelated declarations.
|
|
||||||
- Run declaration + flow semantic suites.
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
- Introducing new receiver features.
|
|
||||||
- Altering `Self` syntax.
|
|
||||||
@ -29,12 +29,20 @@ final class PbsDeclarationRuleValidator {
|
|||||||
final PbsAst.ReturnKind returnKind,
|
final PbsAst.ReturnKind returnKind,
|
||||||
final PbsAst.TypeRef returnType,
|
final PbsAst.TypeRef returnType,
|
||||||
final PbsAst.TypeRef resultErrorType,
|
final PbsAst.TypeRef resultErrorType,
|
||||||
final Span span) {
|
final Span span,
|
||||||
|
final boolean allowSelf) {
|
||||||
validateParameters(parameters, "callable '%s'".formatted(callableName));
|
validateParameters(parameters, "callable '%s'".formatted(callableName));
|
||||||
validateReturnSurface(returnKind, returnType, resultErrorType, "callable '%s'".formatted(callableName), span);
|
validateReturnSurface(
|
||||||
|
returnKind,
|
||||||
|
returnType,
|
||||||
|
resultErrorType,
|
||||||
|
"callable '%s'".formatted(callableName),
|
||||||
|
span,
|
||||||
|
allowSelf);
|
||||||
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(
|
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(
|
||||||
parameters.stream().map(PbsAst.Parameter::typeRef).toList(),
|
parameters.stream().map(PbsAst.Parameter::typeRef).toList(),
|
||||||
"callable '%s'".formatted(callableName),
|
"callable '%s'".formatted(callableName),
|
||||||
|
allowSelf,
|
||||||
diagnostics);
|
diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +66,9 @@ final class PbsDeclarationRuleValidator {
|
|||||||
|
|
||||||
void validateTypeSurfaces(
|
void validateTypeSurfaces(
|
||||||
final List<PbsAst.TypeRef> typeRoots,
|
final List<PbsAst.TypeRef> typeRoots,
|
||||||
final String ownerDescription) {
|
final String ownerDescription,
|
||||||
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(typeRoots, ownerDescription, diagnostics);
|
final boolean allowSelf) {
|
||||||
|
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(typeRoots, ownerDescription, allowSelf, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void validateErrorDeclaration(final PbsAst.ErrorDecl errorDecl) {
|
void validateErrorDeclaration(final PbsAst.ErrorDecl errorDecl) {
|
||||||
@ -114,10 +123,12 @@ final class PbsDeclarationRuleValidator {
|
|||||||
callbackDecl.returnType(),
|
callbackDecl.returnType(),
|
||||||
callbackDecl.resultErrorType(),
|
callbackDecl.resultErrorType(),
|
||||||
"callback '%s'".formatted(callbackDecl.name()),
|
"callback '%s'".formatted(callbackDecl.name()),
|
||||||
callbackDecl.span());
|
callbackDecl.span(),
|
||||||
|
false);
|
||||||
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(
|
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(
|
||||||
callbackDecl.parameters().stream().map(PbsAst.Parameter::typeRef).toList(),
|
callbackDecl.parameters().stream().map(PbsAst.Parameter::typeRef).toList(),
|
||||||
"callback '%s'".formatted(callbackDecl.name()),
|
"callback '%s'".formatted(callbackDecl.name()),
|
||||||
|
false,
|
||||||
diagnostics);
|
diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +142,7 @@ final class PbsDeclarationRuleValidator {
|
|||||||
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(
|
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(
|
||||||
List.of(constDecl.explicitType()),
|
List.of(constDecl.explicitType()),
|
||||||
"const '%s'".formatted(constDecl.name()),
|
"const '%s'".formatted(constDecl.name()),
|
||||||
|
false,
|
||||||
diagnostics);
|
diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +159,8 @@ final class PbsDeclarationRuleValidator {
|
|||||||
final PbsAst.TypeRef returnType,
|
final PbsAst.TypeRef returnType,
|
||||||
final PbsAst.TypeRef resultErrorType,
|
final PbsAst.TypeRef resultErrorType,
|
||||||
final String ownerDescription,
|
final String ownerDescription,
|
||||||
final Span span) {
|
final Span span,
|
||||||
|
final boolean allowSelf) {
|
||||||
if (returnKind == PbsAst.ReturnKind.RESULT && PbsTypeSurfaceSemanticsValidator.isOptionalType(returnType)) {
|
if (returnKind == PbsAst.ReturnKind.RESULT && PbsTypeSurfaceSemanticsValidator.isOptionalType(returnType)) {
|
||||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||||
PbsSemanticsErrors.E_SEM_INVALID_MIXED_OPTIONAL_RESULT_RETURN.name(),
|
PbsSemanticsErrors.E_SEM_INVALID_MIXED_OPTIONAL_RESULT_RETURN.name(),
|
||||||
@ -160,10 +173,10 @@ final class PbsDeclarationRuleValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(List.of(returnType), ownerDescription, diagnostics);
|
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(List.of(returnType), ownerDescription, allowSelf, diagnostics);
|
||||||
}
|
}
|
||||||
if (resultErrorType != null) {
|
if (resultErrorType != null) {
|
||||||
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(List.of(resultErrorType), ownerDescription, diagnostics);
|
PbsTypeSurfaceSemanticsValidator.validateTypeSurfaceRecursive(List.of(resultErrorType), ownerDescription, allowSelf, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
functionDecl.returnType(),
|
functionDecl.returnType(),
|
||||||
functionDecl.resultErrorType(),
|
functionDecl.resultErrorType(),
|
||||||
functionDecl.span(),
|
functionDecl.span(),
|
||||||
|
false,
|
||||||
binder,
|
binder,
|
||||||
rules);
|
rules);
|
||||||
continue;
|
continue;
|
||||||
@ -83,6 +84,10 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
final PbsDeclarationRuleValidator rules,
|
final PbsDeclarationRuleValidator rules,
|
||||||
final DiagnosticSink diagnostics) {
|
final DiagnosticSink diagnostics) {
|
||||||
final var ownerNameId = nameTable.register(structDecl.name());
|
final var ownerNameId = nameTable.register(structDecl.name());
|
||||||
|
rules.validateTypeSurfaces(
|
||||||
|
structDecl.fields().stream().map(PbsAst.StructField::typeRef).toList(),
|
||||||
|
"struct '%s'".formatted(structDecl.name()),
|
||||||
|
false);
|
||||||
final var methodScope = PbsCallableScope.structMethods(ownerNameId);
|
final var methodScope = PbsCallableScope.structMethods(ownerNameId);
|
||||||
for (final var method : structDecl.methods()) {
|
for (final var method : structDecl.methods()) {
|
||||||
validateCallable(
|
validateCallable(
|
||||||
@ -93,6 +98,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
method.returnType(),
|
method.returnType(),
|
||||||
method.resultErrorType(),
|
method.resultErrorType(),
|
||||||
method.span(),
|
method.span(),
|
||||||
|
true,
|
||||||
binder,
|
binder,
|
||||||
rules);
|
rules);
|
||||||
}
|
}
|
||||||
@ -102,7 +108,8 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
rules.validateParameters(ctor.parameters(), "ctor '%s'".formatted(ctor.name()));
|
rules.validateParameters(ctor.parameters(), "ctor '%s'".formatted(ctor.name()));
|
||||||
rules.validateTypeSurfaces(
|
rules.validateTypeSurfaces(
|
||||||
ctor.parameters().stream().map(PbsAst.Parameter::typeRef).toList(),
|
ctor.parameters().stream().map(PbsAst.Parameter::typeRef).toList(),
|
||||||
"ctor '%s'".formatted(ctor.name()));
|
"ctor '%s'".formatted(ctor.name()),
|
||||||
|
true);
|
||||||
|
|
||||||
binder.registerCtor(ctorScope, ctor.name(), PbsCallableShape.ctorShapeKey(ctor.parameters()), ctor.span());
|
binder.registerCtor(ctorScope, ctor.name(), PbsCallableShape.ctorShapeKey(ctor.parameters()), ctor.span());
|
||||||
if (PbsCtorReturnScanner.containsReturnStatement(ctor.body())) {
|
if (PbsCtorReturnScanner.containsReturnStatement(ctor.body())) {
|
||||||
@ -128,6 +135,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
method.returnType(),
|
method.returnType(),
|
||||||
method.resultErrorType(),
|
method.resultErrorType(),
|
||||||
method.span(),
|
method.span(),
|
||||||
|
true,
|
||||||
binder,
|
binder,
|
||||||
rules);
|
rules);
|
||||||
}
|
}
|
||||||
@ -147,6 +155,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
signature.returnType(),
|
signature.returnType(),
|
||||||
signature.resultErrorType(),
|
signature.resultErrorType(),
|
||||||
signature.span(),
|
signature.span(),
|
||||||
|
false,
|
||||||
binder,
|
binder,
|
||||||
rules);
|
rules);
|
||||||
}
|
}
|
||||||
@ -167,6 +176,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
method.returnType(),
|
method.returnType(),
|
||||||
method.resultErrorType(),
|
method.resultErrorType(),
|
||||||
method.span(),
|
method.span(),
|
||||||
|
false,
|
||||||
binder,
|
binder,
|
||||||
rules);
|
rules);
|
||||||
}
|
}
|
||||||
@ -180,9 +190,10 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
final PbsAst.TypeRef returnType,
|
final PbsAst.TypeRef returnType,
|
||||||
final PbsAst.TypeRef resultErrorType,
|
final PbsAst.TypeRef resultErrorType,
|
||||||
final Span span,
|
final Span span,
|
||||||
|
final boolean allowSelf,
|
||||||
final PbsNamespaceBinder binder,
|
final PbsNamespaceBinder binder,
|
||||||
final PbsDeclarationRuleValidator rules) {
|
final PbsDeclarationRuleValidator rules) {
|
||||||
rules.validateCallableHeader(callableName, parameters, returnKind, returnType, resultErrorType, span);
|
rules.validateCallableHeader(callableName, parameters, returnKind, returnType, resultErrorType, span, allowSelf);
|
||||||
binder.registerCallable(
|
binder.registerCallable(
|
||||||
scope,
|
scope,
|
||||||
callableName,
|
callableName,
|
||||||
|
|||||||
@ -97,8 +97,15 @@ final class PbsFlowExpressionAnalyzer {
|
|||||||
if (expression instanceof PbsAst.UnitExpr) {
|
if (expression instanceof PbsAst.UnitExpr) {
|
||||||
return ExprResult.type(TypeView.unit());
|
return ExprResult.type(TypeView.unit());
|
||||||
}
|
}
|
||||||
if (expression instanceof PbsAst.ThisExpr) {
|
if (expression instanceof PbsAst.ThisExpr thisExpr) {
|
||||||
return ExprResult.type(receiverType == null ? TypeView.unknown() : receiverType);
|
if (receiverType == null) {
|
||||||
|
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||||
|
PbsSemanticsErrors.E_SEM_INVALID_THIS_CONTEXT.name(),
|
||||||
|
"Invalid 'this' usage outside struct/service methods and constructors",
|
||||||
|
thisExpr.span());
|
||||||
|
return ExprResult.type(TypeView.unknown());
|
||||||
|
}
|
||||||
|
return ExprResult.type(receiverType);
|
||||||
}
|
}
|
||||||
if (expression instanceof PbsAst.IdentifierExpr identifierExpr) {
|
if (expression instanceof PbsAst.IdentifierExpr identifierExpr) {
|
||||||
final var localType = scope.resolve(identifierExpr.name());
|
final var localType = scope.resolve(identifierExpr.name());
|
||||||
|
|||||||
@ -18,6 +18,8 @@ public enum PbsSemanticsErrors {
|
|||||||
E_SEM_APPLY_AMBIGUOUS_OVERLOAD,
|
E_SEM_APPLY_AMBIGUOUS_OVERLOAD,
|
||||||
E_SEM_BARE_METHOD_EXTRACTION,
|
E_SEM_BARE_METHOD_EXTRACTION,
|
||||||
E_SEM_INVALID_MEMBER_ACCESS,
|
E_SEM_INVALID_MEMBER_ACCESS,
|
||||||
|
E_SEM_INVALID_THIS_CONTEXT,
|
||||||
|
E_SEM_INVALID_SELF_CONTEXT,
|
||||||
E_SEM_IF_NON_BOOL_CONDITION,
|
E_SEM_IF_NON_BOOL_CONDITION,
|
||||||
E_SEM_IF_BRANCH_TYPE_MISMATCH,
|
E_SEM_IF_BRANCH_TYPE_MISMATCH,
|
||||||
E_SEM_SWITCH_SELECTOR_INVALID,
|
E_SEM_SWITCH_SELECTOR_INVALID,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ final class PbsTypeSurfaceSemanticsValidator {
|
|||||||
static void validateTypeSurfaceRecursive(
|
static void validateTypeSurfaceRecursive(
|
||||||
final List<PbsAst.TypeRef> roots,
|
final List<PbsAst.TypeRef> roots,
|
||||||
final String ownerDescription,
|
final String ownerDescription,
|
||||||
|
final boolean allowSelf,
|
||||||
final DiagnosticSink diagnostics) {
|
final DiagnosticSink diagnostics) {
|
||||||
final var pending = new ArrayList<>(roots);
|
final var pending = new ArrayList<>(roots);
|
||||||
while (!pending.isEmpty()) {
|
while (!pending.isEmpty()) {
|
||||||
@ -37,6 +38,14 @@ final class PbsTypeSurfaceSemanticsValidator {
|
|||||||
pending.add(field.typeRef());
|
pending.add(field.typeRef());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case SELF -> {
|
||||||
|
if (!allowSelf) {
|
||||||
|
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||||
|
PbsSemanticsErrors.E_SEM_INVALID_SELF_CONTEXT.name(),
|
||||||
|
"Invalid 'Self' type usage in %s".formatted(ownerDescription),
|
||||||
|
typeRef.span());
|
||||||
|
}
|
||||||
|
}
|
||||||
default -> {
|
default -> {
|
||||||
// No recursive children.
|
// No recursive children.
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
|||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
|
||||||
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.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
class PbsSemanticsControlFlowTest {
|
class PbsSemanticsControlFlowTest {
|
||||||
@ -82,4 +83,44 @@ class PbsSemanticsControlFlowTest {
|
|||||||
.count();
|
.count();
|
||||||
assertEquals(1, duplicateWildcardCount);
|
assertEquals(1, duplicateWildcardCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAllowThisInsideStructServiceAndCtorBodies() {
|
||||||
|
final var source = """
|
||||||
|
declare struct Box(v: int) {
|
||||||
|
fn read() -> int { return this.v; }
|
||||||
|
ctor make(seed: int) { this.v = seed; }
|
||||||
|
}
|
||||||
|
|
||||||
|
declare service Game {
|
||||||
|
fn ping() -> int { this; return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok() -> int { return 0; }
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
assertFalse(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_INVALID_THIS_CONTEXT.name())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRejectThisOutsideReceiverContexts() {
|
||||||
|
final var source = """
|
||||||
|
fn bad() -> int {
|
||||||
|
this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
final var invalidThisCount = diagnostics.stream()
|
||||||
|
.filter(d -> d.getCode().equals(PbsSemanticsErrors.E_SEM_INVALID_THIS_CONTEXT.name()))
|
||||||
|
.count();
|
||||||
|
assertEquals(1, invalidThisCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import p.studio.compiler.pbs.PbsFrontendCompiler;
|
|||||||
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 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;
|
||||||
|
|
||||||
@ -144,4 +145,40 @@ class PbsSemanticsDeclarationsTest {
|
|||||||
assertTrue(diagnostics.stream().anyMatch(d ->
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
d.getCode().equals(PbsSemanticsErrors.E_SEM_DUPLICATE_DECLARATION.name())));
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_DUPLICATE_DECLARATION.name())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAllowSelfInStructServiceMethodsAndCtors() {
|
||||||
|
final var source = """
|
||||||
|
declare struct Box(v: int) {
|
||||||
|
fn merge(other: Self) -> Self { return this; }
|
||||||
|
ctor make(copy: Self) { this.v = copy.v; }
|
||||||
|
}
|
||||||
|
|
||||||
|
declare service Game {
|
||||||
|
fn mirror(current: Self) -> int { return 0; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
assertFalse(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_INVALID_SELF_CONTEXT.name())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRejectSelfOutsideAllowedDeclarationContexts() {
|
||||||
|
final var source = """
|
||||||
|
fn bad(v: Self) -> int { return 0; }
|
||||||
|
declare const GLOBAL: Self = 1;
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
final var invalidSelfCount = diagnostics.stream()
|
||||||
|
.filter(d -> d.getCode().equals(PbsSemanticsErrors.E_SEM_INVALID_SELF_CONTEXT.name()))
|
||||||
|
.count();
|
||||||
|
assertEquals(2, invalidSelfCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user