diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Ordering_Helpers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Ordering_Helpers.enso index 1f72384495fb..4cb1b8cd3222 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Ordering_Helpers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Ordering_Helpers.enso @@ -69,16 +69,16 @@ assert_same_comparators this that ~action = False -> Error.throw (Incomparable_Values.Error this that) compare_with_comparators this that -> Ordering ! Incomparable_Values = - any_result = Panic.catch Type_Error handler=identity <| + yield_an_error _ = Error.throw (Incomparable_Values.Error this that) + Panic.catch Type_Error handler=yield_an_error <| comp_this = Comparable.from this comp_that = Comparable.from that - if Meta.is_same_object comp_this.comparator comp_that.comparator then + any_result = if Meta.is_same_object comp_this.comparator comp_that.comparator then comp_this.comparator.compare comp_this.value comp_that.value - case any_result of - result:Ordering -> result - _ -> Error.throw (Incomparable_Values.Error this that) + result = any_result:Ordering + result ## PRIVATE type Positive_Integer_Comparator @@ -92,7 +92,10 @@ type Positive_Integer_Comparator ## PRIVATE type Ordering_Comparator ## PRIVATE - compare x:Ordering y:Ordering = Ordering.compare x.to_sign y.to_sign + compare x:Ordering y:Ordering = if Meta.is_same_object x y then Ordering.Equal else + if Meta.is_same_object x Ordering.Equal . not then x else + if Meta.is_same_object y Ordering.Less then Ordering.Greater else + Ordering.Less ## PRIVATE hash x:Ordering = x.to_sign diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/BinaryOperatorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/BinaryOperatorNode.java index 6f2036283797..c28b217e05c3 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/BinaryOperatorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/BinaryOperatorNode.java @@ -155,9 +155,8 @@ final Object doThatConversionUncached( for (var thatType : multi.allTypes()) { var fn = findSymbol(symbol, thatType); if (fn != null) { - var result = - doDispatch( - frame, self, multi.castTo(thatType), thatType, fn, convertNode, invokeNode); + var thatCasted = EnsoMultiValue.CastToNode.getUncached().executeCast(thatType, multi); + var result = doDispatch(frame, self, thatCasted, thatType, fn, convertNode, invokeNode); if (result != null) { return result; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java index dfcf357a1c3a..f8d9a2b57714 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java @@ -179,9 +179,10 @@ Object doMultiValue( UnresolvedConversion conversion, Object self, EnsoMultiValue that, - Object[] arguments) { + Object[] arguments, + @Cached EnsoMultiValue.CastToNode castTo) { var type = extractType(self); - var result = that.castTo(type); + var result = castTo.executeCast(type, that); if (result == null) { throw new PanicException( EnsoContext.get(this).getBuiltins().error().makeNoSuchConversion(type, self, conversion), 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 ead711103a77..c06bee97df69 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 @@ -294,10 +294,11 @@ Object doMultiValue( UnresolvedSymbol symbol, EnsoMultiValue self, Object[] arguments, - @Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) { + @Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode, + @Cached EnsoMultiValue.CastToNode castTo) { var fnAndType = self.resolveSymbol(methodResolverNode, symbol); if (fnAndType != null) { - var unwrapSelf = self.castTo(fnAndType.getRight()); + var unwrapSelf = castTo.executeCast(fnAndType.getRight(), self); if (unwrapSelf != null) { assert arguments[0] == self; arguments[0] = unwrapSelf; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java index 0d7bec80bd8a..d61186db70f6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java @@ -287,6 +287,7 @@ abstract static class TypeCheckNode extends ReadArgumentCheckNode { @Child IsValueOfTypeNode checkType; @CompilerDirectives.CompilationFinal private String expectedTypeMessage; @CompilerDirectives.CompilationFinal private LazyCheckRootNode lazyCheck; + @Child private EnsoMultiValue.CastToNode castTo; TypeCheckNode(String name, Type expectedType) { super(name); @@ -354,7 +355,11 @@ final Object findDirectMatch(VirtualFrame frame, Object v) { return lazyCheckFn; } if (v instanceof EnsoMultiValue mv) { - var result = mv.castTo(expectedType); + if (castTo == null) { + CompilerDirectives.transferToInterpreter(); + castTo = insert(EnsoMultiValue.CastToNode.create()); + } + var result = castTo.executeCast(expectedType, mv); if (result != null) { return result; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java index 1eb2c679251d..1be55e9a92a6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java @@ -2,7 +2,11 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; @@ -12,6 +16,7 @@ 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.nodes.Node; import java.math.BigInteger; import java.time.Duration; import java.time.LocalDate; @@ -413,19 +418,40 @@ public String toString() { return Arrays.stream(types).map(t -> t.getName()).collect(Collectors.joining(" & ")); } - /** - * Casts value in this multi value into specific t. - * - * @param type the requested t - * @return instance of the {@code t} or {@code null} if no suitable value was found - */ - public final Object castTo(Type type) { - for (var i = 0; i < types.length; i++) { - if (types[i] == type) { - return values[i]; + /** Casts {@link EnsoMultiValue} to requested type effectively. */ + @GenerateUncached + public abstract static class CastToNode extends Node { + /** + * Casts value in a multi value into specific type. + * + * @param type the requested t + * @param mv a multi value + * @return instance of the {@code t} or {@code null} if no suitable value was found + */ + public abstract Object executeCast(Type type, EnsoMultiValue mv); + + @NeverDefault + public static CastToNode create() { + return EnsoMultiValueFactory.CastToNodeGen.create(); + } + + @NeverDefault + public static CastToNode getUncached() { + return EnsoMultiValueFactory.CastToNodeGen.getUncached(); + } + + @Specialization + Object castsToAType( + Type type, + EnsoMultiValue mv, + @Cached(value = "type", allowUncached = true, neverDefault = true) Type cachedType) { + for (var i = 0; i < mv.types.length; i++) { + if (mv.types[i] == cachedType) { + return mv.values[i]; + } } + return null; } - return null; } /**