From 505a4f72ce5ddc6253c14beeaa035cf2599fc6d8 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Mon, 9 Mar 2026 14:27:06 +0000 Subject: [PATCH] implements PR-08.4 --- .../compiler/pbs/PbsFrontendCompiler.java | 23 +++++- .../services/PBSFrontendPhaseServiceTest.java | 77 +++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java index 2e7e69f2..25e52f41 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java @@ -389,6 +389,10 @@ public final class PbsFrontendCompiler { .add(callableId); returnSlotsByCallableId.put(callableId, importedCallable.returnSlots()); } + final var callableSignatureByCallableId = new HashMap(); + for (final var callableId : callableIdTable.identifiers()) { + callableSignatureByCallableId.put(callableId, callableIdTable.get(callableId)); + } final var executableFunctions = new ArrayList(localCallables.size()); for (final var callable : localCallables) { @@ -411,6 +415,7 @@ public final class PbsFrontendCompiler { intrinsicReturnOwnerByCanonical, builtinConstOwnerByNameId, callableIdsByNameAndArity, + callableSignatureByCallableId, returnSlotsByCallableId, intrinsicIdTable, localSlotByNameId); @@ -964,11 +969,16 @@ public final class PbsFrontendCompiler { return; } final var calleeCallableId = callableCandidates.getFirst(); + final var calleeSignature = context.callableSignatureByCallableId().get(calleeCallableId); + if (calleeSignature == null) { + reportUnsupportedLowering("executable lowering resolved callable without signature metadata", callExpr.span(), context); + return; + } context.instructions().add(new IRBackendExecutableFunction.Instruction( IRBackendExecutableFunction.InstructionKind.CALL_FUNC, - context.moduleId(), - context.moduleKey(), - calleeIdentity.primaryCallableDisplayName(), + calleeSignature.moduleId(), + calleeSignature.moduleKey(), + calleeSignature.callableName(), calleeCallableId, null, null, @@ -1347,6 +1357,7 @@ public final class PbsFrontendCompiler { private final Map intrinsicReturnOwnerByCanonical; private final Map builtinConstOwnerByNameId; private final Map> callableIdsByNameAndArity; + private final Map callableSignatureByCallableId; private final Map returnSlotsByCallableId; private final IntrinsicTable intrinsicIdTable; private final Map localSlotByNameId; @@ -1364,6 +1375,7 @@ public final class PbsFrontendCompiler { final Map intrinsicReturnOwnerByCanonical, final Map builtinConstOwnerByNameId, final Map> callableIdsByNameAndArity, + final Map callableSignatureByCallableId, final Map returnSlotsByCallableId, final IntrinsicTable intrinsicIdTable, final Map localSlotByNameId) { @@ -1376,6 +1388,7 @@ public final class PbsFrontendCompiler { this.intrinsicReturnOwnerByCanonical = intrinsicReturnOwnerByCanonical; this.builtinConstOwnerByNameId = builtinConstOwnerByNameId; this.callableIdsByNameAndArity = callableIdsByNameAndArity; + this.callableSignatureByCallableId = callableSignatureByCallableId; this.returnSlotsByCallableId = returnSlotsByCallableId; this.intrinsicIdTable = intrinsicIdTable; this.localSlotByNameId = localSlotByNameId == null ? Map.of() : localSlotByNameId; @@ -1417,6 +1430,10 @@ public final class PbsFrontendCompiler { return callableIdsByNameAndArity; } + private Map callableSignatureByCallableId() { + return callableSignatureByCallableId; + } + private Map returnSlotsByCallableId() { return returnSlotsByCallableId; } diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java index d68c7de8..a771f26f 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; class PBSFrontendPhaseServiceTest { @@ -138,6 +139,82 @@ class PBSFrontendPhaseServiceTest { assertEquals("good", irBackend.getFunctions().getFirst().name()); } + @Test + void shouldEmitCallFuncWithCalleeModuleIdentityFromResolvedTarget() throws IOException { + final var projectRoot = tempDir.resolve("project-callsite-module-identity"); + final var sourceRoot = projectRoot.resolve("src"); + final var moduleAPath = sourceRoot.resolve("a"); + final var moduleBPath = sourceRoot.resolve("b"); + Files.createDirectories(moduleAPath); + Files.createDirectories(moduleBPath); + + final var sourceA = moduleAPath.resolve("source.pbs"); + final var barrelA = moduleAPath.resolve("mod.barrel"); + Files.writeString(sourceA, """ + fn target() -> int { + return 1; + } + """); + Files.writeString(barrelA, "pub fn target() -> int;"); + + final var sourceB = moduleBPath.resolve("source.pbs"); + final var barrelB = moduleBPath.resolve("mod.barrel"); + Files.writeString(sourceB, """ + import { target } from @app:a; + + fn caller() -> int { + return target(); + } + """); + Files.writeString(barrelB, "pub fn caller() -> int;"); + + final var projectTable = new ProjectTable(); + final var fileTable = new FileTable(1); + final var projectId = projectTable.register(ProjectDescriptor.builder() + .rootPath(projectRoot) + .name("app") + .version("1.0.0") + .sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot))) + .build()); + + registerFile(projectId, projectRoot, sourceA, fileTable); + registerFile(projectId, projectRoot, barrelA, fileTable); + registerFile(projectId, projectRoot, sourceB, fileTable); + registerFile(projectId, projectRoot, barrelB, 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()); + + assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString()); + + final var targetFn = irBackend.getExecutableFunctions().stream() + .filter(function -> "target".equals(function.callableName())) + .findFirst() + .orElseThrow(); + final var callerFn = irBackend.getExecutableFunctions().stream() + .filter(function -> "caller".equals(function.callableName())) + .findFirst() + .orElseThrow(); + final var callInstruction = callerFn.instructions().stream() + .filter(instruction -> instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC) + .findFirst() + .orElseThrow(); + + assertNotNull(callInstruction.calleeModuleId()); + assertEquals(targetFn.moduleId().getIndex(), callInstruction.calleeModuleId().getIndex()); + assertEquals(targetFn.moduleKey(), callInstruction.calleeModuleKey()); + assertTrue(callerFn.moduleId().getIndex() != callInstruction.calleeModuleId().getIndex()); + } + @Test void shouldLowerAllSourcesWhenNoAdmissionErrorsExist() throws IOException { final var projectRoot = tempDir.resolve("project-valid");