diff --git a/docs/language-server/protocol-language-server.md b/docs/language-server/protocol-language-server.md index 4f4aac89bf8..869b790b038 100644 --- a/docs/language-server/protocol-language-server.md +++ b/docs/language-server/protocol-language-server.md @@ -500,8 +500,14 @@ interface Module { /** The documentation string. */ documentation?: string; - /** The fully qualified module name re-exporting this module. */ + /** The fully qualified module name re-exporting this module. + * + * @deprecated use reexports field instead + */ reexport?: string; + + /** The list of fully qualified module names re-exporting this module. */ + reexports: string[]; } interface Type { @@ -520,9 +526,15 @@ interface Type { /** Qualified name of the parent type. */ parentType?: string; - /** The fully qualified module name re-exporting this type. */ + /** The fully qualified module name re-exporting this type. + * + * @deprecated use reexports field instead + */ reexport?: string; + /** The list of fully qualified module names re-exporting this type. */ + reexports: string[]; + /** The documentation string. */ documentation?: string; } @@ -543,9 +555,15 @@ interface Constructor { /** The type of the constructor. */ returnType: string; - /** The fully qualified module name re-exporting this constructor. */ + /** The fully qualified module name re-exporting this constructor. + * + * @deprecated use reexports field instead + */ reexport?: string; + /** The list of fully qualified module names re-exporting this constructor. */ + reexports: string[]; + /** The documentation string. */ documentation?: string; @@ -575,9 +593,15 @@ interface Method { /** The flag indicating whether this method is static or instance. */ isStatic: boolean; - /** The fully qualified module name re-exporting this method. */ + /** The fully qualified module name re-exporting this method. + * + * @deprecated use reexports field instead + */ reexport?: string; + /** The list of fully qualified module names re-exporting this method. */ + reexports: string[]; + /** The documentation string. */ documentation?: string; diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/search/SearchProtocol.scala b/engine/language-server/src/main/scala/org/enso/languageserver/search/SearchProtocol.scala index 0b64e358b87..af8b58e3486 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/search/SearchProtocol.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/search/SearchProtocol.scala @@ -33,6 +33,8 @@ object SearchProtocol { val Documentation = "documentation" val Reexport = "reexport" + + val Reexports = "reexports" } private object CodecType { @@ -64,7 +66,12 @@ object SearchProtocol { case module: Suggestion.Module => Encoder[Suggestion.Module] .apply(module) - .deepMerge(Json.obj(CodecField.Type -> SuggestionType.Module.asJson)) + .deepMerge( + Json.obj( + CodecField.Type -> SuggestionType.Module.asJson, + CodecField.Reexport -> module.reexports.headOption.asJson + ) + ) case tpe: Suggestion.Type => Encoder[Suggestion.Type] @@ -72,7 +79,8 @@ object SearchProtocol { .deepMerge( Json.obj( CodecField.Type -> SuggestionType.Type.asJson, - CodecField.ReturnType -> Json.Null + CodecField.ReturnType -> Json.Null, + CodecField.Reexport -> tpe.reexports.headOption.asJson ) ) .dropNullValues @@ -81,7 +89,10 @@ object SearchProtocol { Encoder[Suggestion.Constructor] .apply(constructor) .deepMerge( - Json.obj(CodecField.Type -> SuggestionType.Constructor.asJson) + Json.obj( + CodecField.Type -> SuggestionType.Constructor.asJson, + CodecField.Reexport -> constructor.reexports.headOption.asJson + ) ) .dropNullValues @@ -89,7 +100,10 @@ object SearchProtocol { Encoder[Suggestion.DefinedMethod] .apply(conversionToMethod(conversion)) .deepMerge( - Json.obj(CodecField.Type -> SuggestionType.Method.asJson) + Json.obj( + CodecField.Type -> SuggestionType.Method.asJson, + CodecField.Reexport -> conversion.reexports.headOption.asJson + ) ) .dropNullValues @@ -97,7 +111,10 @@ object SearchProtocol { Encoder[Suggestion.DefinedMethod] .apply(getterToMethod(getter)) .deepMerge( - Json.obj(CodecField.Type -> SuggestionType.Method.asJson) + Json.obj( + CodecField.Type -> SuggestionType.Method.asJson, + CodecField.Reexport -> getter.reexports.headOption.asJson + ) ) .dropNullValues @@ -105,7 +122,10 @@ object SearchProtocol { Encoder[Suggestion.DefinedMethod] .apply(method) .deepMerge( - Json.obj(CodecField.Type -> SuggestionType.Method.asJson) + Json.obj( + CodecField.Type -> SuggestionType.Method.asJson, + CodecField.Reexport -> method.reexports.headOption.asJson + ) ) .dropNullValues @@ -137,7 +157,7 @@ object SearchProtocol { conversion.isStatic, conversion.documentation, conversion.annotations, - conversion.reexport + conversion.reexports ) private def getterToMethod( @@ -153,7 +173,7 @@ object SearchProtocol { getter.isStatic, getter.documentation, getter.annotations, - getter.reexport + getter.reexports ) private val suggestionTypeDecoder: Decoder[Suggestion.Type] = @@ -171,7 +191,7 @@ object SearchProtocol { documentation <- cursor .downField(CodecField.Documentation) .as[Option[String]] - reexport <- cursor.downField(CodecField.Reexport).as[Option[String]] + reexports <- cursor.downField(CodecField.Reexports).as[Set[String]] } yield { val returnType = QualifiedName.fromString(module).createChild(name).toString @@ -183,7 +203,7 @@ object SearchProtocol { returnType, parentType, documentation, - reexport + reexports ) } } 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 ba5c85eca2e..5b863f9adc1 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 @@ -550,7 +550,7 @@ final class SuggestionsHandler( for { actionResults <- suggestionsRepo.applyActions(msg.actions) treeResults <- suggestionsRepo.applyTree(msg.updates.toVector) - exportResults <- suggestionsRepo.applyExports(msg.exports) + exportResults <- suggestionsRepo.getExportedSymbols(msg.exports) version <- suggestionsRepo.currentVersion } yield { val actionUpdates = actionResults.flatMap { 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 3e73c91997f..a8ea0151a1c 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 @@ -642,7 +642,7 @@ class SuggestionsHandlerSpec DeliverToJsonController( clientId, SearchProtocol.SuggestionsDatabaseUpdateNotification( - updates1.size.toLong + 1, + updates1.size.toLong, updates2 ) ) @@ -690,7 +690,7 @@ class SuggestionsHandlerSpec DeliverToJsonController( clientId, SearchProtocol.SuggestionsDatabaseUpdateNotification( - updates1.size.toLong + 2, + updates1.size.toLong, updates3 ) ) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala index 445dffc8425..fe19731a684 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala @@ -65,7 +65,8 @@ class SuggestionsHandlerEventsTest "tagValues" : null } ], - "parentType" : "Any" + "parentType" : "Any", + "reexports" : [] } } ], @@ -117,7 +118,8 @@ class SuggestionsHandlerEventsTest ], "returnType" : "MyAtom", "documentation" : " PRIVATE\n\n A key-value store. This type assumes all keys are pairwise comparable,\n using the `<`, `>` and `==` operators.\n\n Arguments:\n - one: The first.\n - two_three: The *second*.\n\n ? Info\n Here is a thing.", - "annotations" : ["a"] + "annotations" : ["a"], + "reexports" : [] } } ], @@ -161,7 +163,8 @@ class SuggestionsHandlerEventsTest "selfType" : "MyType", "returnType" : "Any", "isStatic" : false, - "annotations" : [ ] + "annotations" : [ ], + "reexports" : [ ] } } ], @@ -232,7 +235,8 @@ class SuggestionsHandlerEventsTest "returnType" : "Number", "isStatic" : false, "documentation" : "Lovely", - "annotations" : ["foo"] + "annotations" : ["foo"], + "reexports" : [] } } ], @@ -578,7 +582,7 @@ class SuggestionsHandlerEventsTest } } ], - "currentVersion" : 9 + "currentVersion" : 8 } } """) @@ -625,7 +629,7 @@ class SuggestionsHandlerEventsTest "id" : 6 } ], - "currentVersion" : 9 + "currentVersion" : 8 } } """) diff --git a/engine/polyglot-api/src/main/scala/org/enso/polyglot/Suggestion.scala b/engine/polyglot-api/src/main/scala/org/enso/polyglot/Suggestion.scala index 3ee264235a7..986898068c9 100644 --- a/engine/polyglot-api/src/main/scala/org/enso/polyglot/Suggestion.scala +++ b/engine/polyglot-api/src/main/scala/org/enso/polyglot/Suggestion.scala @@ -5,6 +5,8 @@ import org.enso.logger.masking.ToLogString import java.util.UUID +import scala.collection.immutable.ListSet + /** A search suggestion. */ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes( @@ -51,8 +53,7 @@ sealed trait Suggestion extends ToLogString { def returnType: String def documentation: Option[String] - /** Set the reexport field of the suggestion. */ - def withReexport(reexport: Option[String]): Suggestion + def withReexports(reexports: Set[String]): Suggestion } object Suggestion { @@ -223,12 +224,12 @@ object Suggestion { * * @param module the fully qualified module name * @param documentation the documentation string - * @param reexport the module re-exporting this module + * @param reexports modules re-exporting this module */ case class Module( module: String, documentation: Option[String], - reexport: Option[String] = None + reexports: Set[String] = ListSet() ) extends Suggestion with ToLogString { @@ -242,14 +243,14 @@ object Suggestion { module /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Module = - copy(reexport = reexport) + override def withReexports(reexports: Set[String]): Suggestion = + copy(reexports = reexports) /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = s"Module(module=$module,name=$name,documentation=" + (if (shouldMask) documentation.map(_ => STUB) else documentation) + - s",reexport=$reexport)" + s",reexports=$reexports)" } /** A type definition. @@ -261,7 +262,7 @@ object Suggestion { * @param returnType the type of an atom * @param parentType qualified name of the parent type * @param documentation the documentation string - * @param reexport the module re-exporting this atom + * @param reexports modules re-exporting this atom */ case class Type( externalId: Option[ExternalID], @@ -271,13 +272,13 @@ object Suggestion { returnType: String, parentType: Option[String], documentation: Option[String], - reexport: Option[String] = None + reexports: Set[String] = ListSet() ) extends Suggestion with ToLogString { /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Type = - copy(reexport = reexport) + override def withReexports(reexports: Set[String]): Suggestion = + copy(reexports = reexports) /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = @@ -290,7 +291,7 @@ object Suggestion { s"parentType=$parentType" + s",documentation=" + (if (shouldMask) documentation.map(_ => STUB) else documentation) + - s",reexport=$reexport)" + s",reexports=$reexports)" } /** A value constructor. @@ -302,7 +303,7 @@ object Suggestion { * @param returnType the type of an atom * @param documentation the documentation string * @param annotations the list of annotations - * @param reexport the module re-exporting this atom + * @param reexports modules re-exporting this atom */ case class Constructor( externalId: Option[ExternalID], @@ -312,13 +313,13 @@ object Suggestion { returnType: String, documentation: Option[String], annotations: Seq[String], - reexport: Option[String] = None + reexports: Set[String] = ListSet() ) extends Suggestion with ToLogString { /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Constructor = - copy(reexport = reexport) + override def withReexports(reexports: Set[String]): Suggestion = + copy(reexports = reexports) /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = @@ -330,7 +331,7 @@ object Suggestion { s"returnType=$returnType" + s",documentation=" + (if (shouldMask) documentation.map(_ => STUB) else documentation) + - s",reexport=$reexport)" + s",reexports=$reexports)" } /** Base trait for method suggestions. */ @@ -356,7 +357,7 @@ object Suggestion { def selfType: String def isStatic: Boolean def annotations: Seq[String] - def reexport: Option[String] + def reexports: Set[String] } /** A method generated to access constructor field. @@ -369,7 +370,7 @@ object Suggestion { * @param returnType the return type of a method * @param documentation the documentation string * @param annotations the list of annotations - * @param reexport the module re-exporting this method + * @param reexports modules re-exporting this method */ case class Getter( externalId: Option[ExternalID], @@ -380,7 +381,7 @@ object Suggestion { returnType: String, documentation: Option[String], annotations: Seq[String], - reexport: Option[String] = None + reexports: Set[String] = ListSet() ) extends Method with ToLogString { @@ -389,8 +390,8 @@ object Suggestion { override def isStatic: Boolean = false /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Method = - copy(reexport = reexport) + override def withReexports(reexports: Set[String]): Suggestion = + copy(reexports = reexports) /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = @@ -402,7 +403,7 @@ object Suggestion { s"returnType=$returnType," + s"documentation=" + (if (shouldMask) documentation.map(_ => STUB) else documentation) + - s",reexport=$reexport)" + s",reexports=$reexports)" } /** A function defined on a type or a module. @@ -416,7 +417,7 @@ object Suggestion { * @param isStatic the flag indicating whether a method is static or instance * @param documentation the documentation string * @param annotations the list of annotations - * @param reexport the module re-exporting this method + * @param reexports modules re-exporting this method */ case class DefinedMethod( externalId: Option[ExternalID], @@ -428,13 +429,13 @@ object Suggestion { isStatic: Boolean, documentation: Option[String], annotations: Seq[String], - reexport: Option[String] = None + reexports: Set[String] = ListSet() ) extends Method with ToLogString { /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Method = - copy(reexport = reexport) + override def withReexports(reexports: Set[String]): Suggestion = + copy(reexports = reexports) /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = @@ -447,7 +448,7 @@ object Suggestion { s"isStatic=$isStatic," + s"documentation=" + (if (shouldMask) documentation.map(_ => STUB) else documentation) + - s",reexport=$reexport)" + s",reexports=$reexports)" } /** A conversion function. @@ -458,7 +459,7 @@ object Suggestion { * @param selfType the source type of a conversion * @param returnType the return type of a conversion * @param documentation the documentation string - * @param reexport the module re-exporting this conversion + * @param reexports modules re-exporting this conversion */ case class Conversion( externalId: Option[ExternalID], @@ -467,7 +468,7 @@ object Suggestion { selfType: String, returnType: String, documentation: Option[String], - reexport: Option[String] = None + reexports: Set[String] = ListSet() ) extends Method { /** @inheritdoc */ @@ -478,15 +479,15 @@ object Suggestion { @JsonIgnore override def annotations: Seq[String] = Seq() - /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Conversion = - copy(reexport = reexport) - /** @inheritdoc */ @JsonIgnore override def name: String = Kind.Conversion.From + /** @inheritdoc */ + override def withReexports(reexports: Set[String]): Suggestion = + copy(reexports = reexports) + /** @inheritdoc */ override def toLogString(shouldMask: Boolean): String = "Conversion(" + @@ -496,7 +497,7 @@ object Suggestion { s"returnType=$returnType," + s"documentation=" + (if (shouldMask) documentation.map(_ => STUB) else documentation) + - s",reexport=$reexport)" + s",reexports=$reexports)" } /** A local function definition. @@ -521,7 +522,7 @@ object Suggestion { with ToLogString { /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Function = + override def withReexports(reexports: Set[String]): Suggestion = this /** @inheritdoc */ @@ -556,7 +557,7 @@ object Suggestion { ) extends Suggestion { /** @inheritdoc */ - override def withReexport(reexport: Option[String]): Local = + override def withReexports(reexports: Set[String]): Suggestion = this /** @inheritdoc */ diff --git a/engine/runtime-compiler/src/main/java/org/enso/compiler/context/ExportsMap.java b/engine/runtime-compiler/src/main/java/org/enso/compiler/context/ExportsMap.java index 70f203a9c48..142cdb6b739 100644 --- a/engine/runtime-compiler/src/main/java/org/enso/compiler/context/ExportsMap.java +++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/context/ExportsMap.java @@ -1,12 +1,14 @@ package org.enso.compiler.context; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; import org.enso.pkg.QualifiedName; import org.enso.polyglot.ExportedSymbol; import org.enso.polyglot.ModuleExports; import org.enso.polyglot.Suggestion; -import scala.Option; import scala.runtime.BoxedUnit; public final class ExportsMap { @@ -14,18 +16,27 @@ public final class ExportsMap { private static final String MODULE_MAIN = "Main"; private static final String TYPE_SUFFIX = "type"; - private final Map exportsMap; + private static final Comparator EXPORTS_COMPARATOR = + Comparator.comparingInt(ExportsMap::length); + + private final Map> exportsMap; public ExportsMap() { this.exportsMap = new HashMap<>(); } - public ExportsMap(Map exportsMap) { + public ExportsMap(Map> exportsMap) { this.exportsMap = exportsMap; } public void add(ExportedSymbol symbol, QualifiedName moduleName) { - exportsMap.merge(symbol, moduleName, ExportsMap::getShortest); + exportsMap.compute( + symbol, + (k, v) -> { + var set = v == null ? new TreeSet<>(EXPORTS_COMPARATOR) : v; + set.add(moduleName); + return set; + }); } public void addAll(QualifiedName moduleName, ModuleExports moduleExports) { @@ -38,13 +49,10 @@ public final class ExportsMap { }); } - public Option get(Suggestion suggestion) { + public SortedSet get(Suggestion suggestion) { return ExportedSymbol.fromSuggestion(suggestion) - .flatMap(symbol -> Option.apply(exportsMap.get(symbol))); - } - - private static QualifiedName getShortest(QualifiedName name1, QualifiedName name2) { - return length(name1) <= length(name2) ? name1 : name2; + .map(symbol -> exportsMap.getOrDefault(symbol, new TreeSet<>(EXPORTS_COMPARATOR))) + .getOrElse(() -> new TreeSet<>(EXPORTS_COMPARATOR)); } private static int length(QualifiedName qualifiedName) { diff --git a/engine/runtime-compiler/src/main/scala/org/enso/compiler/context/ExportsBuilder.scala b/engine/runtime-compiler/src/main/scala/org/enso/compiler/context/ExportsBuilder.scala index b8b6d5c4cf5..2e567e2ded0 100644 --- a/engine/runtime-compiler/src/main/scala/org/enso/compiler/context/ExportsBuilder.scala +++ b/engine/runtime-compiler/src/main/scala/org/enso/compiler/context/ExportsBuilder.scala @@ -16,7 +16,6 @@ final class ExportsBuilder { */ def build(moduleName: QualifiedName, ir: IR): ModuleExports = { val symbols = getBindings(ir).exportedSymbols.values.flatten - .filter(_.module.getName != moduleName) .collect { case BindingsMap.ResolvedMethod(module, method) => ExportedSymbol.Method(module.getName.toString, method.name) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/compiler/SerializationManagerTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/compiler/SerializationManagerTest.java index 6639c46ed8b..9fc0d8c0096 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/compiler/SerializationManagerTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/compiler/SerializationManagerTest.java @@ -13,6 +13,7 @@ import org.enso.editions.LibraryName; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.util.TruffleFileSystem; import org.enso.interpreter.test.InterpreterContext; +import org.enso.interpreter.util.ScalaConversions; import org.enso.pkg.Package; import org.enso.pkg.PackageManager; import org.enso.polyglot.LanguageInfo; @@ -112,7 +113,9 @@ public class SerializationManagerTest { .filter(constructor -> constructor.name().equals("True")) .findFirst() .get(); - Assert.assertEquals(scala.Some.apply("Standard.Base.Main"), booleanTrueSuggestion.reexport()); + Assert.assertEquals( + ScalaConversions.set("Standard.Base.Main", "Standard.Base.Data.Boolean").toList(), + booleanTrueSuggestion.reexports().toList()); Suggestion.Constructor runtimeContextInputSuggestion = cachedConstructorSuggestions @@ -120,7 +123,8 @@ public class SerializationManagerTest { .filter(constructor -> constructor.name().equals("Input")) .findFirst() .get(); - Assert.assertEquals(scala.None$.MODULE$, runtimeContextInputSuggestion.reexport()); + Assert.assertEquals( + ScalaConversions.set().toList(), runtimeContextInputSuggestion.reexports().toList()); clearLibraryCache(standardBaseLibrary); } diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/context/JacksonTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/context/JacksonTest.java index bf9a2577b98..834bab08da2 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/context/JacksonTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/context/JacksonTest.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.module.scala.DefaultScalaModule; import java.util.List; +import org.enso.interpreter.util.ScalaConversions; import org.enso.polyglot.Suggestion; import org.junit.Test; import scala.Option; @@ -15,7 +16,8 @@ public class JacksonTest { @Test public void testSerdeOfSuggestion() throws Exception { - Object shape = new Suggestion.Module("SampleModule", Option.apply("doc"), Option.empty()); + Object shape = + new Suggestion.Module("SampleModule", Option.apply("doc"), ScalaConversions.set()); final ObjectMapper m = new ObjectMapper().registerModule(new DefaultScalaModule()); String result = m.writerWithDefaultPrettyPrinter().writeValueAsString(shape); @@ -29,7 +31,7 @@ public class JacksonTest { public void testArraySerdeOfSuggestion() throws Exception { Object shape = new Suggestion[] { - new Suggestion.Module("SampleModule", Option.apply("doc"), Option.empty()) + new Suggestion.Module("SampleModule", Option.apply("doc"), ScalaConversions.set()) }; final ObjectMapper m = new ObjectMapper().registerModule(new DefaultScalaModule()); String result = m.writerWithDefaultPrettyPrinter().writeValueAsString(shape); @@ -50,7 +52,9 @@ public class JacksonTest { Object shape = new SuggestionCache( 11, - List.of(new Suggestion.Module("SampleModule", Option.apply("doc"), Option.empty()))); + List.of( + new Suggestion.Module( + "SampleModule", Option.apply("doc"), ScalaConversions.set()))); final ObjectMapper m = new ObjectMapper().registerModule(new DefaultScalaModule()); String result = m.writerWithDefaultPrettyPrinter().writeValueAsString(shape); diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeSuggestionUpdatesTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeSuggestionUpdatesTest.scala index 30b7d10b861..646daeddedc 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeSuggestionUpdatesTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeSuggestionUpdatesTest.scala @@ -16,6 +16,8 @@ import java.nio.file.{Files, Paths} import java.util.UUID import java.util.logging.Level +import scala.collection.immutable.ListSet + @scala.annotation.nowarn("msg=multiarg infix syntax") class RuntimeSuggestionUpdatesTest extends AnyFlatSpec @@ -148,7 +150,15 @@ class RuntimeSuggestionUpdatesTest Api.SuggestionsDatabaseModuleUpdateNotification( module = moduleName, actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + moduleName, + ListSet(ExportedSymbol.Method(moduleName, "main")) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -472,7 +482,15 @@ class RuntimeSuggestionUpdatesTest Api.SuggestionsDatabaseModuleUpdateNotification( module = moduleName, actions = Vector(), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + moduleName, + ListSet(ExportedSymbol.Method(moduleName, "foo")) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -687,7 +705,15 @@ class RuntimeSuggestionUpdatesTest Api.SuggestionsDatabaseModuleUpdateNotification( module = moduleName, actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + moduleName, + ListSet(ExportedSymbol.Method(moduleName, "main")) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -745,7 +771,15 @@ class RuntimeSuggestionUpdatesTest module = "Enso_Test.Foo.Main", actions = Vector(Api.SuggestionsDatabaseAction.Clean("Enso_Test.Foo.Main")), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + "Enso_Test.Foo.Main", + ListSet(ExportedSymbol.Method("Enso_Test.Foo.Main", "main")) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -844,7 +878,15 @@ class RuntimeSuggestionUpdatesTest Api.SuggestionsDatabaseModuleUpdateNotification( module = moduleName, actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + moduleName, + ListSet(ExportedSymbol.Method(moduleName, "main")) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -1026,7 +1068,18 @@ class RuntimeSuggestionUpdatesTest module = "Enso_Test.Test.A", actions = Vector(Api.SuggestionsDatabaseAction.Clean("Enso_Test.Test.A")), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + "Enso_Test.Test.A", + ListSet( + ExportedSymbol.Type("Enso_Test.Test.A", "MyType"), + ExportedSymbol.Method("Enso_Test.Test.A", "hello") + ) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -1148,9 +1201,10 @@ class RuntimeSuggestionUpdatesTest Api.ExportsUpdate( ModuleExports( "Enso_Test.Test.Main", - Set( + ListSet( ExportedSymbol.Type("Enso_Test.Test.A", "MyType"), ExportedSymbol.Constructor("Enso_Test.Test.A", "MkA"), + ExportedSymbol.Method(moduleName, "main"), ExportedSymbol.Method("Enso_Test.Test.A", "hello") ) ), diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeTextEditsTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeTextEditsTest.scala index 6aa93320668..f9bd71f63e0 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeTextEditsTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeTextEditsTest.scala @@ -2,7 +2,9 @@ package org.enso.interpreter.test.instrument import org.enso.interpreter.runtime.`type`.ConstantsGen import org.enso.polyglot.{ + ExportedSymbol, LanguageInfo, + ModuleExports, RuntimeOptions, RuntimeServerInfo, Suggestion @@ -21,6 +23,8 @@ import java.nio.file.{Files, Paths} import java.util.UUID import java.util.logging.Level +import scala.collection.immutable.ListSet + @scala.annotation.nowarn("msg=multiarg infix syntax") class RuntimeTextEditsTest extends AnyFlatSpec @@ -160,7 +164,15 @@ class RuntimeTextEditsTest Api.SuggestionsDatabaseModuleUpdateNotification( module = moduleName, actions = Vector(Api.SuggestionsDatabaseAction.Clean(moduleName)), - exports = Vector(), + exports = Vector( + Api.ExportsUpdate( + ModuleExports( + moduleName, + ListSet(ExportedSymbol.Method(moduleName, "main")) + ), + Api.ExportsAction.Add() + ) + ), updates = Tree.Root( Vector( Tree.Node( @@ -180,7 +192,7 @@ class RuntimeTextEditsTest moduleName, "main", List(), - "Enso_Test.Test.Main", + moduleName, ConstantsGen.ANY, true, None, diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java index b44f17a6d20..98a32938217 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java @@ -45,6 +45,8 @@ import org.enso.polyglot.CompilationStage; import org.enso.polyglot.LanguageInfo; import org.enso.polyglot.Suggestion; import org.enso.polyglot.data.TypeGraph; +import scala.collection.immutable.ListSet; +import scala.collection.immutable.SetOps; final class TruffleCompilerContext implements CompilerContext { @@ -557,8 +559,12 @@ final class TruffleCompilerContext implements CompilerContext { }) .map( suggestion -> { - var reexport = exportsMap.get(suggestion).map(s -> s.toString()); - return suggestion.withReexport(reexport); + scala.collection.immutable.Set identity = new ListSet<>(); + var reexports = + exportsMap.get(suggestion).stream() + .map(QualifiedName::toString) + .reduce(identity, SetOps::incl, SetOps::union); + return suggestion.withReexports(reexports); }) .foreach(suggestions::add); @@ -569,7 +575,7 @@ final class TruffleCompilerContext implements CompilerContext { context .getPackageRepository() .getPackageForLibraryJava(libraryName) - .map(p -> p.listSourcesJava())); + .map(Package::listSourcesJava)); var cache = SuggestionsCache.create(libraryName); var file = saveCache(cache, cachedSuggestions, useGlobalCacheLocations); return file != null; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/util/ScalaConversions.java b/engine/runtime/src/main/java/org/enso/interpreter/util/ScalaConversions.java index 7e501cc94fe..07b866f0d40 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/util/ScalaConversions.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/util/ScalaConversions.java @@ -9,6 +9,9 @@ import scala.jdk.javaapi.OptionConverters; /** Utility class for converting between Scala and Java basic classes. */ public class ScalaConversions { + + private ScalaConversions() {} + /** * Converts a Scala {@link Option} to a Java {@link Optional}. * @@ -38,4 +41,18 @@ public class ScalaConversions { T head, scala.collection.immutable.List tail) { return scala.collection.immutable.$colon$colon$.MODULE$.apply(head, tail); } + + /** + * Create a Scala set from the provided elements. + * + * @param elems the set elements. + * @return the immutable Scala set. + */ + @SafeVarargs + public static scala.collection.immutable.Set set(T... elems) { + var s = new scala.collection.mutable.LinkedHashSet(); + for (T elem : elems) s.add(elem); + + return s.toSet(); + } } 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 abd60af5883..c490f8cb7b6 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 @@ -83,13 +83,13 @@ trait SuggestionsRepo[F[_]] { actions: Seq[SuggestionsDatabaseAction] ): F[Seq[QueryResult[SuggestionsDatabaseAction]]] - /** Apply the sequence of export updates on the database. + /** Get the suggestions related to the export updates. * - * @param updates the list of export updates - * @return the result of applying the updates + * @param actions the list of updates + * @return the suggestions ids associated with the export updates */ - def applyExports( - updates: Seq[ExportsUpdate] + def getExportedSymbols( + actions: Seq[ExportsUpdate] ): F[Seq[QueryResult[ExportsUpdate]]] /** Remove the suggestion. @@ -119,8 +119,7 @@ trait SuggestionsRepo[F[_]] { externalId: Option[Option[Suggestion.ExternalID]], returnType: Option[String], documentation: Option[Option[String]], - scope: Option[Suggestion.Scope], - reexport: Option[Option[String]] + scope: Option[Suggestion.Scope] ): F[(Long, Option[Long])] /** Update a list of suggestions by external id. 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 457e8b7ad2c..f040afb255b 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 @@ -1,7 +1,7 @@ package org.enso.searcher.sql import org.enso.polyglot.runtime.Runtime.Api._ -import org.enso.polyglot.{ExportedSymbol, Suggestion} +import org.enso.polyglot.Suggestion import org.enso.searcher.data.QueryResult import org.enso.searcher.{SuggestionEntry, SuggestionsRepo} import slick.jdbc.SQLiteProfile.api._ @@ -70,10 +70,10 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit db.run(applyActionsQuery(actions).transactionally) /** @inheritdoc */ - override def applyExports( - updates: Seq[ExportsUpdate] + def getExportedSymbols( + actions: Seq[ExportsUpdate] ): Future[Seq[QueryResult[ExportsUpdate]]] = - db.run(applyExportsQuery(updates).transactionally) + db.run(getExportedSymbolsQuery(actions).transactionally) /** @inheritdoc */ override def remove(suggestion: Suggestion): Future[Option[Long]] = @@ -89,8 +89,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit externalId: Option[Option[Suggestion.ExternalID]], returnType: Option[String], documentation: Option[Option[String]], - scope: Option[Suggestion.Scope], - reexport: Option[Option[String]] + scope: Option[Suggestion.Scope] ): Future[(Long, Option[Long])] = db.run( updateQuery( @@ -98,8 +97,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit externalId, returnType, documentation, - scope, - reexport + scope ) ) @@ -310,8 +308,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit extId, returnType, doc, - scope, - reexport + scope ) } else { DBIO.successful(None) @@ -339,70 +336,49 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit DBIO.sequence(removeActions) } - /** The query that applies the sequence of export updates. + /** The query to get the suggestions related to the export updates. * - * @param updates the list of export updates - * @return the result of applying actions + * @param actions the list of updates + * @return the suggestions ids associated with the export updates */ - private def applyExportsQuery( - updates: Seq[ExportsUpdate] + private def getExportedSymbolsQuery( + actions: Seq[ExportsUpdate] ): DBIO[Seq[QueryResult[ExportsUpdate]]] = { - def depth(module: String): Int = - module.count(_ == '.') - - def updateSuggestionReexport(module: String, symbol: ExportedSymbol) = { - val moduleDepth = depth(module) - sql""" - update suggestions - set reexport = $module - where module = ${symbol.module} - and name = ${symbol.name} - and kind = ${SuggestionKind(symbol.kind)} - and ( - reexport is null or - length(reexport) - length(replace(reexport, '.', '')) > $moduleDepth - ) - returning id - """.as[Long] - } - - def unsetSuggestionReexport(module: String, symbol: ExportedSymbol) = - sql""" - update suggestions - set reexport = null - where module = ${symbol.module} - and name = ${symbol.name} - and kind = ${SuggestionKind(symbol.kind)} - and reexport = $module - returning id - """.as[Long] - - val actions = updates.flatMap { update => - val symbols = update.exports.symbols.toSeq - update.action match { - case ExportsAction.Add() => - symbols.map { symbol => - for { - ids <- updateSuggestionReexport(update.exports.module, symbol) - } yield QueryResult(ids, update) - } - case ExportsAction.Remove() => - symbols.map { symbol => - for { - ids <- unsetSuggestionReexport(update.exports.module, symbol) - } yield QueryResult(ids, update) - } + val qs = actions.map { action => + val actionIdQueries = action.exports.symbols.toSeq.map { symbol => + selectExportedSymbolQuery( + symbol.module, + symbol.name, + symbol.kind + ).result } + for { + ids <- DBIO.sequence(actionIdQueries) + } yield QueryResult(ids.flatten, action) } - - for { - rs <- DBIO.sequence(actions) - _ <- - if (rs.flatMap(_.ids).nonEmpty) incrementVersionQuery - else DBIO.successful(()) - } yield rs + DBIO.sequence(qs) } + /** The query to select the exported symbol. + * + * @param module the module name of the exported symbol + * @param name the name of the exported symbol + * @param kind the kind of the exported symbol + * @return the database query returning the list of ids corresponding to the + * exported symbol + */ + private def selectExportedSymbolQuery( + module: String, + name: String, + kind: Suggestion.Kind + ): Query[Rep[Long], Long, Seq] = + Suggestions + .filter(_.module === module) + .filter(_.kind === SuggestionKind(kind)) + .filter(_.name === name) + .take(1) + .map(_.id) + /** The query to select the suggestion. * * @param raw the suggestion converted to the row form @@ -503,8 +479,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit externalId: Option[Option[Suggestion.ExternalID]], returnType: Option[String], documentation: Option[Option[String]], - scope: Option[Suggestion.Scope], - reexport: Option[Option[String]] + scope: Option[Suggestion.Scope] ): DBIO[(Long, Option[Long])] = for { idOpt <- updateSuggestionQuery( @@ -512,8 +487,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit externalId, returnType, documentation, - scope, - reexport + scope ) version <- currentVersionQuery } yield (version, idOpt) @@ -531,8 +505,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit externalId: Option[Option[Suggestion.ExternalID]], returnType: Option[String], documentation: Option[Option[String]], - scope: Option[Suggestion.Scope], - reexport: Option[Option[String]] + scope: Option[Suggestion.Scope] ): DBIO[Option[Long]] = { val raw = toSuggestionRow(suggestion) val query = selectSuggestionQuery(raw) @@ -572,12 +545,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit ) } } - r5 <- DBIO.sequenceOption { - reexport.map { reexportOpt => - query.map(_.reexport).update(reexportOpt) - } - } - } yield (r1 ++ r2 ++ r3 ++ r4 ++ r5).sum + } yield (r1 ++ r2 ++ r3 ++ r4).sum for { id <- query.map(_.id).result.headOption n <- updateQ @@ -770,7 +738,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit /** Convert the suggestion to a row in the suggestions table. */ private def toSuggestionRow(suggestion: Suggestion): SuggestionRow = suggestion match { - case Suggestion.Module(module, doc, reexport) => + case Suggestion.Module(module, doc, _) => SuggestionRow( id = None, externalIdLeast = None, @@ -786,8 +754,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartOffset = ScopeColumn.EMPTY, scopeEndLine = ScopeColumn.EMPTY, scopeEndOffset = ScopeColumn.EMPTY, - documentation = doc, - reexport = reexport + documentation = doc ) case Suggestion.Type( expr, @@ -797,7 +764,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit returnType, parentType, doc, - reexport + _ ) => SuggestionRow( id = None, @@ -814,8 +781,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = ScopeColumn.EMPTY, scopeStartOffset = ScopeColumn.EMPTY, scopeEndLine = ScopeColumn.EMPTY, - scopeEndOffset = ScopeColumn.EMPTY, - reexport = reexport + scopeEndOffset = ScopeColumn.EMPTY ) case Suggestion.Constructor( expr, @@ -825,7 +791,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit returnType, doc, _, - reexport + _ ) => SuggestionRow( id = None, @@ -842,8 +808,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = ScopeColumn.EMPTY, scopeStartOffset = ScopeColumn.EMPTY, scopeEndLine = ScopeColumn.EMPTY, - scopeEndOffset = ScopeColumn.EMPTY, - reexport = reexport + scopeEndOffset = ScopeColumn.EMPTY ) case Suggestion.Getter( expr, @@ -854,7 +819,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit returnType, doc, _, - reexport + _ ) => SuggestionRow( id = None, @@ -871,8 +836,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = ScopeColumn.EMPTY, scopeStartOffset = ScopeColumn.EMPTY, scopeEndLine = ScopeColumn.EMPTY, - scopeEndOffset = ScopeColumn.EMPTY, - reexport = reexport + scopeEndOffset = ScopeColumn.EMPTY ) case Suggestion.DefinedMethod( expr, @@ -884,7 +848,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit isStatic, doc, _, - reexport + _ ) => SuggestionRow( id = None, @@ -901,8 +865,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = ScopeColumn.EMPTY, scopeStartOffset = ScopeColumn.EMPTY, scopeEndLine = ScopeColumn.EMPTY, - scopeEndOffset = ScopeColumn.EMPTY, - reexport = reexport + scopeEndOffset = ScopeColumn.EMPTY ) case Suggestion.Conversion( expr, @@ -911,7 +874,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit sourceType, returnType, doc, - reexport + _ ) => SuggestionRow( id = None, @@ -928,8 +891,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = ScopeColumn.EMPTY, scopeStartOffset = ScopeColumn.EMPTY, scopeEndLine = ScopeColumn.EMPTY, - scopeEndOffset = ScopeColumn.EMPTY, - reexport = reexport + scopeEndOffset = ScopeColumn.EMPTY ) case Suggestion.Function( expr, @@ -955,8 +917,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = scope.start.line, scopeStartOffset = scope.start.character, scopeEndLine = scope.end.line, - scopeEndOffset = scope.end.character, - reexport = None + scopeEndOffset = scope.end.character ) case Suggestion.Local(expr, module, name, returnType, scope, doc) => SuggestionRow( @@ -974,8 +935,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit scopeStartLine = scope.start.line, scopeStartOffset = scope.start.character, scopeEndLine = scope.end.line, - scopeEndOffset = scope.end.character, - reexport = None + scopeEndOffset = scope.end.character ) } @@ -989,8 +949,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit case SuggestionKind.MODULE => Suggestion.Module( module = suggestion.module, - documentation = suggestion.documentation, - reexport = suggestion.reexport + documentation = suggestion.documentation ) case SuggestionKind.TYPE => Suggestion.Type( @@ -1001,8 +960,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit params = Seq(), returnType = suggestion.returnType, parentType = suggestion.parentType, - documentation = suggestion.documentation, - reexport = suggestion.reexport + documentation = suggestion.documentation ) case SuggestionKind.CONSTRUCTOR => Suggestion.Constructor( @@ -1013,8 +971,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit arguments = Seq(), returnType = suggestion.returnType, documentation = suggestion.documentation, - annotations = Seq(), - reexport = suggestion.reexport + annotations = Seq() ) case SuggestionKind.GETTER => Suggestion.Getter( @@ -1026,8 +983,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit selfType = suggestion.selfType, returnType = suggestion.returnType, documentation = suggestion.documentation, - annotations = Seq(), - reexport = suggestion.reexport + annotations = Seq() ) case SuggestionKind.METHOD => Suggestion.DefinedMethod( @@ -1040,8 +996,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit returnType = suggestion.returnType, isStatic = suggestion.isStatic, documentation = suggestion.documentation, - annotations = Seq(), - reexport = suggestion.reexport + annotations = Seq() ) case SuggestionKind.CONVERSION => Suggestion.Conversion( @@ -1051,8 +1006,7 @@ final class SqlSuggestionsRepo(val db: SqlDatabase)(implicit arguments = Seq(), selfType = suggestion.selfType, returnType = suggestion.returnType, - documentation = suggestion.documentation, - reexport = suggestion.reexport + documentation = suggestion.documentation ) case SuggestionKind.FUNCTION => Suggestion.Function( diff --git a/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/Tables.scala b/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/Tables.scala index a38f848c051..ef954db56b5 100644 --- a/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/Tables.scala +++ b/lib/scala/searcher/src/main/scala/org/enso/searcher/sql/Tables.scala @@ -38,8 +38,7 @@ case class SuggestionRow( scopeStartOffset: Int, scopeEndLine: Int, scopeEndOffset: Int, - documentation: Option[String], - reexport: Option[String] + documentation: Option[String] ) /** A row in the suggestions_version table. @@ -143,7 +142,6 @@ final class SuggestionsTable(tag: Tag) def scopeEndOffset = column[Int]("scope_end_offset", O.Default(ScopeColumn.EMPTY)) def documentation = column[Option[String]]("documentation") - def reexport = column[Option[String]]("reexport") def * = ( @@ -161,8 +159,7 @@ final class SuggestionsTable(tag: Tag) scopeStartOffset, scopeEndLine, scopeEndOffset, - documentation, - reexport + documentation ) <> (SuggestionRow.tupled, SuggestionRow.unapply) @@ -172,7 +169,7 @@ final class SuggestionsTable(tag: Tag) def returnTypeIdx = index("suggestions_return_type_idx", returnType) def externalIdIdx = index("suggestions_external_id_idx", (externalIdLeast, externalIdMost)) - def reexportIdx = index("suggestions_reexport_idx", reexport) + // NOTE: unique index should not contain nullable columns because SQLite // teats NULLs as distinct values. def uniqueIdx = @@ -288,5 +285,5 @@ object SuggestionsVersion extends TableQuery(new SuggestionsVersionTable(_)) object SchemaVersion extends TableQuery(new SchemaVersionTable(_)) { /** The current schema version. */ - val CurrentVersion: Long = 11 + val CurrentVersion: Long = 12 } 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 727997b33d3..1309746eb3e 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 @@ -1,7 +1,5 @@ package org.enso.searcher.sql -import java.nio.file.{Files, Path} -import java.util.UUID import org.enso.polyglot.{ExportedSymbol, ModuleExports, Suggestion} import org.enso.polyglot.runtime.Runtime.Api import org.enso.searcher.SuggestionEntry @@ -13,6 +11,9 @@ import org.scalactic.TripleEqualsSupport import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import java.nio.file.{Files, Path} +import java.util.UUID + import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ @@ -69,7 +70,7 @@ class SuggestionsRepoTest thrown.version shouldEqual wrongSchemaVersion } - "insert all suggestions111" taggedAs Retry in withRepo { repo => + "insert all suggestions" taggedAs Retry in withRepo { repo => val action = for { v1 <- repo.currentVersion @@ -284,7 +285,6 @@ class SuggestionsRepoTest Some(Some(newUuid)), None, None, - None, None ) s <- repo.select(id1) @@ -314,7 +314,6 @@ class SuggestionsRepoTest Some(None), None, None, - None, None ) s <- repo.select(id1) @@ -344,7 +343,6 @@ class SuggestionsRepoTest None, Some(newReturnType), None, - None, None ) s <- repo.select(id1) @@ -374,7 +372,6 @@ class SuggestionsRepoTest None, None, Some(Some(newDoc)), - None, None ) s <- repo.select(id1) @@ -407,7 +404,6 @@ class SuggestionsRepoTest None, None, Some(Some(newDoc)), - None, None ) s <- repo.select(id1) @@ -440,7 +436,6 @@ class SuggestionsRepoTest None, None, Some(Some(newDoc)), - None, None ) s <- repo.select(id1) @@ -471,7 +466,6 @@ class SuggestionsRepoTest None, None, Some(Some(newDoc)), - None, None ) s <- repo.select(id1) @@ -504,7 +498,6 @@ class SuggestionsRepoTest None, None, Some(Some(newDoc)), - None, None ) s <- repo.select(id1) @@ -536,7 +529,6 @@ class SuggestionsRepoTest None, None, Some(Some(newDoc)), - None, None ) s <- repo.select(id1) @@ -568,7 +560,6 @@ class SuggestionsRepoTest None, None, Some(None), - None, None ) s <- repo.select(id1) @@ -601,8 +592,7 @@ class SuggestionsRepoTest None, None, None, - Some(newScope), - None + Some(newScope) ) s <- repo.select(id1) } yield (v1, id1, v2, id2, s) @@ -630,7 +620,6 @@ class SuggestionsRepoTest None, None, None, - None, None ) } yield (v1, v2, id1, id2) @@ -679,9 +668,9 @@ class SuggestionsRepoTest v1 shouldEqual v2 } - "apply export updates" taggedAs Retry in withRepo { repo => + "get exported symbols" taggedAs Retry in withRepo { repo => val reexport = "Foo.Bar" - val method = suggestion.method.copy(reexport = Some(reexport)) + val method = suggestion.method.copy(reexports = Set(reexport)) val updates = Seq( Api.ExportsUpdate( ModuleExports( @@ -710,7 +699,7 @@ class SuggestionsRepoTest suggestion.local ) ) - results <- repo.applyExports(updates) + results <- repo.getExportedSymbols(updates) } yield (ids, results) val (ids, results) = Await.result(action, Timeout) @@ -720,126 +709,6 @@ class SuggestionsRepoTest ) } - "not apply exports with bigger module name" taggedAs Retry in withRepo { - repo => - val reexport = "Foo.Bar.Baz" - val method = suggestion.method.copy(reexport = Some("Foo.Bar")) - val updates = Seq( - Api.ExportsUpdate( - ModuleExports( - reexport, - Set(ExportedSymbol.Module(suggestion.module.module)) - ), - Api.ExportsAction.Add() - ), - Api.ExportsUpdate( - ModuleExports( - reexport, - Set(ExportedSymbol.Method(method.module, method.name)) - ), - Api.ExportsAction.Remove() - ) - ) - val action = for { - (_, ids) <- repo.insertAll( - Seq( - suggestion.module, - suggestion.tpe, - suggestion.constructor, - method, - suggestion.conversion, - suggestion.function, - suggestion.local - ) - ) - results <- repo.applyExports(updates) - } yield (ids, results) - - val (ids, results) = Await.result(action, Timeout) - results should contain theSameElementsAs Seq( - QueryResult(Seq(ids(0)), updates(0)), - QueryResult(Seq(), updates(1)) - ) - } - - "change version after applying exports" taggedAs Retry in withRepo { repo => - val reexport = "Foo.Bar" - val method = suggestion.method.copy(reexport = Some(reexport)) - val updates = Seq( - Api.ExportsUpdate( - ModuleExports( - reexport, - Set(ExportedSymbol.Module(suggestion.module.module)) - ), - Api.ExportsAction.Add() - ), - Api.ExportsUpdate( - ModuleExports( - reexport, - Set(ExportedSymbol.Method(method.module, method.name)) - ), - Api.ExportsAction.Remove() - ) - ) - val action = for { - _ <- repo.insertAll( - Seq( - suggestion.module, - suggestion.tpe, - suggestion.constructor, - method, - suggestion.conversion, - suggestion.function, - suggestion.local - ) - ) - v1 <- repo.currentVersion - results <- repo.applyExports(updates) - v2 <- repo.currentVersion - } yield (results, v1, v2) - - val (results, v1, v2) = Await.result(action, Timeout) - results.flatMap(_.ids).isEmpty shouldBe false - v1 should not equal v2 - } - - "not change version when exports not applied" taggedAs Retry in withRepo { - repo => - val reexport = "Foo.Bar" - val updates = Seq( - Api.ExportsUpdate( - ModuleExports( - reexport, - Set( - ExportedSymbol - .Method(suggestion.method.module, suggestion.method.name) - ) - ), - Api.ExportsAction.Remove() - ) - ) - val action = for { - _ <- repo.insertAll( - Seq( - suggestion.module, - suggestion.tpe, - suggestion.constructor, - suggestion.method, - suggestion.conversion, - suggestion.function, - suggestion.local - ) - ) - v1 <- repo.currentVersion - results <- repo.applyExports(updates) - v2 <- repo.currentVersion - } yield (results, v1, v2) - - val (results, v1, v2) = Await.result(action, Timeout) - results.flatMap(_.ids).isEmpty shouldBe true - v1 shouldEqual v2 - } - "search suggestion by empty query" taggedAs Retry in withRepo { repo => val action = for { _ <- repo.insert(suggestion.module)