implements PR-O1.4
This commit is contained in:
parent
3e14c13979
commit
e36c59fe26
@ -158,6 +158,17 @@ public final class PbsFrontendCompiler {
|
||||
intrinsicByMethodName.put(intrinsicSurface.sourceMethodName(), intrinsicSurface);
|
||||
}
|
||||
}
|
||||
final var returnSlotsByCallableAndArity = new HashMap<String, Integer>();
|
||||
for (final var declaredFn : ast.functions()) {
|
||||
final var key = callableArityKey(declaredFn.name(), declaredFn.parameters().size());
|
||||
final var retSlots = returnSlotsFor(declaredFn);
|
||||
if (returnSlotsByCallableAndArity.containsKey(key)
|
||||
&& !returnSlotsByCallableAndArity.get(key).equals(retSlots)) {
|
||||
returnSlotsByCallableAndArity.put(key, null);
|
||||
} else {
|
||||
returnSlotsByCallableAndArity.put(key, retSlots);
|
||||
}
|
||||
}
|
||||
|
||||
final var executableFunctions = new ArrayList<IRBackendExecutableFunction>(ast.functions().size());
|
||||
for (final var fn : ast.functions()) {
|
||||
@ -221,6 +232,8 @@ public final class PbsFrontendCompiler {
|
||||
calleeName,
|
||||
null,
|
||||
null,
|
||||
callExpr.arguments().size(),
|
||||
returnSlotsByCallableAndArity.get(callableArityKey(calleeName, callExpr.arguments().size())),
|
||||
callExpr.span()));
|
||||
}
|
||||
instructions.add(new IRBackendExecutableFunction.Instruction(
|
||||
@ -231,10 +244,7 @@ public final class PbsFrontendCompiler {
|
||||
null,
|
||||
fn.span()));
|
||||
|
||||
final var returnSlots = switch (fn.returnKind()) {
|
||||
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
||||
case PLAIN, RESULT -> 1;
|
||||
};
|
||||
final var returnSlots = returnSlotsFor(fn);
|
||||
final var start = safeToInt(fn.span().getStart());
|
||||
final var end = safeToInt(fn.span().getEnd());
|
||||
executableFunctions.add(new IRBackendExecutableFunction(
|
||||
@ -259,6 +269,19 @@ public final class PbsFrontendCompiler {
|
||||
return (canonicalName + "#" + canonicalVersion).hashCode();
|
||||
}
|
||||
|
||||
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
||||
return switch (functionDecl.returnKind()) {
|
||||
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
||||
case PLAIN, RESULT -> 1;
|
||||
};
|
||||
}
|
||||
|
||||
private String callableArityKey(
|
||||
final String callableName,
|
||||
final int arity) {
|
||||
return callableName + "#" + arity;
|
||||
}
|
||||
|
||||
private int safeToInt(final long value) {
|
||||
if (value > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
|
||||
@ -3,5 +3,6 @@ package p.studio.compiler.backend.irvm;
|
||||
public enum IRVMLoweringErrorCode {
|
||||
LOWER_IRVM_EMPTY_EXECUTABLE_INPUT,
|
||||
LOWER_IRVM_MISSING_CALLEE,
|
||||
LOWER_IRVM_CALL_ARG_SLOTS_MISMATCH,
|
||||
LOWER_IRVM_CALL_RET_SLOTS_MISMATCH,
|
||||
}
|
||||
|
||||
|
||||
@ -65,6 +65,25 @@ public class LowerToIRVMService {
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_MISSING_CALLEE,
|
||||
"missing callee function: " + key);
|
||||
}
|
||||
final var calleeFunction = ordered.get(calleeId);
|
||||
if (instr.expectedArgSlots() != null
|
||||
&& instr.expectedArgSlots() != calleeFunction.paramSlots()) {
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_CALL_ARG_SLOTS_MISMATCH,
|
||||
"call arg_slots mismatch for %s. expected=%d actual=%d".formatted(
|
||||
key,
|
||||
instr.expectedArgSlots(),
|
||||
calleeFunction.paramSlots()));
|
||||
}
|
||||
if (instr.expectedRetSlots() != null
|
||||
&& instr.expectedRetSlots() != calleeFunction.returnSlots()) {
|
||||
throw new IRVMLoweringException(
|
||||
IRVMLoweringErrorCode.LOWER_IRVM_CALL_RET_SLOTS_MISMATCH,
|
||||
"call ret_slots mismatch for %s. expected=%d actual=%d".formatted(
|
||||
key,
|
||||
instr.expectedRetSlots(),
|
||||
calleeFunction.returnSlots()));
|
||||
}
|
||||
instructions.add(new IRVMInstruction(IRVMOp.CALL, calleeId));
|
||||
operations.add(BytecodeEmitter.Operation.callFunc(calleeId));
|
||||
}
|
||||
@ -142,4 +161,3 @@ public class LowerToIRVMService {
|
||||
return (moduleKey == null ? "" : moduleKey) + "::" + callableName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -79,6 +79,20 @@ class LowerToIRVMServiceTest {
|
||||
assertEquals(IRVMLoweringErrorCode.LOWER_IRVM_MISSING_CALLEE, thrown.code());
|
||||
}
|
||||
|
||||
@Test
|
||||
void lowerMustRejectCallArgSlotMismatch() {
|
||||
final var backend = IRBackend.builder()
|
||||
.executableFunctions(ReadOnlyList.from(
|
||||
fn("callee", "app", ReadOnlyList.from(ret())),
|
||||
fn("main", "app", ReadOnlyList.from(
|
||||
callFuncWithExpected("app", "callee", 2, 0),
|
||||
ret()))))
|
||||
.build();
|
||||
|
||||
final var thrown = assertThrows(IRVMLoweringException.class, () -> new LowerToIRVMService().lower(backend));
|
||||
assertEquals(IRVMLoweringErrorCode.LOWER_IRVM_CALL_ARG_SLOTS_MISMATCH, thrown.code());
|
||||
}
|
||||
|
||||
private static IRBackendExecutableFunction fn(
|
||||
final String name,
|
||||
final String moduleKey,
|
||||
@ -117,6 +131,22 @@ class LowerToIRVMServiceTest {
|
||||
Span.none());
|
||||
}
|
||||
|
||||
private static IRBackendExecutableFunction.Instruction callFuncWithExpected(
|
||||
final String moduleKey,
|
||||
final String name,
|
||||
final int expectedArgSlots,
|
||||
final int expectedRetSlots) {
|
||||
return new IRBackendExecutableFunction.Instruction(
|
||||
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
|
||||
moduleKey,
|
||||
name,
|
||||
null,
|
||||
null,
|
||||
expectedArgSlots,
|
||||
expectedRetSlots,
|
||||
Span.none());
|
||||
}
|
||||
|
||||
private static IRBackendExecutableFunction.Instruction callHost(
|
||||
final String module,
|
||||
final String name,
|
||||
@ -145,4 +175,3 @@ class LowerToIRVMServiceTest {
|
||||
Span.none());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user