Skip to content

Commit

Permalink
Giving TypeOfNode richer query API (enso-org#11618)
Browse files Browse the repository at this point in the history
  • Loading branch information
JaroslavTulach authored Nov 22, 2024
1 parent d611939 commit 7c5e692
Show file tree
Hide file tree
Showing 22 changed files with 366 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private String typeOf(Object value) {
resultType = Constants.UNRESOLVED_SYMBOL;
} else {
var typeOfNode = TypeOfNode.getUncached();
Object typeResult = value == null ? null : typeOfNode.execute(value);
Object typeResult = value == null ? null : typeOfNode.findTypeOrError(value);
if (typeResult instanceof Type t) {
resultType = getTypeQualifiedName(t);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ object ProgramExecutionSupport {
Array[Object](
visualization.id,
expressionId,
Try(TypeOfNode.getUncached.execute(expressionValue))
Try(TypeOfNode.getUncached.findTypeOrError(expressionValue))
.getOrElse(expressionValue.getClass)
)
)
Expand Down Expand Up @@ -640,8 +640,7 @@ object ProgramExecutionSupport {
Option(error.getMessage).getOrElse(error.getClass.getSimpleName)
if (!TypesGen.isPanicSentinel(expressionValue)) {
val typeOfNode =
Option(TypeOfNode.getUncached.execute(expressionValue))
.getOrElse(expressionValue.getClass)
TypeOfNode.getUncached.findTypeOrError(expressionValue)
ctx.executionService.getLogger.log(
Level.WARNING,
"Execution of visualization [{0}] on value [{1}] of [{2}] failed. {3} | {4} | {5}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import com.oracle.truffle.api.interop.InteropLibrary;
import org.enso.interpreter.node.expression.foreign.HostValueToEnsoNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
Expand All @@ -23,9 +22,6 @@
import org.junit.Test;

public class CatchPanicNodeTest {

private static final InteropLibrary interop = InteropLibrary.getUncached();

private static Context context;
private static CatchPanicNode catchPanicNode;
private static HostValueToEnsoNode hostValueToEnsoNode;
Expand Down Expand Up @@ -110,7 +106,7 @@ public void catchAnyPanic() throws Exception {
var args =
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
assertEquals("One argument expected", 1, args.length);
var argType = TypeOfNode.getUncached().execute(args[0]);
var argType = TypeOfNode.getUncached().findTypeOrError(args[0]);
if (argType == ctx.getBuiltins().caughtPanic().getType()) {
assertThat(args[0].toString(), Matchers.containsString("Thrown"));
return text;
Expand Down Expand Up @@ -147,7 +143,7 @@ public void catchAnyPanicSentinel() throws Exception {
var args =
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
assertEquals("One argument expected", 1, args.length);
var argType = TypeOfNode.getUncached().execute(args[0]);
var argType = TypeOfNode.getUncached().findTypeOrError(args[0]);
if (argType == ctx.getBuiltins().caughtPanic().getType()) {
assertThat(args[0].toString(), Matchers.containsString("Thrown"));
return text;
Expand Down Expand Up @@ -184,7 +180,7 @@ public void catchSpecificPanic() throws Exception {
var args =
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
assertEquals("One argument expected", 1, args.length);
var argType = TypeOfNode.getUncached().execute(args[0]);
var argType = TypeOfNode.getUncached().findTypeOrError(args[0]);
if (argType == ctx.getBuiltins().caughtPanic().getType()) {
assertThat(args[0].toString(), Matchers.containsString("Thrown"));
return text;
Expand Down Expand Up @@ -221,7 +217,7 @@ public void catchSpecificPanicSentinel() throws Exception {
var args =
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
assertEquals("One argument expected", 1, args.length);
var argType = TypeOfNode.getUncached().execute(args[0]);
var argType = TypeOfNode.getUncached().findTypeOrError(args[0]);
if (argType == ctx.getBuiltins().caughtPanic().getType()) {
assertThat(args[0].toString(), Matchers.containsString("Thrown"));
return text;
Expand Down Expand Up @@ -258,7 +254,7 @@ public void dontCatchSpecificPanic() throws Exception {
var args =
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
assertEquals("One argument expected", 1, args.length);
var argType = TypeOfNode.getUncached().execute(args[0]);
var argType = TypeOfNode.getUncached().findTypeOrError(args[0]);
if (argType == ctx.getBuiltins().caughtPanic().getType()) {
assertThat(args[0].toString(), Matchers.containsString("Thrown"));
return text;
Expand Down Expand Up @@ -300,7 +296,7 @@ public void dontCatchSpecificPanicSentinel() throws Exception {
var args =
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
assertEquals("One argument expected", 1, args.length);
var argType = TypeOfNode.getUncached().execute(args[0]);
var argType = TypeOfNode.getUncached().findTypeOrError(args[0]);
if (argType == ctx.getBuiltins().caughtPanic().getType()) {
assertThat(args[0].toString(), Matchers.containsString("Thrown"));
return text;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.enso.interpreter.node.expression.builtin.meta;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import com.oracle.truffle.api.RootCallTarget;
import java.util.ArrayList;
import java.util.Arrays;
import org.enso.interpreter.runtime.data.EnsoMultiValue;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
import org.enso.interpreter.test.ValuesGenerator;
import org.enso.test.utils.ContextUtils;
import org.enso.test.utils.TestRootNode;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class TypeOfNodeMultiValueTest {

private static RootCallTarget testTypesCall;

@Parameterized.Parameter(0)
public Object value;

@Parameterized.Parameter(1)
public String type;

@Parameterized.Parameter(2)
public int typeIndex;

private static Context ctx;

private static Context ctx() {
if (ctx == null) {
ctx = ContextUtils.defaultContextBuilder().build();
ContextUtils.executeInContext(
ctx,
() -> {
var node = TypeOfNode.create();
var root =
new TestRootNode(
(frame) -> {
var arg = frame.getArguments()[0];
var t = node.findTypeOrError(arg);
var all = node.findAllTypesOrNull(arg);
return new Object[] {t, all};
});
root.insertChildren(node);
testTypesCall = root.getCallTarget();
return null;
});
}
assertNotNull("Test types call initialized", testTypesCall);
return ctx;
}

@Parameterized.Parameters
public static Object[][] allPossibleEnsoInterpreterValues() throws Exception {
var g = ValuesGenerator.create(ctx());
var typeOf =
ContextUtils.evalModule(
ctx(),
"""
from Standard.Base import all
typ obj = Meta.type_of obj
main = typ
""");
var data = new ArrayList<Object[]>();
for (var polyValue : g.allValues()) {
registerValue(g, typeOf, polyValue, data);
}
return data.toArray(new Object[0][]);
}

private static void registerValue(
ValuesGenerator g, Value typeOf, Value polyValue, ArrayList<Object[]> data) {
var t = typeOf.execute(polyValue);
if (!polyValue.isNull()) {
assertTrue("Type of " + polyValue + " is " + t, t.isMetaObject());
var rawValue = ContextUtils.unwrapValue(ctx(), polyValue);
var rawType = ContextUtils.unwrapValue(ctx(), t);
if (rawType instanceof Type type) {
var singleMultiValue = EnsoMultiValue.create(new Type[] {type}, new Object[] {rawValue});
var n = t.getMetaSimpleName();
data.add(new Object[] {singleMultiValue, n, 0});
var rawInt = (Type) ContextUtils.unwrapValue(ctx(), g.typeInteger());
var secondMultiValue =
EnsoMultiValue.create(new Type[] {rawInt, type}, new Object[] {5L, rawValue});
data.add(new Object[] {secondMultiValue, n, 1});
var firstMultiValue =
EnsoMultiValue.create(new Type[] {type, rawInt}, new Object[] {rawValue, 6L});
data.add(new Object[] {firstMultiValue, n, 0});
} else {
if (!t.isHostObject()) {
data.add(new Object[] {rawValue, null, -1});
}
}
}
}

@AfterClass
public static void disposeCtx() throws Exception {
if (ctx != null) {
ctx.close();
ctx = null;
}
}

@Test
public void typeOfCheck() {
assertType(value, type, typeIndex);
}

private static void assertType(Object value, String expectedTypeName, int typeIndex) {
assertNotNull("Value " + value + " should have a type", expectedTypeName);
ContextUtils.executeInContext(
ctx(),
() -> {
var pairResult = (Object[]) testTypesCall.call(value);
var t = pairResult[0];
var all = (Object[]) pairResult[1];

Object symbolType;
if (t instanceof DataflowError) {
assertNull("No types for errors", all);
symbolType = t;
} else {
assertNotNull("All types found for " + value, all);
assertTrue(
"Size is at least " + typeIndex + " but was: " + Arrays.toString(all),
all.length >= typeIndex);
assertEquals("Major type is the same with first of allTypes for" + value, t, all[0]);
symbolType = all[typeIndex];
}

var symbolTypeValue = ctx.asValue(symbolType);
assertTrue("It is meta object: " + symbolTypeValue, symbolTypeValue.isMetaObject());
assertEquals(expectedTypeName, symbolTypeValue.getMetaSimpleName());
return null;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.util.ArrayList;
import org.enso.interpreter.runtime.callable.UnresolvedConstructor;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
import org.enso.interpreter.test.ValuesGenerator;
Expand Down Expand Up @@ -80,12 +81,29 @@ public void typeOfCheckAfterPriming() {
assertType(value, type, true);
}

private void assertType(Object symbol, String expectedTypeName, boolean withPriming) {
private static void assertType(Object symbol, String expectedTypeName, boolean withPriming) {
ContextUtils.executeInContext(
ctx(),
() -> {
var node = TypeOfNode.create();
var root = new TestRootNode((frame) -> node.execute(frame.getArguments()[0]));
var root =
new TestRootNode(
(frame) -> {
var arg = frame.getArguments()[0];
var typeOrNull = node.findTypeOrNull(arg);
var typeOrError = node.findTypeOrError(arg);
if (typeOrNull == null) {
if (typeOrError instanceof EnsoObject) {
assertTrue(
"Expecting error for " + arg, typeOrError instanceof DataflowError);
} else {
// probably HostMetaObject
}
} else {
assertEquals("Types should be the same for " + arg, typeOrNull, typeOrError);
}
return typeOrError;
});
root.insertChildren(node);
var call = root.getCallTarget();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ abstract Object executeThatConversion(
VirtualFrame frame, String symbol, Object self, Object that);

static Type findType(TypeOfNode typeOfNode, Object obj) {
var rawType = typeOfNode.execute(obj);
return rawType instanceof Type type ? type : null;
return typeOfNode.findTypeOrNull(obj);
}

static Type findTypeUncached(Object obj) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.error.DataflowError;
Expand Down Expand Up @@ -57,7 +56,7 @@ abstract Object execute(
int thatArgumentPosition);

static boolean hasType(TypeOfNode typeOfNode, Object value) {
return typeOfNode.execute(value) instanceof Type;
return typeOfNode.hasType(value);
}

@Specialization(guards = {"hasType(typeOfNode, that)"})
Expand All @@ -81,7 +80,7 @@ Object doConvertFrom(
conversionResolverNode.expectNonNull(
that,
InvokeConversionNode.extractType(this, self),
(Type) typeOfNode.execute(that),
typeOfNode.findTypeOrNull(that),
conversion);
return indirectInvokeFunctionNode.execute(
function,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private Type extractType(Object self) {
}

static boolean hasType(TypeOfNode typeOfNode, Object value) {
return typeOfNode.execute(value) instanceof Type;
return typeOfNode.hasType(value);
}

static boolean isDataflowError(Object value) {
Expand All @@ -119,7 +119,7 @@ Object doConvertFrom(
Object[] arguments,
@Shared("typeOfNode") @Cached TypeOfNode dispatch,
@Shared("conversionResolverNode") @Cached ConversionResolverNode resolveNode) {
var thatType = (Type) dispatch.execute(that);
var thatType = dispatch.findTypeOrNull(that);
if (thatType == self) {
return that;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void doPolyglotValue(
Object state,
Object target,
@CachedLibrary(limit = "3") InteropLibrary interop) {
Object tpeOfTarget = typeOfNode.execute(target);
Object tpeOfTarget = typeOfNode.findTypeOrError(target);
boolean test = isSameObject.execute(polyglotSymbol, tpeOfTarget);
if (profile.profile(test)) {
accept(frame, state, new Object[] {target});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ EqualsAndInfo equalsAtomsWithCustomComparator(
@TruffleBoundary
private static boolean orderingOrNullOrError(
Node where, EnsoContext ctx, Object obj, Function fn) {
var type = TypeOfNode.getUncached().execute(obj);
var type = TypeOfNode.getUncached().findTypeOrError(obj);
if (type == ctx.getBuiltins().ordering().getType()) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public static EqualsNode getUncached() {
public EqualsAndInfo execute(VirtualFrame frame, Object self, Object other) {
var areEqual = node.execute(frame, self, other);
if (!areEqual.isTrue()) {
var selfType = types.execute(self);
var otherType = types.execute(other);
var selfType = types.findTypeOrNull(self);
var otherType = types.findTypeOrNull(other);
if (selfType != otherType) {
if (convert == null) {
CompilerDirectives.transferToInterpreter();
Expand Down Expand Up @@ -101,8 +101,7 @@ static WithConversionNode create() {
abstract EqualsAndInfo executeWithConversion(VirtualFrame frame, Object self, Object that);

static Type findType(TypeOfNode typeOfNode, Object obj) {
var rawType = typeOfNode.execute(obj);
return rawType instanceof Type type ? type : null;
return typeOfNode.findTypeOrNull(obj);
}

static Type findTypeUncached(Object obj) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Object doExecute(
@Cached ThunkExecutorNode thunkExecutorNode,
@Cached ExpectStringNode expectStringNode,
@Cached TypeOfNode typeOfNode) {
Object targetTypeResult = typeOfNode.execute(target);
Object targetTypeResult = typeOfNode.findTypeOrError(target);
if (targetTypeResult instanceof DataflowError error) {
return error;
}
Expand Down
Loading

0 comments on commit 7c5e692

Please sign in to comment.