sdk executable service bodies
This commit is contained in:
parent
ffd5f6c801
commit
0d01c0a522
@ -22,11 +22,13 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
final PbsAst.File ast,
|
final PbsAst.File ast,
|
||||||
final ModuleId moduleId,
|
final ModuleId moduleId,
|
||||||
final NameTable nameTable,
|
final NameTable nameTable,
|
||||||
|
final Map<String, String> builtinCanonicalBySourceType,
|
||||||
final ReadOnlyList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables) {
|
final ReadOnlyList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables) {
|
||||||
final var callableIdTable = new CallableTable();
|
final var callableIdTable = new CallableTable();
|
||||||
final var callableIdsByNameAndArity = new HashMap<PbsCallableResolutionKey, List<CallableId>>();
|
final var callableIdsByNameAndArity = new HashMap<PbsCallableResolutionKey, List<CallableId>>();
|
||||||
final var callableIdByDeclaration = new HashMap<PbsLowerableCallable, CallableId>();
|
final var callableIdByDeclaration = new HashMap<PbsLowerableCallable, CallableId>();
|
||||||
final var returnSlotsByCallableId = new HashMap<CallableId, Integer>();
|
final var returnSlotsByCallableId = new HashMap<CallableId, Integer>();
|
||||||
|
final var returnOwnerByCallableId = new HashMap<CallableId, String>();
|
||||||
final var tupleProjectionByCallableId = new HashMap<CallableId, PbsTupleProjection>();
|
final var tupleProjectionByCallableId = new HashMap<CallableId, PbsTupleProjection>();
|
||||||
final var typeSurfaceTable = new TypeSurfaceTable();
|
final var typeSurfaceTable = new TypeSurfaceTable();
|
||||||
final var callableShapeTable = new CallableShapeTable();
|
final var callableShapeTable = new CallableShapeTable();
|
||||||
@ -39,17 +41,21 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
callableIdsByNameAndArity,
|
callableIdsByNameAndArity,
|
||||||
callableIdByDeclaration,
|
callableIdByDeclaration,
|
||||||
returnSlotsByCallableId,
|
returnSlotsByCallableId,
|
||||||
|
returnOwnerByCallableId,
|
||||||
tupleProjectionByCallableId,
|
tupleProjectionByCallableId,
|
||||||
typeSurfaceTable,
|
typeSurfaceTable,
|
||||||
callableShapeTable,
|
callableShapeTable,
|
||||||
localCallables);
|
localCallables,
|
||||||
|
builtinCanonicalBySourceType);
|
||||||
registerImportedCallables(
|
registerImportedCallables(
|
||||||
nameTable,
|
nameTable,
|
||||||
callableIdTable,
|
callableIdTable,
|
||||||
callableIdsByNameAndArity,
|
callableIdsByNameAndArity,
|
||||||
returnSlotsByCallableId,
|
returnSlotsByCallableId,
|
||||||
tupleProjectionByCallableId,
|
tupleProjectionByCallableId,
|
||||||
importedCallables);
|
returnOwnerByCallableId,
|
||||||
|
importedCallables,
|
||||||
|
builtinCanonicalBySourceType);
|
||||||
|
|
||||||
final var callableSignatureByCallableId = new HashMap<CallableId, CallableSignatureRef>();
|
final var callableSignatureByCallableId = new HashMap<CallableId, CallableSignatureRef>();
|
||||||
final var callableSignatures = new ArrayList<CallableSignatureRef>(callableIdTable.size());
|
final var callableSignatures = new ArrayList<CallableSignatureRef>(callableIdTable.size());
|
||||||
@ -64,6 +70,7 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
callableIdsByNameAndArity,
|
callableIdsByNameAndArity,
|
||||||
callableSignatureByCallableId,
|
callableSignatureByCallableId,
|
||||||
returnSlotsByCallableId,
|
returnSlotsByCallableId,
|
||||||
|
returnOwnerByCallableId,
|
||||||
tupleProjectionByCallableId,
|
tupleProjectionByCallableId,
|
||||||
ReadOnlyList.wrap(callableSignatures));
|
ReadOnlyList.wrap(callableSignatures));
|
||||||
}
|
}
|
||||||
@ -91,10 +98,12 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
final Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
|
final Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
|
||||||
final Map<PbsLowerableCallable, CallableId> callableIdByDeclaration,
|
final Map<PbsLowerableCallable, CallableId> callableIdByDeclaration,
|
||||||
final Map<CallableId, Integer> returnSlotsByCallableId,
|
final Map<CallableId, Integer> returnSlotsByCallableId,
|
||||||
|
final Map<CallableId, String> returnOwnerByCallableId,
|
||||||
final Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
|
final Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
|
||||||
final TypeSurfaceTable typeSurfaceTable,
|
final TypeSurfaceTable typeSurfaceTable,
|
||||||
final CallableShapeTable callableShapeTable,
|
final CallableShapeTable callableShapeTable,
|
||||||
final ReadOnlyList<PbsLowerableCallable> localCallables) {
|
final ReadOnlyList<PbsLowerableCallable> localCallables,
|
||||||
|
final Map<String, String> builtinCanonicalBySourceType) {
|
||||||
for (final var declaredCallable : localCallables) {
|
for (final var declaredCallable : localCallables) {
|
||||||
final var declaredFn = declaredCallable.functionDecl();
|
final var declaredFn = declaredCallable.functionDecl();
|
||||||
final var callableShapeId = callableShapeSurfaceService.callableShapeId(
|
final var callableShapeId = callableShapeSurfaceService.callableShapeId(
|
||||||
@ -113,6 +122,13 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
ignored -> new ArrayList<>())
|
ignored -> new ArrayList<>())
|
||||||
.add(callableId);
|
.add(callableId);
|
||||||
returnSlotsByCallableId.put(callableId, returnSlotsFor(declaredFn));
|
returnSlotsByCallableId.put(callableId, returnSlotsFor(declaredFn));
|
||||||
|
final var returnOwner = inferCallableReturnOwner(
|
||||||
|
declaredFn.returnKind(),
|
||||||
|
declaredFn.returnType(),
|
||||||
|
builtinCanonicalBySourceType);
|
||||||
|
if (!returnOwner.isBlank()) {
|
||||||
|
returnOwnerByCallableId.put(callableId, returnOwner);
|
||||||
|
}
|
||||||
final var tupleProjection = tupleProjectionOf(declaredFn.returnKind(), declaredFn.returnType());
|
final var tupleProjection = tupleProjectionOf(declaredFn.returnKind(), declaredFn.returnType());
|
||||||
if (tupleProjection != null) {
|
if (tupleProjection != null) {
|
||||||
tupleProjectionByCallableId.put(callableId, tupleProjection);
|
tupleProjectionByCallableId.put(callableId, tupleProjection);
|
||||||
@ -126,7 +142,9 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
final Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
|
final Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
|
||||||
final Map<CallableId, Integer> returnSlotsByCallableId,
|
final Map<CallableId, Integer> returnSlotsByCallableId,
|
||||||
final Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
|
final Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
|
||||||
final ReadOnlyList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables) {
|
final Map<CallableId, String> returnOwnerByCallableId,
|
||||||
|
final ReadOnlyList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables,
|
||||||
|
final Map<String, String> builtinCanonicalBySourceType) {
|
||||||
for (final var importedCallable : importedCallables) {
|
for (final var importedCallable : importedCallables) {
|
||||||
final var callableId = callableIdTable.register(
|
final var callableId = callableIdTable.register(
|
||||||
importedCallable.moduleId(),
|
importedCallable.moduleId(),
|
||||||
@ -141,6 +159,13 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
ignored -> new ArrayList<>())
|
ignored -> new ArrayList<>())
|
||||||
.add(callableId);
|
.add(callableId);
|
||||||
returnSlotsByCallableId.put(callableId, importedCallable.returnSlots());
|
returnSlotsByCallableId.put(callableId, importedCallable.returnSlots());
|
||||||
|
final var returnOwner = inferCallableReturnOwner(
|
||||||
|
importedCallable.returnKind(),
|
||||||
|
importedCallable.returnType(),
|
||||||
|
builtinCanonicalBySourceType);
|
||||||
|
if (!returnOwner.isBlank()) {
|
||||||
|
returnOwnerByCallableId.put(callableId, returnOwner);
|
||||||
|
}
|
||||||
final var tupleProjection = tupleProjectionOf(importedCallable.returnKind(), importedCallable.returnType());
|
final var tupleProjection = tupleProjectionOf(importedCallable.returnKind(), importedCallable.returnType());
|
||||||
if (tupleProjection != null) {
|
if (tupleProjection != null) {
|
||||||
tupleProjectionByCallableId.put(callableId, tupleProjection);
|
tupleProjectionByCallableId.put(callableId, tupleProjection);
|
||||||
@ -148,6 +173,20 @@ final class PbsExecutableCallableRegistryFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String inferCallableReturnOwner(
|
||||||
|
final PbsAst.ReturnKind returnKind,
|
||||||
|
final PbsAst.TypeRef returnType,
|
||||||
|
final Map<String, String> builtinCanonicalBySourceType) {
|
||||||
|
if (returnKind != PbsAst.ReturnKind.PLAIN || returnType == null || builtinCanonicalBySourceType == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
final var unwrapped = unwrapGroup(returnType);
|
||||||
|
if (unwrapped == null || unwrapped.kind() != PbsAst.TypeRefKind.SIMPLE) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return builtinCanonicalBySourceType.getOrDefault(unwrapped.name(), "");
|
||||||
|
}
|
||||||
|
|
||||||
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
||||||
return PbsCallableSlotCounter.returnSlots(functionDecl.returnKind(), functionDecl.returnType());
|
return PbsCallableSlotCounter.returnSlots(functionDecl.returnKind(), functionDecl.returnType());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -337,18 +337,21 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
final var receiverOwner = resolveReceiverOwnerForCallee(callExpr.callee(), context);
|
final var receiverOwner = resolveReceiverOwnerForCallee(callExpr.callee(), context);
|
||||||
if (receiverOwner.isBlank()) {
|
if (!receiverOwner.isBlank()) {
|
||||||
|
final var key = new PbsIntrinsicOwnerMethodKey(receiverOwner, calleeIdentity.memberSourceMethodName());
|
||||||
|
final var intrinsicCandidates = context.intrinsicByOwnerAndMethod().getOrDefault(key, List.of());
|
||||||
|
if (intrinsicCandidates.size() == 1) {
|
||||||
|
final var intrinsic = intrinsicCandidates.getFirst();
|
||||||
|
return context.intrinsicReturnOwnerByCanonical().getOrDefault(
|
||||||
|
new PbsIntrinsicCanonicalKey(intrinsic.canonicalName(), intrinsic.canonicalVersion()),
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final var callableCandidates = resolveCallableCandidates(callExpr, calleeIdentity, context);
|
||||||
|
if (callableCandidates.size() != 1) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
final var key = new PbsIntrinsicOwnerMethodKey(receiverOwner, calleeIdentity.memberSourceMethodName());
|
return context.returnOwnerByCallableId().getOrDefault(callableCandidates.getFirst(), "");
|
||||||
final var intrinsicCandidates = context.intrinsicByOwnerAndMethod().getOrDefault(key, List.of());
|
|
||||||
if (intrinsicCandidates.size() != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
final var intrinsic = intrinsicCandidates.getFirst();
|
|
||||||
return context.intrinsicReturnOwnerByCanonical().getOrDefault(
|
|
||||||
new PbsIntrinsicCanonicalKey(intrinsic.canonicalName(), intrinsic.canonicalVersion()),
|
|
||||||
"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PbsCalleeIdentity resolveCalleeIdentity(
|
private PbsCalleeIdentity resolveCalleeIdentity(
|
||||||
|
|||||||
@ -96,6 +96,10 @@ final class PbsExecutableLoweringContext {
|
|||||||
return callableRegistry.returnSlotsByCallableId();
|
return callableRegistry.returnSlotsByCallableId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<p.studio.compiler.source.identifiers.CallableId, String> returnOwnerByCallableId() {
|
||||||
|
return callableRegistry.returnOwnerByCallableId();
|
||||||
|
}
|
||||||
|
|
||||||
Map<p.studio.compiler.source.identifiers.CallableId, PbsTupleProjection> tupleProjectionByCallableId() {
|
Map<p.studio.compiler.source.identifiers.CallableId, PbsTupleProjection> tupleProjectionByCallableId() {
|
||||||
return callableRegistry.tupleProjectionByCallableId();
|
return callableRegistry.tupleProjectionByCallableId();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,7 @@ public class PbsExecutableLoweringModels {
|
|||||||
Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
|
Map<PbsCallableResolutionKey, List<CallableId>> callableIdsByNameAndArity,
|
||||||
Map<CallableId, CallableSignatureRef> callableSignatureByCallableId,
|
Map<CallableId, CallableSignatureRef> callableSignatureByCallableId,
|
||||||
Map<CallableId, Integer> returnSlotsByCallableId,
|
Map<CallableId, Integer> returnSlotsByCallableId,
|
||||||
|
Map<CallableId, String> returnOwnerByCallableId,
|
||||||
Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
|
Map<CallableId, PbsTupleProjection> tupleProjectionByCallableId,
|
||||||
ReadOnlyList<CallableSignatureRef> callableSignatures) {
|
ReadOnlyList<CallableSignatureRef> callableSignatures) {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,7 @@ public final class PbsExecutableLoweringService {
|
|||||||
ast,
|
ast,
|
||||||
normalizedModuleId,
|
normalizedModuleId,
|
||||||
nameTable,
|
nameTable,
|
||||||
|
metadataIndex.builtinCanonicalBySourceType(),
|
||||||
importedCallables);
|
importedCallables);
|
||||||
final var intrinsicIdTable = new IntrinsicTable();
|
final var intrinsicIdTable = new IntrinsicTable();
|
||||||
final var executableFunctions = new ArrayList<IRBackendExecutableFunction>(callableRegistry.localCallables().size());
|
final var executableFunctions = new ArrayList<IRBackendExecutableFunction>(callableRegistry.localCallables().size());
|
||||||
|
|||||||
@ -97,7 +97,7 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
binder.registerType(serviceDecl.name(), serviceDecl.span(), "service");
|
binder.registerType(serviceDecl.name(), serviceDecl.span(), "service");
|
||||||
binder.registerValue(serviceDecl.name(), serviceDecl.span(), "service singleton");
|
binder.registerValue(serviceDecl.name(), serviceDecl.span(), "service singleton");
|
||||||
binder.registerVisibleTopLevelSurface(serviceDecl.name(), serviceDecl.span(), "service");
|
binder.registerVisibleTopLevelSurface(serviceDecl.name(), serviceDecl.span(), "service");
|
||||||
validateServiceDeclaration(serviceDecl, binder, rules);
|
validateServiceDeclaration(serviceDecl, binder, rules, interfaceModule, diagnostics);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +221,9 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
private void validateServiceDeclaration(
|
private void validateServiceDeclaration(
|
||||||
final PbsAst.ServiceDecl serviceDecl,
|
final PbsAst.ServiceDecl serviceDecl,
|
||||||
final PbsNamespaceBinder binder,
|
final PbsNamespaceBinder binder,
|
||||||
final PbsDeclarationRuleValidator rules) {
|
final PbsDeclarationRuleValidator rules,
|
||||||
|
final boolean interfaceModule,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
final var methodScope = PbsCallableScope.serviceMethods(nameTable.register(serviceDecl.name()));
|
final var methodScope = PbsCallableScope.serviceMethods(nameTable.register(serviceDecl.name()));
|
||||||
for (final var method : serviceDecl.methods()) {
|
for (final var method : serviceDecl.methods()) {
|
||||||
validateCallable(
|
validateCallable(
|
||||||
@ -235,9 +237,144 @@ public final class PbsDeclarationSemanticsValidator {
|
|||||||
true,
|
true,
|
||||||
binder,
|
binder,
|
||||||
rules);
|
rules);
|
||||||
|
if (interfaceModule) {
|
||||||
|
validateSdkExecutableServiceMethodBody(method, diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateSdkExecutableServiceMethodBody(
|
||||||
|
final PbsAst.FunctionDecl method,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
validateSdkExecutableBlock(method.body(), diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSdkExecutableBlock(
|
||||||
|
final PbsAst.Block block,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
if (block == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (final var statement : block.statements()) {
|
||||||
|
validateSdkExecutableStatement(statement, diagnostics);
|
||||||
|
}
|
||||||
|
if (block.tailExpression() != null) {
|
||||||
|
reportUnsupportedSdkExecutableConstruct(
|
||||||
|
block.tailExpression().span(),
|
||||||
|
"SDK executable service bodies do not support block tail expressions in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSdkExecutableStatement(
|
||||||
|
final PbsAst.Statement statement,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
switch (statement) {
|
||||||
|
case PbsAst.LetStatement letStatement ->
|
||||||
|
validateSdkExecutableExpression(letStatement.initializer(), diagnostics);
|
||||||
|
case PbsAst.AssignStatement assignStatement ->
|
||||||
|
validateSdkExecutableExpression(assignStatement.value(), diagnostics);
|
||||||
|
case PbsAst.ReturnStatement returnStatement ->
|
||||||
|
validateSdkExecutableExpression(returnStatement.value(), diagnostics);
|
||||||
|
case PbsAst.ExpressionStatement expressionStatement ->
|
||||||
|
validateSdkExecutableExpression(expressionStatement.expression(), diagnostics);
|
||||||
|
case PbsAst.IfStatement ignored ->
|
||||||
|
reportUnsupportedSdkExecutableConstruct(
|
||||||
|
statement.span(),
|
||||||
|
"SDK executable service bodies do not support if statements in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
case PbsAst.ForStatement ignored ->
|
||||||
|
reportUnsupportedSdkExecutableConstruct(
|
||||||
|
statement.span(),
|
||||||
|
"SDK executable service bodies do not support for statements in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
case PbsAst.WhileStatement ignored ->
|
||||||
|
reportUnsupportedSdkExecutableConstruct(
|
||||||
|
statement.span(),
|
||||||
|
"SDK executable service bodies do not support while statements in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
case PbsAst.BreakStatement ignored ->
|
||||||
|
reportUnsupportedSdkExecutableConstruct(
|
||||||
|
statement.span(),
|
||||||
|
"SDK executable service bodies do not support break statements in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
case PbsAst.ContinueStatement ignored ->
|
||||||
|
reportUnsupportedSdkExecutableConstruct(
|
||||||
|
statement.span(),
|
||||||
|
"SDK executable service bodies do not support continue statements in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSdkExecutableExpression(
|
||||||
|
final PbsAst.Expression expression,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
if (expression == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (expression) {
|
||||||
|
case PbsAst.IdentifierExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.IntLiteralExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.FloatLiteralExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.BoundedLiteralExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.StringLiteralExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.BoolLiteralExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.ThisExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.UnitExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.NoneExpr ignored -> {
|
||||||
|
}
|
||||||
|
case PbsAst.UnaryExpr unaryExpr ->
|
||||||
|
validateSdkExecutableExpression(unaryExpr.expression(), diagnostics);
|
||||||
|
case PbsAst.BinaryExpr binaryExpr -> {
|
||||||
|
validateSdkExecutableExpression(binaryExpr.left(), diagnostics);
|
||||||
|
validateSdkExecutableExpression(binaryExpr.right(), diagnostics);
|
||||||
|
}
|
||||||
|
case PbsAst.CallExpr callExpr -> {
|
||||||
|
validateSdkExecutableExpression(callExpr.callee(), diagnostics);
|
||||||
|
for (final var argument : callExpr.arguments()) {
|
||||||
|
validateSdkExecutableExpression(argument, diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PbsAst.MemberExpr memberExpr ->
|
||||||
|
validateSdkExecutableExpression(memberExpr.receiver(), diagnostics);
|
||||||
|
case PbsAst.GroupExpr groupExpr ->
|
||||||
|
validateSdkExecutableExpression(groupExpr.expression(), diagnostics);
|
||||||
|
case PbsAst.NewExpr newExpr -> {
|
||||||
|
for (final var argument : newExpr.arguments()) {
|
||||||
|
validateSdkExecutableExpression(argument, diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PbsAst.TupleExpr tupleExpr -> {
|
||||||
|
for (final var item : tupleExpr.items()) {
|
||||||
|
validateSdkExecutableExpression(item.expression(), diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> reportUnsupportedSdkExecutableConstruct(
|
||||||
|
expression.span(),
|
||||||
|
"SDK executable service bodies use an unsupported expression form in the initial restricted subset",
|
||||||
|
diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportUnsupportedSdkExecutableConstruct(
|
||||||
|
final Span span,
|
||||||
|
final String message,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
p.studio.compiler.source.diagnostics.Diagnostics.error(
|
||||||
|
diagnostics,
|
||||||
|
PbsSemanticsErrors.E_SEM_SDK_EXEC_SERVICE_UNSUPPORTED_CONSTRUCT.name(),
|
||||||
|
message,
|
||||||
|
span);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateContractDeclaration(
|
private void validateContractDeclaration(
|
||||||
final PbsAst.ContractDecl contractDecl,
|
final PbsAst.ContractDecl contractDecl,
|
||||||
final PbsNamespaceBinder binder,
|
final PbsNamespaceBinder binder,
|
||||||
|
|||||||
@ -68,6 +68,7 @@ public enum PbsSemanticsErrors {
|
|||||||
E_SEM_HANDLE_NON_RESULT,
|
E_SEM_HANDLE_NON_RESULT,
|
||||||
E_SEM_HANDLE_ERROR_MISMATCH,
|
E_SEM_HANDLE_ERROR_MISMATCH,
|
||||||
E_SEM_HANDLE_ARM_TERMINAL_INVALID,
|
E_SEM_HANDLE_ARM_TERMINAL_INVALID,
|
||||||
|
E_SEM_SDK_EXEC_SERVICE_UNSUPPORTED_CONSTRUCT,
|
||||||
E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE,
|
E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE,
|
||||||
W_SEM_IGNORED_VALUE,
|
W_SEM_IGNORED_VALUE,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,7 +104,9 @@ class PbsGateUSdkInterfaceConformanceTest {
|
|||||||
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
||||||
.anyMatch(t -> t.sourceTypeName().equals("Color")));
|
.anyMatch(t -> t.sourceTypeName().equals("Color")));
|
||||||
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
||||||
.anyMatch(t -> t.sourceTypeName().equals("Input") && t.canonicalTypeName().equals("input")));
|
.anyMatch(t -> t.sourceTypeName().equals("InputType") && t.canonicalTypeName().equals("input")));
|
||||||
|
assertTrue(positive.irBackend().getReservedMetadata().builtinConstSurfaces().stream()
|
||||||
|
.anyMatch(c -> c.sourceConstName().equals("LowInput") && c.canonicalTarget().equals("input")));
|
||||||
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
assertTrue(positive.irBackend().getReservedMetadata().builtinTypeSurfaces().stream()
|
||||||
.anyMatch(t -> t.sourceTypeName().equals("InputButton")
|
.anyMatch(t -> t.sourceTypeName().equals("InputButton")
|
||||||
&& t.intrinsics().stream().anyMatch(i -> i.canonicalName().equals("input.button.hold"))));
|
&& t.intrinsics().stream().anyMatch(i -> i.canonicalName().equals("input.button.hold"))));
|
||||||
@ -157,6 +159,47 @@ class PbsGateUSdkInterfaceConformanceTest {
|
|||||||
assertStableDiagnosticIdentity(notPublic, PbsLinkErrors.E_LINK_IMPORT_SYMBOL_NOT_PUBLIC.name(), DiagnosticPhase.LINKING);
|
assertStableDiagnosticIdentity(notPublic, PbsLinkErrors.E_LINK_IMPORT_SYMBOL_NOT_PUBLIC.name(), DiagnosticPhase.LINKING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gateU_shouldRejectUnsupportedControlFlowInExecutableSdkServiceBodies() {
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
new PbsFrontendCompiler().compileFile(
|
||||||
|
new FileId(60),
|
||||||
|
"""
|
||||||
|
[BuiltinType(name = "input", version = 1)]
|
||||||
|
declare builtin type InputType() {
|
||||||
|
[IntrinsicCall(name = "touch", version = 1)]
|
||||||
|
fn touch() -> InputTouch;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BuiltinType(name = "input.touch", version = 1)]
|
||||||
|
declare builtin type InputTouch() {
|
||||||
|
[IntrinsicCall(name = "x", version = 1)]
|
||||||
|
fn x() -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BuiltinConst(target = "input", name = "global", version = 1)]
|
||||||
|
declare const LowInput: InputType;
|
||||||
|
|
||||||
|
declare service Input {
|
||||||
|
fn touch() -> InputTouch {
|
||||||
|
if (true) {
|
||||||
|
return LowInput.touch();
|
||||||
|
}
|
||||||
|
return LowInput.touch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
diagnostics,
|
||||||
|
SourceKind.SDK_INTERFACE);
|
||||||
|
|
||||||
|
final var diagnostic = firstDiagnostic(diagnostics,
|
||||||
|
d -> d.getCode().equals(PbsSemanticsErrors.E_SEM_SDK_EXEC_SERVICE_UNSUPPORTED_CONSTRUCT.name()));
|
||||||
|
assertStableDiagnosticIdentity(
|
||||||
|
diagnostic,
|
||||||
|
PbsSemanticsErrors.E_SEM_SDK_EXEC_SERVICE_UNSUPPORTED_CONSTRUCT.name(),
|
||||||
|
DiagnosticPhase.STATIC_SEMANTICS);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void gateU_shouldParseReservedDeclarationsInInterfaceModeOnly() {
|
void gateU_shouldParseReservedDeclarationsInInterfaceModeOnly() {
|
||||||
final var source = """
|
final var source = """
|
||||||
|
|||||||
@ -1410,13 +1410,28 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
+ " executableNames="
|
+ " executableNames="
|
||||||
+ executableNames);
|
+ executableNames);
|
||||||
final var frameExecutable = frameExecutableOptional.orElseThrow();
|
final var frameExecutable = frameExecutableOptional.orElseThrow();
|
||||||
|
final var callableCalls = frameExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
|
||||||
|
.map(instruction -> instruction.calleeCallableName())
|
||||||
|
.toList();
|
||||||
final var intrinsicCalls = frameExecutable.instructions().stream()
|
final var intrinsicCalls = frameExecutable.instructions().stream()
|
||||||
.filter(instruction ->
|
.filter(instruction ->
|
||||||
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC)
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC)
|
||||||
.toList();
|
.toList();
|
||||||
|
final var inputPadExecutable = irBackend.getExecutableFunctions().stream()
|
||||||
|
.filter(function -> "Input.pad".equals(function.callableName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
final var inputPadIntrinsics = inputPadExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
|
&& instruction.intrinsicCall() != null)
|
||||||
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
|
.toList();
|
||||||
|
assertTrue(callableCalls.contains("Input.pad"));
|
||||||
assertTrue(intrinsicCalls.stream().anyMatch(instruction -> Integer.valueOf(1).equals(instruction.expectedArgSlots())));
|
assertTrue(intrinsicCalls.stream().anyMatch(instruction -> Integer.valueOf(1).equals(instruction.expectedArgSlots())));
|
||||||
assertTrue(intrinsicCalls.stream().anyMatch(instruction ->
|
assertTrue(inputPadIntrinsics.contains("input.pad"));
|
||||||
instruction.intrinsicCall() != null && "input.pad".equals(instruction.intrinsicCall().canonicalName())));
|
|
||||||
assertTrue(intrinsicCalls.stream().anyMatch(instruction ->
|
assertTrue(intrinsicCalls.stream().anyMatch(instruction ->
|
||||||
instruction.intrinsicCall() != null && "input.pad.a".equals(instruction.intrinsicCall().canonicalName())));
|
instruction.intrinsicCall() != null && "input.pad.a".equals(instruction.intrinsicCall().canonicalName())));
|
||||||
assertTrue(intrinsicCalls.stream().anyMatch(instruction ->
|
assertTrue(intrinsicCalls.stream().anyMatch(instruction ->
|
||||||
@ -1481,16 +1496,43 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
.filter(function -> "frame".equals(function.callableName()))
|
.filter(function -> "frame".equals(function.callableName()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
|
final var callableCalls = frameExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
|
||||||
|
.map(instruction -> instruction.calleeCallableName())
|
||||||
|
.toList();
|
||||||
final var intrinsicCalls = frameExecutable.instructions().stream()
|
final var intrinsicCalls = frameExecutable.instructions().stream()
|
||||||
.filter(instruction ->
|
.filter(instruction ->
|
||||||
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
&& instruction.intrinsicCall() != null)
|
&& instruction.intrinsicCall() != null)
|
||||||
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
.toList();
|
.toList();
|
||||||
assertTrue(intrinsicCalls.contains("input.pad"));
|
final var inputPadExecutable = irBackend.getExecutableFunctions().stream()
|
||||||
|
.filter(function -> "Input.pad".equals(function.callableName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
final var inputTouchExecutable = irBackend.getExecutableFunctions().stream()
|
||||||
|
.filter(function -> "Input.touch".equals(function.callableName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
final var inputPadIntrinsics = inputPadExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
|
&& instruction.intrinsicCall() != null)
|
||||||
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
|
.toList();
|
||||||
|
final var inputTouchIntrinsics = inputTouchExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
|
&& instruction.intrinsicCall() != null)
|
||||||
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
|
.toList();
|
||||||
|
assertTrue(callableCalls.contains("Input.pad"));
|
||||||
|
assertTrue(callableCalls.contains("Input.touch"));
|
||||||
|
assertTrue(inputPadIntrinsics.contains("input.pad"));
|
||||||
assertTrue(intrinsicCalls.contains("input.pad.x"));
|
assertTrue(intrinsicCalls.contains("input.pad.x"));
|
||||||
assertTrue(intrinsicCalls.contains("input.button.pressed"));
|
assertTrue(intrinsicCalls.contains("input.button.pressed"));
|
||||||
assertTrue(intrinsicCalls.contains("input.touch"));
|
assertTrue(inputTouchIntrinsics.contains("input.touch"));
|
||||||
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1547,13 +1589,29 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
.filter(function -> "frame".equals(function.callableName()))
|
.filter(function -> "frame".equals(function.callableName()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
|
final var callableCalls = frameExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
|
||||||
|
.map(instruction -> instruction.calleeCallableName())
|
||||||
|
.toList();
|
||||||
final var intrinsicCalls = frameExecutable.instructions().stream()
|
final var intrinsicCalls = frameExecutable.instructions().stream()
|
||||||
.filter(instruction ->
|
.filter(instruction ->
|
||||||
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
&& instruction.intrinsicCall() != null)
|
&& instruction.intrinsicCall() != null)
|
||||||
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
.toList();
|
.toList();
|
||||||
assertTrue(intrinsicCalls.contains("input.touch"));
|
final var inputTouchExecutable = irBackend.getExecutableFunctions().stream()
|
||||||
|
.filter(function -> "Input.touch".equals(function.callableName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
final var inputTouchIntrinsics = inputTouchExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
|
&& instruction.intrinsicCall() != null)
|
||||||
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
|
.toList();
|
||||||
|
assertTrue(callableCalls.contains("Input.touch"));
|
||||||
|
assertTrue(inputTouchIntrinsics.contains("input.touch"));
|
||||||
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
||||||
assertTrue(intrinsicCalls.contains("input.touch.y"));
|
assertTrue(intrinsicCalls.contains("input.touch.y"));
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user