diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/search/SuggestionsHandler.scala b/engine/language-server/src/main/scala/org/enso/languageserver/search/SuggestionsHandler.scala
index c2f6fca7b4c6..3b64a3bf6447 100644
--- a/engine/language-server/src/main/scala/org/enso/languageserver/search/SuggestionsHandler.scala
+++ b/engine/language-server/src/main/scala/org/enso/languageserver/search/SuggestionsHandler.scala
@@ -1,7 +1,7 @@
package org.enso.languageserver.search
import akka.actor.{Actor, ActorLogging, ActorRef, Props, Stash}
-import akka.pattern.pipe
+import akka.pattern.{ask, pipe}
import org.enso.languageserver.capability.CapabilityProtocol.{
AcquireCapability,
CapabilityAcquired,
@@ -26,6 +26,7 @@ import org.enso.languageserver.session.SessionRouter.DeliverToJsonController
import org.enso.languageserver.util.UnhandledLogging
import org.enso.pkg.PackageManager
import org.enso.polyglot.Suggestion
+import org.enso.polyglot.data.TypeGraph
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.searcher.data.QueryResult
import org.enso.searcher.{FileVersionsRepo, SuggestionsRepo}
@@ -98,6 +99,10 @@ final class SuggestionsHandler(
context.system.eventStream
.subscribe(self, InitializedEvent.SuggestionsRepoInitialized.getClass)
+ runtimeConnector
+ .ask(Api.Request(Api.GetTypeGraphRequest()))(timeout, self)
+ .pipeTo(self)
+
config.contentRoots.foreach { case (_, contentRoot) =>
PackageManager.Default
.fromDirectory(contentRoot)
@@ -122,23 +127,29 @@ final class SuggestionsHandler(
Some(InitializedEvent.SuggestionsRepoInitialized)
)
)
+ case Api.GetTypeGraphResponse(g) =>
+ tryInitialize(init.copy(typeGraph = Some(g)))
case _ => stash()
}
- def initialized(projectName: String, clients: Set[ClientId]): Receive = {
+ def initialized(
+ projectName: String,
+ graph: TypeGraph,
+ clients: Set[ClientId]
+ ): Receive = {
case AcquireCapability(
client,
CapabilityRegistration(ReceivesSuggestionsDatabaseUpdates())
) =>
sender() ! CapabilityAcquired
- context.become(initialized(projectName, clients + client.clientId))
+ context.become(initialized(projectName, graph, clients + client.clientId))
case ReleaseCapability(
client,
CapabilityRegistration(ReceivesSuggestionsDatabaseUpdates())
) =>
sender() ! CapabilityReleased
- context.become(initialized(projectName, clients - client.clientId))
+ context.become(initialized(projectName, graph, clients - client.clientId))
case msg: Api.SuggestionsDatabaseModuleUpdateNotification =>
val isVersionChanged =
@@ -216,6 +227,8 @@ final class SuggestionsHandler(
.pipeTo(sender())
case Completion(path, pos, selfType, returnType, tags) =>
+ val selfTypes =
+ selfType.toList.flatMap(ty => (graph.getParents(ty) + ty).toSeq)
getModuleName(projectName, path)
.fold(
Future.successful,
@@ -223,7 +236,7 @@ final class SuggestionsHandler(
suggestionsRepo
.search(
Some(module),
- selfType,
+ selfTypes,
returnType,
tags.map(_.map(SuggestionKind.toSuggestion)),
Some(toPosition(pos))
@@ -295,7 +308,7 @@ final class SuggestionsHandler(
.pipeTo(self)
case ProjectNameUpdated(name) =>
- context.become(initialized(name, clients))
+ context.become(initialized(name, graph, clients))
}
/** Transition the initialization process.
@@ -303,10 +316,11 @@ final class SuggestionsHandler(
* @param state current initialization state
*/
private def tryInitialize(state: SuggestionsHandler.Initialization): Unit = {
- state.initialized.fold(context.become(initializing(state))) { name =>
- log.debug("Initialized")
- context.become(initialized(name, Set()))
- unstashAll()
+ state.initialized.fold(context.become(initializing(state))) {
+ case (name, graph) =>
+ log.debug("Initialized")
+ context.become(initialized(name, graph, Set()))
+ unstashAll()
}
}
@@ -443,21 +457,25 @@ object SuggestionsHandler {
*
* @param project the project name
* @param suggestions the initialization event of the suggestions repo
+ * @param typeGraph the Enso type hierarchy
*/
private case class Initialization(
- project: Option[String] = None,
- suggestions: Option[InitializedEvent.SuggestionsRepoInitialized.type] = None
+ project: Option[String] = None,
+ suggestions: Option[InitializedEvent.SuggestionsRepoInitialized.type] =
+ None,
+ typeGraph: Option[TypeGraph] = None
) {
/** Check if all the components are initialized.
*
* @return the project name
*/
- def initialized: Option[String] =
+ def initialized: Option[(String, TypeGraph)] =
for {
- _ <- suggestions
- name <- project
- } yield name
+ _ <- suggestions
+ name <- project
+ graph <- typeGraph
+ } yield (name, graph)
}
/** Creates a configuration object used to create a [[SuggestionsHandler]].
@@ -484,5 +502,4 @@ object SuggestionsHandler {
runtimeConnector
)
)
-
}
diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/search/Suggestions.scala b/engine/language-server/src/test/scala/org/enso/languageserver/search/Suggestions.scala
index 11629404f2b5..f10c27efe84e 100644
--- a/engine/language-server/src/test/scala/org/enso/languageserver/search/Suggestions.scala
+++ b/engine/language-server/src/test/scala/org/enso/languageserver/search/Suggestions.scala
@@ -7,57 +7,95 @@ import org.enso.polyglot.Suggestion
/** Suggestion instances used in tests. */
object Suggestions {
- val atom: Suggestion.Atom =
- Suggestion.Atom(
- externalId = None,
- module = "Test.Main",
- name = "MyType",
- arguments = Vector(Suggestion.Argument("a", "Any", false, false, None)),
- returnType = "MyAtom",
- documentation = None
- )
-
- val method: Suggestion.Method =
- Suggestion.Method(
- externalId =
- Some(UUID.fromString("ea9d7734-26a7-4f65-9dd9-c648eaf57d63")),
- module = "Test.Main",
- name = "foo",
- arguments = Vector(
- Suggestion.Argument("this", "MyType", false, false, None),
- Suggestion.Argument("foo", "Number", false, true, Some("42"))
- ),
- selfType = "MyType",
- returnType = "Number",
- documentation = Some("Lovely")
- )
-
- val function: Suggestion.Function =
- Suggestion.Function(
- externalId =
- Some(UUID.fromString("78d452ce-ed48-48f1-b4f2-b7f45f8dff89")),
- module = "Test.Main",
- name = "print",
- arguments = Vector(
- Suggestion.Argument("a", "Any", false, false, None),
- Suggestion.Argument("b", "Any", true, false, None),
- Suggestion.Argument("c", "Any", false, true, Some("C"))
- ),
- returnType = "IO",
- scope =
- Suggestion.Scope(Suggestion.Position(1, 9), Suggestion.Position(1, 22))
- )
-
- val local: Suggestion.Local =
- Suggestion.Local(
- externalId =
- Some(UUID.fromString("dc077227-d9b6-4620-9b51-792c2a69419d")),
- module = "Test.Main",
- name = "x",
- returnType = "Number",
- scope =
- Suggestion.Scope(Suggestion.Position(21, 0), Suggestion.Position(89, 0))
- )
-
- val all = Seq(atom, method, function, local)
+ val atom: Suggestion.Atom = Suggestion.Atom(
+ externalId = None,
+ module = "Test.Main",
+ name = "MyType",
+ arguments = Vector(Suggestion.Argument("a", "Any", false, false, None)),
+ returnType = "MyAtom",
+ documentation = None
+ )
+
+ val method: Suggestion.Method = Suggestion.Method(
+ externalId = Some(UUID.fromString("ea9d7734-26a7-4f65-9dd9-c648eaf57d63")),
+ module = "Test.Main",
+ name = "foo",
+ arguments = Vector(
+ Suggestion.Argument("this", "MyType", false, false, None),
+ Suggestion.Argument("foo", "Number", false, true, Some("42"))
+ ),
+ selfType = "MyType",
+ returnType = "Number",
+ documentation = Some("Lovely")
+ )
+
+ val function: Suggestion.Function = Suggestion.Function(
+ externalId = Some(UUID.fromString("78d452ce-ed48-48f1-b4f2-b7f45f8dff89")),
+ module = "Test.Main",
+ name = "print",
+ arguments = Vector(
+ Suggestion.Argument("a", "Any", false, false, None),
+ Suggestion.Argument("b", "Any", true, false, None),
+ Suggestion.Argument("c", "Any", false, true, Some("C"))
+ ),
+ returnType = "IO",
+ scope =
+ Suggestion.Scope(Suggestion.Position(1, 9), Suggestion.Position(1, 22))
+ )
+
+ val local: Suggestion.Local = Suggestion.Local(
+ externalId = Some(UUID.fromString("dc077227-d9b6-4620-9b51-792c2a69419d")),
+ module = "Test.Main",
+ name = "x",
+ returnType = "Number",
+ scope =
+ Suggestion.Scope(Suggestion.Position(21, 0), Suggestion.Position(89, 0))
+ )
+
+ val methodOnAny: Suggestion.Method = Suggestion.Method(
+ externalId = Some(UUID.fromString("6cfe1538-5df7-42e4-bf55-64f8ac2ededa")),
+ module = "Standard.Base.Data.Any.Extensions",
+ name = "<<",
+ arguments = Vector(
+ Suggestion.Argument("this", "Any", false, false, None),
+ Suggestion.Argument("that", "Any", false, false, None)
+ ),
+ selfType = "Any",
+ returnType = "Any",
+ documentation = Some("Lovely")
+ )
+
+ val methodOnNumber: Suggestion.Method = Suggestion.Method(
+ externalId = Some(UUID.fromString("33b426aa-2f74-42c0-9032-1159b5386eac")),
+ module = "Standard.Base.Data.Number.Extensions",
+ name = "asin",
+ arguments = Vector(
+ Suggestion.Argument("this", "Number", false, false, None)
+ ),
+ selfType = "Number",
+ returnType = "Number",
+ documentation = None
+ )
+
+ val methodOnInteger: Suggestion.Method = Suggestion.Method(
+ externalId = Some(UUID.fromString("2849c0f0-3c27-44df-abcb-5c163dd7ac91")),
+ module = "Builtins.Main",
+ name = "+",
+ arguments = Vector(
+ Suggestion.Argument("that", "Number", false, false, None)
+ ),
+ selfType = "Integer",
+ returnType = "Number",
+ documentation = Some("Blah, blah")
+ )
+
+ val all = Seq(
+ atom,
+ method,
+ function,
+ local,
+ methodOnAny,
+ methodOnNumber,
+ methodOnInteger
+ )
}
diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala
index 9cbd0a9304cf..a0a5cc92ef7c 100644
--- a/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala
+++ b/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala
@@ -3,7 +3,6 @@ package org.enso.languageserver.search
import java.io.File
import java.nio.file.Files
import java.util.UUID
-
import akka.actor.{ActorRef, ActorSystem}
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
import org.apache.commons.io.FileUtils
@@ -17,7 +16,7 @@ import org.enso.languageserver.filemanager.Path
import org.enso.languageserver.search.SearchProtocol.SuggestionDatabaseEntry
import org.enso.languageserver.session.JsonSession
import org.enso.languageserver.session.SessionRouter.DeliverToJsonController
-import org.enso.polyglot.data.Tree
+import org.enso.polyglot.data.{Tree, TypeGraph}
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
import org.enso.searcher.{FileVersionsRepo, SuggestionsRepo}
@@ -95,7 +94,10 @@ class SuggestionsHandlerSpec
router.expectMsg(
DeliverToJsonController(
clientId,
- SearchProtocol.SuggestionsDatabaseUpdateNotification(4L, updates)
+ SearchProtocol.SuggestionsDatabaseUpdateNotification(
+ Suggestions.all.size.toLong,
+ updates
+ )
)
)
@@ -154,7 +156,7 @@ class SuggestionsHandlerSpec
DeliverToJsonController(
clientId,
SearchProtocol.SuggestionsDatabaseUpdateNotification(
- 8L,
+ Suggestions.all.size * 2L,
updatesAdd ++ updatesRemove
)
)
@@ -343,6 +345,13 @@ class SuggestionsHandlerSpec
)
expectMsg(CapabilityAcquired)
+ val suggestions = Seq(
+ Suggestions.atom,
+ Suggestions.method,
+ Suggestions.function,
+ Suggestions.local
+ )
+
val tree1 = Tree.Root(
Vector(
Tree.Node(
@@ -410,7 +419,7 @@ class SuggestionsHandlerSpec
Tree.Root(Vector())
)
- val updates2 = Suggestions.all.zipWithIndex.map { case (_, ix) =>
+ val updates2 = suggestions.zipWithIndex.map { case (_, ix) =>
SearchProtocol.SuggestionsDatabaseUpdate.Remove(ix + 1L)
}
router.expectMsg(
@@ -468,6 +477,15 @@ class SuggestionsHandlerSpec
Await.ready(repo.insert(Suggestions.atom), Timeout)
handler ! SearchProtocol.InvalidateSuggestionsDatabase
+ connector.expectMsgClass(classOf[Api.Request]) match {
+ case Api.Request(_, Api.GetTypeGraphRequest()) =>
+ case Api.Request(_, msg) =>
+ fail(s"Runtime connector receive unexpected message: $msg")
+ }
+ connector.reply(
+ Api.Response(Api.GetTypeGraphResponse(buildTestTypeGraph))
+ )
+
connector.expectMsgClass(classOf[Api.Request]) match {
case Api.Request(_, Api.InvalidateModulesIndexRequest()) =>
case Api.Request(_, msg) =>
@@ -492,15 +510,21 @@ class SuggestionsHandlerSpec
expectMsg(
SearchProtocol.CompletionResult(
- 4L,
- Seq(inserted(0).get, inserted(1).get)
+ 7L,
+ Seq(
+ inserted(0).get,
+ inserted(6).get,
+ inserted(4).get,
+ inserted(5).get,
+ inserted(1).get
+ )
)
)
}
"search entries by self type" taggedAs Retry in withDb {
(config, repo, _, _, handler) =>
- val (_, Seq(_, methodId, _, _)) =
+ val (_, Seq(_, methodId, _, _, methodOnAnyId, _, _)) =
Await.result(repo.insertAll(Suggestions.all), Timeout)
handler ! SearchProtocol.Completion(
file = mkModulePath(config, "Main.enso"),
@@ -510,12 +534,54 @@ class SuggestionsHandlerSpec
tags = None
)
- expectMsg(SearchProtocol.CompletionResult(4L, Seq(methodId).flatten))
+ expectMsg(
+ SearchProtocol.CompletionResult(
+ 7L,
+ Seq(methodOnAnyId, methodId).flatten
+ )
+ )
+ }
+
+ "search entries based on supertypes of self" taggedAs Retry in withDb {
+ (config, repo, _, _, handler) =>
+ val (_, Seq(_, _, _, _, anyMethodId, numberMethodId, integerMethodId)) =
+ Await.result(repo.insertAll(Suggestions.all), Timeout)
+
+ handler ! SearchProtocol.Completion(
+ file = mkModulePath(config, "Main.enso"),
+ position = Position(0, 0),
+ selfType = Some("Integer"),
+ returnType = None,
+ tags = None
+ )
+
+ expectMsg(
+ SearchProtocol.CompletionResult(
+ 7L,
+ Seq(anyMethodId, integerMethodId, numberMethodId).flatten
+ )
+ )
+ }
+
+ "search entries for any" taggedAs Retry in withDb {
+ (config, repo, _, _, handler) =>
+ val (_, Seq(_, _, _, _, anyMethodId, _, _)) =
+ Await.result(repo.insertAll(Suggestions.all), Timeout)
+
+ handler ! SearchProtocol.Completion(
+ file = mkModulePath(config, "Main.enso"),
+ position = Position(0, 0),
+ selfType = Some("Any"),
+ returnType = None,
+ tags = None
+ )
+
+ expectMsg(SearchProtocol.CompletionResult(7L, Seq(anyMethodId).flatten))
}
"search entries by return type" taggedAs Retry in withDb {
(config, repo, _, _, handler) =>
- val (_, Seq(_, _, functionId, _)) =
+ val (_, Seq(_, _, functionId, _, _, _, _)) =
Await.result(repo.insertAll(Suggestions.all), Timeout)
handler ! SearchProtocol.Completion(
file = mkModulePath(config, "Main.enso"),
@@ -525,12 +591,12 @@ class SuggestionsHandlerSpec
tags = None
)
- expectMsg(SearchProtocol.CompletionResult(4L, Seq(functionId).flatten))
+ expectMsg(SearchProtocol.CompletionResult(7L, Seq(functionId).flatten))
}
"search entries by tags" taggedAs Retry in withDb {
(config, repo, _, _, handler) =>
- val (_, Seq(_, _, _, localId)) =
+ val (_, Seq(_, _, _, localId, _, _, _)) =
Await.result(repo.insertAll(Suggestions.all), Timeout)
handler ! SearchProtocol.Completion(
file = mkModulePath(config, "Main.enso"),
@@ -540,7 +606,7 @@ class SuggestionsHandlerSpec
tags = Some(Seq(SearchProtocol.SuggestionKind.Local))
)
- expectMsg(SearchProtocol.CompletionResult(4L, Seq(localId).flatten))
+ expectMsg(SearchProtocol.CompletionResult(7L, Seq(localId).flatten))
}
}
@@ -562,9 +628,18 @@ class SuggestionsHandlerSpec
)
)
handler ! SuggestionsHandler.ProjectNameUpdated("Test")
+ handler ! Api.GetTypeGraphResponse(buildTestTypeGraph)
handler
}
+ def buildTestTypeGraph: TypeGraph = {
+ val graph = TypeGraph("Any")
+ graph.insert("Number", "Any")
+ graph.insert("Integer", "Number")
+
+ graph
+ }
+
def newConfig(root: File): Config = {
Config(
Map(UUID.randomUUID() -> root),
diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala
index 437ca73da7e0..e05800233b39 100644
--- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala
+++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala
@@ -30,6 +30,8 @@ import org.enso.languageserver.runtime.ContextRegistry
import org.enso.languageserver.search.SuggestionsHandler
import org.enso.languageserver.session.SessionRouter
import org.enso.languageserver.text.BufferRegistry
+import org.enso.polyglot.data.TypeGraph
+import org.enso.polyglot.runtime.Runtime.Api
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
import org.enso.text.Sha3_224VersionCalculator
@@ -48,6 +50,13 @@ class BaseServerTest extends JsonRpcServerTestKit {
val runtimeConnectorProbe = TestProbe()
val versionCalculator = Sha3_224VersionCalculator
+ val typeGraph: TypeGraph = {
+ val graph = TypeGraph("Any")
+ graph.insert("Number", "Any")
+ graph.insert("Integer", "Number")
+ graph
+ }
+
sys.addShutdownHook(FileUtils.deleteQuietly(testContentRoot.toFile))
def mkConfig: Config =
@@ -146,6 +155,8 @@ class BaseServerTest extends JsonRpcServerTestKit {
)
// initialize
+ runtimeConnectorProbe.receiveN(1)
+ suggestionsHandler ! Api.GetTypeGraphResponse(typeGraph)
Await.ready(initializationComponent.init(), timeout)
new JsonConnectionControllerFactory(
diff --git a/engine/polyglot-api/src/main/scala/org/enso/polyglot/data/TypeGraph.scala b/engine/polyglot-api/src/main/scala/org/enso/polyglot/data/TypeGraph.scala
new file mode 100644
index 000000000000..e80cb9bdb076
--- /dev/null
+++ b/engine/polyglot-api/src/main/scala/org/enso/polyglot/data/TypeGraph.scala
@@ -0,0 +1,86 @@
+package org.enso.polyglot.data
+
+import com.fasterxml.jackson.annotation.JsonIgnore
+
+import scala.collection.mutable
+
+/** A collection that represents subsumption relationships between types.
+ *
+ * These relationships are useful for dispatch and for collating suggestions
+ * for users. All names in this collection should be represented fully
+ * qualified.
+ *
+ * This structure is a graph and may contain loops. The query functions will
+ * ensure that an infinite loop doesn't occur in such circumstances.
+ *
+ * This collection does not implement the Any : Any axiom as that is currently
+ * not encoded anywhere in the language.
+ *
+ * @param defaultRootType the name of the root type of the type subsumption
+ * hierarchy
+ * @param parentLinks the parent links for the types
+ */
+case class TypeGraph(
+ defaultRootType: String,
+ parentLinks: mutable.HashMap[String, Set[String]] = mutable.HashMap()
+) {
+ insertWithoutParent(defaultRootType)
+
+ /** Inserts a type without a parent into the graph.
+ *
+ * @param name the fully-qualified typename
+ */
+ @JsonIgnore
+ def insertWithoutParent(name: String): Unit = {
+ parentLinks.update(name, Set())
+ }
+
+ /** Insert a type-parent relationship into the graph.
+ *
+ * @param typeName the fully-qualified name of the type to set the parent for
+ * @param parentName the fully-qualified name of the parent of `typeName`
+ */
+ @JsonIgnore
+ def insert(typeName: String, parentName: String): Unit = {
+ parentLinks.updateWith(typeName) {
+ case Some(parents) => Some(parents + parentName)
+ case None => Some(Set(parentName))
+ }
+ }
+
+ /** Get the direct parents of the provided typename.
+ *
+ * The direct parents of a type are those that it is a child of
+ * non-transitively.
+ *
+ * @param typeName the fully-qualified name of the type to get the direct
+ * parents for
+ * @return the set of direct parents for `typeName`
+ */
+ @JsonIgnore
+ def getDirectParents(typeName: String): Set[String] = {
+ parentLinks.getOrElse(typeName, Set(defaultRootType))
+ }
+
+ /** Get all of the parents (transitively) of the provided typename.
+ *
+ * @param typeName the fully-qualified type name for which to get the parents
+ * @return all parents of `typeName`
+ */
+ @JsonIgnore
+ def getParents(typeName: String): Set[String] = {
+ var seenNodes: Set[String] = Set()
+
+ val parents = getDirectParents(typeName)
+ parents ++ parents.flatMap(parent => {
+ if (!seenNodes.contains(parent)) {
+ seenNodes += parent
+ getParents(parent)
+ } else { Set() }
+ })
+ }
+}
+object TypeGraph {
+ def fromJava(rootTypeName: String): TypeGraph =
+ new TypeGraph(rootTypeName)
+}
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 a2c2edee2d75..aee247848379 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
@@ -11,7 +11,7 @@ import com.fasterxml.jackson.module.scala.{
ScalaObjectMapper
}
import org.enso.polyglot.Suggestion
-import org.enso.polyglot.data.Tree
+import org.enso.polyglot.data.{Tree, TypeGraph}
import org.enso.text.ContentVersion
import org.enso.text.editing.model
import org.enso.text.editing.model.{Range, TextEdit}
@@ -188,6 +188,14 @@ object Runtime {
new JsonSubTypes.Type(
value = classOf[Api.ImportSuggestionResponse],
name = "importSuggestionResponse"
+ ),
+ new JsonSubTypes.Type(
+ value = classOf[Api.GetTypeGraphRequest],
+ name = "getTypeGraphRequest"
+ ),
+ new JsonSubTypes.Type(
+ value = classOf[Api.GetTypeGraphResponse],
+ name = "getTypeGraphResponse"
)
)
)
@@ -1052,6 +1060,15 @@ object Runtime {
exports: Seq[Export]
) extends ApiResponse
+ /** A request for the type hierarchy graph. */
+ case class GetTypeGraphRequest() extends ApiRequest
+
+ /** The result of the type graph request.
+ *
+ * @param graph the graph.
+ */
+ case class GetTypeGraphResponse(graph: TypeGraph) extends ApiResponse
+
private lazy val mapper = {
val factory = new CBORFactory()
val mapper = new ObjectMapper(factory) with ScalaObjectMapper
diff --git a/engine/polyglot-api/src/test/scala/org/enso/polyglot/data/TypeGraphTest.scala b/engine/polyglot-api/src/test/scala/org/enso/polyglot/data/TypeGraphTest.scala
new file mode 100644
index 000000000000..cd2ec5e6f303
--- /dev/null
+++ b/engine/polyglot-api/src/test/scala/org/enso/polyglot/data/TypeGraphTest.scala
@@ -0,0 +1,66 @@
+package org.enso.polyglot.data
+
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+
+class TypeGraphTest extends AnyWordSpec with Matchers {
+
+ "The type graph" should {
+ "be able to insert links" in {
+ val graph = new TypeGraph("Builtins.Main.Any")
+ graph.insert("Builtins.Main.Number", "Builtins.Main.Any")
+ graph.insert("Builtins.Main.Decimal", "Builtins.Main.Number")
+ graph.insert("Builtins.Main.Integer", "Builtins.Main.Number")
+ }
+
+ "be able to query direct parents" in {
+ val graph = new TypeGraph("Builtins.Main.Any")
+ graph.insert("Builtins.Main.Number", "Builtins.Main.Any")
+ graph.insert("Builtins.Main.Decimal", "Builtins.Main.Number")
+ graph.insert("Builtins.Main.Integer", "Builtins.Main.Number")
+
+ graph.getDirectParents("Builtins.Main.Decimal") shouldEqual Set(
+ "Builtins.Main.Number"
+ )
+ graph.getDirectParents("Builtins.Main.Integer") shouldEqual Set(
+ "Builtins.Main.Number"
+ )
+ graph.getDirectParents("Builtins.Main.Number") shouldEqual Set(
+ "Builtins.Main.Any"
+ )
+ graph.getDirectParents("Builtins.Main.Any") shouldBe empty
+ }
+
+ "be able to query all parents" in {
+ val graph = new TypeGraph("Builtins.Main.Any")
+ graph.insert("Builtins.Main.Number", "Builtins.Main.Any")
+ graph.insert("Builtins.Main.Decimal", "Builtins.Main.Number")
+ graph.insert("Builtins.Main.Integer", "Builtins.Main.Number")
+
+ graph.getParents("Builtins.Main.Any") shouldEqual Set()
+ graph.getParents("Builtins.Main.Number") shouldEqual Set(
+ "Builtins.Main.Any"
+ )
+ graph.getParents("Builtins.Main.Integer") shouldEqual Set(
+ "Builtins.Main.Number",
+ "Builtins.Main.Any"
+ )
+ graph.getParents("Builtins.Main.Decimal") shouldEqual Set(
+ "Builtins.Main.Number",
+ "Builtins.Main.Any"
+ )
+ }
+
+ "have a fallback parent for any typename" in {
+ val graph = new TypeGraph("Builtins.Main.Any")
+ graph.insert("Builtins.Main.Number", "Builtins.Main.Any")
+ graph.insert("Builtins.Main.Decimal", "Builtins.Main.Number")
+ graph.insert("Builtins.Main.Integer", "Builtins.Main.Number")
+
+ graph.getParents("My_User_Type") shouldEqual Set("Builtins.Main.Any")
+ graph.getParents("Standard.Base.Vector") shouldEqual Set(
+ "Builtins.Main.Any"
+ )
+ }
+ }
+}
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java
index ef7cf6a5b512..f125ea8a810e 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/type/Types.java
@@ -17,6 +17,8 @@
import org.enso.interpreter.runtime.error.PanicSentinel;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.enso.interpreter.runtime.scope.ModuleScope;
+import org.enso.polyglot.data.TypeGraph;
+import org.yaml.snakeyaml.scanner.Constant;
/**
* This class defines the interpreter-level type system for Enso.
@@ -49,6 +51,8 @@
})
public class Types {
+ private static TypeGraph typeHierarchy = buildTypeHierarchy();
+
/**
* A simple pair type
*
@@ -195,4 +199,30 @@ public static Pair extractArguments(Object[] arguments, Class cl
}
return new Pair<>((A) arguments[0], (B) arguments[1]);
}
+
+ /** @return the language type hierarchy */
+ public static TypeGraph getTypeHierarchy() {
+ return typeHierarchy;
+ }
+
+ private static TypeGraph buildTypeHierarchy() {
+ TypeGraph graph = TypeGraph.fromJava(Constants.ANY);
+
+ graph.insert(Constants.ARRAY, Constants.ANY);
+ graph.insert(Constants.BOOLEAN, Constants.ANY);
+ graph.insert(Constants.DECIMAL, Constants.NUMBER);
+ graph.insert(Constants.ERROR, Constants.ANY);
+ graph.insert(Constants.FUNCTION, Constants.ANY);
+ graph.insert(Constants.INTEGER, Constants.NUMBER);
+ graph.insert(Constants.MANAGED_RESOURCE, Constants.ANY);
+ graph.insert(Constants.NOTHING, Constants.ANY);
+ graph.insert(Constants.PANIC, Constants.ANY);
+ graph.insert(Constants.REF, Constants.ANY);
+ graph.insert(Constants.TEXT, Constants.ANY);
+ graph.insertWithoutParent(Constants.PANIC);
+ graph.insertWithoutParent(Constants.THUNK);
+ graph.insertWithoutParent(Constants.UNRESOLVED_SYMBOL);
+
+ return graph;
+ }
}
diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/CommandFactory.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/CommandFactory.scala
index d0d85066958c..f8f025e1f36a 100644
--- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/CommandFactory.scala
+++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/CommandFactory.scala
@@ -54,6 +54,9 @@ object CommandFactory {
throw new IllegalArgumentException(
"ShutDownRuntimeServer request is not convertible to command object"
)
+
+ case _: Api.GetTypeGraphRequest =>
+ new GetTypeGraphCommand(request.requestId)
}
}
diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/GetTypeGraphCommand.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/GetTypeGraphCommand.scala
new file mode 100644
index 000000000000..3b192f9e524d
--- /dev/null
+++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/command/GetTypeGraphCommand.scala
@@ -0,0 +1,21 @@
+package org.enso.interpreter.instrument.command
+
+import org.enso.interpreter.instrument.execution.RuntimeContext
+import org.enso.interpreter.runtime.`type`.Types
+import org.enso.polyglot.runtime.Runtime.Api
+import org.enso.polyglot.runtime.Runtime.Api.RequestId
+
+import scala.concurrent.{ExecutionContext, Future}
+
+class GetTypeGraphCommand(maybeRequestId: Option[RequestId])
+ extends Command(maybeRequestId) {
+
+ /** @inheritdoc */
+ override def execute(implicit
+ ctx: RuntimeContext,
+ ec: ExecutionContext
+ ): Future[Unit] = Future {
+ val typeGraph = Types.getTypeHierarchy
+ reply(Api.GetTypeGraphResponse(typeGraph))
+ }
+}
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 6238db1a3150..e76a2ff55f0f 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
@@ -1,11 +1,12 @@
package org.enso.interpreter.test.instrument
import org.enso.interpreter.instrument.execution.Timer
-import org.enso.interpreter.runtime.`type`.Constants
+import org.enso.interpreter.runtime.`type`.{Constants, Types}
import org.enso.interpreter.runtime.{Context => EnsoContext}
import org.enso.interpreter.test.Metadata
import org.enso.pkg.{Package, PackageManager}
import org.enso.polyglot._
+import org.enso.polyglot.data.TypeGraph
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.text.editing.model
import org.enso.text.editing.model.TextEdit
@@ -3706,4 +3707,13 @@ class RuntimeServerTest
)
}
+ it should "send the type graph" in {
+ val requestId = UUID.randomUUID()
+ val expectedGraph: TypeGraph = Types.getTypeHierarchy
+
+ context.send(Api.Request(requestId, Api.GetTypeGraphRequest()))
+ context.receive shouldEqual Some(
+ Api.Response(requestId, Api.GetTypeGraphResponse(expectedGraph))
+ )
+ }
}
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 9f2dc6020707..0689f9af1c5b 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
@@ -1,5 +1,6 @@
package org.enso.searcher.sql;
+import java.util.ArrayList;
import org.enso.polyglot.Suggestion;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
@@ -18,6 +19,8 @@
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
+import scala.jdk.CollectionConverters;
+
@BenchmarkMode(Mode.AverageTime)
@Fork(1)
@Warmup(iterations = 5)
@@ -69,35 +72,64 @@ static scala.Option none() {
@Benchmark
public Object searchBaseline() throws TimeoutException, InterruptedException {
- return Await.result(repo.search(none(), none(), none(), none(), none()), TIMEOUT);
+ return Await.result(
+ repo.search(
+ none(),
+ CollectionConverters.ListHasAsScala(new ArrayList()).asScala().toSeq(),
+ none(),
+ none(),
+ none()),
+ TIMEOUT);
}
@Benchmark
public Object searchByReturnType() throws TimeoutException, InterruptedException {
return Await.result(
- repo.search(none(), none(), scala.Some.apply("MyType"), none(), none()), TIMEOUT);
+ repo.search(
+ none(),
+ CollectionConverters.ListHasAsScala(new ArrayList()).asScala().toSeq(),
+ scala.Some.apply("MyType"),
+ none(),
+ none()),
+ TIMEOUT);
}
@Benchmark
public Object searchBySelfType() throws TimeoutException, InterruptedException {
+ var selfTypes = new ArrayList();
+ selfTypes.add("MyType");
return Await.result(
- repo.search(none(), scala.Some.apply("MyType"), none(), none(), none()), TIMEOUT);
+ repo.search(
+ none(),
+ CollectionConverters.ListHasAsScala(selfTypes).asScala().toSeq(),
+ none(),
+ none(),
+ none()),
+ TIMEOUT);
}
@Benchmark
public Object searchBySelfReturnTypes() throws TimeoutException, InterruptedException {
+ var selfTypes = new ArrayList();
+ selfTypes.add("SelfType");
return Await.result(
repo.search(
- none(), scala.Some.apply("SelfType"), scala.Some.apply("ReturnType"), none(), none()),
+ none(),
+ CollectionConverters.ListHasAsScala(selfTypes).asScala().toSeq(),
+ scala.Some.apply("ReturnType"),
+ none(),
+ none()),
TIMEOUT);
}
@Benchmark
public Object searchByAll() throws TimeoutException, InterruptedException {
+ var selfTypes = new ArrayList();
+ selfTypes.add("SelfType");
return Await.result(
repo.search(
none(),
- scala.Some.apply("SelfType"),
+ CollectionConverters.ListHasAsScala(selfTypes).asScala().toSeq(),
scala.Some.apply("ReturnType"),
scala.Some.apply(kinds),
none()),
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 92e50f2c650f..68b73de2137a 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
@@ -34,7 +34,7 @@ trait SuggestionsRepo[F[_]] {
/** Search suggestion by various parameters.
*
* @param module the module name search parameter
- * @param selfType the selfType search parameter
+ * @param selfType the self types to search for
* @param returnType the returnType search parameter
* @param kinds the list suggestion kinds to search
* @param position the absolute position in the text
@@ -42,7 +42,7 @@ trait SuggestionsRepo[F[_]] {
*/
def search(
module: Option[String],
- selfType: Option[String],
+ selfType: Seq[String],
returnType: Option[String],
kinds: Option[Seq[Suggestion.Kind]],
position: Option[Suggestion.Position]
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 70b554245f30..762231d6f6ee 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
@@ -56,7 +56,7 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
/** @inheritdoc */
override def search(
module: Option[String],
- selfType: Option[String],
+ selfType: Seq[String],
returnType: Option[String],
kinds: Option[Seq[Suggestion.Kind]],
position: Option[Suggestion.Position]
@@ -219,7 +219,7 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
*/
private def searchQuery(
module: Option[String],
- selfType: Option[String],
+ selfType: Seq[String],
returnType: Option[String],
kinds: Option[Seq[Suggestion.Kind]],
position: Option[Suggestion.Position]
@@ -656,7 +656,7 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
* global symbols (atoms and method).
*
* @param module the module name search parameter
- * @param selfType the selfType search parameter
+ * @param selfTypes the selfType search parameter
* @param returnType the returnType search parameter
* @param kinds the list suggestion kinds to search
* @param position the absolute position in the text
@@ -664,7 +664,7 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
*/
private def searchQueryBuilder(
module: Option[String],
- selfType: Option[String],
+ selfTypes: Seq[String],
returnType: Option[String],
kinds: Option[Seq[Suggestion.Kind]],
position: Option[Suggestion.Position]
@@ -673,9 +673,7 @@ final class SqlSuggestionsRepo(db: SqlDatabase)(implicit ec: ExecutionContext)
.filterOpt(module) { case (row, value) =>
row.scopeStartLine === ScopeColumn.EMPTY || row.module === value
}
- .filterOpt(selfType) { case (row, value) =>
- row.selfType === value
- }
+ .filterIf(selfTypes.nonEmpty) {row => row.selfType.inSet(selfTypes) }
.filterOpt(returnType) { case (row, value) =>
row.returnType === value
}
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 538baa4014b6..464394cd9ce8 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
@@ -718,7 +718,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
- res <- repo.search(None, None, None, None, None)
+ res <- repo.search(None, Seq(), None, None, None)
} yield res._2
val res = Await.result(action, Timeout)
@@ -731,7 +731,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id2 <- repo.insert(suggestion.method)
id3 <- repo.insert(suggestion.function)
id4 <- repo.insert(suggestion.local)
- res <- repo.search(Some("Test.Main"), None, None, None, None)
+ res <- repo.search(Some("Test.Main"), Seq(), None, None, None)
} yield (id1, id2, id3, id4, res._2)
val (id1, id2, id3, id4, res) = Await.result(action, Timeout)
@@ -744,7 +744,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id2 <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
- res <- repo.search(Some(""), None, None, None, None)
+ res <- repo.search(Some(""), Seq(), None, None, None)
} yield (res._2, Seq(id1, id2))
val (res, globals) = Await.result(action, Timeout)
@@ -757,7 +757,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id2 <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
- res <- repo.search(None, Some("Main"), None, None, None)
+ res <- repo.search(None, Seq("Main"), None, None, None)
} yield (id2, res._2)
val (id, res) = Await.result(action, Timeout)
@@ -770,7 +770,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.method)
id3 <- repo.insert(suggestion.function)
id4 <- repo.insert(suggestion.local)
- res <- repo.search(None, None, Some("MyType"), None, None)
+ res <- repo.search(None, Seq(), Some("MyType"), None, None)
} yield (id3, id4, res._2)
val (id1, id2, res) = Await.result(action, Timeout)
@@ -784,7 +784,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
id4 <- repo.insert(suggestion.local)
- res <- repo.search(None, None, None, Some(kinds), None)
+ res <- repo.search(None, Seq(), None, Some(kinds), None)
} yield (id1, id4, res._2)
val (id1, id2, res) = Await.result(action, Timeout)
@@ -797,7 +797,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
- res <- repo.search(None, None, None, Some(Seq()), None)
+ res <- repo.search(None, Seq(), None, Some(Seq()), None)
} yield res._2
val res = Await.result(action, Timeout)
@@ -811,7 +811,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
res <-
- repo.search(None, None, None, None, Some(Suggestion.Position(99, 42)))
+ repo.search(None, Seq(), None, None, Some(Suggestion.Position(99, 42)))
} yield (id1, id2, res._2)
val (id1, id2, res) = Await.result(action, Timeout)
@@ -825,7 +825,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id3 <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
res <-
- repo.search(None, None, None, None, Some(Suggestion.Position(1, 5)))
+ repo.search(None, Seq(), None, None, Some(Suggestion.Position(1, 5)))
} yield (id1, id2, id3, res._2)
val (id1, id2, id3, res) = Await.result(action, Timeout)
@@ -839,7 +839,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id2 <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
- res <- repo.search(Some("Test.Main"), Some("Main"), None, None, None)
+ res <- repo.search(Some("Test.Main"), Seq("Main"), None, None, None)
} yield (id2, res._2)
val (id, res) = Await.result(action, Timeout)
@@ -854,7 +854,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
id4 <- repo.insert(suggestion.local)
- res <- repo.search(None, None, Some("MyType"), Some(kinds), None)
+ res <- repo.search(None, Seq(), Some("MyType"), Some(kinds), None)
} yield (id4, res._2)
val (id, res) = Await.result(action, Timeout)
@@ -870,7 +870,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id4 <- repo.insert(suggestion.local)
res <- repo.search(
None,
- None,
+ Seq(),
Some("MyType"),
None,
Some(Suggestion.Position(42, 0))
@@ -890,7 +890,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.local)
res <- repo.search(
None,
- None,
+ Seq(),
None,
Some(kinds),
Some(Suggestion.Position(99, 1))
@@ -908,7 +908,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.method)
_ <- repo.insert(suggestion.function)
_ <- repo.insert(suggestion.local)
- res <- repo.search(None, Some("Main"), Some("MyType"), None, None)
+ res <- repo.search(None, Seq("Main"), Some("MyType"), None, None)
} yield res._2
val res = Await.result(action, Timeout)
@@ -925,7 +925,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id4 <- repo.insert(suggestion.local)
res <- repo.search(
Some("Test.Main"),
- None,
+ Seq(),
Some("MyType"),
Some(kinds),
None
@@ -946,7 +946,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
id4 <- repo.insert(suggestion.local)
res <- repo.search(
None,
- None,
+ Seq(),
Some("MyType"),
Some(kinds),
Some(Suggestion.Position(42, 0))
@@ -970,7 +970,7 @@ class SuggestionsRepoTest extends AnyWordSpec with Matchers with RetrySpec {
_ <- repo.insert(suggestion.local)
res <- repo.search(
Some("Test.Main"),
- Some("Main"),
+ Seq("Main"),
Some("MyType"),
Some(kinds),
Some(Suggestion.Position(42, 0))