Provide missing arguments when stepping into a function (#10879)

close #10792

Changelog:
- update: replace missing arguments with `Nothing` when schedule a function execution in interactive mode
This commit is contained in:
Dmitry Bushev 2024-08-23 22:13:58 +03:00 committed by GitHub
parent 3d23e22c6f
commit 09722b36dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 120 additions and 2 deletions

View File

@ -202,7 +202,7 @@ public final class ExecutionService {
Object p = context.getThreadManager().enter();
try {
execute.getCallTarget().call(call);
execute.getCallTarget().call(substituteMissingArguments(call));
} finally {
context.getThreadManager().leave(p);
eventNodeFactory.ifPresent(EventBinding::dispose);
@ -261,6 +261,28 @@ public final class ExecutionService {
onExecutedVisualizationCallback);
}
/**
* Replace missing arguments of the provided function call with {@link
* org.enso.interpreter.node.expression.builtin.Nothing} to make sure that the function call can
* be invoked.
*
* @param functionCall the function call to update
* @return a function call with the updated arguments
*/
private FunctionCallInstrumentationNode.FunctionCall substituteMissingArguments(
FunctionCallInstrumentationNode.FunctionCall functionCall) {
var arguments = functionCall.getArguments().clone();
var argumentInfos = functionCall.getFunction().getSchema().getArgumentInfos();
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] == null && !argumentInfos[i].hasDefaultValue()) {
arguments[i] = context.getBuiltins().nothing();
}
}
return new FunctionCallInstrumentationNode.FunctionCall(
functionCall.getFunction(), functionCall.getState(), arguments);
}
/**
* Evaluates an expression in the scope of the provided module.
*

View File

@ -489,6 +489,96 @@ class RuntimeServerTest
)
}
it should "substitute Nothing when pushing method with unapplied arguments" in {
val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID()
val moduleName = "Enso_Test.Test.Main"
val metadata = new Metadata
val identityResultId = metadata.addItem(13, 1, "aa")
val identityCallId = metadata.addItem(27, 8, "ab")
val code =
"""identity x = x
|
|main =
| identity
|""".stripMargin.linesIterator.mkString("\n")
val contents = metadata.appendToCode(code)
val mainFile = context.writeMain(contents)
// create context
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
context.receive shouldEqual Some(
Api.Response(requestId, Api.CreateContextResponse(contextId))
)
// open file
context.send(
Api.Request(requestId, Api.OpenFileRequest(mainFile, contents))
)
context.receive shouldEqual Some(
Api.Response(Some(requestId), Api.OpenFileResponse)
)
// push main
context.send(
Api.Request(
requestId,
Api.PushContextRequest(
contextId,
Api.StackItem.ExplicitCall(
Api.MethodPointer(moduleName, moduleName, "main"),
None,
Vector()
)
)
)
)
context.receiveN(3) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)),
TestMessages.update(
contextId,
identityCallId,
ConstantsGen.FUNCTION_BUILTIN,
methodCall = Some(
Api.MethodCall(
Api.MethodPointer(moduleName, moduleName, "identity"),
Vector(0)
)
),
payload = Api.ExpressionUpdate.Payload.Value(
functionSchema = Some(
Api.FunctionSchema(
Api.MethodPointer(moduleName, moduleName, "identity"),
Vector(0)
)
)
)
),
context.executionComplete(contextId)
)
context.consumeOut shouldEqual List()
// push identity
context.send(
Api.Request(
requestId,
Api.PushContextRequest(
contextId,
Api.StackItem.LocalCall(identityCallId)
)
)
)
context.receiveN(3) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)),
TestMessages
.update(contextId, identityResultId, ConstantsGen.NOTHING_BUILTIN),
context.executionComplete(contextId)
)
context.consumeOut shouldEqual List()
}
it should "push method with default arguments on top of the stack" in {
val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID()
@ -7244,4 +7334,5 @@ class RuntimeServerTest
)
context.consumeOut shouldEqual List("Hello World!")
}
}

View File

@ -120,7 +120,12 @@ public class FunctionCallInstrumentationNode extends Node implements Instrumenta
}
/**
* @return the arguments passed to the function in this call.
* Get the arguments passed to the function in this call.
*
* <p>The {@code null} value in the arguments array indicates that the corresponding argument
* was not provided, and the default value should be used.
*
* @return the function arguments provided to this call
*/
public Object[] getArguments() {
return arguments;