Skip to content

Commit

Permalink
Members on Atom and Type include inherited methods from Any (#12099)
Browse files Browse the repository at this point in the history
* Test members on Atom and Type include inherited methods from Any

* Add test for consistency between Meta.get_type_methods and interop members on Type.

* Type has methods from Any as members

* Atom has instance methods from Any as members

* Update AtomInteropTest

* Update TypeMembersTest

* Member names are not qualified

* GetTypeMethodsNode delegates to Type.getMethods

* Update Meta_Spec test

* Fix Locale.predefined_locale_fields

* Update Array_Spec test

* Fix constants in RuntimeTypesTest

* Remove member key size test from ExecCompilerTest

* Remove prop size test from DebuggingEnsoTest

* Fix constants in RuntimeErrorsTest

* Update engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/interop/AtomInteropTest.java

Co-authored-by: Jaroslav Tulach <[email protected]>

* Add test for members from Number hierarchy

* Include methods from the whole type hierarchy

* Collect expected methods

* Keep overriden methods.

* Type.Invoke member uses InvokeCallableNode

* Don't replace instance methods with static methods from eigen type

* Add minimal reproducer for failing RUntimeErrorsTest

* Add tests for MethodResolverNode

* Add MethodInvocationOnTypeConsistencyTest

* Add ArgumentMappingTest

* Use resolveFunction from InvokeMethodNode

* Extract shouldPrependSyntheticSelfArg from InvokeMethodNode

* Ignore consistency tests

* Methods are found on eigen types

* When invoking members on type, the type must be first argument

* Add TypeMembersTest.builtinMethodIsPresent

* Fix slow context access error

* When invoking members on type, the type must be first argument

* fmt

---------

Co-authored-by: Jaroslav Tulach <[email protected]>
  • Loading branch information
Akirathan and JaroslavTulach authored Feb 25, 2025
1 parent ba5f651 commit 6790780
Show file tree
Hide file tree
Showing 20 changed files with 1,116 additions and 148 deletions.
21 changes: 19 additions & 2 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Data/Locale.enso
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,25 @@ type Locale
predefined_locale_fields : Vector Text
predefined_locale_fields =
locale_meta = Meta.meta Locale
remove_us = locale_meta.methods + ["Value", "new", "default", "from_language_tag", "from_java", "predefined_locale_fields", "default_widget", "widget_options"]
Meta.Type.Value (Meta.type_of locale_meta.value) . methods . filter (Filter_Condition.Is_In remove_us ..Remove) . sort
methods_to_remove = Vector.build bldr->
bldr.append "Value"
bldr.append "new"
bldr.append "default"
bldr.append "from_language_tag"
bldr.append "from_java"
bldr.append "java_locale"
bldr.append "predefined_locale_fields"
bldr.append "default_widget"
bldr.append "widget_options"
bldr.append "display_country"
bldr.append "display_variant"
bldr.append "display_language"
bldr.append "variant"
bldr.append "language"
bldr.append "country"
bldr.append "default"
bldr.append_vector_range <| Meta.meta Any . methods
locale_meta . methods . filter (Filter_Condition.Is_In methods_to_remove ..Remove) . sort

## PRIVATE
widget_options : Vector Option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ public void redefinedArgument() throws Exception {
var run = module.invokeMember("eval_expression", "My_Type.Value");
var atom = run.newInstance(1, 2, 3, 4);
assertFalse("In spite of error we get an instance back: " + atom, atom.isException());
assertEquals("Just three keys", 3, atom.getMemberKeys().size());
assertTrue("Check a: " + atom.getMemberKeys(), atom.getMemberKeys().contains("a"));
assertTrue("Check b: " + atom.getMemberKeys(), atom.getMemberKeys().contains("b"));
assertTrue("Check c: " + atom.getMemberKeys(), atom.getMemberKeys().contains("c"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ public static void closeCtx() throws Exception {
}

private static Value getRef(Value ref) {
return refType.invokeMember("get", ref);
return refType.invokeMember("get", refType, ref);
}

private static Value newRef(Object object) {
return refType.invokeMember("new", object);
return refType.invokeMember("new", refType, object);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -643,18 +643,10 @@ public void testAtomFieldsAreReadable() {
assertThat(objValue.isInternal(), is(false));
assertThat(objValue.hasReadSideEffects(), is(false));

var field1Prop = objValue.getProperty("field_1");
assertThat(field1Prop.isReadable(), is(true));
assertThat(field1Prop.isNumber(), is(true));
assertThat(field1Prop.asInt(), is(1));

assertThat(objValue.getProperties().size(), is(2));
for (var prop : objValue.getProperties()) {
assertThat(
"Property '" + prop.getName() + "' should be readable",
prop.isReadable(),
is(true));
assertThat(prop.isNumber(), is(true));
for (var propName : List.of("field_1", "field_2")) {
var fieldProp = objValue.getProperty(propName);
assertThat(fieldProp.isReadable(), is(true));
assertThat(fieldProp.isNumber(), is(true));
}
}
}
Expand Down Expand Up @@ -690,13 +682,10 @@ public void testAtomFieldAreReadable_MultipleConstructors() {
assertThat(objValue.isInternal(), is(false));
assertThat(objValue.hasReadSideEffects(), is(false));

assertThat("Has fields f1 and f2", objValue.getProperties().size(), is(2));
for (var prop : objValue.getProperties()) {
assertThat(
"Property '" + prop.getName() + "' should be readable",
prop.isReadable(),
is(true));
assertThat(prop.isNumber(), is(true));
for (var propName : List.of("f1", "f2")) {
var fieldProp = objValue.getProperty(propName);
assertThat(fieldProp.isReadable(), is(true));
assertThat(fieldProp.isNumber(), is(true));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package org.enso.interpreter.test;

import static org.enso.test.utils.ContextUtils.createDefaultContext;
import static org.enso.test.utils.ContextUtils.evalModule;
import static org.enso.test.utils.ContextUtils.executeInContext;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;

import org.enso.interpreter.Constants.Names;
import org.enso.interpreter.node.callable.resolver.MethodResolverNode;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public final class MethodResolutionTest {
private static MethodResolverNode methodResolverNode;
private static Context ctx;

@BeforeClass
public static void initCtx() {
ctx = createDefaultContext();
executeInContext(
ctx,
() -> {
methodResolverNode = MethodResolverNode.getUncached();
return null;
});
}

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

@Test
public void resolveStaticMethodFromAny() {
var myTypeVal =
evalModule(
ctx,
"""
from Standard.Base import all
type My_Type
method self = 42
main = My_Type
""");
executeInContext(
ctx,
() -> {
var myType = unwrapType(myTypeVal);
var symbol = UnresolvedSymbol.build("to_display_text", myType.getDefinitionScope());
var func = methodResolverNode.executeResolution(myType, symbol);
assertThat("to_display_text method is found", func, is(notNullValue()));
assertSingleSelfArgument(func);
return null;
});
}

@Test
public void resolveInstanceMethodFromMyType() {
var myTypeVal =
evalModule(
ctx,
"""
type My_Type
method self = 42
main = My_Type
""",
"Module",
"main");
executeInContext(
ctx,
() -> {
var myType = unwrapType(myTypeVal);
var symbol = UnresolvedSymbol.build("method", myType.getDefinitionScope());
var func = methodResolverNode.executeResolution(myType, symbol);
assertThat("method is found", func, is(notNullValue()));
assertSingleSelfArgument(func);
return null;
});
}

@Test
public void resolveStaticMethodFromMyType() {
var myTypeVal =
evalModule(
ctx,
"""
type My_Type
method = 42
main = My_Type
""",
"Module",
"main");
executeInContext(
ctx,
() -> {
var myType = unwrapType(myTypeVal);
var symbol = UnresolvedSymbol.build("method", myType.getDefinitionScope());
var func = methodResolverNode.executeResolution(myType, symbol);
assertThat("method is found", func, is(notNullValue()));
assertSingleSelfArgument(func);
return null;
});
}

@Test
public void resolveExtensionMethodFromMyType() {
var myTypeVal =
evalModule(
ctx,
"""
type My_Type
My_Type.method = 42
main = My_Type
""",
"Module",
"main");
executeInContext(
ctx,
() -> {
var myType = unwrapType(myTypeVal);
var symbol = UnresolvedSymbol.build("method", myType.getDefinitionScope());
var func = methodResolverNode.executeResolution(myType, symbol);
assertThat("method is found", func, is(notNullValue()));
assertSingleSelfArgument(func);
return null;
});
}

private void assertSingleSelfArgument(Function func) {
assertThat("Has single self argument", func.getSchema().getArgumentsCount(), is(1));
assertThat(
"Has single self argument",
func.getSchema().getArgumentInfos()[0].getName(),
is(Names.SELF_ARGUMENT));
}

private Type unwrapType(Value val) {
var unwrapped = ContextUtils.unwrapValue(ctx, val);
return (Type) unwrapped;
}
}
Loading

0 comments on commit 6790780

Please sign in to comment.