From 845e03040864dc25377c80b3e6bb121654298133 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 1 Nov 2024 12:24:46 +0100 Subject: [PATCH 01/27] Remove leftover typo from tests --- .../org/enso/compiler/test/semantic/TypeSignaturesTest.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/semantic/TypeSignaturesTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/semantic/TypeSignaturesTest.scala index 3bab4f826e92..1191d4676478 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/semantic/TypeSignaturesTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/compiler/test/semantic/TypeSignaturesTest.scala @@ -243,7 +243,7 @@ class TypeSignaturesTest ) } - "XX resolve imported names" in { + "resolve imported names" in { val code = """ |from project.Util import all From b80e0b0424cbc0b13e83f449aae408641b3edf62 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 1 Nov 2024 12:51:52 +0100 Subject: [PATCH 02/27] Add tests --- .../interpreter/test/DebuggingEnsoTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index c36cc56519ed..397ed8e6df93 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -246,6 +246,89 @@ public void testHostValues() { } } + @Test + public void builtinAtomHasProperties() { + Value fooFunc = + createEnsoMethod( + """ + from Standard.Base import Date + + foo _ = + d_java = Date.parse "2024-12-15" + tmp = 42 + """, + "foo"); + + try (DebuggerSession session = + debugger.startSession( + (SuspendedEvent event) -> { + switch (event.getSourceSection().getCharacters().toString().strip()) { + case "tmp = 42" -> { + DebugScope scope = event.getTopStackFrame().getScope(); + DebugValue ensoDate = scope.getDeclaredValue("d_enso"); + assertThat(ensoDate.isReadable(), is(true)); + assertThat(ensoDate.isInternal(), is(false)); + assertThat( + "If d_enso is readable, the getProperties() must not be null", + ensoDate.getProperties(), + is(notNullValue())); + } + } + event.getSession().suspendNextExecution(); + })) { + session.suspendNextExecution(); + fooFunc.execute(0); + } + } + + /** + * Both {@code Date.new 2024 12 15} and {@code Date.parse "2024-12-15"} should be seen by the + * debugger as the exact same objects. Internally, the value from {@code Date.parse} is a host + * value. + */ + @Test + public void hostValueIsTreatedAsItsEnsoCounterpart() { + Value fooFunc = + createEnsoMethod( + """ + from Standard.Base import Date + + foo _ = + d_enso = Date.new 2024 12 15 + d_java = Date.parse "2024-12-15" + tmp = 42 + """, + "foo"); + + try (DebuggerSession session = + debugger.startSession( + (SuspendedEvent event) -> { + switch (event.getSourceSection().getCharacters().toString().strip()) { + case "tmp = 42" -> { + DebugScope scope = event.getTopStackFrame().getScope(); + DebugValue ensoDate = scope.getDeclaredValue("d_enso"); + assertThat(ensoDate.isReadable(), is(true)); + assertThat(ensoDate.isInternal(), is(false)); + assertThat(ensoDate.isDate(), is(true)); + + DebugValue javaDate = scope.getDeclaredValue("d_java"); + assertThat(javaDate.isReadable(), is(true)); + assertThat(javaDate.isInternal(), is(false)); + assertThat(javaDate.isDate(), is(true)); + + assertThat( + "Number of properties for d_enso and d_java should be the same", + ensoDate.getProperties().size(), + is(javaDate.getProperties().size())); + } + } + event.getSession().suspendNextExecution(); + })) { + session.suspendNextExecution(); + fooFunc.execute(0); + } + } + @Test public void testHostValueAsAtomField() { Value fooFunc = From 1f68c9a32a91179094f52206d19c90f20667b151 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 1 Nov 2024 13:09:20 +0100 Subject: [PATCH 03/27] Discard warnings from the compiler in the test. And only print them when a test fails --- .../interpreter/test/DebuggingEnsoTest.java | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index 397ed8e6df93..ad420bc804f8 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -17,6 +17,8 @@ import com.oracle.truffle.api.debug.SuspendedCallback; import com.oracle.truffle.api.debug.SuspendedEvent; import com.oracle.truffle.api.nodes.LanguageInfo; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.URI; import java.nio.file.Paths; import java.util.ArrayDeque; @@ -42,15 +44,20 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; public class DebuggingEnsoTest { private Context context; private Engine engine; private Debugger debugger; + private final ByteArrayOutputStream out = new ByteArrayOutputStream(); @Before public void initContext() { + out.reset(); engine = Engine.newBuilder() .allowExperimentalOptions(true) @@ -58,7 +65,9 @@ public void initContext() { RuntimeOptions.LANGUAGE_HOME_OVERRIDE, Paths.get("../../distribution/component").toFile().getAbsolutePath()) .option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName()) - .logHandler(System.err) + .logHandler(out) + .err(out) + .out(out) .build(); context = @@ -76,13 +85,26 @@ public void initContext() { } @After - public void disposeContext() { + public void disposeContext() throws IOException { context.close(); context = null; engine.close(); engine = null; } + /** Only print warnings from the compiler if a test fails. */ + @Rule + public TestWatcher testWatcher = + new TestWatcher() { + @Override + protected void failed(Throwable e, Description description) { + System.err.println("Test failed: " + description.getMethodName()); + System.err.println("Error: " + e.getMessage()); + System.err.println("Logs from the compiler and the engine: "); + System.err.println(out); + } + }; + private static void expectStackFrame( DebugStackFrame actualFrame, Map expectedValues) { Map actualValues = new HashMap<>(); @@ -254,7 +276,7 @@ public void builtinAtomHasProperties() { from Standard.Base import Date foo _ = - d_java = Date.parse "2024-12-15" + d_enso = Date.new 2024 12 15 tmp = 42 """, "foo"); From 4289d6cd08c951143d629b61fd244a0d47cc2944 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 1 Nov 2024 17:45:12 +0100 Subject: [PATCH 04/27] Remove the test for non-null properties --- .../interpreter/test/DebuggingEnsoTest.java | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index ad420bc804f8..a181fbd2128f 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -268,41 +268,6 @@ public void testHostValues() { } } - @Test - public void builtinAtomHasProperties() { - Value fooFunc = - createEnsoMethod( - """ - from Standard.Base import Date - - foo _ = - d_enso = Date.new 2024 12 15 - tmp = 42 - """, - "foo"); - - try (DebuggerSession session = - debugger.startSession( - (SuspendedEvent event) -> { - switch (event.getSourceSection().getCharacters().toString().strip()) { - case "tmp = 42" -> { - DebugScope scope = event.getTopStackFrame().getScope(); - DebugValue ensoDate = scope.getDeclaredValue("d_enso"); - assertThat(ensoDate.isReadable(), is(true)); - assertThat(ensoDate.isInternal(), is(false)); - assertThat( - "If d_enso is readable, the getProperties() must not be null", - ensoDate.getProperties(), - is(notNullValue())); - } - } - event.getSession().suspendNextExecution(); - })) { - session.suspendNextExecution(); - fooFunc.execute(0); - } - } - /** * Both {@code Date.new 2024 12 15} and {@code Date.parse "2024-12-15"} should be seen by the * debugger as the exact same objects. Internally, the value from {@code Date.parse} is a host From b354f800623cf8f40af4975d75c0d22391b9c63a Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 1 Nov 2024 17:45:36 +0100 Subject: [PATCH 05/27] Update test to reflect that atom with builtin type has null properties --- .../java/org/enso/interpreter/test/DebuggingEnsoTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index a181fbd2128f..278d72c4f0b7 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -303,10 +303,10 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { assertThat(javaDate.isInternal(), is(false)); assertThat(javaDate.isDate(), is(true)); - assertThat( - "Number of properties for d_enso and d_java should be the same", - ensoDate.getProperties().size(), - is(javaDate.getProperties().size())); + assertThat("ensoDate has no members (properties)", + ensoDate.getProperties(), is(nullValue())); + assertThat("javaDate's properties is either null or empty", + javaDate.getProperties(), isOneOf(nullValue(), hasSize(0))); } } event.getSession().suspendNextExecution(); From ae1432621ba7b566cc1f05d1a1b194b8150f0506 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Tue, 5 Nov 2024 17:36:51 +0100 Subject: [PATCH 06/27] Try to convert HostObject in DebugLocalScope.readMember --- .../interpreter/test/DebuggingEnsoTest.java | 12 +++-- .../runtime/scope/DebugLocalScope.java | 48 ++++++++++++++++++- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index 278d72c4f0b7..ef991f96b15c 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -303,10 +303,14 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { assertThat(javaDate.isInternal(), is(false)); assertThat(javaDate.isDate(), is(true)); - assertThat("ensoDate has no members (properties)", - ensoDate.getProperties(), is(nullValue())); - assertThat("javaDate's properties is either null or empty", - javaDate.getProperties(), isOneOf(nullValue(), hasSize(0))); + assertThat( + "ensoDate has no members (properties)", + ensoDate.getProperties(), + is(nullValue())); + assertThat( + "javaDate's properties is either null or empty", + javaDate.getProperties(), + isOneOf(nullValue(), hasSize(0))); } } event.getSession().suspendNextExecution(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java index dcec2f91e0a8..93336633bfdf 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java @@ -4,6 +4,7 @@ import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; @@ -19,7 +20,11 @@ import org.enso.compiler.pass.analyse.FramePointer; import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.node.EnsoRootNode; +import org.enso.interpreter.node.callable.resolver.HostMethodCallNode; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.function.Function; +import org.enso.interpreter.runtime.data.EnsoDate; import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.error.DataflowError; @@ -188,15 +193,56 @@ boolean isMemberReadable(String memberName) { @ExportMessage @TruffleBoundary Object readMember(String member, @CachedLibrary("this") InteropLibrary interop) - throws UnknownIdentifierException { + throws UnknownIdentifierException, UnsupportedMessageException { if (!allBindings.containsKey(member)) { throw UnknownIdentifierException.create(member); } FramePointer framePtr = allBindings.get(member); var value = getValue(frame, framePtr); + if (value != null) { + if (isHostObject(value)) { + // Determine if the host object can be converted to corresponding Enso value. + var interopUncached = InteropLibrary.getUncached(); + var firstMember = readFirstMember(value); + if (firstMember != null) { + var builtinsScope = EnsoContext.get(interop).getBuiltins().getScope(); + var symbol = UnresolvedSymbol.build(firstMember, builtinsScope); + var polyglotCallType = + HostMethodCallNode.getPolyglotCallType(value, symbol, interopUncached); + try { + switch (polyglotCallType) { + case CONVERT_TO_DATE -> { + var localDate = interopUncached.asDate(value); + value = new EnsoDate(localDate); + } + } + } catch (UnsupportedMessageException e) { + throw e; + } + } + } + } return value != null ? value : DataflowError.UNINITIALIZED; } + private String readFirstMember(Object object) { + var interop = InteropLibrary.getUncached(); + try { + if (interop.hasMembers(object)) { + var members = interop.getMembers(object, true); + var firstMember = interop.readArrayElement(members, 0); + return interop.asString(firstMember); + } + } catch (UnsupportedMessageException | InvalidArrayIndexException e) { + return null; + } + return null; + } + + private boolean isHostObject(Object object) { + return EnsoContext.get(null).isJavaPolyglotObject(object); + } + @ExportMessage @TruffleBoundary void writeMember(String member, Object value) throws UnknownIdentifierException { From a7c110cb5612c104baa9bcac53665b5832a33d3c Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 8 Nov 2024 11:27:02 +0100 Subject: [PATCH 07/27] Fix testests --- .../test/java/org/enso/interpreter/test/DebuggingEnsoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index ef991f96b15c..b771a75d1b38 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -310,7 +310,7 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { assertThat( "javaDate's properties is either null or empty", javaDate.getProperties(), - isOneOf(nullValue(), hasSize(0))); + anyOf(hasSize(0), nullValue())); } } event.getSession().suspendNextExecution(); From c038f558128411d79d31395ab44de9bf703679b6 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 8 Nov 2024 14:19:19 +0100 Subject: [PATCH 08/27] Implement getPolyglotConversionType --- .../callable/resolver/HostMethodCallNode.java | 142 ++++++++++++++---- 1 file changed, 115 insertions(+), 27 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java index cab2c0456df0..54537493ce34 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java @@ -117,6 +117,46 @@ public boolean isInteropLibrary() { } } + /** + * Given a polyglot (foreign) object, this enum represents a target Enso type that the object + * should be converted to before further dispatch. + * + *

For example, a {@code java.lang.String}, or any other polyglot object that {@link + * InteropLibrary#isString(Object) is a string}, should be converted to the {@link + * org.enso.interpreter.runtime.data.text.Text} builtin Enso type. + */ + public enum PolyglotConversionType { + /** The object should be converted to {@link org.enso.interpreter.runtime.data.text.Text}. */ + CONVERT_TO_TEXT, + /** + * The object should be converted to {@link org.enso.interpreter.runtime.number.EnsoBigInteger}. + */ + CONVERT_TO_BIG_INT, + /** The object should be converted to {@link org.enso.interpreter.runtime.data.vector.Array}. */ + CONVERT_TO_ARRAY, + /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDate}. */ + CONVERT_TO_DATE, + /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDateTime}. */ + CONVERT_TO_ZONED_DATE_TIME, + /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDateTime}. */ + CONVERT_TO_DATE_TIME, + /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDuration}. */ + CONVERT_TO_DURATION, + /** + * The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoTimeOfDay}. + */ + CONVERT_TO_TIME_OF_DAY, + /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoTimeZone}. */ + CONVERT_TO_TIME_ZONE, + /** + * The object should be converted to {@link org.enso.interpreter.runtime.data.hash.EnsoHashMap}. + */ + CONVERT_TO_HASH_MAP, + + /** No need to convert the polyglot object, just pass it as is. */ + NO_CONVERSION + } + private static final String NEW_NAME = "new"; static final int LIB_LIMIT = 3; @@ -150,37 +190,46 @@ public static PolyglotCallType getPolyglotCallType( UnresolvedSymbol symbol, InteropLibrary library, MethodResolverNode methodResolverNode) { - if (library.isDate(self)) { - if (library.isTime(self)) { - if (library.isTimeZone(self)) { - return PolyglotCallType.CONVERT_TO_ZONED_DATE_TIME; - } else { - return PolyglotCallType.CONVERT_TO_DATE_TIME; - } - } else { + var conversionType = getPolyglotConversionType(self, library); + switch (conversionType) { + case CONVERT_TO_TEXT -> { + return PolyglotCallType.CONVERT_TO_TEXT; + } + case CONVERT_TO_BIG_INT -> { + return PolyglotCallType.CONVERT_TO_BIG_INT; + } + case CONVERT_TO_DATE -> { return PolyglotCallType.CONVERT_TO_DATE; } - } else if (library.isTime(self)) { - return PolyglotCallType.CONVERT_TO_TIME_OF_DAY; - } else if (library.isDuration(self)) { - return PolyglotCallType.CONVERT_TO_DURATION; - } else if (library.isTimeZone(self)) { - return PolyglotCallType.CONVERT_TO_TIME_ZONE; - } else if (library.fitsInBigInteger(self)) { - return PolyglotCallType.CONVERT_TO_BIG_INT; - } else if (library.isString(self)) { - return PolyglotCallType.CONVERT_TO_TEXT; - } else if (library.hasArrayElements(self)) { - if (methodResolverNode != null) { - var ctx = EnsoContext.get(library); - var arrayType = ctx.getBuiltins().array(); - var fn = methodResolverNode.execute(arrayType, symbol); - if (fn != null) { - return PolyglotCallType.CONVERT_TO_ARRAY; + case CONVERT_TO_ZONED_DATE_TIME -> { + return PolyglotCallType.CONVERT_TO_ZONED_DATE_TIME; + } + case CONVERT_TO_DATE_TIME -> { + return PolyglotCallType.CONVERT_TO_DATE_TIME; + } + case CONVERT_TO_DURATION -> { + return PolyglotCallType.CONVERT_TO_DURATION; + } + case CONVERT_TO_TIME_OF_DAY -> { + return PolyglotCallType.CONVERT_TO_TIME_OF_DAY; + } + case CONVERT_TO_TIME_ZONE -> { + return PolyglotCallType.CONVERT_TO_TIME_ZONE; + } + case CONVERT_TO_HASH_MAP -> { + return PolyglotCallType.CONVERT_TO_HASH_MAP; + } + case CONVERT_TO_ARRAY -> { + if (methodResolverNode != null) { + var ctx = EnsoContext.get(library); + var arrayType = ctx.getBuiltins().array(); + var fn = methodResolverNode.execute(arrayType, symbol); + if (fn != null) { + return PolyglotCallType.CONVERT_TO_ARRAY; + } } } - } else if (library.hasHashEntries(self)) { - return PolyglotCallType.CONVERT_TO_HASH_MAP; + default -> {} } try { @@ -198,6 +247,45 @@ public static PolyglotCallType getPolyglotCallType( return PolyglotCallType.NOT_SUPPORTED; } + /** + * Returns a target Enso builtin type that the {@code polyglotObj} should be converted to before + * further dispatch. + * + *

For example, {@code java.lang.String} should be converted to {@link + * org.enso.interpreter.runtime.data.text.Text}. + * + * @param polyglotObj Polyglot (foreign) object to check for conversion. + */ + public static PolyglotConversionType getPolyglotConversionType( + Object polyglotObj, InteropLibrary interop) { + if (interop.isDate(polyglotObj)) { + if (interop.isTime(polyglotObj)) { + if (interop.isTimeZone(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_ZONED_DATE_TIME; + } else { + return PolyglotConversionType.CONVERT_TO_DATE_TIME; + } + } else { + return PolyglotConversionType.CONVERT_TO_DATE; + } + } else if (interop.isTime(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_TIME_OF_DAY; + } else if (interop.isDuration(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_DURATION; + } else if (interop.isTimeZone(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_TIME_ZONE; + } else if (interop.fitsInBigInteger(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_BIG_INT; + } else if (interop.isString(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_TEXT; + } else if (interop.hasArrayElements(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_ARRAY; + } else if (interop.hasHashEntries(polyglotObj)) { + return PolyglotConversionType.CONVERT_TO_HASH_MAP; + } + return PolyglotConversionType.NO_CONVERSION; + } + /** * Calls a method on an object, using a specified {@link PolyglotCallType}. * From d2cd44a06e612e4c3feeae7eebf094c83df93910 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 8 Nov 2024 14:19:36 +0100 Subject: [PATCH 09/27] DebugLocalScope uses getPolyglotConversionType --- .../runtime/data/hash/HashMapInsertNode.java | 4 + .../runtime/scope/DebugLocalScope.java | 86 +++++++++++++++---- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java index d2cca32666e1..263a11125999 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapInsertNode.java @@ -32,6 +32,10 @@ public static HashMapInsertNode build() { return HashMapInsertNodeGen.create(); } + public static HashMapInsertNode getUncached() { + return HashMapInsertNodeGen.getUncached(); + } + public abstract EnsoHashMap execute(VirtualFrame frame, Object self, Object key, Object value); @Specialization diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java index 93336633bfdf..f1c11955ecf3 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java @@ -11,6 +11,7 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.source.SourceSection; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -22,11 +23,22 @@ import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.node.callable.resolver.HostMethodCallNode; import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.EnsoDate; +import org.enso.interpreter.runtime.data.EnsoDateTime; +import org.enso.interpreter.runtime.data.EnsoDuration; import org.enso.interpreter.runtime.data.EnsoObject; +import org.enso.interpreter.runtime.data.EnsoTimeOfDay; +import org.enso.interpreter.runtime.data.EnsoTimeZone; +import org.enso.interpreter.runtime.data.hash.EnsoHashMap; +import org.enso.interpreter.runtime.data.hash.HashMapInsertNode; +import org.enso.interpreter.runtime.data.hash.HashMapToVectorNode; +import org.enso.interpreter.runtime.data.text.Text; +import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode; +import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers; +import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode; import org.enso.interpreter.runtime.error.DataflowError; +import org.enso.interpreter.runtime.number.EnsoBigInteger; /** * This class serves as a basic support for debugging with Chrome inspector. Currently, only @@ -199,27 +211,63 @@ Object readMember(String member, @CachedLibrary("this") InteropLibrary interop) } FramePointer framePtr = allBindings.get(member); var value = getValue(frame, framePtr); - if (value != null) { - if (isHostObject(value)) { - // Determine if the host object can be converted to corresponding Enso value. - var interopUncached = InteropLibrary.getUncached(); - var firstMember = readFirstMember(value); - if (firstMember != null) { - var builtinsScope = EnsoContext.get(interop).getBuiltins().getScope(); - var symbol = UnresolvedSymbol.build(firstMember, builtinsScope); - var polyglotCallType = - HostMethodCallNode.getPolyglotCallType(value, symbol, interopUncached); - try { - switch (polyglotCallType) { - case CONVERT_TO_DATE -> { - var localDate = interopUncached.asDate(value); - value = new EnsoDate(localDate); - } + if (value != null && isHostObject(value)) { + // Determine if the host object can be converted to corresponding Enso value. + var interopUncached = InteropLibrary.getUncached(); + var conversionType = HostMethodCallNode.getPolyglotConversionType(value, interopUncached); + try { + switch (conversionType) { + case CONVERT_TO_DATE -> { + var localDate = interopUncached.asDate(value); + return new EnsoDate(localDate); + } + case CONVERT_TO_ARRAY -> { + return ArrayLikeHelpers.asVectorFromArray(value); + } + case CONVERT_TO_BIG_INT -> { + return new EnsoBigInteger(interopUncached.asBigInteger(value)); + } + case CONVERT_TO_DATE_TIME, CONVERT_TO_ZONED_DATE_TIME -> { + var date = interopUncached.asDate(value); + var time = interopUncached.asTime(value); + var zonedDt = date.atTime(time).atZone(ZoneId.systemDefault()); + return new EnsoDateTime(zonedDt); + } + case CONVERT_TO_DURATION -> { + return new EnsoDuration(interopUncached.asDuration(value)); + } + case CONVERT_TO_HASH_MAP -> { + var ensoHash = EnsoHashMap.empty(); + var insertNode = HashMapInsertNode.getUncached(); + var vec = HashMapToVectorNode.getUncached().execute(value); + var arrayAtNode = ArrayLikeAtNode.getUncached(); + var size = ArrayLikeLengthNode.getUncached().executeLength(vec); + for (long i = 0; i < size; i++) { + var pair = arrayAtNode.executeAt(vec, i); + var key = arrayAtNode.executeAt(pair, 0); + var val = arrayAtNode.executeAt(pair, 1); + ensoHash = insertNode.execute(null, ensoHash, key, val); } - } catch (UnsupportedMessageException e) { - throw e; + return ensoHash; + } + case CONVERT_TO_TEXT -> { + return Text.create(interopUncached.asString(value)); + } + case CONVERT_TO_TIME_ZONE -> { + return new EnsoTimeZone(interopUncached.asTimeZone(value)); + } + case CONVERT_TO_TIME_OF_DAY -> { + var time = interopUncached.asTime(value); + return new EnsoTimeOfDay(time); + } + case NO_CONVERSION -> { + return value; } } + } catch (UnsupportedMessageException e) { + throw e; + } catch (InvalidArrayIndexException e) { + throw UnsupportedMessageException.create(e); } } return value != null ? value : DataflowError.UNINITIALIZED; From 08c066f59be49c4843c4cfbe84fa482ddc593cc2 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 8 Nov 2024 14:19:43 +0100 Subject: [PATCH 10/27] Add tests --- .../interpreter/test/DebuggingEnsoTest.java | 67 +++++++++++++------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index b771a75d1b38..da9381dec088 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -23,6 +23,7 @@ import java.nio.file.Paths; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -278,12 +279,23 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { Value fooFunc = createEnsoMethod( """ - from Standard.Base import Date + from Standard.Base import Date, Date_Time, Dictionary + polyglot java import java.lang.String + polyglot java import java.util.List as JList + polyglot java import java.util.Map as JMap foo _ = d_enso = Date.new 2024 12 15 d_java = Date.parse "2024-12-15" - tmp = 42 + dt_enso = Date_Time.now + dt_java = Date_Time.parse "2020-05-06 04:30:20" "yyyy-MM-dd HH:mm:ss" + str_enso = "Hello_World" + str_java = String.new "Hello_World" + list_enso = [1, 2, 3] + list_java = JList.of 1 2 3 + dict_enso = Dictionary.from_vector [["A", 1], ["B", 2]] + dict_java = JMap.of "A" 1 "B" 2 + end = 42 """, "foo"); @@ -291,26 +303,28 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { debugger.startSession( (SuspendedEvent event) -> { switch (event.getSourceSection().getCharacters().toString().strip()) { - case "tmp = 42" -> { + case "end = 42" -> { DebugScope scope = event.getTopStackFrame().getScope(); - DebugValue ensoDate = scope.getDeclaredValue("d_enso"); - assertThat(ensoDate.isReadable(), is(true)); - assertThat(ensoDate.isInternal(), is(false)); - assertThat(ensoDate.isDate(), is(true)); + DebugValue ensoDate = scope.getDeclaredValue("d_enso"); DebugValue javaDate = scope.getDeclaredValue("d_java"); - assertThat(javaDate.isReadable(), is(true)); - assertThat(javaDate.isInternal(), is(false)); - assertThat(javaDate.isDate(), is(true)); - - assertThat( - "ensoDate has no members (properties)", - ensoDate.getProperties(), - is(nullValue())); - assertThat( - "javaDate's properties is either null or empty", - javaDate.getProperties(), - anyOf(hasSize(0), nullValue())); + assertSameProperties(ensoDate.getProperties(), javaDate.getProperties()); + + DebugValue ensoDateTime = scope.getDeclaredValue("dt_enso"); + DebugValue javaDateTime = scope.getDeclaredValue("dt_java"); + assertSameProperties(ensoDateTime.getProperties(), javaDateTime.getProperties()); + + DebugValue ensoString = scope.getDeclaredValue("str_enso"); + DebugValue javaString = scope.getDeclaredValue("str_java"); + assertSameProperties(ensoString.getProperties(), javaString.getProperties()); + + DebugValue ensoList = scope.getDeclaredValue("list_enso"); + DebugValue javaList = scope.getDeclaredValue("list_java"); + assertSameProperties(ensoList.getProperties(), javaList.getProperties()); + + DebugValue ensoDict = scope.getDeclaredValue("dict_enso"); + DebugValue javaDict = scope.getDeclaredValue("dict_java"); + assertSameProperties(ensoDict.getProperties(), javaDict.getProperties()); } } event.getSession().suspendNextExecution(); @@ -320,6 +334,21 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { } } + /** Asserts that the given values have same property names. */ + private void assertSameProperties( + Collection expectedProps, Collection actualProps) { + if (expectedProps == null) { + assertThat(actualProps, is(nullValue())); + return; + } + assertThat(actualProps.size(), is(expectedProps.size())); + var expectedPropNames = + expectedProps.stream().map(DebugValue::getName).collect(Collectors.toUnmodifiableSet()); + var actualPropNames = + actualProps.stream().map(DebugValue::getName).collect(Collectors.toUnmodifiableSet()); + assertThat(actualPropNames, is(expectedPropNames)); + } + @Test public void testHostValueAsAtomField() { Value fooFunc = From c18ad2c10cb0165c16aaf18a823bde64d94a3828 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Fri, 8 Nov 2024 14:25:04 +0100 Subject: [PATCH 11/27] Remove unused method --- .../interpreter/runtime/scope/DebugLocalScope.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java index f1c11955ecf3..5354643c9c59 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java @@ -273,20 +273,6 @@ Object readMember(String member, @CachedLibrary("this") InteropLibrary interop) return value != null ? value : DataflowError.UNINITIALIZED; } - private String readFirstMember(Object object) { - var interop = InteropLibrary.getUncached(); - try { - if (interop.hasMembers(object)) { - var members = interop.getMembers(object, true); - var firstMember = interop.readArrayElement(members, 0); - return interop.asString(firstMember); - } - } catch (UnsupportedMessageException | InvalidArrayIndexException e) { - return null; - } - return null; - } - private boolean isHostObject(Object object) { return EnsoContext.get(null).isJavaPolyglotObject(object); } From 2c46980beecdddbd33a5ecaec87e416198edc83e Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 12:27:40 +0100 Subject: [PATCH 12/27] Testing also js and py foreign languages --- .../interpreter/test/DebuggingEnsoTest.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index da9381dec088..805e738f389f 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -284,16 +284,43 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { polyglot java import java.util.List as JList polyglot java import java.util.Map as JMap + foreign js js_date = ''' + return new Date(); + + foreign js js_str = ''' + return "Hello_World"; + + foreign js js_list = ''' + return [1, 2, 3]; + + foreign js js_map = ''' + let m = new Map(); + m.set('A', 1); + m.set('B', 2); + return m; + + foreign python py_list = ''' + return [1, 2, 3] + + foreign python py_dict = ''' + return {'A': 1, 'B': 2} + foo _ = d_enso = Date.new 2024 12 15 + d_js = js_date d_java = Date.parse "2024-12-15" dt_enso = Date_Time.now dt_java = Date_Time.parse "2020-05-06 04:30:20" "yyyy-MM-dd HH:mm:ss" str_enso = "Hello_World" + str_js = js_str str_java = String.new "Hello_World" list_enso = [1, 2, 3] + list_js = js_list + list_py = py_list list_java = JList.of 1 2 3 dict_enso = Dictionary.from_vector [["A", 1], ["B", 2]] + dict_js = js_map + dict_py = py_dict dict_java = JMap.of "A" 1 "B" 2 end = 42 """, @@ -308,7 +335,9 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { DebugValue ensoDate = scope.getDeclaredValue("d_enso"); DebugValue javaDate = scope.getDeclaredValue("d_java"); + DebugValue jsDate = scope.getDeclaredValue("d_js"); assertSameProperties(ensoDate.getProperties(), javaDate.getProperties()); + assertSameProperties(ensoDate.getProperties(), jsDate.getProperties()); DebugValue ensoDateTime = scope.getDeclaredValue("dt_enso"); DebugValue javaDateTime = scope.getDeclaredValue("dt_java"); @@ -316,15 +345,25 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { DebugValue ensoString = scope.getDeclaredValue("str_enso"); DebugValue javaString = scope.getDeclaredValue("str_java"); + DebugValue jsString = scope.getDeclaredValue("str_js"); assertSameProperties(ensoString.getProperties(), javaString.getProperties()); + assertSameProperties(ensoString.getProperties(), jsString.getProperties()); DebugValue ensoList = scope.getDeclaredValue("list_enso"); DebugValue javaList = scope.getDeclaredValue("list_java"); + DebugValue jsList = scope.getDeclaredValue("list_js"); + DebugValue pyList = scope.getDeclaredValue("list_py"); assertSameProperties(ensoList.getProperties(), javaList.getProperties()); + assertSameProperties(ensoList.getProperties(), jsList.getProperties()); + assertSameProperties(ensoList.getProperties(), pyList.getProperties()); DebugValue ensoDict = scope.getDeclaredValue("dict_enso"); DebugValue javaDict = scope.getDeclaredValue("dict_java"); + DebugValue jsDict = scope.getDeclaredValue("dict_js"); + DebugValue pyDict = scope.getDeclaredValue("dict_py"); assertSameProperties(ensoDict.getProperties(), javaDict.getProperties()); + assertSameProperties(ensoDict.getProperties(), jsDict.getProperties()); + assertSameProperties(ensoDict.getProperties(), pyDict.getProperties()); } } event.getSession().suspendNextExecution(); @@ -338,7 +377,7 @@ public void hostValueIsTreatedAsItsEnsoCounterpart() { private void assertSameProperties( Collection expectedProps, Collection actualProps) { if (expectedProps == null) { - assertThat(actualProps, is(nullValue())); + assertThat(actualProps, anyOf(empty(), nullValue())); return; } assertThat(actualProps.size(), is(expectedProps.size())); From 9134e528a7101c25606f9a57b8d4cff37c4bd558 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 12:39:12 +0100 Subject: [PATCH 13/27] Polyglot conversion logic is in EnsoLanguage.getLanguageView --- .../org/enso/interpreter/EnsoLanguage.java | 82 ++++++++++++++++++- .../runtime/scope/DebugLocalScope.java | 82 +------------------ 2 files changed, 84 insertions(+), 80 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index 998276aa4551..e5e5aa5802e1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -1,5 +1,7 @@ package org.enso.interpreter; +import static org.enso.interpreter.node.callable.resolver.HostMethodCallNode.PolyglotConversionType.CONVERT_TO_TEXT; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.ContextThreadLocal; import com.oracle.truffle.api.Option; @@ -9,11 +11,15 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.ProvidedTags; import com.oracle.truffle.api.instrumentation.StandardTags; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.InvalidArrayIndexException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.ExecutableNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.time.ZoneId; import java.util.List; import java.util.Objects; import org.enso.common.LanguageInfo; @@ -31,13 +37,27 @@ import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ProgramRootNode; +import org.enso.interpreter.node.callable.resolver.HostMethodCallNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.IrToTruffle; +import org.enso.interpreter.runtime.data.EnsoDate; +import org.enso.interpreter.runtime.data.EnsoDateTime; +import org.enso.interpreter.runtime.data.EnsoDuration; +import org.enso.interpreter.runtime.data.EnsoTimeOfDay; +import org.enso.interpreter.runtime.data.EnsoTimeZone; import org.enso.interpreter.runtime.data.atom.AtomNewInstanceNode; +import org.enso.interpreter.runtime.data.hash.EnsoHashMap; +import org.enso.interpreter.runtime.data.hash.HashMapInsertNode; +import org.enso.interpreter.runtime.data.hash.HashMapToVectorNode; +import org.enso.interpreter.runtime.data.text.Text; +import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode; +import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers; +import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode; import org.enso.interpreter.runtime.instrument.NotificationHandler; import org.enso.interpreter.runtime.instrument.NotificationHandler.Forwarder; import org.enso.interpreter.runtime.instrument.NotificationHandler.TextMode$; import org.enso.interpreter.runtime.instrument.Timer; +import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.state.ExecutionEnvironment; import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag; import org.enso.interpreter.runtime.tag.IdentifiedTag; @@ -51,6 +71,8 @@ import org.graalvm.options.OptionDescriptors; import org.graalvm.options.OptionKey; import org.graalvm.options.OptionType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The root of the Enso implementation. @@ -91,6 +113,8 @@ public final class EnsoLanguage extends TruffleLanguage { private final ContextThreadLocal executionEnvironment = locals.createContextThreadLocal((ctx, thread) -> new ExecutionEnvironment[1]); + private static final Logger logger = LoggerFactory.getLogger(EnsoLanguage.class); + public static EnsoLanguage get(Node node) { return REFERENCE.get(node); } @@ -365,14 +389,68 @@ protected Object getScope(EnsoContext context) { return context.getTopScope(); } - /** Conversions of primitive values */ + /** Conversion of foreign/polyglot values to their Enso builtin counterparts. */ @Override - protected Object getLanguageView(EnsoContext context, Object value) { + public Object getLanguageView(EnsoContext context, Object value) { if (value instanceof Boolean b) { var bool = context.getBuiltins().bool(); var cons = b ? bool.getTrue() : bool.getFalse(); return AtomNewInstanceNode.getUncached().newInstance(cons); } + var interop = InteropLibrary.getUncached(); + var conversionType = HostMethodCallNode.getPolyglotConversionType(value, interop); + try { + switch (conversionType) { + case CONVERT_TO_DATE -> { + var localDate = interop.asDate(value); + return new EnsoDate(localDate); + } + case CONVERT_TO_ARRAY -> { + return ArrayLikeHelpers.asVectorFromArray(value); + } + case CONVERT_TO_BIG_INT -> { + return new EnsoBigInteger(interop.asBigInteger(value)); + } + case CONVERT_TO_DATE_TIME, CONVERT_TO_ZONED_DATE_TIME -> { + var date = interop.asDate(value); + var time = interop.asTime(value); + var zonedDt = date.atTime(time).atZone(ZoneId.systemDefault()); + return new EnsoDateTime(zonedDt); + } + case CONVERT_TO_DURATION -> { + return new EnsoDuration(interop.asDuration(value)); + } + case CONVERT_TO_HASH_MAP -> { + var ensoHash = EnsoHashMap.empty(); + var insertNode = HashMapInsertNode.getUncached(); + var vec = HashMapToVectorNode.getUncached().execute(value); + var arrayAtNode = ArrayLikeAtNode.getUncached(); + var size = ArrayLikeLengthNode.getUncached().executeLength(vec); + for (long i = 0; i < size; i++) { + var pair = arrayAtNode.executeAt(vec, i); + var key = arrayAtNode.executeAt(pair, 0); + var val = arrayAtNode.executeAt(pair, 1); + ensoHash = insertNode.execute(null, ensoHash, key, val); + } + return ensoHash; + } + case CONVERT_TO_TEXT -> { + return Text.create(interop.asString(value)); + } + case CONVERT_TO_TIME_ZONE -> { + return new EnsoTimeZone(interop.asTimeZone(value)); + } + case CONVERT_TO_TIME_OF_DAY -> { + var time = interop.asTime(value); + return new EnsoTimeOfDay(time); + } + case NO_CONVERSION -> { + return value; + } + } + } catch (UnsupportedMessageException | InvalidArrayIndexException e) { + logger.warn("Unexpected exception", e); + } return null; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java index 5354643c9c59..a8cfd4e52026 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java @@ -4,14 +4,12 @@ import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.source.SourceSection; -import java.time.ZoneId; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -21,24 +19,10 @@ import org.enso.compiler.pass.analyse.FramePointer; import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.node.EnsoRootNode; -import org.enso.interpreter.node.callable.resolver.HostMethodCallNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.callable.function.Function; -import org.enso.interpreter.runtime.data.EnsoDate; -import org.enso.interpreter.runtime.data.EnsoDateTime; -import org.enso.interpreter.runtime.data.EnsoDuration; import org.enso.interpreter.runtime.data.EnsoObject; -import org.enso.interpreter.runtime.data.EnsoTimeOfDay; -import org.enso.interpreter.runtime.data.EnsoTimeZone; -import org.enso.interpreter.runtime.data.hash.EnsoHashMap; -import org.enso.interpreter.runtime.data.hash.HashMapInsertNode; -import org.enso.interpreter.runtime.data.hash.HashMapToVectorNode; -import org.enso.interpreter.runtime.data.text.Text; -import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode; -import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers; -import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode; import org.enso.interpreter.runtime.error.DataflowError; -import org.enso.interpreter.runtime.number.EnsoBigInteger; /** * This class serves as a basic support for debugging with Chrome inspector. Currently, only @@ -211,72 +195,14 @@ Object readMember(String member, @CachedLibrary("this") InteropLibrary interop) } FramePointer framePtr = allBindings.get(member); var value = getValue(frame, framePtr); - if (value != null && isHostObject(value)) { - // Determine if the host object can be converted to corresponding Enso value. - var interopUncached = InteropLibrary.getUncached(); - var conversionType = HostMethodCallNode.getPolyglotConversionType(value, interopUncached); - try { - switch (conversionType) { - case CONVERT_TO_DATE -> { - var localDate = interopUncached.asDate(value); - return new EnsoDate(localDate); - } - case CONVERT_TO_ARRAY -> { - return ArrayLikeHelpers.asVectorFromArray(value); - } - case CONVERT_TO_BIG_INT -> { - return new EnsoBigInteger(interopUncached.asBigInteger(value)); - } - case CONVERT_TO_DATE_TIME, CONVERT_TO_ZONED_DATE_TIME -> { - var date = interopUncached.asDate(value); - var time = interopUncached.asTime(value); - var zonedDt = date.atTime(time).atZone(ZoneId.systemDefault()); - return new EnsoDateTime(zonedDt); - } - case CONVERT_TO_DURATION -> { - return new EnsoDuration(interopUncached.asDuration(value)); - } - case CONVERT_TO_HASH_MAP -> { - var ensoHash = EnsoHashMap.empty(); - var insertNode = HashMapInsertNode.getUncached(); - var vec = HashMapToVectorNode.getUncached().execute(value); - var arrayAtNode = ArrayLikeAtNode.getUncached(); - var size = ArrayLikeLengthNode.getUncached().executeLength(vec); - for (long i = 0; i < size; i++) { - var pair = arrayAtNode.executeAt(vec, i); - var key = arrayAtNode.executeAt(pair, 0); - var val = arrayAtNode.executeAt(pair, 1); - ensoHash = insertNode.execute(null, ensoHash, key, val); - } - return ensoHash; - } - case CONVERT_TO_TEXT -> { - return Text.create(interopUncached.asString(value)); - } - case CONVERT_TO_TIME_ZONE -> { - return new EnsoTimeZone(interopUncached.asTimeZone(value)); - } - case CONVERT_TO_TIME_OF_DAY -> { - var time = interopUncached.asTime(value); - return new EnsoTimeOfDay(time); - } - case NO_CONVERSION -> { - return value; - } - } - } catch (UnsupportedMessageException e) { - throw e; - } catch (InvalidArrayIndexException e) { - throw UnsupportedMessageException.create(e); - } + if (value != null) { + var ensoLang = EnsoLanguage.get(interop); + var ensoCtx = EnsoContext.get(interop); + value = ensoLang.getLanguageView(ensoCtx, value); } return value != null ? value : DataflowError.UNINITIALIZED; } - private boolean isHostObject(Object object) { - return EnsoContext.get(null).isJavaPolyglotObject(object); - } - @ExportMessage @TruffleBoundary void writeMember(String member, Object value) throws UnknownIdentifierException { From 19e37984ff41e9ef7cd982d2e5d46ab374a6f252 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 14:05:01 +0100 Subject: [PATCH 14/27] Use only PolyglotCallType --- .../org/enso/interpreter/EnsoLanguage.java | 17 ++- .../callable/resolver/HostMethodCallNode.java | 142 ++++-------------- .../callable/resolver/MethodResolverNode.java | 4 + 3 files changed, 43 insertions(+), 120 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index e5e5aa5802e1..c69dad9872f4 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -1,7 +1,5 @@ package org.enso.interpreter; -import static org.enso.interpreter.node.callable.resolver.HostMethodCallNode.PolyglotConversionType.CONVERT_TO_TEXT; - import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.ContextThreadLocal; import com.oracle.truffle.api.Option; @@ -38,8 +36,10 @@ import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ProgramRootNode; import org.enso.interpreter.node.callable.resolver.HostMethodCallNode; +import org.enso.interpreter.node.callable.resolver.MethodResolverNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.IrToTruffle; +import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.data.EnsoDate; import org.enso.interpreter.runtime.data.EnsoDateTime; import org.enso.interpreter.runtime.data.EnsoDuration; @@ -398,9 +398,16 @@ public Object getLanguageView(EnsoContext context, Object value) { return AtomNewInstanceNode.getUncached().newInstance(cons); } var interop = InteropLibrary.getUncached(); - var conversionType = HostMethodCallNode.getPolyglotConversionType(value, interop); + // We want to know if the `value` can be converted to some Enso builtin type. + // In order to do that, we are trying to infer PolyglotCallType of `value.to` method. + var anyModuleScope = context.getBuiltins().any().getDefinitionScope(); + var unresolvedSymbol = UnresolvedSymbol.build("to", anyModuleScope); + var methodResolverNode = MethodResolverNode.getUncached(); + var callType = + HostMethodCallNode.getPolyglotCallType( + value, unresolvedSymbol, interop, methodResolverNode); try { - switch (conversionType) { + switch (callType) { case CONVERT_TO_DATE -> { var localDate = interop.asDate(value); return new EnsoDate(localDate); @@ -444,7 +451,7 @@ public Object getLanguageView(EnsoContext context, Object value) { var time = interop.asTime(value); return new EnsoTimeOfDay(time); } - case NO_CONVERSION -> { + case NOT_SUPPORTED -> { return value; } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java index 54537493ce34..cab2c0456df0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java @@ -117,46 +117,6 @@ public boolean isInteropLibrary() { } } - /** - * Given a polyglot (foreign) object, this enum represents a target Enso type that the object - * should be converted to before further dispatch. - * - *

For example, a {@code java.lang.String}, or any other polyglot object that {@link - * InteropLibrary#isString(Object) is a string}, should be converted to the {@link - * org.enso.interpreter.runtime.data.text.Text} builtin Enso type. - */ - public enum PolyglotConversionType { - /** The object should be converted to {@link org.enso.interpreter.runtime.data.text.Text}. */ - CONVERT_TO_TEXT, - /** - * The object should be converted to {@link org.enso.interpreter.runtime.number.EnsoBigInteger}. - */ - CONVERT_TO_BIG_INT, - /** The object should be converted to {@link org.enso.interpreter.runtime.data.vector.Array}. */ - CONVERT_TO_ARRAY, - /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDate}. */ - CONVERT_TO_DATE, - /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDateTime}. */ - CONVERT_TO_ZONED_DATE_TIME, - /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDateTime}. */ - CONVERT_TO_DATE_TIME, - /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoDuration}. */ - CONVERT_TO_DURATION, - /** - * The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoTimeOfDay}. - */ - CONVERT_TO_TIME_OF_DAY, - /** The object should be converted to {@link org.enso.interpreter.runtime.data.EnsoTimeZone}. */ - CONVERT_TO_TIME_ZONE, - /** - * The object should be converted to {@link org.enso.interpreter.runtime.data.hash.EnsoHashMap}. - */ - CONVERT_TO_HASH_MAP, - - /** No need to convert the polyglot object, just pass it as is. */ - NO_CONVERSION - } - private static final String NEW_NAME = "new"; static final int LIB_LIMIT = 3; @@ -190,46 +150,37 @@ public static PolyglotCallType getPolyglotCallType( UnresolvedSymbol symbol, InteropLibrary library, MethodResolverNode methodResolverNode) { - var conversionType = getPolyglotConversionType(self, library); - switch (conversionType) { - case CONVERT_TO_TEXT -> { - return PolyglotCallType.CONVERT_TO_TEXT; - } - case CONVERT_TO_BIG_INT -> { - return PolyglotCallType.CONVERT_TO_BIG_INT; - } - case CONVERT_TO_DATE -> { + if (library.isDate(self)) { + if (library.isTime(self)) { + if (library.isTimeZone(self)) { + return PolyglotCallType.CONVERT_TO_ZONED_DATE_TIME; + } else { + return PolyglotCallType.CONVERT_TO_DATE_TIME; + } + } else { return PolyglotCallType.CONVERT_TO_DATE; } - case CONVERT_TO_ZONED_DATE_TIME -> { - return PolyglotCallType.CONVERT_TO_ZONED_DATE_TIME; - } - case CONVERT_TO_DATE_TIME -> { - return PolyglotCallType.CONVERT_TO_DATE_TIME; - } - case CONVERT_TO_DURATION -> { - return PolyglotCallType.CONVERT_TO_DURATION; - } - case CONVERT_TO_TIME_OF_DAY -> { - return PolyglotCallType.CONVERT_TO_TIME_OF_DAY; - } - case CONVERT_TO_TIME_ZONE -> { - return PolyglotCallType.CONVERT_TO_TIME_ZONE; - } - case CONVERT_TO_HASH_MAP -> { - return PolyglotCallType.CONVERT_TO_HASH_MAP; - } - case CONVERT_TO_ARRAY -> { - if (methodResolverNode != null) { - var ctx = EnsoContext.get(library); - var arrayType = ctx.getBuiltins().array(); - var fn = methodResolverNode.execute(arrayType, symbol); - if (fn != null) { - return PolyglotCallType.CONVERT_TO_ARRAY; - } + } else if (library.isTime(self)) { + return PolyglotCallType.CONVERT_TO_TIME_OF_DAY; + } else if (library.isDuration(self)) { + return PolyglotCallType.CONVERT_TO_DURATION; + } else if (library.isTimeZone(self)) { + return PolyglotCallType.CONVERT_TO_TIME_ZONE; + } else if (library.fitsInBigInteger(self)) { + return PolyglotCallType.CONVERT_TO_BIG_INT; + } else if (library.isString(self)) { + return PolyglotCallType.CONVERT_TO_TEXT; + } else if (library.hasArrayElements(self)) { + if (methodResolverNode != null) { + var ctx = EnsoContext.get(library); + var arrayType = ctx.getBuiltins().array(); + var fn = methodResolverNode.execute(arrayType, symbol); + if (fn != null) { + return PolyglotCallType.CONVERT_TO_ARRAY; } } - default -> {} + } else if (library.hasHashEntries(self)) { + return PolyglotCallType.CONVERT_TO_HASH_MAP; } try { @@ -247,45 +198,6 @@ public static PolyglotCallType getPolyglotCallType( return PolyglotCallType.NOT_SUPPORTED; } - /** - * Returns a target Enso builtin type that the {@code polyglotObj} should be converted to before - * further dispatch. - * - *

For example, {@code java.lang.String} should be converted to {@link - * org.enso.interpreter.runtime.data.text.Text}. - * - * @param polyglotObj Polyglot (foreign) object to check for conversion. - */ - public static PolyglotConversionType getPolyglotConversionType( - Object polyglotObj, InteropLibrary interop) { - if (interop.isDate(polyglotObj)) { - if (interop.isTime(polyglotObj)) { - if (interop.isTimeZone(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_ZONED_DATE_TIME; - } else { - return PolyglotConversionType.CONVERT_TO_DATE_TIME; - } - } else { - return PolyglotConversionType.CONVERT_TO_DATE; - } - } else if (interop.isTime(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_TIME_OF_DAY; - } else if (interop.isDuration(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_DURATION; - } else if (interop.isTimeZone(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_TIME_ZONE; - } else if (interop.fitsInBigInteger(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_BIG_INT; - } else if (interop.isString(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_TEXT; - } else if (interop.hasArrayElements(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_ARRAY; - } else if (interop.hasHashEntries(polyglotObj)) { - return PolyglotConversionType.CONVERT_TO_HASH_MAP; - } - return PolyglotConversionType.NO_CONVERSION; - } - /** * Calls a method on an object, using a specified {@link PolyglotCallType}. * diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java index 40536bcc6ee1..2a7bef2d84c1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java @@ -18,6 +18,10 @@ public abstract class MethodResolverNode extends Node { protected static final int CACHE_SIZE = 10; + public static MethodResolverNode getUncached() { + return MethodResolverNodeGen.getUncached(); + } + @NonIdempotent EnsoContext getContext() { return EnsoContext.get(this); From e28335588e49f2069c186668c0e963409941ccc8 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 14:06:41 +0100 Subject: [PATCH 15/27] long is wrapped in LanguageViewWrapper --- .../org/enso/interpreter/EnsoLanguage.java | 6 ++- .../enso/interpreter/LanguageViewWrapper.java | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index c69dad9872f4..4c2963d15618 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -416,7 +416,11 @@ public Object getLanguageView(EnsoContext context, Object value) { return ArrayLikeHelpers.asVectorFromArray(value); } case CONVERT_TO_BIG_INT -> { - return new EnsoBigInteger(interop.asBigInteger(value)); + if (interop.fitsInLong(value)) { + return new LanguageViewWrapper(interop.asLong(value)); + } else { + return new EnsoBigInteger(interop.asBigInteger(value)); + } } case CONVERT_TO_DATE_TIME, CONVERT_TO_ZONED_DATE_TIME -> { var date = interop.asDate(value); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java b/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java new file mode 100644 index 000000000000..65fa09913b67 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java @@ -0,0 +1,37 @@ +package org.enso.interpreter; + +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import org.enso.interpreter.runtime.data.EnsoObject; + +/** + * Just a wrapper for a value providing {@link + * com.oracle.truffle.api.interop.InteropLibrary#hasLanguage(Object)} message implementation. + */ +@ExportLibrary(value = InteropLibrary.class, delegateTo = "delegate") +final class LanguageViewWrapper implements EnsoObject { + final Object delegate; + + LanguageViewWrapper(Object delegate) { + this.delegate = delegate; + } + + @ExportMessage + boolean hasLanguage() { + return true; + } + + @ExportMessage + Class> getLanguage() { + return EnsoLanguage.class; + } + + @ExportMessage + Object toDisplayString( + boolean allowSideEffects, @CachedLibrary("this.delegate") InteropLibrary interop) { + return interop.toDisplayString(delegate, allowSideEffects); + } +} From b95d4bb24b2b725442dfb7216ca3a14cb379d12a Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 14:07:04 +0100 Subject: [PATCH 16/27] ArrayBuilder exports hasLanguage and getLanguage messages --- .../runtime/data/vector/ArrayBuilder.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java index c15ab12d5567..7a4242e8470b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java @@ -1,6 +1,7 @@ package org.enso.interpreter.runtime.data.vector; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.UnknownIdentifierException; @@ -11,6 +12,7 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import java.util.Arrays; +import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.warning.WarningsLibrary; @@ -242,6 +244,16 @@ String toDisplayString(boolean ignore) { return "Array_Builder"; } + @ExportMessage + boolean hasLanguage() { + return true; + } + + @ExportMessage + Class> getLanguage() { + return EnsoLanguage.class; + } + Object asVector(boolean mustBeExact) { var res = toArray(mustBeExact); if (res instanceof long[] longs) { From 61e363ae2683cc303124e6446a061e5ae79dc333 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 18:42:14 +0100 Subject: [PATCH 17/27] Call Value.asString instead of Value.toString --- .../src/test/java/org/enso/compiler/test/ExecCompilerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/ExecCompilerTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/ExecCompilerTest.java index f3c52c146d9c..87d340a15641 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/ExecCompilerTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/ExecCompilerTest.java @@ -567,7 +567,7 @@ public void resultOfConversionIsTypeChecked() throws Exception { ex.getMessage().toLowerCase(), AllOf.allOf(containsString("type"), containsString("error"))); var typeError = ex.getGuestObject(); - assertEquals("Expected type", "First_Type", typeError.getMember("expected").toString()); + assertEquals("Expected type", "First_Type", typeError.getMember("expected").asString()); assertEquals("Got wrong value", 42, typeError.getMember("actual").asInt()); } } From 5fab1daeed54266401e5bbeef2f045a97a386b72 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 18:50:23 +0100 Subject: [PATCH 18/27] Test that WithWarnings has meta object --- .../java/org/enso/interpreter/test/WarningsTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java index 61aead7772ee..8f381796706a 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java @@ -2,6 +2,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -90,6 +92,15 @@ public void wrapAndUnwrap() { fail("One shall not be created WithWarnings without any warnings " + without); } + @Test + public void withWarningHasMetaObject() { + var warning42 = wrap.execute("warn:1", 42); + assertThat( + "Value (" + warning42 + ") wrapped in warning must have a meta object", + warning42.getMetaObject(), + is(notNullValue())); + } + @Test public void warningIsAnException() { var warning42 = wrap.execute("warn:1", 42); From 293811e70f1594a9624b3e53345172402750cbea Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 18:50:46 +0100 Subject: [PATCH 19/27] Implement hasLanguage and getLanguage messages for EnsoBigInt and Text --- .../org/enso/interpreter/runtime/data/text/Text.java | 12 ++++++++++++ .../interpreter/runtime/number/EnsoBigInteger.java | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java index 5a882bf17e02..c5c18db25f01 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java @@ -2,6 +2,7 @@ import com.ibm.icu.text.Normalizer2; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.interop.InteropLibrary; @@ -14,6 +15,7 @@ import java.util.Deque; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.dsl.Builtin; import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode; import org.enso.interpreter.runtime.EnsoContext; @@ -216,6 +218,16 @@ boolean hasMetaObject() { return true; } + @ExportMessage + boolean hasLanguage() { + return true; + } + + @ExportMessage + Class> getLanguage() { + return EnsoLanguage.class; + } + private void setContents(String contents) { assert length == -1 || length == contents.length(); this.contents = contents; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java index 00dc63ae935e..c7bf873b0c5a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java @@ -1,6 +1,7 @@ package org.enso.interpreter.runtime.number; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -9,6 +10,7 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import java.math.BigInteger; +import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.data.Type; @@ -144,6 +146,16 @@ Type getType(@Bind("$node") Node node) { return EnsoContext.get(node).getBuiltins().number().getInteger(); } + @ExportMessage + boolean hasLanguage() { + return true; + } + + @ExportMessage + Class> getLanguage() { + return EnsoLanguage.class; + } + @Override public boolean equals(Object obj) { if (obj instanceof EnsoBigInteger otherBigInt) { From f4b199be31a08a0fdcf5590081037f6aa2a9dbc3 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Mon, 11 Nov 2024 18:51:47 +0100 Subject: [PATCH 20/27] EnsoLanguage.getLanguageView returns null by default --- .../src/main/java/org/enso/interpreter/EnsoLanguage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index 4c2963d15618..3167895cb78a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -456,7 +456,7 @@ public Object getLanguageView(EnsoContext context, Object value) { return new EnsoTimeOfDay(time); } case NOT_SUPPORTED -> { - return value; + return null; } } } catch (UnsupportedMessageException | InvalidArrayIndexException e) { From cdc0ba3146786c923fae791bd1681bcceb8d725d Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Tue, 26 Nov 2024 13:40:07 +0100 Subject: [PATCH 21/27] Classes that extend EnsoObject do not export getLanguage and hasLanguage. This is a fix after merge of develop. --- .../org/enso/interpreter/runtime/data/text/Text.java | 12 ------------ .../runtime/data/vector/ArrayBuilder.java | 12 ------------ .../interpreter/runtime/number/EnsoBigInteger.java | 12 ------------ 3 files changed, 36 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java index e0aa214700cd..7ae2fac6fbc1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/text/Text.java @@ -2,7 +2,6 @@ import com.ibm.icu.text.Normalizer2; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.interop.InteropLibrary; @@ -15,7 +14,6 @@ import java.util.Deque; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.dsl.Builtin; import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode; import org.enso.interpreter.runtime.EnsoContext; @@ -224,16 +222,6 @@ boolean hasMetaObject() { return true; } - @ExportMessage - boolean hasLanguage() { - return true; - } - - @ExportMessage - Class> getLanguage() { - return EnsoLanguage.class; - } - private void setContents(String contents) { assert length == -1 || length == contents.length(); this.contents = contents; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java index 75074118e869..5da2ece85bdf 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/vector/ArrayBuilder.java @@ -1,7 +1,6 @@ package org.enso.interpreter.runtime.data.vector; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.UnknownIdentifierException; @@ -12,7 +11,6 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import java.util.Arrays; -import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.warning.WarningsLibrary; @@ -245,16 +243,6 @@ public String toDisplayString(boolean ignore) { return "Array_Builder"; } - @ExportMessage - boolean hasLanguage() { - return true; - } - - @ExportMessage - Class> getLanguage() { - return EnsoLanguage.class; - } - Object asVector(boolean mustBeExact) { var res = toArray(mustBeExact); if (res instanceof long[] longs) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java index a347370d28b0..961d31e88027 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/number/EnsoBigInteger.java @@ -1,7 +1,6 @@ package org.enso.interpreter.runtime.number; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -10,7 +9,6 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import java.math.BigInteger; -import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.data.Type; @@ -147,16 +145,6 @@ Type getType(@Bind("$node") Node node) { return EnsoContext.get(node).getBuiltins().number().getInteger(); } - @ExportMessage - boolean hasLanguage() { - return true; - } - - @ExportMessage - Class> getLanguage() { - return EnsoLanguage.class; - } - @Override public boolean equals(Object obj) { if (obj instanceof EnsoBigInteger otherBigInt) { From b7431069bb3d4036ec4581c1d9826944690ff04a Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Tue, 26 Nov 2024 13:45:41 +0100 Subject: [PATCH 22/27] Build fixes after merge --- .../enso/interpreter/LanguageViewWrapper.java | 21 ++++++++----------- .../runtime/scope/DebugLocalScope.java | 1 + 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java b/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java index 65fa09913b67..c6d122218fa8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/LanguageViewWrapper.java @@ -1,6 +1,6 @@ package org.enso.interpreter; -import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; @@ -12,26 +12,23 @@ * com.oracle.truffle.api.interop.InteropLibrary#hasLanguage(Object)} message implementation. */ @ExportLibrary(value = InteropLibrary.class, delegateTo = "delegate") -final class LanguageViewWrapper implements EnsoObject { +final class LanguageViewWrapper extends EnsoObject { final Object delegate; LanguageViewWrapper(Object delegate) { this.delegate = delegate; } - @ExportMessage - boolean hasLanguage() { - return true; - } - - @ExportMessage - Class> getLanguage() { - return EnsoLanguage.class; - } - @ExportMessage Object toDisplayString( boolean allowSideEffects, @CachedLibrary("this.delegate") InteropLibrary interop) { return interop.toDisplayString(delegate, allowSideEffects); } + + @Override + @TruffleBoundary + @ExportMessage.Ignore + public Object toDisplayString(boolean allowSideEffects) { + return toDisplayString(allowSideEffects, InteropLibrary.getUncached()); + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java index 2d39609f72a7..ad8164569333 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java @@ -16,6 +16,7 @@ import java.util.Map.Entry; import java.util.stream.Collectors; import org.enso.compiler.pass.analyse.FramePointer; +import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.callable.function.Function; From 368415f21b9b944fbc1d44df95a5dd3d55c5f5e7 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Tue, 26 Nov 2024 16:25:19 +0100 Subject: [PATCH 23/27] Update WithWarning test - do not use primitive value. Primitive values is expected not to have meta object. --- .../test/java/org/enso/interpreter/test/WarningsTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java index c5188414c98b..129956012752 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/WarningsTest.java @@ -104,12 +104,14 @@ public void wrapAndUnwrap() { } @Test - public void withWarningHasMetaObject() { - var warning42 = wrap.execute("warn:1", 42); + public void withWarningsDelegatesToMetaObject() { + var warning42 = wrap.execute("warn:1", "Text"); + var meta = warning42.getMetaObject(); assertThat( "Value (" + warning42 + ") wrapped in warning must have a meta object", - warning42.getMetaObject(), + meta, is(notNullValue())); + assertThat(meta.toString(), containsString("Text")); } @Test From 19328ac4bf9d1790283f4960953368b1fc1af905 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Tue, 26 Nov 2024 18:58:32 +0100 Subject: [PATCH 24/27] Add test for polyglot semantics of Enso numbers --- .../enso/interpreter/test/BigNumberTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java index 88419a34f7fc..565d147e3b44 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java @@ -1,5 +1,7 @@ package org.enso.interpreter.test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -177,4 +179,39 @@ public void doubleBigInteger() throws Exception { var fourtyTwo = assertMul(6.0, new BigInteger("7")); assertEquals(42, fourtyTwo.asInt()); } + + @Test + public void everyValueSmallerThanIntegerMaxVal_IsPrimitiveInt() { + var almostMaxInt = Integer.toString(Integer.MAX_VALUE - 1); + var intVal = ContextUtils.evalModule(ctx, "main = " + almostMaxInt); + assertThat("Is a number", intVal.isNumber(), is(true)); + assertThat("Fits in int", intVal.fitsInInt(), is(true)); + assertThat("Fits in long", intVal.fitsInLong(), is(true)); + assertThat("Fits in double", intVal.fitsInDouble(), is(true)); + assertThat("Fits in big int", intVal.fitsInBigInteger(), is(true)); + } + + @Test + public void everyValueSmallerThanLongMaxVal_IsPrimitiveLong() { + var almostMaxLong = Long.toString(Long.MAX_VALUE - 1); + var longVal = ContextUtils.evalModule(ctx, "main = " + almostMaxLong); + assertThat("Is a number", longVal.isNumber(), is(true)); + assertThat("Does not fit in int", longVal.fitsInInt(), is(false)); + assertThat("Fits in long", longVal.fitsInLong(), is(true)); + assertThat("Does not fit in double (but could)", longVal.fitsInDouble(), is(false)); + assertThat("Fits in big int", longVal.fitsInBigInteger(), is(true)); + } + + @Test + public void everyValueBiggerThanLongMaxVal_IsEnsoBigInt() { + // This number is bigger than Long.MAX_VALUE, but smaller than Double.MAX_VALUE + // so it could technically fit in double, but in Enso, it is automatically converted + // to EnsoBigInteger + var bigIntVal = ContextUtils.evalModule(ctx, "main = 9223372036854775808"); + assertThat("Is a number", bigIntVal.isNumber(), is(true)); + assertThat("Does not fit in int", bigIntVal.fitsInInt(), is(false)); + assertThat("Does not fit in long", bigIntVal.fitsInLong(), is(false)); + assertThat("Does not fit in double (but could)", bigIntVal.fitsInDouble(), is(false)); + assertThat("Fits in big int", bigIntVal.fitsInBigInteger(), is(true)); + } } From 1826dde2aa7d1b5e6f8ccf745814717af3719ed2 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Wed, 27 Nov 2024 16:18:14 +0100 Subject: [PATCH 25/27] Add comments to BigNumberTest --- .../java/org/enso/interpreter/test/BigNumberTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java index 565d147e3b44..3f51b5d76ba4 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/BigNumberTest.java @@ -198,20 +198,20 @@ public void everyValueSmallerThanLongMaxVal_IsPrimitiveLong() { assertThat("Is a number", longVal.isNumber(), is(true)); assertThat("Does not fit in int", longVal.fitsInInt(), is(false)); assertThat("Fits in long", longVal.fitsInLong(), is(true)); - assertThat("Does not fit in double (but could)", longVal.fitsInDouble(), is(false)); + // Does not fit in double, because it is not a power of 2 and therefore a precision would + // be lost if converted to double. + assertThat("Does not fit in double", longVal.fitsInDouble(), is(false)); assertThat("Fits in big int", longVal.fitsInBigInteger(), is(true)); } @Test public void everyValueBiggerThanLongMaxVal_IsEnsoBigInt() { - // This number is bigger than Long.MAX_VALUE, but smaller than Double.MAX_VALUE - // so it could technically fit in double, but in Enso, it is automatically converted - // to EnsoBigInteger + // This number is bigger than Long.MAX_VALUE, and not a power of 2. var bigIntVal = ContextUtils.evalModule(ctx, "main = 9223372036854775808"); assertThat("Is a number", bigIntVal.isNumber(), is(true)); assertThat("Does not fit in int", bigIntVal.fitsInInt(), is(false)); assertThat("Does not fit in long", bigIntVal.fitsInLong(), is(false)); - assertThat("Does not fit in double (but could)", bigIntVal.fitsInDouble(), is(false)); + assertThat("Does not fit in double (not a power of 2)", bigIntVal.fitsInDouble(), is(false)); assertThat("Fits in big int", bigIntVal.fitsInBigInteger(), is(true)); } } From 1d012215e4ebdb42e13fc8eb98f96d1ca2f6ca27 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Wed, 27 Nov 2024 16:20:14 +0100 Subject: [PATCH 26/27] A value that fits in double is double, not converted to BigInt --- .../src/main/java/org/enso/interpreter/EnsoLanguage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index 3167895cb78a..4dcea57333a8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -416,8 +416,11 @@ public Object getLanguageView(EnsoContext context, Object value) { return ArrayLikeHelpers.asVectorFromArray(value); } case CONVERT_TO_BIG_INT -> { + // long and doubles are valid primitive types in Enso if (interop.fitsInLong(value)) { return new LanguageViewWrapper(interop.asLong(value)); + } else if (interop.fitsInDouble(value)) { + return new LanguageViewWrapper(interop.asDouble(value)); } else { return new EnsoBigInteger(interop.asBigInteger(value)); } From 65553f300fbdfe9402a3e0c59bd38f5cfeb0b242 Mon Sep 17 00:00:00 2001 From: Pavel Marek Date: Wed, 27 Nov 2024 17:45:34 +0100 Subject: [PATCH 27/27] EnsoObject is returned from getLanguageView without any conversions --- .../src/main/java/org/enso/interpreter/EnsoLanguage.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index 4dcea57333a8..4d52bc042670 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -43,6 +43,7 @@ import org.enso.interpreter.runtime.data.EnsoDate; import org.enso.interpreter.runtime.data.EnsoDateTime; import org.enso.interpreter.runtime.data.EnsoDuration; +import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.data.EnsoTimeOfDay; import org.enso.interpreter.runtime.data.EnsoTimeZone; import org.enso.interpreter.runtime.data.atom.AtomNewInstanceNode; @@ -397,6 +398,9 @@ public Object getLanguageView(EnsoContext context, Object value) { var cons = b ? bool.getTrue() : bool.getFalse(); return AtomNewInstanceNode.getUncached().newInstance(cons); } + if (value instanceof EnsoObject ensoObject) { + return ensoObject; + } var interop = InteropLibrary.getUncached(); // We want to know if the `value` can be converted to some Enso builtin type. // In order to do that, we are trying to infer PolyglotCallType of `value.to` method.