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 20 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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"
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
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
package org.enso.interpreter.test.interop;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
Expand Down Expand Up @@ -102,7 +111,76 @@ public void ensureNonBuiltinMembersArePresent() throws Exception {

var module = ctx.eval(src);
var compileError = module.invokeMember("eval_expression", "v");
assertEquals("all members", Set.of("to_display_text", "message"), compileError.getMemberKeys());
assertEquals(
"all members",
Set.of("to_display_text", "message", "to_text", "==", "catch_primitive", "pretty"),
compileError.getMemberKeys());
}

@Test
public void inheritedMembersFromAnyAreIncluded() {
var type =
ContextUtils.evalModule(
ctx,
"""
from Standard.Base.Any import all

type My_Type
method self = 42

main = My_Type
""");
ContextUtils.executeInContext(
ctx,
() -> {
var typeUnwrapped = ContextUtils.unwrapValue(ctx, type);
var memberNames = getAllMemberNames(typeUnwrapped);
var anyMethods = ContextUtils.allMethodsFromAny(ctx);
for (var anyMethod : anyMethods) {
assertThat("Has method from Any", memberNames, hasItem(containsString(anyMethod)));
}
return null;
});
}

@Test
public void typeMemberNames_AreNotQualified() {
var type =
ContextUtils.evalModule(
ctx,
"""
from Standard.Base.Any import all

type My_Type
method self = 42

main = My_Type
""");
ContextUtils.executeInContext(
ctx,
() -> {
var typeUnwrapped = ContextUtils.unwrapValue(ctx, type);
var memberNames = getAllMemberNames(typeUnwrapped);
assertThat(
"Member names are not qualified", memberNames, not(hasItem(containsString("."))));
return null;
});
}

/**
* @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;
}

private static void assertMembers(String msg, Value v, String... keys) {
Expand Down
Loading
Loading