Consistent self types (#6867)

close #6800

Update the `executionContext/expressionUpdates` notification and send the list of not applied arguments in addition to the method pointer.

# Important Notes
IDE is updated to support the new API.
This commit is contained in:
Dmitry Bushev 2023-05-31 16:47:48 +01:00 committed by GitHub
parent 65958cba92
commit ed3f9b306e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1218 additions and 225 deletions

View File

@ -348,7 +348,7 @@ fn test_computed_value_update() {
let update = &expression_updates.updates.first().unwrap();
assert_eq!(update.expression_id, id);
assert_eq!(update.typename.as_deref(), Some(typename));
assert!(update.method_pointer.is_none());
assert!(update.method_call.is_none());
assert!(update.from_cache);
assert!(matches!(update.payload, ExpressionUpdatePayload::Value { warnings: None }))
}

View File

@ -216,7 +216,7 @@ pub struct ExpressionUpdate {
pub expression_id: ExpressionId,
#[serde(rename = "type")] // To avoid collision with the `type` keyword.
pub typename: Option<String>,
pub method_pointer: Option<MethodPointer>,
pub method_call: Option<MethodCall>,
pub profiling_info: Vec<ProfilingInfo>,
pub from_cache: bool,
pub payload: ExpressionUpdatePayload,
@ -740,6 +740,16 @@ pub struct MethodPointer {
pub name: String,
}
/// A representation of a method call.
#[derive(Hash, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MethodCall {
/// The method pointer of a call.
pub method_pointer: MethodPointer,
/// Indexes of arguments that have not been applied to this method.
pub not_applied_arguments: Vec<usize>,
}
/// Used for entering a method. The first item on the execution context stack should always be
/// an `ExplicitCall`.
#[derive(Hash, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -1226,7 +1236,7 @@ pub mod test {
ExpressionUpdate {
expression_id: id,
typename: Some(typename.into()),
method_pointer: None,
method_call: None,
profiling_info: default(),
from_cache: false,
payload: ExpressionUpdatePayload::Value { warnings: None },
@ -1242,7 +1252,7 @@ pub mod test {
ExpressionUpdate {
expression_id: id,
typename: None,
method_pointer: Some(method_pointer),
method_call: Some(MethodCall { method_pointer, not_applied_arguments: vec![] }),
profiling_info: default(),
from_cache: false,
payload: ExpressionUpdatePayload::Value { warnings: None },
@ -1256,7 +1266,7 @@ pub mod test {
ExpressionUpdate {
expression_id: id,
typename: None,
method_pointer: None,
method_call: None,
profiling_info: default(),
from_cache: false,
payload: ExpressionUpdatePayload::DataflowError { trace },
@ -1274,7 +1284,7 @@ pub mod test {
ExpressionUpdate {
expression_id: id,
typename: None,
method_pointer: None,
method_call: None,
profiling_info: default(),
from_cache: false,
payload: ExpressionUpdatePayload::Panic { trace, message },

View File

@ -64,7 +64,7 @@ impl From<ExpressionUpdate> for ComputedValueInfo {
fn from(update: ExpressionUpdate) -> Self {
ComputedValueInfo {
typename: update.typename.map(ImString::new),
method_call: update.method_pointer,
method_call: update.method_call.map(|mc| mc.method_pointer),
payload: update.payload,
}
}

View File

@ -950,7 +950,10 @@ mod test {
// Context now has the information about type.
let value_info = value_registry.get(&expression_id).unwrap();
assert_eq!(value_info.typename, value_update.typename.clone().map(ImString::new));
assert_eq!(value_info.method_call, value_update.method_pointer);
assert_eq!(
value_info.method_call,
value_update.method_call.clone().map(|mc| mc.method_pointer)
);
}

View File

@ -22,6 +22,7 @@ transport formats, please look [here](./protocol-architecture).
- [`ExpressionId`](#expressionid)
- [`ContextId`](#contextid)
- [`StackItem`](#stackitem)
- [`MethodCall`](#methodcall)
- [`MethodPointer`](#methodpointer)
- [`ProfilingInfo`](#profilinginfo)
- [`ExpressionUpdate`](#expressionupdate)
@ -271,6 +272,20 @@ interface LocalCall {
}
```
### `MethodCall`
A representation of a method call.
```typescript
interface MethodCall {
/** The method pointer of a call. */
methodPointer: MethodPointer;
/** Indexes of arguments that have not been applied to this method. */
notAppliedArguments: number[];
}
```
### `MethodPointer`
Points to a method definition.
@ -331,9 +346,9 @@ interface ExpressionUpdate {
type?: String;
/**
* The updated pointer to the method call.
* The updated method call info.
*/
methodPointer?: MethodPointer;
methodCall?: MethodCall;
/**
* Profiling information about the expression.

View File

@ -186,7 +186,7 @@ final class ContextEventsListener(
ContextRegistryProtocol.ExpressionUpdate(
update.expressionId,
update.expressionType,
update.methodCall.map(toProtocolMethodPointer),
update.methodCall.map(toProtocolMethodCall),
update.profilingInfo.map(toProtocolProfilingInfo),
update.fromCache,
toProtocolPayload(update.payload)
@ -248,8 +248,20 @@ final class ContextEventsListener(
ProfilingInfo.ExecutionTime(t)
}
/** Convert the runtime method call to the context registry protocol
* representation.
*
* @param methodCall the method call
* @return the registry protocol representation of the method call
*/
private def toProtocolMethodCall(methodCall: Api.MethodCall): MethodCall =
MethodCall(
toProtocolMethodPointer(methodCall.methodPointer),
methodCall.notAppliedArguments
)
/** Convert the runtime method pointer to the context registry protocol
* representation
* representation.
*
* @param methodPointer the method pointer
* @return the registry protocol representation of the method pointer

View File

@ -176,7 +176,7 @@ object ContextRegistryProtocol {
*
* @param expressionId the id of updated expression
* @param `type` the updated type of expression
* @param methodPointer the updated method pointer
* @param methodCall the updated method call
* @param profilingInfo profiling information about the expression
* @param fromCache whether or not the expression's value came from the cache
* @param payload an extra information about the computed value
@ -184,7 +184,7 @@ object ContextRegistryProtocol {
case class ExpressionUpdate(
expressionId: UUID,
`type`: Option[String],
methodPointer: Option[MethodPointer],
methodCall: Option[MethodCall],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean,
payload: ExpressionUpdate.Payload

View File

@ -0,0 +1,32 @@
package org.enso.languageserver.runtime
import org.enso.polyglot.runtime.Runtime.Api
/** A representation of a method call.
*
* @param methodPointer the method pointer of a call
* @param notAppliedArguments indexes of arguments that have not been applied
* to this method
*/
case class MethodCall(
methodPointer: MethodPointer,
notAppliedArguments: Vector[Int]
) {
/** Convert this method call to the corresponding [[Api]] message. */
def toApi: Api.MethodCall =
Api.MethodCall(methodPointer.toApi, notAppliedArguments)
}
/** An object pointing to a method definition.
*
* @param module the module of the method file
* @param definedOnType method type
* @param name method name
*/
case class MethodPointer(module: String, definedOnType: String, name: String) {
/** Convert this method pointer to the corresponding [[Api]] message. */
def toApi: Api.MethodPointer =
Api.MethodPointer(module, definedOnType, name)
}

View File

@ -1,16 +0,0 @@
package org.enso.languageserver.runtime
import org.enso.polyglot.runtime.Runtime.Api
/** An object pointing to a method definition.
*
* @param module the module of the method file
* @param definedOnType method type
* @param name method name
*/
case class MethodPointer(module: String, definedOnType: String, name: String) {
/** Convert to corresponding [[Api]] message. */
def toApi: Api.MethodPointer =
Api.MethodPointer(module, definedOnType, name)
}

View File

@ -55,13 +55,14 @@ class ContextEventsListenerSpec
Suggestions.method.selfType,
Suggestions.method.name
)
val methodCall = Api.MethodCall(methodPointer)
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate(
Suggestions.method.externalId.get,
Some(Suggestions.method.returnType),
Some(methodPointer),
Some(methodCall),
Vector(),
false,
true,
@ -79,7 +80,7 @@ class ContextEventsListenerSpec
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.method.externalId.get,
Some(Suggestions.method.returnType),
Some(toProtocolMethodPointer(methodPointer)),
Some(toProtocolMethodCall(methodCall)),
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload.Value(None)
@ -477,6 +478,12 @@ class ContextEventsListenerSpec
}
}
def toProtocolMethodCall(methodCall: Api.MethodCall): MethodCall =
MethodCall(
toProtocolMethodPointer(methodCall.methodPointer),
methodCall.notAppliedArguments
)
def toProtocolMethodPointer(methodPointer: Api.MethodPointer): MethodPointer =
MethodPointer(
methodPointer.module,

View File

@ -307,14 +307,34 @@ object Runtime {
*/
sealed trait Error extends ApiResponse
/** A representation of a pointer to a method definition.
*/
/** A representation of a pointer to a method definition. */
case class MethodPointer(
module: String,
definedOnType: String,
name: String
)
/** A representation of a method call.
*
* @param methodPointer the method pointer of a call
* @param notAppliedArguments indexes of arguments that have not been applied
* to this method
*/
case class MethodCall(
methodPointer: MethodPointer,
notAppliedArguments: Vector[Int]
)
object MethodCall {
/** Create a method call with all the arguments applied.
*
* @param methodPointer the method pointer of a call
* @return a new [[MethodCall]].
*/
def apply(methodPointer: MethodPointer): MethodCall =
MethodCall(methodPointer, Vector())
}
/** A representation of an executable position in code.
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@ -362,7 +382,7 @@ object Runtime {
*
* @param expressionId the expression id
* @param expressionType the type of expression
* @param methodCall the pointer to a method definition
* @param methodCall the underlying method call of this expression
* @param profilingInfo profiling information about the execution of this
* expression
* @param fromCache whether or not the value for this expression came
@ -374,7 +394,7 @@ object Runtime {
case class ExpressionUpdate(
expressionId: ExpressionId,
expressionType: Option[String],
methodCall: Option[MethodPointer],
methodCall: Option[MethodCall],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean,
typeChanged: Boolean,

View File

@ -308,8 +308,7 @@ public class IdExecutionInstrument extends TruffleInstrument implements IdExecut
@CompilerDirectives.TruffleBoundary
private void onFunctionReturn(UUID nodeId, FunctionCallInstrumentationNode.FunctionCall result, EventContext context) throws ThreadDeath {
calls.put(
nodeId, new FunctionCallInfo(result));
calls.put(nodeId, new FunctionCallInfo(result));
functionCallCallback.accept(new ExpressionCall(nodeId, result));
// Return cached value after capturing the enterable function call in `functionCallCallback`
Object cachedResult = cache.get(nodeId);

View File

@ -28,10 +28,10 @@ import static org.junit.Assert.fail;
services = NodeCountingTestInstrument.class)
public class NodeCountingTestInstrument extends TruffleInstrument {
public static final String INSTRUMENT_ID = "node-count-test";
private Map<Node, Node> all = new ConcurrentHashMap<>();
private final Map<Node, Node> all = new ConcurrentHashMap<>();
private Map<Class, List<Node>> counter = new ConcurrentHashMap<>();
private Map<UUID, FunctionCallInfo> calls = new ConcurrentHashMap<>();
private final Map<UUID, FunctionCallInfo> calls = new ConcurrentHashMap<>();
private Env env;
@Override
@ -107,7 +107,7 @@ public class NodeCountingTestInstrument extends TruffleInstrument {
}
}
private class NodeWrapper extends ExecutionEventNode {
private static class NodeWrapper extends ExecutionEventNode {
private final EventContext context;
@ -134,7 +134,7 @@ public class NodeCountingTestInstrument extends TruffleInstrument {
}
public class FunctionCallInfo {
public static class FunctionCallInfo {
private final QualifiedName moduleName;
private final QualifiedName typeName;

View File

@ -19,6 +19,7 @@ import org.enso.polyglot.runtime.Runtime$Api$EditFileNotification;
import org.enso.polyglot.runtime.Runtime$Api$ExecutionFailed;
import org.enso.polyglot.runtime.Runtime$Api$ExpressionUpdates;
import org.enso.polyglot.runtime.Runtime$Api$InitializedNotification;
import org.enso.polyglot.runtime.Runtime$Api$MethodCall;
import org.enso.polyglot.runtime.Runtime$Api$MethodPointer;
import org.enso.polyglot.runtime.Runtime$Api$PushContextRequest;
import org.enso.polyglot.runtime.Runtime$Api$PushContextResponse;
@ -39,6 +40,7 @@ import scala.collection.immutable.List;
import scala.collection.immutable.Seq;
import scala.collection.immutable.Set;
import scala.collection.immutable.Set$;
import scala.collection.immutable.Vector$;
import scala.collection.immutable.Vector1;
public class IncrementalUpdatesTest {
@ -217,14 +219,14 @@ public class IncrementalUpdatesTest {
assertSameElements(context.receiveNIgnorePendingExpressionUpdates(5, 10, emptySet()),
Response(requestId, new Runtime$Api$PushContextResponse(contextId)),
TestMessages.update(contextId, mainFoo, exprType, new Runtime$Api$MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo")),
TestMessages.update(contextId, mainFoo, exprType, new Runtime$Api$MethodCall(new Runtime$Api$MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo"), Vector$.MODULE$.empty())),
TestMessages.update(contextId, mainRes, ConstantsGen.NOTHING),
context.executionComplete(contextId),
Response(new Runtime$Api$BackgroundJobsStartedNotification())
);
assertEquals(List.newBuilder().addOne(originalOutput), context.consumeOut());
nodeCountingInstrument.assertNewNodes("Execution creates some nodes", 20, 35);
var allNodesAfterException = nodeCountingInstrument.assertNewNodes("Execution creates some nodes", 20, 35);
// push foo call
context.send(
@ -241,7 +243,7 @@ public class IncrementalUpdatesTest {
);
assertEquals(List.newBuilder().addOne(originalOutput), context.consumeOut());
var allNodesAfterException = nodeCountingInstrument.assertNewNodes("There shall be more nodes after execution", 23, Integer.MAX_VALUE);
nodeCountingInstrument.assertNewNodes("No new nodes created", 0, 0);
var literalNode = findLiteralNode(truffleNodeType, allNodesAfterException);
assertEquals("Check Literal node text in the source", originalText, literalNode.getSourceSection().getCharacters().toString());

View File

@ -366,7 +366,9 @@ class RuntimeErrorsTest
TestMessages.panic(
contextId,
mainBodyId,
Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo"),
Api.MethodCall(
Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo")
),
Api.ExpressionUpdate.Payload.Panic(
"Compile_Error.Error",
Seq(mainBodyId)
@ -440,7 +442,9 @@ class RuntimeErrorsTest
TestMessages.panic(
contextId,
mainBodyId,
Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo"),
Api.MethodCall(
Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo")
),
Api.ExpressionUpdate.Payload.Panic(
"Compile error: The name `x` could not be found.",
Seq(mainBodyId)
@ -994,7 +998,7 @@ class RuntimeErrorsTest
TestMessages.error(
contextId,
xId,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "foo")),
Api.ExpressionUpdate.Payload.DataflowError(Seq(fooThrowId, xId))
),
TestMessages.error(
@ -1449,7 +1453,7 @@ class RuntimeErrorsTest
TestMessages.panic(
contextId,
xId,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "foo")),
Api.ExpressionUpdate.Payload.Panic(
"9 (Integer)",
Seq(xId)
@ -1498,7 +1502,7 @@ class RuntimeErrorsTest
contextId,
xId,
ConstantsGen.INTEGER,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "foo")),
fromCache = false,
typeChanged = true
),
@ -1568,7 +1572,7 @@ class RuntimeErrorsTest
TestMessages.panic(
contextId,
xId,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "foo")),
Api.ExpressionUpdate.Payload.Panic(
"java.lang.NullPointerException",
Seq(xId)
@ -1637,7 +1641,7 @@ class RuntimeErrorsTest
TestMessages.error(
contextId,
xId,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "foo")),
Api.ExpressionUpdate.Payload.DataflowError(Seq(xId))
),
TestMessages.error(
@ -1677,7 +1681,7 @@ class RuntimeErrorsTest
contextId,
xId,
ConstantsGen.INTEGER,
Api.MethodPointer(moduleName, moduleName, "foo"),
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "foo")),
fromCache = false,
typeChanged = true
),

View File

@ -31,7 +31,7 @@ class RuntimeExecutionEnvironmentTest
with BeforeAndAfterAll
with OsSpec {
import RuntimeExecutionEnvironmentTest.IF_ENABLED_METH_PTR
import RuntimeExecutionEnvironmentTest.IF_ENABLED_METH_CALL
override val timeLimit = 5.minutes
@ -186,7 +186,7 @@ class RuntimeExecutionEnvironmentTest
TestMessages.panic(
contextId,
idRes,
IF_ENABLED_METH_PTR,
IF_ENABLED_METH_CALL,
Api.ExpressionUpdate.Payload
.Panic("Forbidden operation: Output.", Seq(idRes)),
false
@ -218,7 +218,7 @@ class RuntimeExecutionEnvironmentTest
Api.ExpressionUpdate(
idRes,
Some(ConstantsGen.NOTHING),
Some(IF_ENABLED_METH_PTR),
Some(IF_ENABLED_METH_CALL),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
true,
@ -286,7 +286,7 @@ class RuntimeExecutionEnvironmentTest
TestMessages.panic(
contextId,
idRes,
IF_ENABLED_METH_PTR,
IF_ENABLED_METH_CALL,
Api.ExpressionUpdate.Payload
.Panic("Forbidden operation: Input.", Seq(idRes)),
false
@ -318,7 +318,7 @@ class RuntimeExecutionEnvironmentTest
Api.ExpressionUpdate(
idRes,
Some(ConstantsGen.INTEGER),
Some(IF_ENABLED_METH_PTR),
Some(IF_ENABLED_METH_CALL),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
true,
@ -337,9 +337,14 @@ class RuntimeExecutionEnvironmentTest
}
object RuntimeExecutionEnvironmentTest {
val IF_ENABLED_METH_PTR = Api.MethodPointer(
"Standard.Base.Runtime",
"Standard.Base.Runtime.Context",
"if_enabled"
)
private val IF_ENABLED_METH_CALL =
Api.MethodCall(
Api.MethodPointer(
"Standard.Base.Runtime",
"Standard.Base.Runtime.Context",
"if_enabled"
),
Vector(2)
)
}

View File

@ -248,7 +248,7 @@ class RuntimeInstrumentTest
contextId,
mainBody,
fooTypeName,
Api.MethodPointer(moduleName, fooTypeName, "from")
Api.MethodCall(Api.MethodPointer(moduleName, fooTypeName, "from"))
),
context.executionComplete(contextId)
)
@ -607,7 +607,9 @@ class RuntimeInstrumentTest
contextId,
xExpr,
ConstantsGen.INTEGER_BUILTIN,
Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "f")
Api.MethodCall(
Api.MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "f")
)
),
TestMessages.update(contextId, mainRes, ConstantsGen.INTEGER_BUILTIN),
TestMessages.update(contextId, mainExpr, ConstantsGen.INTEGER_BUILTIN),

View File

@ -158,10 +158,12 @@ class RuntimeVisualizationsTest
Main.idMainY,
Some(ConstantsGen.INTEGER),
Some(
Api.MethodPointer(
"Enso_Test.Test.Main",
ConstantsGen.NUMBER,
"foo"
Api.MethodCall(
Api.MethodPointer(
"Enso_Test.Test.Main",
ConstantsGen.NUMBER,
"foo"
)
)
),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
@ -3114,11 +3116,13 @@ class RuntimeVisualizationsTest
contextId,
idX,
ConstantsGen.INTEGER,
methodPointer = Some(
Api.MethodPointer(
warningModuleName.toString,
warningTypeName.toString + ".type",
"attach"
methodCall = Some(
Api.MethodCall(
Api.MethodPointer(
warningModuleName.toString,
warningTypeName.toString,
"attach"
)
)
),
payload = Api.ExpressionUpdate.Payload.Value(
@ -3131,13 +3135,15 @@ class RuntimeVisualizationsTest
contextId,
idRes,
s"$moduleName.Newtype",
methodCall = Some(
Api.MethodCall(
Api.MethodPointer(moduleName, s"$moduleName.Newtype", "Mk_Newtype")
)
),
payload = Api.ExpressionUpdate.Payload.Value(
Some(
Api.ExpressionUpdate.Payload.Value.Warnings(1, Some("'x'"), false)
)
),
methodPointer = Some(
Api.MethodPointer(moduleName, s"$moduleName.Newtype", "Mk_Newtype")
)
),
context.executionComplete(contextId)
@ -3246,14 +3252,14 @@ class RuntimeVisualizationsTest
contextId,
idY,
ConstantsGen.INTEGER_BUILTIN,
Api.MethodPointer(moduleName, s"$moduleName.T", "inc")
Api.MethodCall(Api.MethodPointer(moduleName, s"$moduleName.T", "inc"))
),
TestMessages.update(contextId, idS, ConstantsGen.INTEGER_BUILTIN),
TestMessages.update(
contextId,
idZ,
ConstantsGen.INTEGER_BUILTIN,
Api.MethodPointer(moduleName, moduleName, "p")
Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "p"))
),
TestMessages.update(contextId, idZexprS, ConstantsGen.INTEGER_BUILTIN),
TestMessages.update(contextId, idZexpr1, ConstantsGen.INTEGER_BUILTIN),

View File

@ -4,6 +4,7 @@ import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.instrumentation.EventBinding;
import com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory;
import com.oracle.truffle.api.nodes.RootNode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
@ -15,7 +16,10 @@ import org.enso.interpreter.node.MethodRootNode;
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
import org.enso.interpreter.node.expression.atom.QualifiedAccessorNode;
import org.enso.interpreter.runtime.Module;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.data.Type;
import org.enso.logger.masking.MaskedString;
import org.enso.pkg.QualifiedName;
@ -203,6 +207,8 @@ public interface IdExecutionService {
private final QualifiedName typeName;
private final String functionName;
private final int[] notAppliedArguments;
/**
* Creates a new instance of this class.
*
@ -210,24 +216,31 @@ public interface IdExecutionService {
*/
public FunctionCallInfo(FunctionCallInstrumentationNode.FunctionCall call) {
RootNode rootNode = call.getFunction().getCallTarget().getRootNode();
if (rootNode instanceof MethodRootNode methodNode) {
moduleName = methodNode.getModuleScope().getModule().getName();
typeName = methodNode.getType().getQualifiedName();
functionName = methodNode.getMethodName();
} else if (rootNode instanceof QualifiedAccessorNode qualifiedAccessor) {
AtomConstructor atomConstructor = qualifiedAccessor.getAtomConstructor();
moduleName = atomConstructor.getDefinitionScope().getModule().getName();
typeName = atomConstructor.getType().getQualifiedName();
functionName = atomConstructor.getDisplayName();
} else if (rootNode instanceof EnsoRootNode ensoRootNode) {
moduleName = ensoRootNode.getModuleScope().getModule().getName();
typeName = null;
functionName = rootNode.getName();
} else {
moduleName = null;
typeName = null;
functionName = rootNode.getName();
switch (rootNode) {
case MethodRootNode methodNode -> {
moduleName = methodNode.getModuleScope().getModule().getName();
typeName = methodNode.getType().getQualifiedName();
functionName = methodNode.getMethodName();
}
case QualifiedAccessorNode qualifiedAccessor -> {
AtomConstructor atomConstructor = qualifiedAccessor.getAtomConstructor();
moduleName = atomConstructor.getDefinitionScope().getModule().getName();
typeName = atomConstructor.getType().getQualifiedName();
functionName = atomConstructor.getDisplayName();
}
case EnsoRootNode ensoRootNode -> {
moduleName = ensoRootNode.getModuleScope().getModule().getName();
typeName = null;
functionName = rootNode.getName();
}
case default -> {
moduleName = null;
typeName = null;
functionName = rootNode.getName();
}
}
notAppliedArguments = collectNotAppliedArguments(call);
}
@Override
@ -268,5 +281,27 @@ public interface IdExecutionService {
public String getFunctionName() {
return functionName;
}
/** @return the arguments of this function that have not yet been applied. */
public int[] getNotAppliedArguments() {
return notAppliedArguments;
}
private static int[] collectNotAppliedArguments(FunctionCallInstrumentationNode.FunctionCall call) {
Object[] arguments = call.getArguments();
int[] notAppliedArgs = new int[arguments.length];
int notAppliedArgsSize = 0;
boolean isStatic = arguments[0] instanceof Type;
int selfTypePosition = isStatic ? -1 : 0;
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] == null) {
notAppliedArgs[notAppliedArgsSize] = i + selfTypePosition;
notAppliedArgsSize += 1;
}
}
return Arrays.copyOf(notAppliedArgs, notAppliedArgsSize);
}
}
}

View File

@ -377,16 +377,18 @@ public class ExecutionService {
throw new SourceNotFoundException(module.getName(), e);
}
JavaEditorAdapter.applyEdits(module.getLiteralSource(), edits)
.fold(
failure -> {
throw new FailedToApplyEditsException(
module.getName(), edits, failure, module.getLiteralSource());
},
rope -> {
module.setLiteralSource(rope, simpleUpdate);
return new Object();
});
if (edits.nonEmpty() || simpleUpdate != null) {
JavaEditorAdapter.applyEdits(module.getLiteralSource(), edits)
.fold(
failure -> {
throw new FailedToApplyEditsException(
module.getName(), edits, failure, module.getLiteralSource());
},
rope -> {
module.setLiteralSource(rope, simpleUpdate);
return new Object();
});
}
}
/**

View File

@ -961,7 +961,7 @@ class IrToTruffle(
* @param block the block to generate code for
* @return the truffle nodes corresponding to `block`
*/
def processBlock(block: IR.Expression.Block): RuntimeExpression = {
private def processBlock(block: IR.Expression.Block): RuntimeExpression = {
if (block.suspended) {
val scopeInfo = block
.unsafeGetMetadata(
@ -1383,7 +1383,9 @@ class IrToTruffle(
* @param binding the binding to generate code for
* @return the truffle nodes corresponding to `binding`
*/
def processBinding(binding: IR.Expression.Binding): RuntimeExpression = {
private def processBinding(
binding: IR.Expression.Binding
): RuntimeExpression = {
val occInfo = binding
.unsafeGetMetadata(
AliasAnalysis,

View File

@ -326,7 +326,7 @@ object ProgramExecutionSupport {
value: ExpressionValue
)(implicit ctx: RuntimeContext): Unit = {
val expressionId = value.getExpressionId
val methodPointer = toMethodPointer(value)
val methodPointer = toMethodCall(value)
if (
!syncState.isExpressionSync(expressionId) ||
(
@ -391,7 +391,7 @@ object ProgramExecutionSupport {
Api.ProfilingInfo.ExecutionTime(e.getNanoTimeElapsed)
}.toVector,
value.wasCached(),
value.isTypeChanged() || value.isFunctionCallChanged(),
value.isTypeChanged || value.isFunctionCallChanged,
payload
)
)
@ -535,23 +535,26 @@ object ProgramExecutionSupport {
)
}
/** Extract method pointer information from the expression value.
/** Extract the method call information from the provided expression value.
*
* @param value the expression value.
* @return the method pointer info
* @return the method call info
*/
private def toMethodPointer(
value: ExpressionValue
): Option[Api.MethodPointer] =
private def toMethodCall(value: ExpressionValue): Option[Api.MethodCall] =
for {
call <- Option(value.getCallInfo).orElse(Option(value.getCachedCallInfo))
moduleName <- Option(call.getModuleName)
typeName <- Option(call.getTypeName)
} yield Api.MethodPointer(
moduleName.toString,
typeName.toString,
call.getFunctionName
)
} yield {
Api.MethodCall(
methodPointer = Api.MethodPointer(
moduleName.toString,
typeName.toString.stripSuffix(TypeSuffix),
call.getFunctionName
),
notAppliedArguments = call.getNotAppliedArguments.toVector
)
}
/** Find source file path by the module name.
*
@ -590,4 +593,6 @@ object ProgramExecutionSupport {
cache: RuntimeCache,
syncState: UpdatesSynchronizationState
)
private val TypeSuffix = ".type"
}

View File

@ -71,7 +71,7 @@ object TestMessages {
* @param expressionType a type of the expression
* @param fromCache whether or not the value for this expression came from cache
* @param typeChanged a flag indicating whether the the type of expression has changed
* @param methodPointer method pointer
* @param methodCall the method call
* @param payload the update payload
* @return the expression update response
*/
@ -79,10 +79,10 @@ object TestMessages {
contextId: UUID,
expressionId: UUID,
expressionType: String,
fromCache: Boolean = false,
typeChanged: Boolean = true,
methodPointer: Option[Api.MethodPointer] = None,
payload: Api.ExpressionUpdate.Payload = Api.ExpressionUpdate.Payload.Value()
fromCache: Boolean = false,
typeChanged: Boolean = true,
methodCall: Option[Api.MethodCall] = None,
payload: Api.ExpressionUpdate.Payload = Api.ExpressionUpdate.Payload.Value()
): Api.Response =
Api.Response(
Api.ExpressionUpdates(
@ -91,7 +91,7 @@ object TestMessages {
Api.ExpressionUpdate(
expressionId,
Some(expressionType),
methodPointer,
methodCall,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache,
typeChanged,
@ -106,23 +106,23 @@ object TestMessages {
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param expressionType a type of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @return the expression update response
*/
def update(
contextId: UUID,
expressionId: UUID,
expressionType: String,
methodPointer: Api.MethodPointer
methodCall: Api.MethodCall
): Api.Response =
update(contextId, expressionId, expressionType, methodPointer, false, true)
update(contextId, expressionId, expressionType, methodCall, false, true)
/** Create an update response.
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param expressionType a type of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @param fromCache whether or not the value for this expression came
* from the cache
* @param typeChanged a flag indicating whether the the type of expression has changed
@ -132,7 +132,7 @@ object TestMessages {
contextId: UUID,
expressionId: UUID,
expressionType: String,
methodPointer: Api.MethodPointer,
methodCall: Api.MethodCall,
fromCache: Boolean,
typeChanged: Boolean
): Api.Response =
@ -143,7 +143,7 @@ object TestMessages {
Api.ExpressionUpdate(
expressionId,
Some(expressionType),
Some(methodPointer),
Some(methodCall),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache,
typeChanged,
@ -178,20 +178,20 @@ object TestMessages {
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @param payload the error payload
* @return the expression update response
*/
def error(
contextId: UUID,
expressionId: UUID,
methodPointer: Api.MethodPointer,
methodCall: Api.MethodCall,
payload: Api.ExpressionUpdate.Payload
): Api.Response =
error(
contextId,
expressionId,
methodPointer,
methodCall,
false,
true,
payload
@ -201,7 +201,7 @@ object TestMessages {
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @param fromCache whether or not the value for this expression came
* from the cache
* @param typeChanged a flag indicating whether the the type of expression has changed
@ -211,7 +211,7 @@ object TestMessages {
def error(
contextId: UUID,
expressionId: UUID,
methodPointer: Api.MethodPointer,
methodCall: Api.MethodCall,
fromCache: Boolean,
typeChanged: Boolean,
payload: Api.ExpressionUpdate.Payload
@ -219,7 +219,7 @@ object TestMessages {
errorBuilder(
contextId,
expressionId,
Some(methodPointer),
Some(methodCall),
fromCache,
typeChanged,
payload
@ -229,7 +229,7 @@ object TestMessages {
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointerOpt a pointer to the method definition
* @param methodCallOpt a pointer to the method definition
* @param fromCache whether or not the value for this expression came
* from the cache
* @param typeChanged a flag indicating whether the the type of expression has changed
@ -239,7 +239,7 @@ object TestMessages {
private def errorBuilder(
contextId: UUID,
expressionId: UUID,
methodPointerOpt: Option[Api.MethodPointer],
methodCallOpt: Option[Api.MethodCall],
fromCache: Boolean,
typeChanged: Boolean,
payload: Api.ExpressionUpdate.Payload
@ -251,7 +251,7 @@ object TestMessages {
Api.ExpressionUpdate(
expressionId,
Some(ConstantsGen.ERROR),
methodPointerOpt,
methodCallOpt,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache,
typeChanged,
@ -304,7 +304,7 @@ object TestMessages {
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @param payload the error payload
* @param builtin a flag indicating what is the type of Panic (a builtin Panic type or stdlib Panic)
* @return the expression update response
@ -312,14 +312,14 @@ object TestMessages {
def panic(
contextId: UUID,
expressionId: UUID,
methodPointer: Api.MethodPointer,
methodCall: Api.MethodCall,
payload: Api.ExpressionUpdate.Payload,
builtin: Boolean
): Api.Response =
panicBuilder(
contextId,
expressionId,
Some(methodPointer),
Some(methodCall),
payload,
builtin,
true
@ -329,7 +329,7 @@ object TestMessages {
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @param payload the error payload
* @param builtin the type to use
* @return the expression update response
@ -337,14 +337,14 @@ object TestMessages {
def panic(
contextId: UUID,
expressionId: UUID,
methodPointer: Api.MethodPointer,
methodCall: Api.MethodCall,
payload: Api.ExpressionUpdate.Payload,
builtin: Option[String]
): Api.Response =
panicBuilder(
contextId,
expressionId,
Some(methodPointer),
Some(methodCall),
payload,
builtin,
true
@ -353,7 +353,7 @@ object TestMessages {
def panic(
contextId: UUID,
expressionId: UUID,
methodPointer: Api.MethodPointer,
methodCall: Api.MethodCall,
payload: Api.ExpressionUpdate.Payload,
builtin: Option[String],
typeChanged: Boolean
@ -361,7 +361,7 @@ object TestMessages {
panicBuilder(
contextId,
expressionId,
Some(methodPointer),
Some(methodCall),
payload,
builtin,
typeChanged
@ -371,7 +371,7 @@ object TestMessages {
*
* @param contextId an identifier of the context
* @param expressionId an identifier of the expression
* @param methodPointer a pointer to the method definition
* @param methodCall a pointer to the method definition
* @param payload the error payload
* @param builtin a flag indicating what is the type of Panic (a builtin Panic type or stdlib Panic)
* @param typeChanged a flag indicating whether the the type of expression has changed
@ -380,14 +380,14 @@ object TestMessages {
private def panicBuilder(
contextId: UUID,
expressionId: UUID,
methodPointer: Option[Api.MethodPointer],
methodCall: Option[Api.MethodCall],
payload: Api.ExpressionUpdate.Payload,
builtin: Boolean,
typeChanged: Boolean
): Api.Response = panicBuilder(
contextId,
expressionId,
methodPointer,
methodCall,
payload,
Some(
if (builtin) ConstantsGen.PANIC_BUILTIN else ConstantsGen.PANIC
@ -398,7 +398,7 @@ object TestMessages {
private def panicBuilder(
contextId: UUID,
expressionId: UUID,
methodPointer: Option[Api.MethodPointer],
methodCall: Option[Api.MethodCall],
payload: Api.ExpressionUpdate.Payload,
builtin: Option[String],
typeChanged: Boolean
@ -410,7 +410,7 @@ object TestMessages {
Api.ExpressionUpdate(
expressionId,
builtin,
methodPointer,
methodCall,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
typeChanged,