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

Members on Atom and Type include inherited methods from Any #12099

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
87cece0
Test members on Atom and Type include inherited methods from Any
Akirathan Jan 21, 2025
bd458d0
Add test for consistency between Meta.get_type_methods and interop me…
Akirathan Jan 21, 2025
58b825b
Type has methods from Any as members
Akirathan Jan 22, 2025
8aa5131
Atom has instance methods from Any as members
Akirathan Jan 22, 2025
ede07e2
Update AtomInteropTest
Akirathan Jan 22, 2025
34bd4e2
Update TypeMembersTest
Akirathan Jan 22, 2025
d8ebddf
Member names are not qualified
Akirathan Jan 22, 2025
8ced357
GetTypeMethodsNode delegates to Type.getMethods
Akirathan Jan 22, 2025
d2c0d2d
Update Meta_Spec test
Akirathan Jan 22, 2025
5bb54a4
Fix Locale.predefined_locale_fields
Akirathan Jan 22, 2025
3ec63bc
Update Array_Spec test
Akirathan Jan 22, 2025
6ed4a20
Fix constants in RuntimeTypesTest
Akirathan Jan 22, 2025
3c6050d
Remove member key size test from ExecCompilerTest
Akirathan Jan 22, 2025
049dd6d
Remove prop size test from DebuggingEnsoTest
Akirathan Jan 22, 2025
d5d7d05
Fix constants in RuntimeErrorsTest
Akirathan Jan 22, 2025
f94e7c1
Merge branch 'develop' into wip/akirathan/12045-type-get-members
Akirathan Jan 22, 2025
cae43f7
Update engine/runtime-integration-tests/src/test/java/org/enso/interp…
Akirathan Jan 23, 2025
9b98189
Add test for members from Number hierarchy
Akirathan Jan 23, 2025
106b35d
Include methods from the whole type hierarchy
Akirathan Jan 23, 2025
2edaa22
Collect expected methods
Akirathan Jan 23, 2025
80e80e4
Keep overriden methods.
Akirathan Jan 23, 2025
e69ce1c
Type.Invoke member uses InvokeCallableNode
Akirathan Jan 24, 2025
07c403c
Don't replace instance methods with static methods from eigen type
Akirathan Jan 24, 2025
8a4d67e
Add minimal reproducer for failing RUntimeErrorsTest
Akirathan Jan 24, 2025
9d99e37
Add tests for MethodResolverNode
Akirathan Jan 24, 2025
b95e3ea
Add MethodInvocationOnTypeConsistencyTest
Akirathan Jan 27, 2025
d14550b
Merge branch 'develop' into wip/akirathan/12045-type-get-members
Akirathan Jan 28, 2025
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
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"
Copy link
Member

Choose a reason for hiding this comment

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

This one should be private unless something horribly breaks.

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 @@ -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
@@ -1,8 +1,10 @@
package org.enso.interpreter.test.interop;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
Expand All @@ -11,8 +13,11 @@
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import java.util.ArrayList;
import java.util.List;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -35,6 +40,25 @@ public void disposeCtx() {
ctx = null;
}

@Test
public void atomMemberNames_AreNotQualified() {
var myTypeAtom =
ContextUtils.evalModule(
ctx,
"""
import Standard.Base.Any.Any

type My_Type
Cons field_1 field_2

main =
My_Type.Cons 1 2
""");
assertThat(myTypeAtom.hasMembers(), is(true));
var memberNames = myTypeAtom.getMemberKeys();
assertThat("Member names are not qualified", memberNames, hasItem(not(containsString("."))));
}

@Test
public void atomMembersAreConstructorFields_SingleConstructor() {
var myTypeAtom =
Expand All @@ -49,13 +73,11 @@ public void atomMembersAreConstructorFields_SingleConstructor() {
""");
assertThat(myTypeAtom.hasMembers(), is(true));
var memberNames = myTypeAtom.getMemberKeys();
assertThat("Has two fields", memberNames.size(), is(2));
assertThat(
"Member names are not qualified", memberNames, containsInAnyOrder("field_1", "field_2"));
for (var memberName : memberNames) {
var member = myTypeAtom.getMember(memberName);
assertThat("Member " + memberName + " should be readable", member, is(notNullValue()));
assertThat("All fields are numbers", member.isNumber(), is(true));
assertThat("Has at least two fields", memberNames.size(), is(greaterThan(2)));
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
for (var consName : List.of("field_1", "field_2")) {
var member = myTypeAtom.getMember(consName);
assertThat("Member " + consName + " should be readable", member, is(notNullValue()));
assertThat("Cons field is number", member.isNumber(), is(true));
}
}

Expand Down Expand Up @@ -111,7 +133,7 @@ public void atomMembersAreConstructorFields_ManyConstructors() {
assertThat(
"Member names correspond to constructor field names for a single constructor",
myTypeAtom.getMemberKeys(),
containsInAnyOrder("g1", "g2", "g3"));
allOf(hasItem("g1"), hasItem("g2"), hasItem("g3"), not(hasItem("h1"))));
}

@Test
Expand Down Expand Up @@ -142,12 +164,17 @@ public void methodIsAtomMember_InteropLibrary() {

main = My_Type.Cons "a" "b"
""");
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var interop = InteropLibrary.getUncached();
assertThat("Atom has members", interop.hasMembers(atom), is(true));
assertThat("Method is readable", interop.isMemberReadable(atom, "method"), is(true));
assertThat("Method is invocable", interop.isMemberInvocable(atom, "method"), is(true));
assertThat("Field is readable", interop.isMemberReadable(atom, "a"), is(true));
ContextUtils.executeInContext(
ctx,
() -> {
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var interop = InteropLibrary.getUncached();
assertThat("Atom has members", interop.hasMembers(atom), is(true));
assertThat("Method is readable", interop.isMemberReadable(atom, "method"), is(true));
assertThat("Method is invocable", interop.isMemberInvocable(atom, "method"), is(true));
assertThat("Field is readable", interop.isMemberReadable(atom, "a"), is(true));
return null;
});
}

