diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java index dfca6bd78e032..404fcd3f2d62d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java @@ -1,9 +1,10 @@ package org.enso.interpreter.node.callable; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; @@ -12,17 +13,20 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.source.SourceSection; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.locks.Lock; -import org.enso.interpreter.Language; import org.enso.interpreter.node.BaseNode; import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode; import org.enso.interpreter.node.callable.resolver.*; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo; +import org.enso.interpreter.runtime.callable.atom.Atom; +import org.enso.interpreter.runtime.callable.atom.AtomConstructor; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.ArrayRope; import org.enso.interpreter.runtime.data.text.Text; @@ -34,7 +38,6 @@ public abstract class InvokeMethodNode extends BaseNode { private @Child InvokeFunctionNode invokeFunctionNode; private final ConditionProfile errorReceiverProfile = ConditionProfile.createCountingProfile(); - private final BranchProfile polyglotArgumentErrorProfile = BranchProfile.create(); private @Child InvokeMethodNode childDispatch; private final int argumentCount; private final int thisArgumentPosition; @@ -162,8 +165,7 @@ Stateful doWarning( guards = { "!methods.hasFunctionalDispatch(_this)", "!methods.hasSpecialDispatch(_this)", - "polyglotCallType != NOT_SUPPORTED", - "polyglotCallType != CONVERT_TO_TEXT" + "polyglotCallType.isInteropLibrary()", }) Stateful doPolyglot( VirtualFrame frame, @@ -235,6 +237,53 @@ Stateful doConvertText( } } + @Specialization( + guards = { + "!methods.hasFunctionalDispatch(_this)", + "!methods.hasSpecialDispatch(_this)", + "getPolyglotCallType(_this, symbol.getName(), interop) == CONVERT_TO_DATE" + }) + Stateful doConvertDate( + VirtualFrame frame, + Object state, + UnresolvedSymbol symbol, + Object _this, + Object[] arguments, + @CachedLibrary(limit = "10") MethodDispatchLibrary methods, + @CachedLibrary(limit = "1") MethodDispatchLibrary dateDispatch, + @CachedLibrary(limit = "10") InteropLibrary interop, + @Cached("wrapDateInAtom(interop)") java.util.function.Function wrapDate + ) { + try { + Atom date = wrapDate.apply(_this); + Function function = dateDispatch.getFunctionalDispatch(date, symbol); + arguments[0] = date; + return invokeFunctionNode.execute(function, frame, state, arguments); + } catch (MethodDispatchLibrary.NoSuchMethodException e) { + throw new PanicException( + Context.get(this).getBuiltins().error().makeNoSuchMethodError(_this, symbol), this); + } + } + + final java.util.function.Function wrapDateInAtom(InteropLibrary iop) { + CompilerAsserts.neverPartOfCompilation(); + final Context ctx = Context.get(this); + ctx.ensureModuleIsLoaded("Standard.Base.Data.Time.Date"); + Optional dateModule = ctx.findModule("Standard.Base.Data.Time.Date"); + if (dateModule.isPresent()) { + try { + Object constrDate = iop.invokeMember(dateModule.get(), "get_constructor", "Date"); + if (constrDate instanceof AtomConstructor) { + AtomConstructor c = (AtomConstructor) constrDate; + return c::newInstance; + } + } catch (InteropException ex) { + throw new IllegalStateException("Impossible, _this is guaranteed to be a string."); + } + } + return null; + } + @Specialization( guards = { "!methods.hasFunctionalDispatch(_this)", 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 6cb255fa090b1..8420f51dd3c99 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 @@ -43,8 +43,25 @@ public enum PolyglotCallType { * org.enso.interpreter.runtime.data.text.Text} and dispatching natively. */ CONVERT_TO_TEXT, + /** + * The method call should be handled by converting {@code _this} to a {@code + * Standard.Base.Data.Time.Date} and dispatching natively. + */ + CONVERT_TO_DATE, /** The method call should be handled by dispatching through the {@code Any} type. */ - NOT_SUPPORTED + NOT_SUPPORTED; + + /** + * Directly use {@link InteropLibrary}, or not. Types that return false are + * either {@link #NOT_SUPPORTED unsupported} or require + * additional conversions like {@link #CONVERT_TO_TEXT} and {@link #CONVERT_TO_DATE}. + * + * @return true if one can directly pass this object to + * {@link InteropLibrary} + */ + public boolean isInteropLibrary() { + return this != NOT_SUPPORTED && this != CONVERT_TO_TEXT && this != CONVERT_TO_DATE; + } } private static final String ARRAY_LENGTH_NAME = "length"; @@ -76,9 +93,12 @@ public static PolyglotCallType getPolyglotCallType( return PolyglotCallType.READ_ARRAY_ELEMENT; } else if (library.isString(_this)) { return PolyglotCallType.CONVERT_TO_TEXT; - } else { - return PolyglotCallType.NOT_SUPPORTED; + } else if (library.isDate(_this)) { + if (!library.isTime(_this)) { + return PolyglotCallType.CONVERT_TO_DATE; + } } + return PolyglotCallType.NOT_SUPPORTED; } /** diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java index 2a94e18156e04..53e12fa141199 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java @@ -76,36 +76,6 @@ Atom doNull( @Fallback Object doOther(Object o, @CachedLibrary(limit = "3") InteropLibrary dates) { - if (o instanceof Atom) { - return o; - } - if (dates.isDate(o) && !dates.isTime(o)) { - o = convertToStandardBaseDataTimeDate(dates, o); - } return o; } - - private static Object convertToStandardBaseDataTimeDate(InteropLibrary dates, Object o) { - CompilerAsserts.neverPartOfCompilation(); - final Context ctx = Context.get(dates); - final InteropLibrary iop = InteropLibrary.getUncached(); - ctx.ensureModuleIsLoaded("Standard.Base.Data.Time.Date"); - Optional dateModule = ctx.findModule("Standard.Base.Data.Time.Date"); - if (!dateModule.isPresent()) { - return o; - } - try { - Object constrDate = iop.invokeMember(dateModule.get(), "get_constructor", "Date"); - if (constrDate instanceof AtomConstructor) { - AtomConstructor c = (AtomConstructor) constrDate; - final LocalDate maybeDate = iop.asDate(o); - if (maybeDate instanceof LocalDate) { - return c.newInstance(o); - } - } - return o; - } catch (InteropException ex) { - return o; - } - } }