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

Every builtin type has a common super class #11861

Merged
merged 35 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
007d74c
All builtin types extend BuiltinObject
Akirathan Dec 13, 2024
dc01c8e
Fix names in Builtins
Akirathan Dec 13, 2024
1fe2f3e
Builtin annotation processor enforces subclassing BuiltinObject
Akirathan Dec 13, 2024
60d854b
fix typo
Akirathan Dec 13, 2024
0d92891
Add BuiltinsJavaInteropTest
Akirathan Dec 13, 2024
8feab15
Update docs
Akirathan Dec 13, 2024
7510906
[WIP] Try to remove builtin type caching in BuiltinObject
Akirathan Dec 16, 2024
78002d1
Revert "[WIP] Try to remove builtin type caching in BuiltinObject"
Akirathan Dec 16, 2024
fcd043f
BuiltinObject guards cached builtin type with WeakReference to context
Akirathan Dec 16, 2024
78b1832
Utility class has private constructor
Akirathan Dec 17, 2024
b310f6c
Revert "BuiltinObject guards cached builtin type with WeakReference t…
Akirathan Dec 17, 2024
b58a29d
[WIP] Throw AssertionError on context mismatch in cached builtin type.
Akirathan Dec 17, 2024
8bfea5d
[WIP] Append name of the builtin to the assertion error
Akirathan Dec 17, 2024
0f5dcc9
[WIP] Record stack trace of cached builtin type
Akirathan Dec 17, 2024
4dbfdb6
builtin name is fetched from annotation
Akirathan Dec 18, 2024
fab5b90
Add unnecessary Builtin annotations
Akirathan Dec 18, 2024
d9f733e
Buil;tinObject contains no fields and caches receiver class
Akirathan Dec 18, 2024
08136c4
builtin anot processor does not hardcode switch for Text
Akirathan Dec 18, 2024
bd8ff66
fmt
Akirathan Dec 18, 2024
3221115
Revert "builtin anot processor does not hardcode switch for Text"
Akirathan Dec 18, 2024
ce17f5f
BuiltinObject has abstract builtinName method
Akirathan Dec 18, 2024
0de4099
Revert Builtin annotation
Akirathan Dec 18, 2024
8eae88c
Revert fab5b901dc19725e1d5a956e958f531bc8f177cc
Akirathan Dec 18, 2024
a28f50d
Revert Builtin.name values to develop
Akirathan Dec 18, 2024
73fafc0
fmt
Akirathan Dec 18, 2024
a58012c
Revert "Fix names in Builtins"
Akirathan Dec 18, 2024
9092a0a
BuiltinObject.GetType does not access annotation for builtin name
Akirathan Dec 18, 2024
99a62c3
Reintroduce static singleton vectors in Vector
Akirathan Dec 18, 2024
2854937
Remove unnecessary empty protected constructors
Akirathan Dec 18, 2024
4a2aa02
Merge branch 'develop' into wip/akirathan/builtin-object
Akirathan Dec 23, 2024
7a2ea7c
BuiltinObject is final and has package-protected constructor
Akirathan Dec 23, 2024
32bd042
Do not call `EnsoContext.get(null)`.
Akirathan Dec 23, 2024
36e39c2
Add TruffleBoundary.
Akirathan Dec 23, 2024
7969907
Replace Fallback with Specialization with replaces
Akirathan Dec 24, 2024
b8111b0
fmt
Akirathan Dec 24, 2024
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
@@ -0,0 +1,20 @@
package org.enso.example;

import java.time.LocalDate;
import org.graalvm.polyglot.Value;

