diff --git a/docs/language-server/protocol-language-server.md b/docs/language-server/protocol-language-server.md index 60b84deeec..75994d1bb4 100644 --- a/docs/language-server/protocol-language-server.md +++ b/docs/language-server/protocol-language-server.md @@ -28,6 +28,8 @@ transport formats, please look [here](./protocol-architecture). - [`SuggestionEntryArgument`](#suggestionentryargument) - [`SuggestionEntry`](#suggestionentry) - [`SuggestionEntryType`](#suggestionentrytype) + - [`SuggestionId`](#suggestionid) + - [`SuggestionsDatabaseEntry`](#suggestionsdatabaseentry) - [`SuggestionsDatabaseUpdate`](#suggestionsdatabaseupdate) - [`File`](#file) - [`DirectoryTree`](#directorytree) @@ -203,8 +205,13 @@ Points to a method definition. ```typescript interface MethodPointer { - file: Path; + /** The fully qualified module name. */ + module: String; + + /** The type on which the method is defined. */ definedOnType: String; + + /** The method name. */ name: String; } ``` @@ -216,8 +223,11 @@ interface ExpressionValueUpdate { /** The id of updated expression */ expressionId: ExpressionId; - /** The updated suggestion id */ - suggestionId: number; + /** The updated type of the expression */ + type?: String; + + /** The updated pointer to the method call */ + methodPointer?: SuggestionId; } ``` @@ -335,6 +345,16 @@ The suggestion entry type that is used as a filter in search requests. type SuggestionEntryType = Atom | Method | Function | Local; ``` +### `SuggestionId` + +The suggestion entry id of the suggestions database. + +#### Format + +```typescript +type SuggestionId = number; +``` + ### `SuggestionsDatabaseEntry` #### Format @@ -344,7 +364,7 @@ The entry in the suggestions database. ```typescript interface SuggestionsDatabaseEntry { // suggestion entry id - id: number; + id: SuggestionId; // suggestion entry suggestion: SuggestionEntry; } @@ -362,19 +382,19 @@ type SuggestionsDatabaseUpdate = Add | Remove | Modify; interface Add { // suggestion entry id - id: number; + id: SuggestionId; // suggestion entry suggestion: SuggestionEntry; } interface Remove { // suggestion entry id - id: number; + id: SuggestionId; } interface Modify { // suggestion entry id - id: number; + id: SuggestionId; // new return type returnType: String; } diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala index 02c1d9f0f8..17772d7413 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala @@ -89,16 +89,41 @@ final class ContextEventsListener( sessionRouter ! DeliverToBinaryController(rpcSession.clientId, payload) case RunExpressionUpdates if expressionUpdates.nonEmpty => - val updatedExpressionIds = expressionUpdates.map(_.expressionId) + def toMethodPointer(call: Api.MethodPointer): (String, String, String) = + (call.module, call.definedOnType, call.name) + val methodPointerToExpression = expressionUpdates + .flatMap(update => + update.methodCall.map(call => + toMethodPointer(call) -> update.expressionId + ) + ) + .toMap + val methodPointers = methodPointerToExpression.keys.toSeq repo - .getAllByExternalIds(updatedExpressionIds) + .getAllMethods(methodPointers) .map { suggestionIds => - val valueUpdates = updatedExpressionIds.zip(suggestionIds).flatMap { - case (expressionId, Some(suggestionId)) => - Some(ExpressionValueUpdate(expressionId, suggestionId)) - case (id, None) => - log.error("Unable to find suggestion with expression id: {}", id) - None + val methodPointerToSuggestion = + methodPointers + .zip(suggestionIds) + .collect { + case (ptr, Some(suggestionId)) => + ptr -> suggestionId + } + .toMap + val valueUpdates = expressionUpdates.map { update => + ExpressionValueUpdate( + update.expressionId, + update.expressionType, + update.methodCall.flatMap { call => + val pointer = toMethodPointer(call) + methodPointerToSuggestion.get(pointer) match { + case suggestionId @ Some(_) => suggestionId + case None => + log.error(s"Unable to find suggestion for $pointer") + None + } + } + ) } val payload = ContextRegistryProtocol.ExpressionValuesComputedNotification( diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextRegistry.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextRegistry.scala index f761a4f588..94968874ba 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextRegistry.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextRegistry.scala @@ -8,7 +8,6 @@ import org.enso.languageserver.event.{ ExecutionContextCreated, ExecutionContextDestroyed } -import org.enso.languageserver.filemanager.FileSystemFailure import org.enso.languageserver.monitoring.MonitoringProtocol.{Ping, Pong} import org.enso.languageserver.runtime.handler._ import org.enso.languageserver.util.UnhandledLogging @@ -134,14 +133,11 @@ final class ContextRegistry( case PushContextRequest(client, contextId, stackItem) => if (store.hasContext(client.clientId, contextId)) { - getRuntimeStackItem(stackItem) match { - case Right(stackItem) => - val handler = - context.actorOf(PushContextHandler.props(timeout, runtime)) - handler.forward(Api.PushContextRequest(contextId, stackItem)) - case Left(error) => - sender() ! FileSystemError(error) - } + val item = getRuntimeStackItem(stackItem) + val handler = + context.actorOf(PushContextHandler.props(timeout, runtime)) + handler.forward(Api.PushContextRequest(contextId, item)) + } else { sender() ! AccessDenied } @@ -224,27 +220,24 @@ final class ContextRegistry( private def getRuntimeStackItem( stackItem: StackItem - ): Either[FileSystemFailure, Api.StackItem] = + ): Api.StackItem = stackItem match { case StackItem.ExplicitCall(pointer, argument, arguments) => - getRuntimeMethodPointer(pointer).map { methodPointer => - Api.StackItem.ExplicitCall(methodPointer, argument, arguments) - } + val methodPointer = getRuntimeMethodPointer(pointer) + Api.StackItem.ExplicitCall(methodPointer, argument, arguments) case StackItem.LocalCall(expressionId) => - Right(Api.StackItem.LocalCall(expressionId)) + Api.StackItem.LocalCall(expressionId) } private def getRuntimeMethodPointer( pointer: MethodPointer - ): Either[FileSystemFailure, Api.MethodPointer] = - config.findContentRoot(pointer.file.rootId).map { rootPath => - Api.MethodPointer( - file = pointer.file.toFile(rootPath), - definedOnType = pointer.definedOnType, - name = pointer.name - ) - } + ): Api.MethodPointer = + Api.MethodPointer( + module = pointer.module, + definedOnType = pointer.definedOnType, + name = pointer.name + ) private def toRuntimeInvalidatedExpressions( expressions: InvalidatedExpressions diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala index 4d6e34293a..6e8fa61653 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala @@ -6,6 +6,11 @@ import org.enso.languageserver.runtime.ExecutionApi.ExpressionId * An update containing information about expression. * * @param expressionId the id of updated expression - * @param suggestionId the updated suggestion id + * @param `type` the updated type of expression + * @param methodPointer the suggestion id of the updated method pointer */ -case class ExpressionValueUpdate(expressionId: ExpressionId, suggestionId: Long) +case class ExpressionValueUpdate( + expressionId: ExpressionId, + `type`: Option[String], + methodPointer: Option[Long] +) diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/MethodPointer.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/MethodPointer.scala index a619da7821..7ea0e8f534 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/MethodPointer.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/MethodPointer.scala @@ -1,12 +1,10 @@ package org.enso.languageserver.runtime -import org.enso.languageserver.filemanager.Path - /** * An object pointing to a method definition. * - * @param file path to the method file + * @param module the module of the method file * @param definedOnType method type * @param name method name */ -case class MethodPointer(file: Path, definedOnType: String, name: String) +case class MethodPointer(module: String, definedOnType: String, name: String) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala index ba19fa48f2..264f864e8e 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala @@ -74,8 +74,14 @@ class ContextEventsListenerSpec Vector( Api.ExpressionValueUpdate( Suggestions.method.externalId.get, - None, - None + Some(Suggestions.method.returnType), + Some( + Api.MethodPointer( + Suggestions.method.module, + Suggestions.method.selfType, + Suggestions.method.name + ) + ) ) ) ) @@ -88,7 +94,8 @@ class ContextEventsListenerSpec Vector( ExpressionValueUpdate( Suggestions.method.externalId.get, - suggestionIds(1).get + Some(Suggestions.method.returnType), + Some(suggestionIds(1).get) ) ) ) @@ -98,7 +105,7 @@ class ContextEventsListenerSpec "send expression updates grouped" taggedAs Retry in withDb(0.seconds) { (clientId, contextId, repo, router, listener) => - val (_, suggestionIds) = Await.result( + Await.result( repo.insertAll( Seq( Suggestions.atom, @@ -142,11 +149,13 @@ class ContextEventsListenerSpec Vector( ExpressionValueUpdate( Suggestions.method.externalId.get, - suggestionIds(1).get + None, + None ), ExpressionValueUpdate( Suggestions.local.externalId.get, - suggestionIds(3).get + None, + None ) ) ) diff --git a/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala b/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala index 28b9be501b..00c07edc90 100644 --- a/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala +++ b/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala @@ -198,7 +198,11 @@ object Runtime { /** * A representation of a pointer to a method definition. */ - case class MethodPointer(file: File, definedOnType: String, name: String) + case class MethodPointer( + module: String, + definedOnType: String, + name: String + ) /** * A representation of an executable position in code. diff --git a/engine/runtime/src/main/java/org/enso/interpreter/service/ExecutionService.java b/engine/runtime/src/main/java/org/enso/interpreter/service/ExecutionService.java index c8cc43437b..92ef77c59c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/service/ExecutionService.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/service/ExecutionService.java @@ -119,7 +119,7 @@ public class ExecutionService { * Executes a method described by its name, constructor it's defined on and the module it's * defined in. * - * @param modulePath the path to the module where the method is defined. + * @param moduleName the module where the method is defined. * @param consName the name of the constructor the method is defined on. * @param methodName the method name. * @param cache the precomputed expression values. @@ -129,7 +129,7 @@ public class ExecutionService { * @param funCallCallback the consumer for function call events. */ public void execute( - File modulePath, + String moduleName, String consName, String methodName, RuntimeCache cache, @@ -140,7 +140,7 @@ public class ExecutionService { throws UnsupportedMessageException, ArityException, UnsupportedTypeException { Optional callMay = context - .getModuleForFile(modulePath) + .findModule(moduleName) .flatMap(module -> prepareFunctionCall(module, consName, methodName)); if (!callMay.isPresent()) { return; diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala index 7efa7a0156..2cd09bc30f 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledJob.scala @@ -21,7 +21,7 @@ import scala.jdk.OptionConverters._ * * @param files a files to compile */ -class EnsureCompiledJob(protected val files: List[File]) +class EnsureCompiledJob(protected val files: Iterable[File]) extends Job[Unit](List.empty, true, false) { /** diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledStackJob.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledStackJob.scala index 58a0c5f801..3d4a126630 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledStackJob.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/EnsureCompiledStackJob.scala @@ -14,8 +14,9 @@ import scala.jdk.OptionConverters._ * * @param stack a call stack */ -class EnsureCompiledStackJob(stack: Iterable[InstrumentFrame]) - extends EnsureCompiledJob(EnsureCompiledStackJob.extractFiles(stack)) { +class EnsureCompiledStackJob(stack: Iterable[InstrumentFrame])(implicit + ctx: RuntimeContext +) extends EnsureCompiledJob(EnsureCompiledStackJob.extractFiles(stack)) { /** @inheritdoc */ override def ensureCompiled( @@ -38,7 +39,7 @@ class EnsureCompiledStackJob(stack: Iterable[InstrumentFrame]) )(implicit ctx: RuntimeContext): Option[CachePreferenceAnalysis.Metadata] = stack.lastOption flatMap { case InstrumentFrame(Api.StackItem.ExplicitCall(ptr, _, _), _) => - ctx.executionService.getContext.getModuleForFile(ptr.file).toScala.map { + ctx.executionService.getContext.findModule(ptr.module).toScala.map { module => module.getIr .unsafeGetMetadata( @@ -58,12 +59,19 @@ object EnsureCompiledStackJob { * @param stack a call stack * @return a list of files to compile */ - private def extractFiles(stack: Iterable[InstrumentFrame]): List[File] = + private def extractFiles(stack: Iterable[InstrumentFrame])(implicit + ctx: RuntimeContext + ): Iterable[File] = stack .map(_.item) - .collect { + .flatMap { case Api.StackItem.ExplicitCall(methodPointer, _, _) => - methodPointer.file + ctx.executionService.getContext + .findModule(methodPointer.module) + .flatMap(module => java.util.Optional.ofNullable(module.getPath)) + .map(path => new File(path)) + .toScala + case _ => + None } - .toList } diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala index b00e3dab8b..d203aa7fbe 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala @@ -1,6 +1,5 @@ package org.enso.interpreter.instrument.job -import java.io.File import java.util.{Objects, UUID} import java.util.function.Consumer import java.util.logging.Level @@ -25,8 +24,6 @@ import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode.Functi import org.enso.polyglot.runtime.Runtime.Api import org.enso.polyglot.runtime.Runtime.Api.ContextId -import scala.jdk.javaapi.OptionConverters - /** * Provides support for executing Enso code. Adds convenient methods to * run Enso programs in a Truffle context. @@ -56,9 +53,12 @@ trait ProgramExecutionSupport { enterables += fun.getExpressionId -> fun.getCall } executionFrame match { - case ExecutionFrame(ExecutionItem.Method(file, cons, function), cache) => + case ExecutionFrame( + ExecutionItem.Method(module, cons, function), + cache + ) => ctx.executionService.execute( - file, + module, cons, function, cache, @@ -250,21 +250,15 @@ trait ProgramExecutionSupport { private def toMethodPointer( value: ExpressionValue - )(implicit ctx: RuntimeContext): Option[Api.MethodPointer] = + ): Option[Api.MethodPointer] = for { call <- Option(value.getCallInfo) moduleName <- Option(call.getModuleName) - functionName = call.getFunctionName - typeName <- Option(call.getTypeName).map(_.item) - module <- OptionConverters.toScala( - ctx.executionService.getContext.getTopScope - .getModule(moduleName.toString) - ) - modulePath <- Option(module.getPath) + typeName <- Option(call.getTypeName).map(_.item) } yield Api.MethodPointer( - new File(modulePath), + moduleName.toString, typeName, - functionName + call.getFunctionName ) } @@ -296,11 +290,11 @@ object ProgramExecutionSupport { /** The explicit method call. * - * @param file the file containing the method + * @param module the module containing the method * @param constructor the type on which the method is defined * @param function the method name */ - case class Method(file: File, constructor: String, function: String) + case class Method(module: String, constructor: String, function: String) extends ExecutionItem object Method { @@ -312,7 +306,7 @@ object ProgramExecutionSupport { */ def apply(call: Api.StackItem.ExplicitCall): Method = Method( - call.methodPointer.file, + call.methodPointer.module, call.methodPointer.definedOnType, call.methodPointer.name ) diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala index d939d09620..c3c3fb20cd 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala @@ -144,7 +144,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( Main.idMainY, Some("Number"), - Some(Api.MethodPointer(pkg.mainFile, "Number", "foo")) + Some(Api.MethodPointer("Test.Main", "Number", "foo")) ) ) ) @@ -228,7 +228,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainY, Some("Number"), - Some(Api.MethodPointer(pkg.mainFile, "Main", "foo")) + Some(Api.MethodPointer("Test.Main", "Main", "foo")) ) ) ) @@ -242,7 +242,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainZ, Some("Number"), - Some(Api.MethodPointer(pkg.mainFile, "Main", "bar")) + Some(Api.MethodPointer("Test.Main", "Main", "bar")) ) ) ) @@ -284,7 +284,7 @@ class RuntimeServerTest } "RuntimeServer" should "push and pop functions on the stack" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -306,7 +306,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -333,7 +333,7 @@ class RuntimeServerTest // push method pointer on top of the non-empty stack val invalidExplicitCall = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -402,7 +402,7 @@ class RuntimeServerTest Api.PushContextRequest( contextId, Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer(moduleName, "Main", "main"), None, Vector() ) @@ -521,7 +521,7 @@ class RuntimeServerTest Api.PushContextRequest( contextId, Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer(moduleName, "Main", "main"), None, Vector() ) @@ -689,7 +689,7 @@ class RuntimeServerTest Api.PushContextRequest( contextId, Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer(moduleName, "Main", "main"), None, Vector() ) @@ -818,7 +818,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some("Number"), - Some(Api.MethodPointer(mainFile, "Number", "x")) + Some(Api.MethodPointer(moduleName, "Number", "x")) ) ) ) @@ -865,7 +865,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some("Number"), - Some(Api.MethodPointer(mainFile, "Main", "pie")) + Some(Api.MethodPointer(moduleName, "Main", "pie")) ) ) ) @@ -895,7 +895,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some("Number"), - Some(Api.MethodPointer(mainFile, "Main", "uwu")) + Some(Api.MethodPointer(moduleName, "Main", "uwu")) ) ) ) @@ -925,7 +925,7 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some("Text"), - Some(Api.MethodPointer(mainFile, "Main", "hie")) + Some(Api.MethodPointer(moduleName, "Main", "hie")) ) ) ) @@ -992,7 +992,7 @@ class RuntimeServerTest contextId, Api.StackItem .ExplicitCall( - Api.MethodPointer(fooFile, "Foo", "main"), + Api.MethodPointer("Test.Foo", "Foo", "main"), None, Vector() ) @@ -1080,7 +1080,7 @@ class RuntimeServerTest contextId, Api.StackItem .ExplicitCall( - Api.MethodPointer(fooFile, "Foo", "main"), + Api.MethodPointer("Test.Foo", "Foo", "main"), None, Vector() ) @@ -1168,7 +1168,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1329,7 +1329,7 @@ class RuntimeServerTest contextId, Api.StackItem .ExplicitCall( - Api.MethodPointer(fooFile, "Foo", "main"), + Api.MethodPointer("Test.Foo", "Foo", "main"), None, Vector() ) @@ -1405,7 +1405,7 @@ class RuntimeServerTest } it should "recompute expressions without invalidation" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -1417,7 +1417,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1441,7 +1441,7 @@ class RuntimeServerTest } it should "recompute expressions invalidating all" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -1453,7 +1453,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1483,7 +1483,7 @@ class RuntimeServerTest } it should "recompute expressions invalidating some" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -1495,7 +1495,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1527,7 +1527,7 @@ class RuntimeServerTest } it should "return error when computing erroneous code" in { - val mainFile = context.writeMain(context.MainWithError.code) + context.writeMain(context.MainWithError.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -1539,7 +1539,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1562,7 +1562,7 @@ class RuntimeServerTest } it should "skip side effects when evaluating cached expression" in { - val file = context.writeMain(context.Main2.code) + context.writeMain(context.Main2.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -1574,7 +1574,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(file, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1601,7 +1601,7 @@ class RuntimeServerTest } it should "emit visualisation update when expression is evaluated" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val visualisationFile = context.writeInSrcDir("Visualisation", context.Visualisation.code) @@ -1627,7 +1627,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -1752,7 +1752,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer(moduleName, "Main", "main"), None, Vector() ) @@ -1918,7 +1918,7 @@ class RuntimeServerTest } it should "be able to modify visualisations" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val visualisationFile = context.writeInSrcDir("Visualisation", context.Visualisation.code) @@ -1944,7 +1944,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -2031,7 +2031,7 @@ class RuntimeServerTest } it should "not emit visualisation updates when visualisation is detached" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val visualisationFile = context.writeInSrcDir("Visualisation", context.Visualisation.code) @@ -2075,7 +2075,7 @@ class RuntimeServerTest ) // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) @@ -2130,7 +2130,7 @@ class RuntimeServerTest } it should "rename a project" in { - val mainFile = context.writeMain(context.Main.code) + context.writeMain(context.Main.code) val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -2142,7 +2142,7 @@ class RuntimeServerTest // push main val item1 = Api.StackItem.ExplicitCall( - Api.MethodPointer(mainFile, "Main", "main"), + Api.MethodPointer("Test.Main", "Main", "main"), None, Vector() ) diff --git a/lib/scala/searcher/src/bench/java/org/enso/searcher/sql/SuggestionsRepoBenchmark.java b/lib/scala/searcher/src/bench/java/org/enso/searcher/sql/SuggestionsRepoBenchmark.java index fdaa8d2d15..9f2dc60207 100644 --- a/lib/scala/searcher/src/bench/java/org/enso/searcher/sql/SuggestionsRepoBenchmark.java +++ b/lib/scala/searcher/src/bench/java/org/enso/searcher/sql/SuggestionsRepoBenchmark.java @@ -32,7 +32,8 @@ public class SuggestionsRepoBenchmark { final Path dbfile = Path.of(System.getProperty("java.io.tmpdir"), "bench-suggestions.db"); final Seq kinds = SuggestionRandom.nextKinds(); final Seq> updateInput = SuggestionRandom.nextUpdateAllInput(); - final Seq getAllByExternalIdsInput = SuggestionRandom.nextGetByExternalIdsInput(); + final Seq> getAllMethodsInput = + SuggestionRandom.nextGetAllMethodsInput(); SqlSuggestionsRepo repo; @@ -104,8 +105,8 @@ public class SuggestionsRepoBenchmark { } @Benchmark - public Object searchByExternalIds() throws TimeoutException, InterruptedException { - return Await.result(repo.getAllByExternalIds(getAllByExternalIdsInput), TIMEOUT); + public Object getAllMethods() throws TimeoutException, InterruptedException { + return Await.result(repo.getAllMethods(getAllMethodsInput), TIMEOUT); } @Benchmark diff --git a/lib/scala/searcher/src/bench/scala/org/enso/searcher/sql/SuggestionRandom.scala b/lib/scala/searcher/src/bench/scala/org/enso/searcher/sql/SuggestionRandom.scala index 17a829fb55..aa771eed69 100644 --- a/lib/scala/searcher/src/bench/scala/org/enso/searcher/sql/SuggestionRandom.scala +++ b/lib/scala/searcher/src/bench/scala/org/enso/searcher/sql/SuggestionRandom.scala @@ -11,8 +11,11 @@ object SuggestionRandom { def nextUpdateAllInput(): Seq[(UUID, String)] = Seq(UUID.randomUUID() -> nextString()) - def nextGetByExternalIdsInput(): Seq[UUID] = - Seq(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID()) + def nextGetAllMethodsInput(): Seq[(String, String, String)] = + Seq( + (nextString(), nextString(), nextString()), + (nextString(), nextString(), nextString()) + ) def nextKinds(): Seq[Suggestion.Kind] = Set.fill(1)(nextKind()).toSeq diff --git a/lib/scala/searcher/src/main/scala/org/enso/searcher/SuggestionsRepo.scala b/lib/scala/searcher/src/main/scala/org/enso/searcher/SuggestionsRepo.scala index e9c575aeea..e6e6011ef7 100644 --- a/lib/scala/searcher/src/main/scala/org/enso/searcher/SuggestionsRepo.scala +++ b/lib/scala/searcher/src/main/scala/org/enso/searcher/SuggestionsRepo.scala @@ -14,12 +14,12 @@ trait SuggestionsRepo[F[_]] { */ def getAll: F[(Long, Seq[SuggestionEntry])] - /** Get suggestions by external ids. + /** Get suggestions by the method call info. * - * @param ids the list of external ids + * @param calls the list of triples: module, self type and method name * @return the list of found suggestion ids */ - def getAllByExternalIds(ids: Seq[Suggestion.ExternalId]): F[Seq[Option[Long]]] + def getAllMethods(calls: Seq[(String, String, String)]): F[Seq[Option[Long]]] /** Search suggestion by various parameters. * diff --git a/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/SqlSuggestionsRepo.scala b/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/SqlSuggestionsRepo.scala index 06e8971411..4b6b1a8c93 100644 --- a/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/SqlSuggestionsRepo.scala +++ b/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/SqlSuggestionsRepo.scala @@ -40,10 +40,10 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext) db.run(getAllQuery) /** @inheritdoc */ - override def getAllByExternalIds( - ids: Seq[Suggestion.ExternalId] + override def getAllMethods( + calls: Seq[(String, String, String)] ): Future[Seq[Option[Long]]] = - db.run(getAllByExternalIdsQuery(ids)) + db.run(getAllMethodsQuery(calls)) /** @inheritdoc */ override def search( @@ -140,34 +140,32 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext) query.transactionally } - /** The query to get suggestions by external ids. + /** The query to get the suggestions by the method call info. * - * @param ids the list of external ids + * @param calls the triples containing module name, self type, method name * @return the list of found suggestion ids */ - private def getAllByExternalIdsQuery( - ids: Seq[Suggestion.ExternalId] + def getAllMethodsQuery( + calls: Seq[(String, String, String)] ): DBIO[Seq[Option[Long]]] = - if (ids.isEmpty) { + if (calls.isEmpty) { DBIO.successful(Seq()) } else { - val bits = - ids.map(id => (id.getLeastSignificantBits, id.getMostSignificantBits)) val query = Suggestions .filter { row => - bits + calls .map { - case (least, most) => - row.externalIdLeast === least && row.externalIdMost === most + case (module, selfType, name) => + row.module === module && row.selfType === selfType && row.name === name } .reduce(_ || _) } - .map(row => (row.id, row.externalIdLeast, row.externalIdMost)) - query.result.map { triples => - val result = triples.flatMap { - case (id, least, most) => toUUID(least, most).map(_ -> id) + .map(row => (row.id, row.module, row.selfType, row.name)) + query.result.map { tuples => + val result = tuples.map { + case (id, module, selfType, name) => (module, selfType, name) -> id }.toMap - ids.map(result.get) + calls.map(result.get) } } diff --git a/lib/scala/searcher/src/test/scala/org/enso/searcher/sql/SuggestionsRepoTest.scala b/lib/scala/searcher/src/test/scala/org/enso/searcher/sql/SuggestionsRepoTest.scala index 16159de0f7..129b11834a 100644 --- a/lib/scala/searcher/src/test/scala/org/enso/searcher/sql/SuggestionsRepoTest.scala +++ b/lib/scala/searcher/src/test/scala/org/enso/searcher/sql/SuggestionsRepoTest.scala @@ -63,7 +63,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec { ) } - "get suggestions by external ids" taggedAs Retry in withRepo { repo => + "get suggestions by method call info" taggedAs Retry in withRepo { repo => val action = for { (_, ids) <- repo.insertAll( Seq( @@ -73,30 +73,31 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec { suggestion.local ) ) - results <- repo.getAllByExternalIds( - Seq(suggestion.method.externalId.get, suggestion.local.externalId.get) + results <- repo.getAllMethods( + Seq(("Test.Main", "Main", "main"), ("Test.Main", "Main", "foo")) ) } yield (ids, results) val (ids, results) = Await.result(action, Timeout) - results should contain theSameElementsAs Seq(ids(1), ids(3)) + results should contain theSameElementsInOrderAs Seq(ids(1), None) } - "get suggestions by empty external ids" taggedAs Retry in withRepo { repo => - val action = for { - _ <- repo.insertAll( - Seq( - suggestion.atom, - suggestion.method, - suggestion.function, - suggestion.local + "get suggestions by empty method call info" taggedAs Retry in withRepo { + repo => + val action = for { + _ <- repo.insertAll( + Seq( + suggestion.atom, + suggestion.method, + suggestion.function, + suggestion.local + ) ) - ) - results <- repo.getAllByExternalIds(Seq()) - } yield results + results <- repo.getAllMethods(Seq()) + } yield results - val results = Await.result(action, Timeout) - results.isEmpty shouldEqual true + val results = Await.result(action, Timeout) + results.isEmpty shouldEqual true } "fail to insert duplicate suggestion" taggedAs Retry in withRepo { repo =>