From 22259e696d4a4d7903a3fe58b15cb46a62e28327 Mon Sep 17 00:00:00 2001 From: Dmitry Bushev Date: Tue, 27 Jun 2023 14:11:12 +0100 Subject: [PATCH] Add method call info for infix operators (#7090) close #6374 In order to provide the method pointer information, the `IrToTruffle` pass sets the module name and the type name of the builtin node. --- CHANGELOG.md | 2 + .../Base/0.0.0-dev/src/System/File.enso | 2 +- .../instrument/IdExecutionService.java | 13 +- .../instrument/IdExecutionInstrument.java | 2 +- .../test/instrument/BuiltinTypesTest.scala | 4 +- .../test/instrument/RuntimeErrorsTest.scala | 63 ++++- .../test/instrument/RuntimeServerTest.scala | 252 ++++++++++++++++-- .../RuntimeVisualizationsTest.scala | 34 ++- .../expression/builtin/BuiltinRootNode.java | 24 ++ .../runtime/scope/ModuleScope.java | 6 +- .../enso/compiler/codegen/IrToTruffle.scala | 67 +++-- .../instrument/InstrumentTestContext.scala | 2 +- .../interpreter/test/semantic/DateTest.scala | 4 +- .../enso/interpreter/dsl/MethodProcessor.java | 9 +- .../Base/0.0.0-dev/src/Data/Time/Date.enso | 4 +- .../lib/Standard/Base/0.0.0-dev/src/Meta.enso | 2 + .../Standard/Base/0.0.0-dev/src/Polyglot.enso | 2 +- 17 files changed, 417 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4839d44ea8..dded0772c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -842,6 +842,7 @@ - [Add special handling for static method calls on Any][7033] - [Improve parallel execution of commands and jobs in Language Server][7042] - [Added retries when executing GraalVM updater][7079] +- [Add method call info for infix operators][7090] [3227]: https://github.com/enso-org/enso/pull/3227 [3248]: https://github.com/enso-org/enso/pull/3248 @@ -963,6 +964,7 @@ [7033]: https://github.com/enso-org/enso/pull/7033 [7042]: https://github.com/enso-org/enso/pull/7042 [7079]: https://github.com/enso-org/enso/pull/7079 +[7090]: https://github.com/enso-org/enso/pull/7090 # Enso 2.0.0-alpha.18 (2021-10-12) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso index 6e2b348aff..a070797c5b 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso @@ -331,7 +331,7 @@ type File ## PRIVATE Internal method to join two path segments together. resolve : File - resolve self = @Builtin_Method "File.resolve" + resolve self subpath = @Builtin_Method "File.resolve" ## PRIVATE Convert the file descriptor to a JS_Object. diff --git a/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/IdExecutionService.java b/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/IdExecutionService.java index 4e4743390d..3b81268acb 100644 --- a/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/IdExecutionService.java +++ b/engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/IdExecutionService.java @@ -9,10 +9,10 @@ import java.util.Objects; import java.util.UUID; import java.util.function.Consumer; import org.enso.interpreter.instrument.profiling.ProfilingInfo; -import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.node.MethodRootNode; import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode; import org.enso.interpreter.node.expression.atom.QualifiedAccessorNode; +import org.enso.interpreter.node.expression.builtin.BuiltinRootNode; import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.data.Type; @@ -212,6 +212,7 @@ public interface IdExecutionService { */ public FunctionCallInfo(FunctionCallInstrumentationNode.FunctionCall call) { RootNode rootNode = call.getFunction().getCallTarget().getRootNode(); + switch (rootNode) { case MethodRootNode methodNode -> { moduleName = methodNode.getModuleScope().getModule().getName(); @@ -224,12 +225,12 @@ public interface IdExecutionService { typeName = atomConstructor.getType().getQualifiedName(); functionName = atomConstructor.getName(); } - case EnsoRootNode ensoRootNode -> { - moduleName = ensoRootNode.getModuleScope().getModule().getName(); - typeName = null; - functionName = rootNode.getName(); + case BuiltinRootNode builtinRootNode -> { + moduleName = builtinRootNode.getModuleName(); + typeName = builtinRootNode.getTypeName(); + functionName = QualifiedName.fromString(builtinRootNode.getName()).item(); } - case default -> { + default -> { moduleName = null; typeName = null; functionName = rootNode.getName(); diff --git a/engine/runtime-instrument-id-execution/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java b/engine/runtime-instrument-id-execution/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java index cb1e8de81d..f85845ca72 100644 --- a/engine/runtime-instrument-id-execution/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java +++ b/engine/runtime-instrument-id-execution/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java @@ -271,9 +271,9 @@ public class IdExecutionInstrument extends TruffleInstrument implements IdExecut // appropriately invalidate all dependent expressions. if (!isPanic) { cache.offer(nodeId, result); + cache.putCall(nodeId, call); } cache.putType(nodeId, resultType); - cache.putCall(nodeId, call); passExpressionValueToCallback(expressionValue); if (isPanic) { diff --git a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/BuiltinTypesTest.scala b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/BuiltinTypesTest.scala index 2f339c3119..6b9db86752 100644 --- a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/BuiltinTypesTest.scala +++ b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/BuiltinTypesTest.scala @@ -411,13 +411,13 @@ class BuiltinTypesTest val requestId = UUID.randomUUID() val metadata = new Metadata - val idMain = metadata.addItem(43, 18) + val idMain = metadata.addItem(48, 25) val code = """import Standard.Base.Data.Time.Date | |main = - | Date.new 2000 + | Date.new_builtin 2000 1 1 |""".stripMargin.linesIterator.mkString("\n") val contents = metadata.appendToCode(code) diff --git a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeErrorsTest.scala b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeErrorsTest.scala index 3be5da4d57..789ee9ea93 100644 --- a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeErrorsTest.scala +++ b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeErrorsTest.scala @@ -514,6 +514,13 @@ class RuntimeErrorsTest TestMessages.error( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), Api.ExpressionUpdate.Payload.DataflowError(Seq(xId)) ), TestMessages.error( @@ -682,6 +689,13 @@ class RuntimeErrorsTest TestMessages.error( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), Api.ExpressionUpdate.Payload.DataflowError(Seq(xId)) ), TestMessages.update(contextId, yId, ConstantsGen.INTEGER), @@ -747,6 +761,13 @@ class RuntimeErrorsTest TestMessages.error( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), Api.ExpressionUpdate.Payload.DataflowError(Seq(xId)) ), TestMessages.error( @@ -902,6 +923,13 @@ class RuntimeErrorsTest TestMessages.error( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), Api.ExpressionUpdate.Payload.DataflowError(Seq(xId)) ), TestMessages.error( @@ -1039,7 +1067,7 @@ class RuntimeErrorsTest val requestId = UUID.randomUUID() val moduleName = "Enso_Test.Test.Main" val metadata = new Metadata - val xId = metadata.addItem(60, 19) + val xId = metadata.addItem(60, 19, "aa") val yId = metadata.addItem(88, 5) val mainResId = metadata.addItem(98, 12) @@ -1090,10 +1118,18 @@ class RuntimeErrorsTest TestMessages.panic( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), Api.ExpressionUpdate.Payload.Panic( "MyError", Seq(xId) - ) + ), + Some("Standard.Base.Panic.Panic") ), TestMessages.panic( contextId, @@ -1318,10 +1354,18 @@ class RuntimeErrorsTest TestMessages.panic( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), Api.ExpressionUpdate.Payload.Panic( "MyError1", Seq(xId) - ) + ), + Some("Standard.Base.Panic.Panic") ), TestMessages.panic( contextId, @@ -1364,12 +1408,18 @@ class RuntimeErrorsTest TestMessages.panic( contextId, xId, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), Api.ExpressionUpdate.Payload.Panic( "MyError2", Seq(xId) ), - builtin = false, - typeChanged = false + Some("Standard.Base.Panic.Panic") ), TestMessages.panic( contextId, @@ -1388,8 +1438,7 @@ class RuntimeErrorsTest "MyError2", Seq(xId) ), - builtin = false, - typeChanged = false + builtin = false ), context.executionComplete(contextId) ) diff --git a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala index facaa8bede..eab6db95fc 100644 --- a/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala +++ b/engine/runtime-with-instruments/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala @@ -1692,6 +1692,187 @@ class RuntimeServerTest ) } + it should "send method pointer updates of a builtin method" in { + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + + val metadata = new Metadata + val id_x = metadata.addItem(46, 17, "aa") + + val code = + """from Standard.Base import all + | + |main = + | x = "hello" + "world" + | 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 file + context.send( + Api.Request(Api.OpenFileNotification(mainFile, contents)) + ) + context.receiveNone shouldEqual None + + // push main + context.send( + Api.Request( + requestId, + Api.PushContextRequest( + contextId, + Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + ) + ) + ) + context.receiveNIgnoreStdLib(4) should contain theSameElementsAs Seq( + Api.Response(Api.BackgroundJobsStartedNotification()), + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update( + contextId, + id_x, + ConstantsGen.TEXT, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Text", + "Standard.Base.Data.Text.Text", + "+" + ) + ) + ), + context.executionComplete(contextId) + ) + } + + it should "send method pointer updates of a builtin method called as static" in { + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + + val metadata = new Metadata + val id_x = metadata.addItem(52, 25, "aa") + val id_y = metadata.addItem(86, 16, "ab") + + val code = + """import Standard.Base.Data.Time.Date + | + |main = + | x = Date.new_builtin 1970 1 1 + | y = Date.Date.year x + | y + |""".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 file + context.send( + Api.Request(Api.OpenFileNotification(mainFile, contents)) + ) + context.receiveNone shouldEqual None + + // push main + context.send( + Api.Request( + requestId, + Api.PushContextRequest( + contextId, + Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + ) + ) + ) + context.receiveNIgnoreStdLib(5) should contain theSameElementsAs Seq( + Api.Response(Api.BackgroundJobsStartedNotification()), + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, id_x, ConstantsGen.DATE), + TestMessages.update( + contextId, + id_y, + ConstantsGen.INTEGER_BUILTIN, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Data.Time.Date", + "Standard.Base.Data.Time.Date.Date", + "year" + ) + ) + ), + context.executionComplete(contextId) + ) + } + + it should "not send method pointer updates of a builtin method defined as static" in { + val contextId = UUID.randomUUID() + val requestId = UUID.randomUUID() + val moduleName = "Enso_Test.Test.Main" + + val metadata = new Metadata + val id_x = metadata.addItem(52, 25, "aa") + + val code = + """import Standard.Base.Data.Time.Date + | + |main = + | x = Date.new_builtin 2022 1 1 + | 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 file + context.send( + Api.Request(Api.OpenFileNotification(mainFile, contents)) + ) + context.receiveNone shouldEqual None + + // push main + context.send( + Api.Request( + requestId, + Api.PushContextRequest( + contextId, + Api.StackItem.ExplicitCall( + Api.MethodPointer(moduleName, moduleName, "main"), + None, + Vector() + ) + ) + ) + ) + context.receiveNIgnoreStdLib(4) should contain theSameElementsAs Seq( + Api.Response(Api.BackgroundJobsStartedNotification()), + Api.Response(requestId, Api.PushContextResponse(contextId)), + TestMessages.update(contextId, id_x, "Standard.Base.Data.Time.Date.Date"), + context.executionComplete(contextId) + ) + } + it should "send updates from last line" in { val contextId = UUID.randomUUID() val requestId = UUID.randomUUID() @@ -2108,7 +2289,12 @@ class RuntimeServerTest context.receiveN(4) should contain theSameElementsAs Seq( Api.Response(requestId, Api.PopContextResponse(contextId)), TestMessages - .update(contextId, mainRes, ConstantsGen.NOTHING, typeChanged = false), + .update( + contextId, + mainRes, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages.update( contextId, mainFoo, @@ -2231,8 +2417,12 @@ class RuntimeServerTest fromCache = false, typeChanged = false ), - TestMessages - .update(contextId, mainRes, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + mainRes, + ConstantsGen.NOTHING, + typeChanged = false + ), context.executionComplete(contextId) ) context.consumeOut shouldEqual List("6") @@ -2489,8 +2679,12 @@ class RuntimeServerTest ConstantsGen.INTEGER, Api.MethodCall(Api.MethodPointer(moduleName, ConstantsGen.NUMBER, "x")) ), - TestMessages - .update(contextId, idMainP, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idMainP, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages .update(contextId, idMain, ConstantsGen.NOTHING, typeChanged = false), context.executionComplete(contextId) @@ -2522,8 +2716,12 @@ class RuntimeServerTest fromCache = false, typeChanged = false ), - TestMessages - .update(contextId, idMainP, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idMainP, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages .update(contextId, idMain, ConstantsGen.NOTHING, typeChanged = false), context.executionComplete(contextId) @@ -2555,8 +2753,12 @@ class RuntimeServerTest fromCache = false, typeChanged = true ), - TestMessages - .update(contextId, idMainP, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idMainP, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages .update(contextId, idMain, ConstantsGen.NOTHING, typeChanged = false), context.executionComplete(contextId) @@ -2588,8 +2790,12 @@ class RuntimeServerTest fromCache = false, typeChanged = true ), - TestMessages - .update(contextId, idMainP, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idMainP, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages .update(contextId, idMain, ConstantsGen.NOTHING, typeChanged = false), context.executionComplete(contextId) @@ -2619,8 +2825,12 @@ class RuntimeServerTest ConstantsGen.TEXT, Api.MethodCall(Api.MethodPointer(moduleName, moduleName, "hie")) ), - TestMessages - .update(contextId, idMainP, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idMainP, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages .update(contextId, idMain, ConstantsGen.NOTHING, typeChanged = false), context.executionComplete(contextId) @@ -2652,8 +2862,12 @@ class RuntimeServerTest fromCache = false, typeChanged = true ), - TestMessages - .update(contextId, idMainP, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idMainP, + ConstantsGen.NOTHING, + typeChanged = false + ), TestMessages .update(contextId, idMain, ConstantsGen.NOTHING, typeChanged = false), context.executionComplete(contextId) @@ -3500,8 +3714,12 @@ class RuntimeServerTest ) should contain theSameElementsAs Seq( TestMessages .update(contextId, idText, ConstantsGen.TEXT, typeChanged = false), - TestMessages - .update(contextId, idRes, ConstantsGen.NOTHING, typeChanged = false), + TestMessages.update( + contextId, + idRes, + ConstantsGen.NOTHING, + typeChanged = false + ), context.executionComplete(contextId) ) context.consumeOut shouldEqual List(prompt2) diff --git a/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala b/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala index 51bb60382b..964930a168 100644 --- a/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala +++ b/engine/runtime-with-polyglot/src/test/scala/org/enso/interpreter/test/instrument/RuntimeVisualizationsTest.scala @@ -2047,6 +2047,13 @@ class RuntimeVisualizationsTest TestMessages.error( contextId, idMain, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), Api.ExpressionUpdate.Payload.DataflowError(Seq(idMain)) ), context.executionComplete(contextId) @@ -2138,7 +2145,15 @@ class RuntimeVisualizationsTest TestMessages.panic( contextId, idMain, - Api.ExpressionUpdate.Payload.Panic("42 (Integer)", Seq(idMain)) + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), + Api.ExpressionUpdate.Payload.Panic("42 (Integer)", Seq(idMain)), + Some("Standard.Base.Panic.Panic") ), context.executionComplete(contextId) ) @@ -2167,9 +2182,15 @@ class RuntimeVisualizationsTest TestMessages.panic( contextId, idMain, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Panic", + "Standard.Base.Panic.Panic", + "throw" + ) + ), Api.ExpressionUpdate.Payload.Panic("42 (Integer)", Seq(idMain)), - builtin = false, - typeChanged = false + builtin = false ), Api.Response( Api.VisualizationEvaluationFailed( @@ -2253,6 +2274,13 @@ class RuntimeVisualizationsTest TestMessages.error( contextId, idMain, + Api.MethodCall( + Api.MethodPointer( + "Standard.Base.Error", + "Standard.Base.Error.Error", + "throw" + ) + ), Api.ExpressionUpdate.Payload.DataflowError(Seq(idMain)) ), context.executionComplete(contextId) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java index 4d7fd66050..f845b53fef 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/BuiltinRootNode.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import org.enso.interpreter.EnsoLanguage; +import org.enso.pkg.QualifiedName; /** Root node for use by all the builtin functions. */ @NodeInfo(shortName = "BuiltinRoot", description = "Root node for builtin functions.") @@ -12,6 +13,29 @@ public abstract class BuiltinRootNode extends RootNode { super(language); } + protected QualifiedName moduleName = null; + protected QualifiedName typeName = null; + + /** Get the module name where the builtin is defined. */ + public QualifiedName getModuleName() { + return moduleName; + } + + /** Set the module name where the builtin is defined. */ + public void setModuleName(QualifiedName moduleName) { + this.moduleName = moduleName; + } + + /** Get the type name of the builtin. */ + public QualifiedName getTypeName() { + return typeName; + } + + /** Set the type name of the builtin. */ + public void setTypeName(QualifiedName typeName) { + this.typeName = typeName; + } + /** * Executes this node's logic, returning a pair of return value and the new state. * diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java index 4e3d3c532e..2b9112f1f6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/ModuleScope.java @@ -116,9 +116,9 @@ public final class ModuleScope implements TruffleObject { public void registerMethod(Type type, String method, Function function) { Map methodMap = ensureMethodMapFor(type); - if (methodMap.containsKey(method)) { - // Builtin types will have double definition because of - // BuiltinMethod and that's OK + // Builtin types will have double definition because of + // BuiltinMethod and that's OK + if (methodMap.containsKey(method) && !type.isBuiltin()) { throw new RedefinedMethodException(type.getName(), method); } else { methodMap.put(method, function); diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index 9a6490f6db..853e2288d6 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -48,6 +48,7 @@ import org.enso.interpreter.node.expression.atom.{ ConstantNode, QualifiedAccessorNode } +import org.enso.interpreter.node.expression.builtin.BuiltinRootNode import org.enso.interpreter.node.expression.constant._ import org.enso.interpreter.node.expression.foreign.ForeignMethodCallNode import org.enso.interpreter.node.expression.literal.LiteralNode @@ -83,6 +84,7 @@ import org.enso.interpreter.runtime.scope.{ import org.enso.interpreter.{Constants, EnsoLanguage} import java.math.BigInteger + import scala.annotation.tailrec import scala.collection.mutable import scala.collection.mutable.ArrayBuffer @@ -441,34 +443,47 @@ class IrToTruffle( else Left(l) } .map(fOpt => - // Register builtin iff it has not been automatically registered at an early stage - // of builtins initialization or if it is a static wrapper. - fOpt - .filter(m => !m.isAutoRegister() || staticWrapper) - .map { m => - if (staticWrapper) { - // Static wrappers differ in the number of arguments by 1. - // Therefore we cannot simply get the registered function. - // BuiltinRootNode.execute will infer the right order of arguments. - val bodyBuilder = - new expressionProcessor.BuildFunctionBody( - fn.arguments, - fn.body, - effectContext, - true - ) - new RuntimeFunction( - m.getFunction.getCallTarget, - null, - new FunctionSchema( - new Array[RuntimeAnnotation](0), - bodyBuilder.args(): _* - ) + fOpt.map { m => + if (m.isAutoRegister) { + val irFunctionArgumentsCount = fn.arguments.length + val builtinArgumentsCount = + m.getFunction.getSchema.getArgumentsCount + if (irFunctionArgumentsCount != builtinArgumentsCount) { + val irFunctionArguments = + fn.arguments.map(_.name.name).mkString(",") + val builtinArguments = + m.getFunction.getSchema.getArgumentInfos + .map(_.getName) + .mkString(",") + throw new CompilerError( + s"Wrong number of arguments provided in the definition of builtin function ${cons.getName}.${methodDef.methodName.name}. " + + s"[$irFunctionArguments] vs [$builtinArguments]" ) - } else { - m.getFunction } + val bodyBuilder = + new expressionProcessor.BuildFunctionBody( + fn.arguments, + fn.body, + effectContext, + true + ) + val builtinRootNode = + m.getFunction.getCallTarget.getRootNode + .asInstanceOf[BuiltinRootNode] + builtinRootNode.setModuleName(moduleScope.getModule.getName) + builtinRootNode.setTypeName(cons.getQualifiedName) + new RuntimeFunction( + m.getFunction.getCallTarget, + null, + new FunctionSchema( + new Array[RuntimeAnnotation](0), + bodyBuilder.args(): _* + ) + ) + } else { + m.getFunction } + } ) case fn: IR.Function => val bodyBuilder = @@ -1750,7 +1765,7 @@ class IrToTruffle( * @param binding whether the function is right inside a binding * @return a truffle node representing the described function */ - def processFunctionBody( + private def processFunctionBody( arguments: List[IR.DefinitionArgument], body: IR.Expression, location: Option[IdentifiedLocation], diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/InstrumentTestContext.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/InstrumentTestContext.scala index 43506a58a5..496f7aef69 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/InstrumentTestContext.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/InstrumentTestContext.scala @@ -70,7 +70,7 @@ class InstrumentTestContext { n: Int, timeoutSeconds: Long = 60 ): List[Api.Response] = { - receiveNWithFilter(n, (_ => true), timeoutSeconds) + receiveNWithFilter(n, _ => true, timeoutSeconds) } private def receiveNWithFilter( diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/DateTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/DateTest.scala index be401d1e91..c2bde01b4b 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/DateTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/DateTest.scala @@ -15,7 +15,7 @@ class DateTest extends InterpreterTest { |import Standard.Base.Data.Time.Date | |main = - | IO.println (Date.new 2022 04 01) + | IO.println (Date.new_builtin 2022 04 01) |""".stripMargin eval(code) consumeOut shouldEqual List("2022-04-01") @@ -60,7 +60,7 @@ class DateTest extends InterpreterTest { |import Standard.Base.Data.Time.Date | |main = - | ensodate = Date.new 2022 4 1 + | ensodate = Date.new_builtin 2022 4 1 | ensoyear = ensodate.year | ensomonth = ensodate.month | ensoday = ensodate.day diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java index 60b25b6e9d..1347a1eed1 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java @@ -478,9 +478,14 @@ public class MethodProcessor extends BuiltinsMetadataProcessor