public final class PolyglotTestClass {
private PolyglotTestClass() {}

public static boolean isPolyglotDate_Object(Object obj) {
return obj instanceof Value polyglotVal && polyglotVal.isDate();
}

public static boolean isPolyglotDate_LocalDate(LocalDate date) {
return date != null;
}

public static boolean isPolyglotDate_Value(Value val) {
return val != null && val.isDate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.enso.interpreter.test.builtins;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

import java.io.ByteArrayOutputStream;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* In these tests, we call Java methods from Enso. Java methods have different signatures that
* accept Enso values in different ways.
*/
public class BuiltinsJavaInteropTest {
private static Context ctx;
private static final ByteArrayOutputStream out = new ByteArrayOutputStream();

@BeforeClass
public static void prepareCtx() {
ctx = ContextUtils.createDefaultContext(out);
}

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

@After
public void resetOutput() {
out.reset();
}

/**
* This test reflects the state of many Java methods in stdlibs that accept Enso values as {@link
* java.lang.Object}. If the Java method has a single argument of type {@link java.lang.Object},
* and we pass {@code Date_Time} in it, we expect the host interop conversion to convert it to
* {@link java.time.LocalDateTime}.
*/
@Test
public void javaMethodAcceptsEnsoTimeOfDay_AsObject() {
var src =
"""
from Standard.Base import Date_Time
polyglot java import org.enso.example.PolyglotTestClass

main =
dt = Date_Time.now
PolyglotTestClass.isPolyglotDate_Object dt
""";
var result = ContextUtils.evalModule(ctx, src);
assertThat(result.asBoolean(), is(true));
}

@Test
public void javaMethodAcceptsEnsoTimeOfDay_AsLocalDate() {
var src =
"""
from Standard.Base import Date_Time
polyglot java import org.enso.example.PolyglotTestClass

main =
dt = Date_Time.now
PolyglotTestClass.isPolyglotDate_LocalDate dt
""";
var result = ContextUtils.evalModule(ctx, src);
assertThat(result.asBoolean(), is(true));
}

@Test
public void javaMethodAcceptsEnsoTimeOfDay_AsValue() {
var src =
"""
from Standard.Base import Date_Time
polyglot java import org.enso.example.PolyglotTestClass

main =
dt = Date_Time.now
PolyglotTestClass.isPolyglotDate_Value dt
""";
var result = ContextUtils.evalModule(ctx, src);
assertThat(result.asBoolean(), is(true));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.enso.interpreter.runtime.builtin;

import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Idempotent;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.node.expression.builtin.Builtin;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;

/**
* Base class for every Enso builtin object. Not type. Note that base class for a builtin type is
* {@link Builtin}.
*
* <p>In other words, this class represents an object of builtin type in a similar way that {@link
* org.enso.interpreter.runtime.data.atom.Atom} represents an object of a non-builtin type.
*/
@ExportLibrary(InteropLibrary.class)
@ExportLibrary(TypesLibrary.class)
public abstract class BuiltinObject extends EnsoObject {

@ExportMessage
public final boolean hasType() {
return true;
}

/**
* Returns the name of the builtin as saved inside {@link Builtins#builtinsByName}. Not fully
* qualified.
*
* @return
*/
protected abstract String builtinName();

protected final Type getBuiltinType() {
return GetType.uncached(this);
}

/**
* Must return false, otherwise if a builtin object is passed to a host method that has a single
* {@code Object} argument, host interop would convert the builtin object to a {@code Map} with
* all its members. Even if the builtin object is, e.g., a number of a date.
*
* <p>Must return false as long as all our stdlib Java methods accept {@code Object} and not
* {@link org.graalvm.polyglot.Value} as arguments comming from Enso.
*/
@ExportMessage
public final boolean hasMembers() {
return false;
}

@ExportMessage
public final Object getMembers(boolean includeInternal) throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}

@ExportMessage
public final boolean hasMetaObject() {
return true;
}

@ExportMessage(name = "getType", library = TypesLibrary.class)
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
@ExportMessage(name = "getMetaObject", library = InteropLibrary.class)
public static class GetType {
Akirathan marked this conversation as resolved.
Show resolved Hide resolved

/**
* Caching on class of the receiver - as long as there is the same class, its {@link
* #builtinName()} method will return the same value. Note that we don't want to cache on the
* builtin name, as that would create a separate polymorph cache for every instance of the
* receiver.
*/
@Specialization(
guards = {"cachedReceiverClass == receiver.getClass()", "getCtx(node) == cachedCtx"},
limit = "1")
public static Type doItCached(
BuiltinObject receiver,
@Bind("$node") Node node,
@Cached("receiver.getClass()") Class<? extends BuiltinObject> cachedReceiverClass,
@Cached(value = "getCtx(node)", allowUncached = true) EnsoContext cachedCtx,
@Cached(value = "getBuiltinType(receiver, cachedCtx)", allowUncached = true)
Builtin cachedBuiltinType) {
return cachedBuiltinType.getType();
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
}

@Fallback
public static Type uncached(BuiltinObject receiver) {
var ctx = getCtx(null);
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
return getBuiltinType(receiver, ctx).getType();
}

public static Builtin getBuiltinType(BuiltinObject receiver, EnsoContext ctx) {
return ctx.getBuiltins().getBuiltinType(receiver.builtinName());
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
}

@Idempotent
public static EnsoContext getCtx(Node node) {
return EnsoContext.get(node);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
package org.enso.interpreter.runtime.data;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.Node;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import org.enso.interpreter.dsl.Builtin;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.builtin.BuiltinObject;
import org.enso.polyglot.common_utils.Core_Date_Utils;

@ExportLibrary(InteropLibrary.class)
@ExportLibrary(TypesLibrary.class)
@Builtin(pkg = "date", name = "Date", stdlibName = "Standard.Base.Data.Time.Date.Date")
public final class EnsoDate extends EnsoObject {
public final class EnsoDate extends BuiltinObject {
private final LocalDate date;

public EnsoDate(LocalDate date) {
this.date = date;
}

@Override
protected String builtinName() {
return "Date";
}

@Builtin.Method(description = "Return current Date", autoRegister = false)
@CompilerDirectives.TruffleBoundary
public static EnsoDate today() {
Expand Down Expand Up @@ -77,26 +78,6 @@ LocalTime asTime() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}

@ExportMessage
Type getMetaObject(@Bind("$node") Node node) {
return EnsoContext.get(node).getBuiltins().date();
}

@ExportMessage
boolean hasMetaObject() {
return true;
}

@ExportMessage
boolean hasType() {
return true;
}

@ExportMessage
Type getType(@Bind("$node") Node node) {
return EnsoContext.get(node).getBuiltins().date();
}

@CompilerDirectives.TruffleBoundary
@ExportMessage
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
package org.enso.interpreter.runtime.data;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.Node;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import org.enso.interpreter.dsl.Builtin;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.BuiltinObject;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.polyglot.common_utils.Core_Date_Utils;

@ExportLibrary(InteropLibrary.class)
@ExportLibrary(TypesLibrary.class)
@Builtin(
pkg = "date",
name = "DateTime",
stdlibName = "Standard.Base.Data.Time.Date_Time.Date_Time")
public final class EnsoDateTime extends EnsoObject {
public final class EnsoDateTime extends BuiltinObject {
private final ZonedDateTime dateTime;

public EnsoDateTime(ZonedDateTime dateTime) {
this.dateTime = dateTime;
}

@Override
protected String builtinName() {
return "Date_Time";
}

@Builtin.Method(
name = "epoch_start",
description = "Return the Enso start of the Epoch",
Expand Down Expand Up @@ -205,26 +205,6 @@ ZoneId asTimeZone() {
return dateTime.getZone();
}

@ExportMessage
Type getMetaObject(@CachedLibrary("this") InteropLibrary thisLib) {
return EnsoContext.get(thisLib).getBuiltins().dateTime();
}

@ExportMessage
boolean hasMetaObject() {
return true;
}

@ExportMessage
boolean hasType() {
return true;
}

@ExportMessage
Type getType(@Bind("$node") Node node) {
return EnsoContext.get(node).getBuiltins().dateTime();
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
}

@ExportMessage
@CompilerDirectives.TruffleBoundary
@Override
Expand Down
Loading
Loading