Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Giving TypeOfNode richer query API #11618

Merged
merged 11 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private static Context ctx() {
ctx = ContextUtils.createDefaultContext();

Copy link
Member Author

@JaroslavTulach JaroslavTulach Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might make a difference in initialization time for example in testOnly command - e.g. when the class is loaded, but no test is executed, right?

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
Loading