diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala index 06b09f6d16..77522e5640 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala @@ -7472,6 +7472,199 @@ class RuntimeServerTest context.consumeOut shouldEqual List("16") } + it should "resolve multiple autoscoped atomconstructor with no IDs initially" in { + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val moduleNameLib = "Enso_Test.Test.Lib" + val moduleNameTypes = "Enso_Test.Test.Types" + val metadata = new Metadata + + val idS = UUID.randomUUID() + val idX = UUID.randomUUID() + val idAArg = UUID.randomUUID() + val idBArg = UUID.randomUUID() + val idRes = UUID.randomUUID() + + val typesMetadata = new Metadata + val codeTypes = typesMetadata.appendToCode( + """type Foo + | A + | + |type Bar + | B + |""".stripMargin.linesIterator.mkString("\n") + ) + val typesFile = context.writeInSrcDir("Types", codeTypes) + + val libMetadata = new Metadata + val codeLib = libMetadata.appendToCode( + """from project.Types import Foo, Bar + |from Standard.Base import all + | + |type Singleton + | S value + | + | test : Foo -> Bar -> Number + | test self (x : Foo = ..A) (y : Bar = ..B) = + | Singleton.from_test x y + | + | from_test : Foo -> Bar -> Number + | from_test (x : Foo = ..A) (y : Bar = ..B) = + | _ = x + | _ = y + | 42 + |""".stripMargin.linesIterator.mkString("\n") + ) + + val libFile = context.writeInSrcDir("Lib", codeLib) + + val code = + """from project.Lib import Singleton + | + |main = + | s = Singleton.S 1 + | x = s.test ..A ..B + | x + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open files + context.send( + Api.Request(requestId, Api.OpenFileRequest(typesFile, codeTypes)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(libFile, codeLib)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 2 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + context.executionComplete(contextId) + ) + + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq(), + execute = true, + idMap = Some( + model.IdMap( + Vector( + model.Span(50, 63) -> idS, + model.Span(72, 86) -> idX, + model.Span(79, 82) -> idAArg, + model.Span(83, 86) -> idBArg, + model.Span(91, 92) -> idRes + ) + ) + ) + ) + ) + ) + val afterIdMapUpdate = context.receiveN(6) + + afterIdMapUpdate shouldEqual Seq( + TestMessages.update( + contextId, + idS, + s"$moduleNameLib.Singleton", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer(moduleNameLib, s"$moduleNameLib.Singleton", "S") + ) + ), + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + TestMessages.update( + contextId, + idAArg, + s"$moduleNameTypes.Foo", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer( + moduleNameTypes, + s"$moduleNameTypes.Foo", + "A" + ) + ) + ), + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + TestMessages.update( + contextId, + idBArg, + s"$moduleNameTypes.Bar", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer( + moduleNameTypes, + s"$moduleNameTypes.Bar", + "B" + ) + ) + ), + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + TestMessages.update( + contextId, + idX, + s"Standard.Base.Data.Numbers.Integer", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer( + moduleNameLib, + s"$moduleNameLib.Singleton", + "test" + ) + ) + ), + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + TestMessages.update( + contextId, + idRes, + s"Standard.Base.Data.Numbers.Integer", + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + context.executionComplete(contextId) + ) + } + } object RuntimeServerTest { diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala index f94890d891..482e2f78c5 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala @@ -2,6 +2,7 @@ package org.enso.interpreter.test.instrument import org.enso.interpreter.runtime.`type`.ConstantsGen import org.enso.interpreter.test.Metadata + import org.enso.pkg.QualifiedName import org.enso.common.RuntimeOptions import org.enso.polyglot._ @@ -4074,6 +4075,237 @@ class RuntimeVisualizationsTest extends AnyFlatSpec with Matchers { new String(data, StandardCharsets.UTF_8) shouldEqual "(Mk_Newtype 42)" } + it should "resolve multiple autoscoped atomconstructor" in withContext() { + context => + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val visualizationId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + val moduleNameLib = "Enso_Test.Test.Lib" + val metadata = new Metadata + + val idS = metadata.addItem(50, 13, "eeee") + val idX = metadata.addItem(72, 14, "aaaa") + val idAArg = UUID.randomUUID() + val idBArg = UUID.randomUUID() + val idRes = metadata.addItem(91, 1, "dddd") + + val typesMetadata = new Metadata + val codeTypes = typesMetadata.appendToCode( + """type Foo + | A + | + |type Bar + | B + |""".stripMargin.linesIterator.mkString("\n") + ) + val typesFile = context.writeInSrcDir("Types", codeTypes) + + val libMetadata = new Metadata + val codeLib = libMetadata.appendToCode( + """from project.Types import Foo, Bar + |from Standard.Base import all + | + |type Singleton + | S value + | + | test : Foo -> Bar -> Number + | test self (x : Foo = ..A) (y : Bar = ..B) = + | Singleton.from_test x y + | + | from_test : Foo -> Bar -> Number + | from_test (x : Foo = ..A) (y : Bar = ..B) = + | _ = x + | _ = y + | 42 + |""".stripMargin.linesIterator.mkString("\n") + ) + + val libFile = context.writeInSrcDir("Lib", codeLib) + + val code = + """from project.Lib import Singleton + | + |main = + | s = Singleton.S 1 + | x = s.test ..A ..B + | x + |""".stripMargin.linesIterator.mkString("\n") + val contents = metadata.appendToCode(code) + val mainFile = context.writeMain(contents) + + metadata.assertInCode(idS, code, "Singleton.S 1") + metadata.assertInCode(idX, code, "s.test ..A ..B") + metadata.assertInCode(idRes, code, "x") + + // create context + context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) + context.receive shouldEqual Some( + Api.Response(requestId, Api.CreateContextResponse(contextId)) + ) + + // Open files + context.send( + Api.Request(requestId, Api.OpenFileRequest(typesFile, codeTypes)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(libFile, codeLib)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + context.send( + Api.Request(requestId, Api.OpenFileRequest(mainFile, contents)) + ) + context.receive shouldEqual Some( + Api.Response(Some(requestId), Api.OpenFileResponse) + ) + + // push main + val item1 = Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"), + None, + Vector() + ) + context.send( + Api.Request(requestId, Api.PushContextRequest(contextId, item1)) + ) + context.receiveNIgnorePendingExpressionUpdates( + 5 + ) should contain theSameElementsAs Seq( + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( + contextId, + idS, + s"$moduleNameLib.Singleton", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer(moduleNameLib, s"$moduleNameLib.Singleton", "S") + ) + ), + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + TestMessages.update( + contextId, + idX, + s"Standard.Base.Data.Numbers.Integer", + methodCall = Some( + Api.MethodCall( + Api + .MethodPointer( + moduleNameLib, + s"$moduleNameLib.Singleton", + "test" + ) + ) + ), + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + TestMessages.update( + contextId, + idRes, + s"Standard.Base.Data.Numbers.Integer", + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + context.executionComplete(contextId) + ) + + // attach visualization + context.send( + Api.Request( + requestId, + Api.AttachVisualization( + visualizationId, + idRes, + Api.VisualizationConfiguration( + contextId, + Api.VisualizationExpression.Text( + "Enso_Test.Test.Main", + "x -> x.to_text", + Vector() + ), + "Enso_Test.Test.Main" + ) + ) + ) + ) + + val attachVisualizationResponses = + context.receiveNIgnoreExpressionUpdates(3) + attachVisualizationResponses should contain allOf ( + Api.Response(requestId, Api.VisualizationAttached()), + context.executionComplete(contextId) + ) + val Some(data) = attachVisualizationResponses.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idRes` + ), + data + ) + ) => + data + } + new String(data, StandardCharsets.UTF_8) shouldEqual "42" + + context.send( + Api.Request( + Api.EditFileNotification( + mainFile, + Seq(), + execute = true, + idMap = Some( + model.IdMap( + Vector( + model.Span(79, 82) -> idAArg, + model.Span(83, 86) -> idBArg + ) + ) + ) + ) + ) + ) + val afterIdMapUpdate = context.receiveN(3) + + // Can't do comparison directly because of Arrays https://github.com/scalatest/scalatest/issues/491 + afterIdMapUpdate should contain allOf ( + TestMessages.update( + contextId, + idRes, + s"Standard.Base.Data.Numbers.Integer", + typeChanged = false, + payload = Api.ExpressionUpdate.Payload.Value(None) + ), + context.executionComplete(contextId) + ) + + val Some(data2) = afterIdMapUpdate.collectFirst { + case Api.Response( + None, + Api.VisualizationUpdate( + Api.VisualizationContext( + `visualizationId`, + `contextId`, + `idRes` + ), + data + ) + ) => + data + } + + new String(data2, StandardCharsets.UTF_8) shouldEqual "42" + + } + it should "emit visualization update for the target of a method call (subexpression)" in withContext() { context => val contextId = UUID.randomUUID() diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java index b58140afbd..d20afaed99 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java @@ -429,4 +429,9 @@ public abstract class InvokeCallableNode extends BaseNode { childDispatch.setId(id); } } + + /** Returns expression ID of this node. */ + public UUID getId() { + return invokeFunctionNode.getId(); + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java index a5c768f5a7..1933cb9e27 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java @@ -21,6 +21,7 @@ import org.enso.interpreter.node.ClosureRootNode; import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.callable.ApplicationNode; +import org.enso.interpreter.node.callable.InvokeCallableNode; import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode; import org.enso.interpreter.node.callable.argument.ReadArgumentNode; import org.enso.interpreter.node.callable.function.BlockNode; @@ -177,10 +178,14 @@ public final class UnresolvedConstructor implements EnsoObject { prototype.where.getRootNode() instanceof EnsoRootNode root ? root.getModuleScope() : null; for (var where = prototype.where; where != null; where = where.getParent()) { if (where instanceof ExpressionNode withId && withId.getId() != null) { - id = withId.getId(); + if (!(where instanceof ApplicationNode)) { + id = withId.getId(); + } section = withId.getSourceSection(); scope = withId.getRootNode() instanceof EnsoRootNode root ? root.getModuleScope() : null; break; + } else if (where instanceof InvokeCallableNode callable && callable.getId() != null) { + id = callable.getId(); } } var fn = ReadArgumentNode.build(0, null, null); @@ -191,7 +196,9 @@ public final class UnresolvedConstructor implements EnsoObject { prototype.descs[i].getName(), ReadArgumentNode.build(1 + i, null, null)); } var expr = ApplicationNode.build(fn, args, DefaultsExecutionMode.EXECUTE); - expr.setId(id); + if (id != null) { + expr.setId(id); + } if (section != null) { expr.setSourceLocation(section.getCharIndex(), section.getCharLength()); }