implements PR-05.0.4
This commit is contained in:
parent
0149b85e7d
commit
19f293d8ea
@ -15,14 +15,19 @@ import p.studio.compiler.pbs.semantics.PbsFlowSemanticsValidator;
|
||||
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||
import p.studio.compiler.source.identifiers.CallableShapeId;
|
||||
import p.studio.compiler.source.identifiers.CallableId;
|
||||
import p.studio.compiler.source.identifiers.FileId;
|
||||
import p.studio.compiler.source.identifiers.IntrinsicId;
|
||||
import p.studio.compiler.source.identifiers.NameId;
|
||||
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
||||
import p.studio.compiler.source.tables.CallableShapeTable;
|
||||
import p.studio.compiler.source.tables.CallableSignatureRef;
|
||||
import p.studio.compiler.source.tables.CallableTable;
|
||||
import p.studio.compiler.source.tables.IntrinsicReference;
|
||||
import p.studio.compiler.source.tables.IntrinsicTable;
|
||||
import p.studio.compiler.source.tables.NameTable;
|
||||
import p.studio.compiler.source.tables.TypeSurfaceTable;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -144,7 +149,7 @@ public final class PbsFrontendCompiler {
|
||||
final var loweringErrorBaseline = diagnostics.errorCount();
|
||||
final var executableLowering = sourceKind == SourceKind.SDK_INTERFACE
|
||||
? new ExecutableLoweringResult(ReadOnlyList.empty(), ReadOnlyList.empty(), ReadOnlyList.empty())
|
||||
: lowerExecutableFunctions(fileId, ast, moduleKey, reservedMetadata, diagnostics);
|
||||
: lowerExecutableFunctions(fileId, ast, moduleKey, reservedMetadata, effectiveNameTable, diagnostics);
|
||||
if (diagnostics.errorCount() > loweringErrorBaseline) {
|
||||
return IRBackendFile.empty(fileId);
|
||||
}
|
||||
@ -175,6 +180,7 @@ public final class PbsFrontendCompiler {
|
||||
final PbsAst.File ast,
|
||||
final String moduleKey,
|
||||
final IRReservedMetadata reservedMetadata,
|
||||
final NameTable nameTable,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var normalizedModuleKey = moduleKey == null ? "" : moduleKey;
|
||||
final var hostByMethodName = new HashMap<String, IRReservedMetadata.HostMethodBinding>();
|
||||
@ -188,19 +194,24 @@ public final class PbsFrontendCompiler {
|
||||
}
|
||||
}
|
||||
final var callableIdTable = new CallableTable();
|
||||
final var callableIdsByNameAndArity = new HashMap<String, List<CallableId>>();
|
||||
final var callableIdsByNameAndArity = new HashMap<CallableResolutionKey, List<CallableId>>();
|
||||
final var callableIdByDeclaration = new HashMap<PbsAst.FunctionDecl, CallableId>();
|
||||
final var returnSlotsByCallableId = new HashMap<CallableId, Integer>();
|
||||
final var intrinsicIdTable = new IntrinsicTable();
|
||||
final var typeSurfaceTable = new TypeSurfaceTable();
|
||||
final var callableShapeTable = new CallableShapeTable();
|
||||
for (final var declaredFn : ast.functions()) {
|
||||
final var callableShapeId = callableShapeId(declaredFn, typeSurfaceTable, callableShapeTable);
|
||||
final var callableId = callableIdTable.register(
|
||||
normalizedModuleKey,
|
||||
declaredFn.name(),
|
||||
declaredFn.parameters().size(),
|
||||
callableShapeKey(declaredFn));
|
||||
callableShapeSurface(callableShapeId, typeSurfaceTable, callableShapeTable));
|
||||
callableIdByDeclaration.put(declaredFn, callableId);
|
||||
callableIdsByNameAndArity
|
||||
.computeIfAbsent(callableArityKey(declaredFn.name(), declaredFn.parameters().size()), ignored -> new ArrayList<>())
|
||||
.computeIfAbsent(
|
||||
new CallableResolutionKey(nameTable.register(declaredFn.name()), declaredFn.parameters().size()),
|
||||
ignored -> new ArrayList<>())
|
||||
.add(callableId);
|
||||
final var retSlots = returnSlotsFor(declaredFn);
|
||||
returnSlotsByCallableId.put(callableId, retSlots);
|
||||
@ -261,7 +272,8 @@ public final class PbsFrontendCompiler {
|
||||
continue;
|
||||
}
|
||||
|
||||
final var candidateCallableIds = callableIdsByNameAndArity.get(callableArityKey(calleeName, callExpr.arguments().size()));
|
||||
final var candidateCallableIds = callableIdsByNameAndArity.get(
|
||||
new CallableResolutionKey(nameTable.register(calleeName), callExpr.arguments().size()));
|
||||
if (candidateCallableIds == null || candidateCallableIds.isEmpty()) {
|
||||
diagnostics.error(
|
||||
DiagnosticPhase.STATIC_SEMANTICS,
|
||||
@ -354,38 +366,51 @@ public final class PbsFrontendCompiler {
|
||||
};
|
||||
}
|
||||
|
||||
private String callableArityKey(
|
||||
final String callableName,
|
||||
final int arity) {
|
||||
return callableName + "#" + arity;
|
||||
private CallableShapeId callableShapeId(
|
||||
final PbsAst.FunctionDecl functionDecl,
|
||||
final TypeSurfaceTable typeSurfaceTable,
|
||||
final CallableShapeTable callableShapeTable) {
|
||||
final var parameterSurfaceIds = new ArrayList<TypeSurfaceId>(functionDecl.parameters().size());
|
||||
for (final var parameter : functionDecl.parameters()) {
|
||||
parameterSurfaceIds.add(typeSurfaceTable.register(typeSurfaceKey(parameter.typeRef())));
|
||||
}
|
||||
final var outputSurfaceId = typeSurfaceTable.register(outputShapeSurface(
|
||||
functionDecl.returnKind(),
|
||||
functionDecl.returnType(),
|
||||
functionDecl.resultErrorType()));
|
||||
return callableShapeTable.register(ReadOnlyList.wrap(parameterSurfaceIds), outputSurfaceId);
|
||||
}
|
||||
|
||||
private String callableShapeKey(final PbsAst.FunctionDecl functionDecl) {
|
||||
private String callableShapeSurface(
|
||||
final CallableShapeId callableShapeId,
|
||||
final TypeSurfaceTable typeSurfaceTable,
|
||||
final CallableShapeTable callableShapeTable) {
|
||||
final var shape = callableShapeTable.get(callableShapeId);
|
||||
final var builder = new StringBuilder();
|
||||
builder.append('(');
|
||||
for (var i = 0; i < functionDecl.parameters().size(); i++) {
|
||||
for (var i = 0; i < shape.parameterTypeSurfaces().size(); i++) {
|
||||
if (i > 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(typeKey(functionDecl.parameters().get(i).typeRef()));
|
||||
builder.append(typeSurfaceTable.get(shape.parameterTypeSurfaces().get(i)).surface());
|
||||
}
|
||||
builder.append(")->");
|
||||
builder.append(outputShapeKey(functionDecl.returnKind(), functionDecl.returnType(), functionDecl.resultErrorType()));
|
||||
builder.append(typeSurfaceTable.get(shape.outputTypeSurface()).surface());
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String outputShapeKey(
|
||||
private String outputShapeSurface(
|
||||
final PbsAst.ReturnKind returnKind,
|
||||
final PbsAst.TypeRef returnType,
|
||||
final PbsAst.TypeRef resultErrorType) {
|
||||
return switch (returnKind) {
|
||||
case INFERRED_UNIT, EXPLICIT_UNIT -> "unit";
|
||||
case PLAIN -> typeKey(returnType);
|
||||
case RESULT -> "result<" + typeKey(resultErrorType) + ">" + typeKey(returnType);
|
||||
case PLAIN -> typeSurfaceKey(returnType);
|
||||
case RESULT -> "result<" + typeSurfaceKey(resultErrorType) + ">" + typeSurfaceKey(returnType);
|
||||
};
|
||||
}
|
||||
|
||||
private String typeKey(final PbsAst.TypeRef typeRef) {
|
||||
private String typeSurfaceKey(final PbsAst.TypeRef typeRef) {
|
||||
final var unwrapped = unwrapGroup(typeRef);
|
||||
if (unwrapped == null) {
|
||||
return "unit";
|
||||
@ -393,11 +418,11 @@ public final class PbsFrontendCompiler {
|
||||
return switch (unwrapped.kind()) {
|
||||
case SIMPLE -> "simple:" + unwrapped.name();
|
||||
case SELF -> "self";
|
||||
case OPTIONAL -> "optional(" + typeKey(unwrapped.inner()) + ")";
|
||||
case OPTIONAL -> "optional(" + typeSurfaceKey(unwrapped.inner()) + ")";
|
||||
case UNIT -> "unit";
|
||||
case GROUP -> typeKey(unwrapped.inner());
|
||||
case GROUP -> typeSurfaceKey(unwrapped.inner());
|
||||
case NAMED_TUPLE -> "tuple(" + unwrapped.fields().stream()
|
||||
.map(field -> typeKey(field.typeRef()))
|
||||
.map(field -> typeSurfaceKey(field.typeRef()))
|
||||
.reduce((left, right) -> left + "," + right)
|
||||
.orElse("") + ")";
|
||||
case ERROR -> "error";
|
||||
@ -681,6 +706,11 @@ public final class PbsFrontendCompiler {
|
||||
ReadOnlyList<IntrinsicReference> intrinsicPool) {
|
||||
}
|
||||
|
||||
private record CallableResolutionKey(
|
||||
NameId callableNameId,
|
||||
int arity) {
|
||||
}
|
||||
|
||||
private static final class ExecutableLoweringAnalysisException extends RuntimeException {
|
||||
private ExecutableLoweringAnalysisException(final String message) {
|
||||
super(message);
|
||||
|
||||
@ -6,8 +6,12 @@ import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||
import p.studio.compiler.source.diagnostics.RelatedSpan;
|
||||
import p.studio.compiler.source.diagnostics.Severity;
|
||||
import p.studio.compiler.source.identifiers.FileId;
|
||||
import p.studio.compiler.source.identifiers.CallableShapeId;
|
||||
import p.studio.compiler.source.identifiers.NameId;
|
||||
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
||||
import p.studio.compiler.source.tables.CallableShapeTable;
|
||||
import p.studio.compiler.source.tables.NameTable;
|
||||
import p.studio.compiler.source.tables.TypeSurfaceTable;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -29,10 +33,11 @@ public final class PbsModuleVisibilityValidator {
|
||||
final ReadOnlyList<ModuleUnit> modules,
|
||||
final NameTable nameTable,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var signatureInterning = new SignatureInterning(new TypeSurfaceTable(), new CallableShapeTable());
|
||||
final var exportsByModule = new HashMap<ModuleRefKey, ModuleExports>();
|
||||
|
||||
for (final var module : modules) {
|
||||
final var exports = validateModule(module, nameTable, diagnostics);
|
||||
final var exports = validateModule(module, nameTable, signatureInterning, diagnostics);
|
||||
exportsByModule.put(toModuleRef(module.coordinates()), exports);
|
||||
}
|
||||
|
||||
@ -44,6 +49,7 @@ public final class PbsModuleVisibilityValidator {
|
||||
private ModuleExports validateModule(
|
||||
final ModuleUnit module,
|
||||
final NameTable nameTable,
|
||||
final SignatureInterning signatureInterning,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var exports = new ModuleExports();
|
||||
|
||||
@ -79,7 +85,7 @@ public final class PbsModuleVisibilityValidator {
|
||||
}
|
||||
|
||||
final var barrel = module.barrelFiles().getFirst();
|
||||
final var declarations = collectDeclarations(module, nameTable);
|
||||
final var declarations = collectDeclarations(module, nameTable, signatureInterning);
|
||||
exports.declaredNameIds.addAll(declarations.declaredNameIds);
|
||||
final Map<NonFunctionSymbolKey, Span> seenNonFunctionEntries = new HashMap<>();
|
||||
final Map<FunctionSymbolKey, Span> seenFunctionEntries = new HashMap<>();
|
||||
@ -92,7 +98,8 @@ public final class PbsModuleVisibilityValidator {
|
||||
functionItem.returnKind(),
|
||||
functionItem.returnType(),
|
||||
functionItem.resultErrorType(),
|
||||
nameTable);
|
||||
nameTable,
|
||||
signatureInterning);
|
||||
final var firstFunctionEntry = seenFunctionEntries.putIfAbsent(functionKey, functionItem.span());
|
||||
if (firstFunctionEntry != null) {
|
||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||
@ -231,7 +238,8 @@ public final class PbsModuleVisibilityValidator {
|
||||
|
||||
private ModuleDeclarations collectDeclarations(
|
||||
final ModuleUnit module,
|
||||
final NameTable nameTable) {
|
||||
final NameTable nameTable,
|
||||
final SignatureInterning signatureInterning) {
|
||||
final var declarations = new ModuleDeclarations();
|
||||
|
||||
for (final var sourceFile : module.sourceFiles()) {
|
||||
@ -243,7 +251,8 @@ public final class PbsModuleVisibilityValidator {
|
||||
functionDecl.returnKind(),
|
||||
functionDecl.returnType(),
|
||||
functionDecl.resultErrorType(),
|
||||
nameTable);
|
||||
nameTable,
|
||||
signatureInterning);
|
||||
declarations.functionsBySignature
|
||||
.computeIfAbsent(key, ignored -> new ArrayList<>())
|
||||
.add(functionDecl.span());
|
||||
@ -295,37 +304,37 @@ public final class PbsModuleVisibilityValidator {
|
||||
final PbsAst.ReturnKind returnKind,
|
||||
final PbsAst.TypeRef returnType,
|
||||
final PbsAst.TypeRef resultErrorType,
|
||||
final NameTable nameTable) {
|
||||
final var signatureSurface = signatureSurfaceKey(parameterTypes, returnKind, returnType, resultErrorType);
|
||||
return new FunctionSymbolKey(nameTable.register(name), signatureSurface);
|
||||
final NameTable nameTable,
|
||||
final SignatureInterning signatureInterning) {
|
||||
return new FunctionSymbolKey(
|
||||
nameTable.register(name),
|
||||
callableShapeId(parameterTypes, returnKind, returnType, resultErrorType, signatureInterning));
|
||||
}
|
||||
|
||||
private String signatureSurfaceKey(
|
||||
private CallableShapeId callableShapeId(
|
||||
final List<PbsAst.TypeRef> parameterTypes,
|
||||
final PbsAst.ReturnKind returnKind,
|
||||
final PbsAst.TypeRef returnType,
|
||||
final PbsAst.TypeRef resultErrorType,
|
||||
final SignatureInterning signatureInterning) {
|
||||
final var parameterSurfaceIds = new ArrayList<TypeSurfaceId>(parameterTypes.size());
|
||||
for (final var parameterType : parameterTypes) {
|
||||
parameterSurfaceIds.add(signatureInterning.typeSurfaces().register(typeSurfaceKey(parameterType)));
|
||||
}
|
||||
final var outputSurfaceId = signatureInterning.typeSurfaces().register(outputSurfaceKey(returnKind, returnType, resultErrorType));
|
||||
return signatureInterning.callableShapes().register(ReadOnlyList.wrap(parameterSurfaceIds), outputSurfaceId);
|
||||
}
|
||||
|
||||
private String outputSurfaceKey(
|
||||
final PbsAst.ReturnKind returnKind,
|
||||
final PbsAst.TypeRef returnType,
|
||||
final PbsAst.TypeRef resultErrorType) {
|
||||
final var builder = new StringBuilder();
|
||||
builder.append('(');
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
if (i > 0) {
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(typeSurfaceKey(parameterTypes.get(i)));
|
||||
}
|
||||
builder.append(")->");
|
||||
|
||||
switch (returnKind) {
|
||||
case INFERRED_UNIT -> builder.append("infer_unit");
|
||||
case EXPLICIT_UNIT -> builder.append("unit");
|
||||
case PLAIN -> builder.append(typeSurfaceKey(returnType));
|
||||
case RESULT -> builder.append("result<")
|
||||
.append(typeSurfaceKey(resultErrorType))
|
||||
.append('>')
|
||||
.append(typeSurfaceKey(returnType));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
return switch (returnKind) {
|
||||
case INFERRED_UNIT -> "infer_unit";
|
||||
case EXPLICIT_UNIT -> "unit";
|
||||
case PLAIN -> typeSurfaceKey(returnType);
|
||||
case RESULT -> "result<" + typeSurfaceKey(resultErrorType) + ">" + typeSurfaceKey(returnType);
|
||||
};
|
||||
}
|
||||
|
||||
private String typeSurfaceKey(final PbsAst.TypeRef typeRef) {
|
||||
@ -489,7 +498,12 @@ public final class PbsModuleVisibilityValidator {
|
||||
|
||||
private record FunctionSymbolKey(
|
||||
NameId nameId,
|
||||
String signatureSurface) {
|
||||
CallableShapeId callableShapeId) {
|
||||
}
|
||||
|
||||
private record SignatureInterning(
|
||||
TypeSurfaceTable typeSurfaces,
|
||||
CallableShapeTable callableShapes) {
|
||||
}
|
||||
|
||||
private static final class ModuleDeclarations {
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package p.studio.compiler.source.identifiers;
|
||||
|
||||
public class CallableShapeId extends SourceIdentifier {
|
||||
public CallableShapeId(final int id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package p.studio.compiler.source.identifiers;
|
||||
|
||||
public class TypeSurfaceId extends SourceIdentifier {
|
||||
public TypeSurfaceId(final int id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package p.studio.compiler.source.tables;
|
||||
|
||||
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record CallableShapeRef(
|
||||
ReadOnlyList<TypeSurfaceId> parameterTypeSurfaces,
|
||||
TypeSurfaceId outputTypeSurface) {
|
||||
public CallableShapeRef {
|
||||
parameterTypeSurfaces = parameterTypeSurfaces == null ? ReadOnlyList.empty() : parameterTypeSurfaces;
|
||||
outputTypeSurface = Objects.requireNonNull(outputTypeSurface, "outputTypeSurface");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package p.studio.compiler.source.tables;
|
||||
|
||||
import p.studio.compiler.source.identifiers.CallableShapeId;
|
||||
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
public class CallableShapeTable extends InternTable<CallableShapeId, CallableShapeRef> {
|
||||
|
||||
public CallableShapeTable() {
|
||||
super(CallableShapeId::new);
|
||||
}
|
||||
|
||||
public CallableShapeId register(
|
||||
final ReadOnlyList<TypeSurfaceId> parameterTypeSurfaces,
|
||||
final TypeSurfaceId outputTypeSurface) {
|
||||
return register(new CallableShapeRef(parameterTypeSurfaces, outputTypeSurface));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package p.studio.compiler.source.tables;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record TypeSurfaceRef(
|
||||
String surface) {
|
||||
public TypeSurfaceRef {
|
||||
surface = Objects.requireNonNull(surface, "surface");
|
||||
if (surface.isBlank()) {
|
||||
throw new IllegalArgumentException("surface must not be blank");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package p.studio.compiler.source.tables;
|
||||
|
||||
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
||||
|
||||
public class TypeSurfaceTable extends InternTable<TypeSurfaceId, TypeSurfaceRef> {
|
||||
|
||||
public TypeSurfaceTable() {
|
||||
super(TypeSurfaceId::new);
|
||||
}
|
||||
|
||||
public TypeSurfaceId register(final String surface) {
|
||||
return register(new TypeSurfaceRef(surface));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package p.studio.compiler.source.tables;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class CallableShapeTableTest {
|
||||
|
||||
@Test
|
||||
void shouldInternEqualShapesToSameIdentifier() {
|
||||
final var surfaces = new TypeSurfaceTable();
|
||||
final var shapes = new CallableShapeTable();
|
||||
|
||||
final var intType = surfaces.register("simple:int");
|
||||
final var unitType = surfaces.register("unit");
|
||||
final var first = shapes.register(ReadOnlyList.from(intType, intType), unitType);
|
||||
final var second = shapes.register(ReadOnlyList.from(intType, intType), unitType);
|
||||
final var third = shapes.register(ReadOnlyList.from(intType), unitType);
|
||||
|
||||
assertEquals(first, second);
|
||||
assertEquals(2, shapes.size());
|
||||
assertEquals(1, shapes.get(third).parameterTypeSurfaces().size());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package p.studio.compiler.source.tables;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class TypeSurfaceTableTest {
|
||||
|
||||
@Test
|
||||
void shouldInternEqualSurfacesToSameIdentifier() {
|
||||
final var table = new TypeSurfaceTable();
|
||||
|
||||
final var first = table.register("simple:int");
|
||||
final var second = table.register("simple:int");
|
||||
final var third = table.register("result<error>simple:int");
|
||||
|
||||
assertEquals(first, second);
|
||||
assertEquals(2, table.size());
|
||||
assertEquals("result<error>simple:int", table.get(third).surface());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectInvalidSurfaceContract() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new TypeSurfaceRef(""));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user