@Test
Expand Down Expand Up @@ -225,6 +252,67 @@ public void allMethodsAreInternalMembers() {
is(true));
}

/**
* Builtin methods from Any are present even if the Standard.Base.Any module is not imported.
*
* @throws Exception
*/
@Test
public void internalMembersIncludeMethodsFromAny_WithoutImport() throws Exception {
var myTypeAtom =
ContextUtils.evalModule(
ctx,
"""
type My_Type
Cons a

main = My_Type.Cons "a"
""");
ContextUtils.executeInContext(
ctx,
() -> {
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var memberNames = getAllMemberNames(atom);
var anyBuiltinMethods = ContextUtils.builtinMethodsFromAny(ctx);
for (var method : anyBuiltinMethods) {
assertThat(
"Builtin method (from Any) is a member of atom", memberNames, hasItem(method));
}
return null;
});
}

/**
* When Standard.Base.Any module is imported, all the methods (both builtin and non-builtin) from
* Any should be present as internal members of the atom.
*/
@Test
public void internalMembersIncludeMethodsFromAny_WithImport() throws Exception {
ContextUtils.executeInContext(
ctx,
() -> {
var myTypeAtom =
ContextUtils.evalModule(
ctx,
"""
from Standard.Base.Any import all

type My_Type
Cons a

main = My_Type.Cons "a"
""");
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var memberNames = getAllMemberNames(atom);
var anyMethods = ContextUtils.allMethodsFromAny(ctx);
for (var method : anyMethods) {
assertThat(
"Non-builtin method (from Any) is a member of atom", memberNames, hasItem(method));
}
return null;
});
}

@Test
public void allMembersAreReadableAndInvocable()
throws UnsupportedMessageException, InvalidArrayIndexException {
Expand All @@ -239,20 +327,25 @@ public void allMembersAreReadableAndInvocable()

main = My_Type.Cons "a"
""");
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var interop = InteropLibrary.getUncached();
var members = interop.getMembers(atom, true);
for (long i = 0; i < interop.getArraySize(members); i++) {
var memberName = interop.asString(interop.readArrayElement(members, i));
assertThat(
"Member " + memberName + " should be readable",
interop.isMemberReadable(atom, memberName),
is(true));
assertThat(
"Member " + memberName + " should be invocable",
interop.isMemberInvocable(atom, memberName),
is(true));
}
ContextUtils.executeInContext(
ctx,
() -> {
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var interop = InteropLibrary.getUncached();
var members = interop.getMembers(atom, true);
for (long i = 0; i < interop.getArraySize(members); i++) {
var memberName = interop.asString(interop.readArrayElement(members, i));
assertThat(
"Member " + memberName + " should be readable",
interop.isMemberReadable(atom, memberName),
is(true));
assertThat(
"Member " + memberName + " should be invocable",
interop.isMemberInvocable(atom, memberName),
is(true));
}
return null;
});
}

@Test
Expand Down Expand Up @@ -335,19 +428,24 @@ public void staticMethodIsNotAtomMember() {

@Test
public void constructorIsNotAtomMember_InteropLibrary() {
var myTypeAtom =
ContextUtils.evalModule(
ctx,
"""
type My_Type
Cons a b
method self = 42

main = My_Type.Cons "a" "b"
""");
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var interop = InteropLibrary.getUncached();
assertThat("Cons is not atom member", interop.isMemberExisting(atom, "Cons"), is(false));
ContextUtils.executeInContext(
ctx,
() -> {
var myTypeAtom =
ContextUtils.evalModule(
ctx,
"""
type My_Type
Cons a b
method self = 42

main = My_Type.Cons "a" "b"
""");
var atom = ContextUtils.unwrapValue(ctx, myTypeAtom);
var interop = InteropLibrary.getUncached();
assertThat("Cons is not atom member", interop.isMemberExisting(atom, "Cons"), is(false));
return null;
});
}

@Test
Expand All @@ -369,4 +467,20 @@ public void typeMembersAreConstructors() {
myType.getMember("Cons_1").canInstantiate(),
is(true));
}

/**
* @param obj {@link ContextUtils#unwrapValue(Context, Value) unwrapped} {@link Value value}.
*/
private List<String> getAllMemberNames(Object obj)
throws UnsupportedMessageException, InvalidArrayIndexException {
var interop = InteropLibrary.getUncached();
var allMembers = interop.getMembers(obj, true);
var memberNames = new ArrayList<String>();
for (var i = 0; i < interop.getArraySize(allMembers); i++) {
var member = interop.readArrayElement(allMembers, i);
var memberName = interop.asString(member);
memberNames.add(memberName);
}
return memberNames;
}
}
Loading
Loading