resolveFor(Node node, Type type) {
if (type != null) {
for (var current : type.allTypes(EnsoContext.get(node))) {
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiType.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiType.java
new file mode 100644
index 000000000000..e531ed8f6fdf
--- /dev/null
+++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiType.java
@@ -0,0 +1,182 @@
+package org.enso.interpreter.runtime.data;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
+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.nodes.Node;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.concurrent.ConcurrentHashMap;
+import org.enso.interpreter.runtime.EnsoContext;
+
+/**
+ * Internal representation of {@code Type[]} that supports identity comparision with {@code ==} to
+ * support inline caching of {@link EnsoMultiValue}. This is a separate and hidden concept from
+ * {@link Type} which is used thru out the Enso codebase.
+ *
+ * Think twice before opening this type to public!
+ */
+final class EnsoMultiType {
+ private static final ConcurrentHashMap ALL_TYPES =
+ new ConcurrentHashMap<>();
+
+ @CompilerDirectives.CompilationFinal(dimensions = 1)
+ private final Type[] types;
+
+ private EnsoMultiType(Type[] types) {
+ this.types = types;
+ }
+
+ @CompilerDirectives.TruffleBoundary
+ static EnsoMultiType findOrCreateSlow(Type[] types, int from, int to) {
+ var mt = new EnsoMultiType(Arrays.copyOfRange(types, from, to));
+ return ALL_TYPES.computeIfAbsent(mt, java.util.function.Function.identity());
+ }
+
+ final int typesLength() {
+ return types.length;
+ }
+
+ final Type firstType() {
+ return types[0];
+ }
+
+ private int find(EnsoContext ctx, Type type) {
+ for (var i = 0; i < types.length; i++) {
+ for (var t : types[i].allTypes(ctx)) {
+ if (t == type) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ @CompilerDirectives.TruffleBoundary
+ public int hashCode() {
+ int hash = 7;
+ hash = 89 * hash + Arrays.deepHashCode(this.types);
+ return hash;
+ }
+
+ @Override
+ @CompilerDirectives.TruffleBoundary
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final EnsoMultiType other = (EnsoMultiType) obj;
+ return Arrays.deepEquals(this.types, other.types);
+ }
+
+ @Override
+ @CompilerDirectives.TruffleBoundary
+ public String toString() {
+ return "MultiType{" + "types=" + Arrays.toString(types) + '}';
+ }
+
+ @CompilerDirectives.TruffleBoundary
+ final boolean hasIntersectionWith(EnsoMultiType other) {
+ var my = new HashSet<>(Arrays.asList(types));
+ var their = Arrays.asList(other.types);
+ my.removeAll(their);
+ return my.size() < types.length;
+ }
+
+ @GenerateUncached
+ abstract static class FindIndexNode extends Node {
+ private static final String INLINE_CACHE_LIMIT = "5";
+
+ abstract int executeFindIndex(Type type, EnsoMultiType mt);
+
+ @NeverDefault
+ public static FindIndexNode create() {
+ return EnsoMultiTypeFactory.FindIndexNodeGen.create();
+ }
+
+ @NeverDefault
+ public static FindIndexNode getUncached() {
+ return EnsoMultiTypeFactory.FindIndexNodeGen.getUncached();
+ }
+
+ @Specialization(
+ guards = {"type == cachedType", "mt == cachedMt"},
+ limit = INLINE_CACHE_LIMIT)
+ int findsCachedIndexOfAType(
+ Type type,
+ EnsoMultiType mt,
+ @Cached("type") Type cachedType,
+ @Cached("mt") EnsoMultiType cachedMt,
+ @Cached(allowUncached = true, value = "findsAnIndexOfAType(type, mt)") int cachedIndex) {
+ return cachedIndex;
+ }
+
+ @Specialization(replaces = "findsCachedIndexOfAType")
+ int findsAnIndexOfAType(Type type, EnsoMultiType mt) {
+ var ctx = EnsoContext.get(this);
+ var index = mt.find(ctx, type);
+ return index;
+ }
+ }
+
+ @GenerateUncached
+ abstract static class AllTypesWith extends Node {
+ private static final String INLINE_CACHE_LIMIT = "5";
+
+ @NeverDefault
+ static AllTypesWith getUncached() {
+ return EnsoMultiTypeFactory.AllTypesWithNodeGen.getUncached();
+ }
+
+ @NeverDefault
+ static AllTypesWith create() {
+ return EnsoMultiTypeFactory.AllTypesWithNodeGen.create();
+ }
+
+ /**
+ * Don't modify the return value. It maybe cached!
+ *
+ * @param first first set of types
+ * @param second second set of types
+ * @return union of both types
+ */
+ abstract Type[] executeAllTypes(EnsoMultiType first, EnsoMultiType second);
+
+ @Specialization(
+ limit = INLINE_CACHE_LIMIT,
+ guards = {
+ "self == cachedSelf",
+ "nextOrNull == cachedNextOrNull",
+ })
+ Type[] optimizeForTypes(
+ EnsoMultiType self,
+ EnsoMultiType nextOrNull,
+ @Cached("self") EnsoMultiType cachedSelf,
+ @Cached("nextOrNull") EnsoMultiType cachedNextOrNull,
+ @Cached("slowlyComputeTypes(self, nextOrNull)") Type[] result) {
+ return result;
+ }
+
+ @Specialization(replaces = "optimizeForTypes")
+ Type[] slowlyComputeTypes(EnsoMultiType self, EnsoMultiType nextOrNull) {
+ if (nextOrNull == null || nextOrNull.types.length == 0) {
+ return self.types.clone();
+ } else {
+ var next = nextOrNull;
+ var arr = new Type[self.types.length + next.types.length];
+ System.arraycopy(self.types, 0, arr, 0, self.types.length);
+ System.arraycopy(next.types, 0, arr, self.types.length, next.types.length);
+ return arr;
+ }
+ }
+ }
+}
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 22f31f090bd1..69cff2aeef74 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
@@ -1,7 +1,9 @@
package org.enso.interpreter.runtime.data;
+import com.oracle.truffle.api.CompilerAsserts;
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;
@@ -15,6 +17,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.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import java.math.BigInteger;
import java.time.Duration;
@@ -29,6 +32,7 @@
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.EnsoMultiType.AllTypesWith;
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.graalvm.collections.Pair;
@@ -36,40 +40,109 @@
@ExportLibrary(TypesLibrary.class)
@ExportLibrary(InteropLibrary.class)
public final class EnsoMultiValue extends EnsoObject {
-
- @CompilationFinal(dimensions = 1)
- private final Type[] types;
-
- @CompilationFinal private final int methodDispatchTypes;
+ private final EnsoMultiType dispatch;
+ private final EnsoMultiType extra;
@CompilationFinal(dimensions = 1)
private final Object[] values;
- private EnsoMultiValue(Type[] types, int dispatchTypes, Object[] values) {
- this.types = types;
- this.methodDispatchTypes = dispatchTypes;
- assert types.length == values.length;
+ private EnsoMultiValue(EnsoMultiType dispatch, EnsoMultiType extra, Object[] values) {
+ assert !dispatch.hasIntersectionWith(extra)
+ : "Dispatch (" + dispatch + " and extra " + extra + " should be disjoin!";
+ this.dispatch = dispatch;
+ this.extra = extra;
this.values = values;
- assert !Stream.of(values).anyMatch(v -> v instanceof EnsoMultiValue)
- : "Avoid double wrapping " + Arrays.toString(values);
+ }
+
+ /** Creates new instance of EnsoMultiValue from provided information. */
+ @GenerateUncached
+ public abstract static class NewNode extends Node {
+ private static final String INLINE_CACHE_LIMIT = "5";
+
+ @NeverDefault
+ public static NewNode create() {
+ return EnsoMultiValueFactory.NewNodeGen.create();
+ }
+
+ @NeverDefault
+ public static NewNode getUncached() {
+ return EnsoMultiValueFactory.NewNodeGen.getUncached();
+ }
+
+ /**
+ * Creates new multi value from provided information.
+ *
+ * @param types all the types this value can be {@link CastToNode cast to}
+ * @param dispatchTypes the (subset of) types that the value is cast to currently - bigger than
+ * {@code 0} and at most {@code type.length}
+ * @param values value of each of the provided {@code types}
+ * @return non-{@code null} multi value instance
+ */
+ @NeverDefault
+ public EnsoMultiValue newValue(
+ @NeverDefault Type[] types,
+ @NeverDefault int dispatchTypes,
+ @NeverDefault Object... values) {
+ assert dispatchTypes > 0;
+ assert dispatchTypes <= types.length;
+ assert types.length == values.length;
+ assert !Stream.of(values).anyMatch(v -> v instanceof EnsoMultiValue)
+ : "Avoid double wrapping " + Arrays.toString(values);
+ var dt = executeTypes(types, 0, dispatchTypes);
+ var et = executeTypes(types, dispatchTypes, types.length);
+ return new EnsoMultiValue(dt, et, values);
+ }
+
+ abstract EnsoMultiType executeTypes(Type[] types, int from, int to);
+
+ @Specialization(
+ guards = {"compareTypes(cachedTypes, types, from, to)"},
+ limit = INLINE_CACHE_LIMIT)
+ final EnsoMultiType cachedMultiType(
+ Type[] types,
+ int from,
+ int to,
+ @Cached(value = "clone(types, from, to)", dimensions = 1) Type[] cachedTypes,
+ @Cached("createMultiType(types, from, to)") EnsoMultiType result) {
+ return result;
+ }
+
+ @Specialization(replaces = "cachedMultiType")
+ final EnsoMultiType createMultiType(Type[] types, int from, int to) {
+ return EnsoMultiType.findOrCreateSlow(types, from, to);
+ }
+
+ @TruffleBoundary
+ static final Type[] clone(Type[] types, int from, int to) {
+ return Arrays.copyOfRange(types, from, to);
+ }
+
+ @ExplodeLoop
+ static final boolean compareTypes(Type[] cached, Type[] arr, int from, int to) {
+ CompilerAsserts.partialEvaluationConstant(cached);
+ if (cached.length != to - from) {
+ return false;
+ }
+ CompilerAsserts.partialEvaluationConstant(cached.length);
+ for (var i = 0; i < cached.length; i++) {
+ CompilerAsserts.partialEvaluationConstant(cached[i]);
+ if (cached[i] != arr[from++]) {
+ return false;
+ }
+ }
+ return true;
+ }
}
/**
- * Creates new instance of EnsoMultiValue from provided information.
+ * The "dispatch identity" of the multi value. If two multivalues have the same identity, they are
+ * going to resolve methods the same way.
*
- * @param types all the types this value can be {@link CastToNode cast to}
- * @param dispatchTypes the (subset of) types that the value is cast to currently - bigger than
- * {@code 0} and at most {@code type.length}
- * @param values value of each of the provided {@code types}
- * @return non-{@code null} multi value instance
+ * @return an opaque object that can be used for caching dispatch logic
*/
- @NeverDefault
- public static EnsoMultiValue create(
- @NeverDefault Type[] types, @NeverDefault int dispatchTypes, @NeverDefault Object... values) {
- assert dispatchTypes > 0;
- assert dispatchTypes <= types.length;
- assert types.length == values.length;
- return new EnsoMultiValue(types, dispatchTypes, values);
+ public final Object getDispatchId() {
+ // intentionally typed as Object to avoid exposing EnsoMultiType
+ return dispatch;
}
@ExportMessage
@@ -84,15 +157,16 @@ boolean hasSpecialDispatch() {
@ExportMessage
final Type getType() {
- return types[0];
+ return dispatch.firstType();
}
@ExportMessage
- final Type[] allTypes(boolean includeExtraTypes) {
- if (includeExtraTypes || methodDispatchTypes == types.length) {
- return types.clone();
+ final Type[] allTypes(
+ boolean includeExtraTypes, @Cached EnsoMultiType.AllTypesWith allTypesWith) {
+ if (!includeExtraTypes) {
+ return allTypesWith.executeAllTypes(dispatch, null);
} else {
- return Arrays.copyOf(types, methodDispatchTypes);
+ return allTypesWith.executeAllTypes(dispatch, extra);
}
}
@@ -151,16 +225,20 @@ static Value find(Object[] values, int max, InteropLibrary iop) {
}
}
+ private InteropType.Value findInteropTypeValue(InteropLibrary iop) {
+ return InteropType.find(values, dispatch.typesLength(), iop);
+ }
+
@ExportMessage
boolean isBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.BOOLEAN;
}
@ExportMessage
boolean asBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.BOOLEAN) {
return iop.asBoolean(both.value());
}
@@ -169,14 +247,14 @@ boolean asBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary
@ExportMessage
boolean isString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.STRING;
}
@ExportMessage
String asString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.STRING) {
return iop.asString(both.value());
}
@@ -185,50 +263,50 @@ String asString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary i
@ExportMessage
boolean isNumber(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER;
}
@ExportMessage
boolean fitsInByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInByte(both.value());
}
@ExportMessage
boolean fitsInShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInShort(both.value());
}
@ExportMessage
boolean fitsInInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInInt(both.value());
}
@ExportMessage
boolean fitsInLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInLong(both.value());
}
@ExportMessage
boolean fitsInFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInFloat(both.value());
}
@ExportMessage
boolean fitsInDouble(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInDouble(both.value());
}
@ExportMessage
byte asByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asByte(both.value());
}
@@ -238,7 +316,7 @@ byte asByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
@ExportMessage
short asShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asShort(both.value());
}
@@ -248,7 +326,7 @@ short asShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop
@ExportMessage
int asInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asInt(both.value());
}
@@ -258,7 +336,7 @@ int asInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
@ExportMessage
long asLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asLong(both.value());
}
@@ -268,7 +346,7 @@ long asLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
@ExportMessage
float asFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asFloat(both.value());
}
@@ -278,7 +356,7 @@ float asFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop
@ExportMessage
double asDouble(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asDouble(both.value());
}
@@ -287,14 +365,14 @@ float asFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop
@ExportMessage
boolean fitsInBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.NUMBER && iop.fitsInBigInteger(both.value());
}
@ExportMessage
BigInteger asBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.NUMBER) {
return iop.asBigInteger(both.value());
}
@@ -303,14 +381,14 @@ BigInteger asBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropL
@ExportMessage
boolean isTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.DATE_TIME_ZONE && iop.isTime(both.value());
}
@ExportMessage
LocalTime asTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.DATE_TIME_ZONE) {
return iop.asTime(both.value());
}
@@ -319,14 +397,14 @@ LocalTime asTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary
@ExportMessage
boolean isDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.DATE_TIME_ZONE && iop.isDate(both.value());
}
@ExportMessage
LocalDate asDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.DATE_TIME_ZONE) {
return iop.asDate(both.value());
}
@@ -335,14 +413,14 @@ LocalDate asDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary
@ExportMessage
boolean isTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.DATE_TIME_ZONE && iop.isTimeZone(both.value());
}
@ExportMessage
ZoneId asTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.DATE_TIME_ZONE) {
return iop.asTimeZone(both.value());
}
@@ -351,14 +429,14 @@ ZoneId asTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary
@ExportMessage
boolean isDuration(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
return both.type() == InteropType.DURATION;
}
@ExportMessage
Duration asDuration(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
- var both = InteropType.find(values, methodDispatchTypes, iop);
+ var both = findInteropTypeValue(iop);
if (both.type() == InteropType.DURATION) {
return iop.asDuration(both.value());
}
@@ -375,7 +453,7 @@ boolean hasMembers() {
Object getMembers(
boolean includeInternal, @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
var names = new TreeSet();
- for (var i = 0; i < methodDispatchTypes; i++) {
+ for (var i = 0; i < dispatch.typesLength(); i++) {
try {
var members = iop.getMembers(values[i]);
var len = iop.getArraySize(members);
@@ -392,7 +470,7 @@ Object getMembers(
@ExportMessage
boolean isMemberInvocable(
String name, @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
- for (var i = 0; i < methodDispatchTypes; i++) {
+ for (var i = 0; i < dispatch.typesLength(); i++) {
if (iop.isMemberInvocable(values[i], name)) {
return true;
}
@@ -409,7 +487,7 @@ Object invokeMember(
ArityException,
UnsupportedTypeException,
UnknownIdentifierException {
- for (var i = 0; i < methodDispatchTypes; i++) {
+ for (var i = 0; i < dispatch.typesLength(); i++) {
if (iop.isMemberInvocable(values[i], name)) {
return iop.invokeMember(values[i], name, args);
}
@@ -420,12 +498,39 @@ Object invokeMember(
@TruffleBoundary
@Override
public String toString() {
- return Arrays.stream(types).map(t -> t.getName()).collect(Collectors.joining(" & "));
+ var both = EnsoMultiType.AllTypesWith.getUncached().executeAllTypes(dispatch, extra);
+ return Stream.of(both).map(t -> t.getName()).collect(Collectors.joining(" & "));
}
/** Casts {@link EnsoMultiValue} to requested type effectively. */
- @GenerateUncached
- public abstract static class CastToNode extends Node {
+ public static final class CastToNode extends Node {
+ private static final CastToNode UNCACHED =
+ new CastToNode(
+ EnsoMultiType.FindIndexNode.getUncached(),
+ NewNode.getUncached(),
+ AllTypesWith.getUncached());
+ @Child private EnsoMultiType.FindIndexNode findNode;
+ @Child private NewNode newNode;
+ @Child private AllTypesWith allTypesWith;
+
+ private CastToNode(EnsoMultiType.FindIndexNode f, NewNode n, AllTypesWith a) {
+ this.findNode = f;
+ this.newNode = n;
+ this.allTypesWith = a;
+ }
+
+ @NeverDefault
+ public static CastToNode create() {
+ return new CastToNode(
+ EnsoMultiType.FindIndexNode.create(), NewNode.create(), AllTypesWith.create());
+ }
+
+ @NeverDefault
+ @TruffleBoundary
+ public static CastToNode getUncached() {
+ return UNCACHED;
+ }
+
/**
* Casts value in a multi value into specific type.
*
@@ -438,44 +543,32 @@ public abstract static class CastToNode extends Node {
*/
public final Object findTypeOrNull(
Type type, EnsoMultiValue mv, boolean reorderOnly, boolean allTypes) {
- return executeCast(type, mv, reorderOnly, allTypes);
- }
-
- abstract Object executeCast(
- Type type, EnsoMultiValue mv, boolean reorderOnly, boolean allTypes);
-
- @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, boolean reorderOnly, boolean allTypes) {
- var ctx = EnsoContext.get(this);
- var max = allTypes ? mv.types.length : mv.methodDispatchTypes;
- for (var i = 0; i < max; i++) {
- for (var t : mv.types[i].allTypes(ctx)) {
- if (t == type) {
- if (reorderOnly) {
- var copyTypes = mv.types.clone();
- var copyValues = mv.values.clone();
- copyTypes[i] = mv.types[0];
- copyValues[i] = mv.values[0];
- copyTypes[0] = mv.types[i];
- copyValues[0] = mv.values[i];
- return EnsoMultiValue.create(copyTypes, 1, copyValues);
- } else {
- return mv.values[i];
- }
+ var dispatch = mv.dispatch;
+ var i = findNode.executeFindIndex(type, dispatch);
+ if (i == -1 && allTypes) {
+ var extraIndex = findNode.executeFindIndex(type, mv.extra);
+ i = extraIndex == -1 ? -1 : dispatch.typesLength() + extraIndex;
+ }
+ if (i != -1) {
+ if (reorderOnly) {
+ var copyTypes = allTypesWith.executeAllTypes(dispatch, mv.extra);
+ if (i == 0 && dispatch.typesLength() == 1) {
+ return newNode.newValue(copyTypes, 1, mv.values);
+ } else {
+ copyTypes = copyTypes.clone();
+ var copyValues = mv.values.clone();
+ copyTypes[0] = copyTypes[i];
+ copyValues[0] = copyValues[i];
+ copyTypes[i] = dispatch.firstType();
+ copyValues[i] = mv.values[0];
+ return newNode.newValue(copyTypes, 1, copyValues);
}
+ } else {
+ return mv.values[i];
}
+ } else {
+ return null;
}
- return null;
}
}
@@ -490,11 +583,10 @@ public final Pair resolveSymbol(
MethodResolverNode node, UnresolvedSymbol symbol) {
var ctx = EnsoContext.get(node);
Pair foundAnyMethod = null;
- for (var i = 0; i < methodDispatchTypes; i++) {
- var t = types[i];
+ for (var t : EnsoMultiType.AllTypesWith.getUncached().executeAllTypes(dispatch, null)) {
var fnAndType = node.execute(t, symbol);
if (fnAndType != null) {
- if (methodDispatchTypes == 1 || fnAndType.getRight() != ctx.getBuiltins().any()) {
+ if (dispatch.typesLength() == 1 || fnAndType.getRight() != ctx.getBuiltins().any()) {
return Pair.create(fnAndType.getLeft(), t);
}
foundAnyMethod = fnAndType;
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java
index 468bbbbffa5f..e1a5a55ae42a 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/PanicException.java
@@ -55,10 +55,7 @@ public PanicException(Object payload, Node location) {
*/
public PanicException(Object payload, Throwable cause, Node location) {
super(null, cause, UNLIMITED_STACK_TRACE, location);
- if (!InteropLibrary.isValidValue(payload)) {
- CompilerDirectives.transferToInterpreter();
- throw new IllegalArgumentException("Only interop values are supported: " + payload);
- }
+ assert InteropLibrary.isValidValue(payload) : "Only interop values are supported: " + payload;
this.payload = payload;
}