mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 14:52:01 +03:00
Make sure Enso FrameDescriptors have non-null default value (#6977)
This commit is contained in:
parent
e6652b8c9f
commit
9f39fb30b7
@ -16,7 +16,7 @@ import org.enso.polyglot.runtime.Runtime$Api$BackgroundJobsStartedNotification;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$CreateContextRequest;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$CreateContextResponse;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$EditFileNotification;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$ExecutionFailed;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$ExecutionComplete;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$ExpressionUpdates;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$InitializedNotification;
|
||||
import org.enso.polyglot.runtime.Runtime$Api$MethodCall;
|
||||
@ -107,8 +107,11 @@ public class IncrementalUpdatesTest {
|
||||
|
||||
@Test
|
||||
public void sendNotANumberChange() {
|
||||
var failed = sendUpdatesWhenFunctionBodyIsChangedBySettingValue("4", ConstantsGen.INTEGER, "4", "x", null, LiteralNode.class);
|
||||
assertTrue("Execution failed: " + failed, failed.head().payload() instanceof Runtime$Api$ExecutionFailed);
|
||||
var result = sendUpdatesWhenFunctionBodyIsChangedBySettingValue("4", ConstantsGen.INTEGER, "4", "x", null, LiteralNode.class);
|
||||
assertTrue("Execution succeeds: " + result, result.head().payload() instanceof Runtime$Api$ExecutionComplete);
|
||||
assertEquals("Error is printed as a result",
|
||||
List.newBuilder().addOne("(Error: Uninitialized value)"), context.consumeOut()
|
||||
);
|
||||
}
|
||||
|
||||
private static String extractPositions(String code, String chars, Map<Character, int[]> beginAndLength) {
|
||||
|
@ -0,0 +1,94 @@
|
||||
package org.enso.interpreter.test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Language;
|
||||
import org.graalvm.polyglot.Source;
|
||||
import org.junit.After;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class InsightForEnsoTest {
|
||||
private Context ctx;
|
||||
private AutoCloseable insightHandle;
|
||||
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
@Before
|
||||
public void initContext() throws Exception {
|
||||
this.ctx = Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath()
|
||||
)
|
||||
.logHandler(OutputStream.nullOutputStream())
|
||||
.allowExperimentalOptions(true)
|
||||
.allowIO(true)
|
||||
.out(out)
|
||||
.allowAllAccess(true)
|
||||
.build();
|
||||
|
||||
var engine = ctx.getEngine();
|
||||
Map<String, Language> langs = engine.getLanguages();
|
||||
assertNotNull("Enso found: " + langs, langs.get("enso"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
var fn = (Function<Source,AutoCloseable>) engine.getInstruments().get("insight").lookup(Function.class);
|
||||
assertNotNull(fn);
|
||||
|
||||
var insightScript = Source.newBuilder("js", """
|
||||
insight.on('enter', (ctx, frame) => {
|
||||
print(`${ctx.name} at ${ctx.source.name}:${ctx.line}:`);
|
||||
let dump = "";
|
||||
for (let p in frame) {
|
||||
dump += ` ${p}=${frame[p]}`;
|
||||
}
|
||||
print(dump);
|
||||
}, {
|
||||
roots : true
|
||||
});
|
||||
""", "trace.js").build();
|
||||
this.insightHandle = fn.apply(insightScript);
|
||||
}
|
||||
|
||||
@After
|
||||
public void disposeContext() throws Exception {
|
||||
this.insightHandle.close();
|
||||
this.ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void computeFactorial() throws Exception {
|
||||
var code = Source.newBuilder("enso", """
|
||||
fac n =
|
||||
acc n v = if n <= 1 then v else
|
||||
@Tail_Call acc n-1 n*v
|
||||
|
||||
acc n 1
|
||||
""", "factorial.enso").build();
|
||||
|
||||
var m = ctx.eval(code);
|
||||
var fac = m.invokeMember("eval_expression", "fac");
|
||||
var res = fac.execute(5);
|
||||
assertEquals(120, res.asInt());
|
||||
|
||||
var msgs = out.toString();
|
||||
assertNotEquals("Step one: " + msgs, -1, msgs.indexOf("n=5 v=1 acc=function"));
|
||||
assertNotEquals("Step two: " + msgs, -1, msgs.indexOf("n=4 v=5 acc=function"));
|
||||
assertNotEquals("3rd step: " + msgs, -1, msgs.indexOf("n=3 v=20 acc=function"));
|
||||
assertNotEquals("4th step: " + msgs, -1, msgs.indexOf("n=2 v=60 acc=function"));
|
||||
|
||||
assertNotEquals(
|
||||
"Uninitialized variables are seen as JavaScript null: " + msgs,
|
||||
-1, msgs.indexOf("n=null v=null acc=function")
|
||||
);
|
||||
}
|
||||
}
|
@ -9,10 +9,7 @@ import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
@ -1,8 +1,14 @@
|
||||
package org.enso.interpreter.runtime.builtin;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -10,8 +16,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import org.enso.compiler.Passes;
|
||||
import org.enso.compiler.context.FreshNameSupply;
|
||||
import org.enso.compiler.exception.CompilerError;
|
||||
@ -19,16 +24,20 @@ import org.enso.compiler.phase.BuiltinsIrBuilder;
|
||||
import org.enso.interpreter.EnsoLanguage;
|
||||
import org.enso.interpreter.dsl.TypeProcessor;
|
||||
import org.enso.interpreter.dsl.model.MethodDefinition;
|
||||
import org.enso.interpreter.node.expression.builtin.Any;
|
||||
import org.enso.interpreter.node.expression.builtin.Boolean;
|
||||
import org.enso.interpreter.node.expression.builtin.*;
|
||||
import org.enso.interpreter.node.expression.builtin.Builtin;
|
||||
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
|
||||
import org.enso.interpreter.node.expression.builtin.Nothing;
|
||||
import org.enso.interpreter.node.expression.builtin.Polyglot;
|
||||
import org.enso.interpreter.node.expression.builtin.debug.Debug;
|
||||
import org.enso.interpreter.node.expression.builtin.error.CaughtPanic;
|
||||
import org.enso.interpreter.node.expression.builtin.error.Warning;
|
||||
import org.enso.interpreter.node.expression.builtin.immutable.Vector;
|
||||
import org.enso.interpreter.node.expression.builtin.io.File;
|
||||
import org.enso.interpreter.node.expression.builtin.meta.ProjectDescription;
|
||||
import org.enso.interpreter.node.expression.builtin.mutable.Array;
|
||||
import org.enso.interpreter.node.expression.builtin.mutable.Ref;
|
||||
import org.enso.interpreter.node.expression.builtin.immutable.Vector;
|
||||
import org.enso.interpreter.node.expression.builtin.ordering.Comparable;
|
||||
import org.enso.interpreter.node.expression.builtin.ordering.DefaultComparator;
|
||||
import org.enso.interpreter.node.expression.builtin.ordering.Ordering;
|
||||
@ -37,24 +46,18 @@ import org.enso.interpreter.node.expression.builtin.runtime.Context;
|
||||
import org.enso.interpreter.node.expression.builtin.text.Text;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.Module;
|
||||
import org.enso.interpreter.runtime.builtin.Error;
|
||||
import org.enso.interpreter.runtime.builtin.Number;
|
||||
import org.enso.interpreter.runtime.builtin.System;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.type.TypesFromProxy;
|
||||
import org.enso.pkg.QualifiedName;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** Container class for static predefined atoms, methods, and their containing scope. */
|
||||
public class Builtins {
|
||||
public final class Builtins {
|
||||
|
||||
private static final List<Constructor<? extends Builtin>> loadedBuiltinConstructors;
|
||||
private static final Map<String, LoadedBuiltinMethod> loadedBuiltinMethods;
|
||||
@ -133,12 +136,9 @@ public class Builtins {
|
||||
builtinMethodNodes = readBuiltinMethodsMetadata(loadedBuiltinMethods, scope);
|
||||
registerBuiltinMethods(scope, language);
|
||||
|
||||
error = new Error(this, context);
|
||||
ordering = getBuiltinType(Ordering.class);
|
||||
comparable = getBuiltinType(Comparable.class);
|
||||
defaultComparator = getBuiltinType(DefaultComparator.class);
|
||||
system = new System(this);
|
||||
number = new Number(this);
|
||||
bool = this.getBuiltinType(Boolean.class);
|
||||
contexts = this.getBuiltinType(Context.class);
|
||||
|
||||
@ -161,8 +161,12 @@ public class Builtins {
|
||||
duration = builtins.get(org.enso.interpreter.node.expression.builtin.date.Duration.class);
|
||||
timeOfDay = builtins.get(org.enso.interpreter.node.expression.builtin.date.TimeOfDay.class);
|
||||
timeZone = builtins.get(org.enso.interpreter.node.expression.builtin.date.TimeZone.class);
|
||||
special = new Special(language);
|
||||
warning = builtins.get(Warning.class);
|
||||
|
||||
error = new Error(this, context);
|
||||
system = new System(this);
|
||||
number = new Number(this);
|
||||
special = new Special(language);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,7 @@ import org.enso.interpreter.runtime.data.text.Text;
|
||||
import static com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate;
|
||||
|
||||
/** Container for builtin Error types */
|
||||
public class Error {
|
||||
public final class Error {
|
||||
private final EnsoContext context;
|
||||
private final SyntaxError syntaxError;
|
||||
private final TypeError typeError;
|
||||
|
@ -9,6 +9,7 @@ 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.util.Objects;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
@ -21,7 +22,10 @@ import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
*/
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
public class DataflowError extends AbstractTruffleException {
|
||||
public final class DataflowError extends AbstractTruffleException {
|
||||
/** Signals (local) values that haven't yet been initialized */
|
||||
public static final DataflowError UNINITIALIZED = new DataflowError(null, (Node) null);
|
||||
|
||||
private final Object payload;
|
||||
|
||||
/**
|
||||
@ -34,6 +38,7 @@ public class DataflowError extends AbstractTruffleException {
|
||||
* @return a new dataflow error
|
||||
*/
|
||||
public static DataflowError withoutTrace(Object payload, Node location) {
|
||||
assert payload != null;
|
||||
DataflowError result = new DataflowError(payload, location);
|
||||
TruffleStackTrace.fillIn(result);
|
||||
return result;
|
||||
@ -50,6 +55,7 @@ public class DataflowError extends AbstractTruffleException {
|
||||
* @return a new dataflow error
|
||||
*/
|
||||
public static DataflowError withTrace(Object payload, AbstractTruffleException prototype) {
|
||||
assert payload != null;
|
||||
return new DataflowError(payload, prototype);
|
||||
}
|
||||
|
||||
@ -69,7 +75,7 @@ public class DataflowError extends AbstractTruffleException {
|
||||
* @return the payload object
|
||||
*/
|
||||
public Object getPayload() {
|
||||
return payload;
|
||||
return payload != null ? payload : "Uninitialized value";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,18 +84,17 @@ public class DataflowError extends AbstractTruffleException {
|
||||
* @return a string representation of this object
|
||||
*/
|
||||
@Override
|
||||
@TruffleBoundary
|
||||
public String toString() {
|
||||
return "Error:" + getPayload().toString();
|
||||
return "Error:" + Objects.toString(getPayload());
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@TruffleBoundary
|
||||
public String toDisplayString(
|
||||
boolean allowSideEffects,
|
||||
@CachedLibrary(limit = "3") InteropLibrary displays,
|
||||
@CachedLibrary(limit = "3") InteropLibrary strings) {
|
||||
public String toDisplayString(boolean allowSideEffects) {
|
||||
try {
|
||||
return "(Error: " + strings.asString(displays.toDisplayString(payload)) + ")";
|
||||
var iop = InteropLibrary.getUncached();
|
||||
return "(Error: " + iop.asString(iop.toDisplayString(getPayload())) + ")";
|
||||
} catch (UnsupportedMessageException e) {
|
||||
return "Error";
|
||||
}
|
||||
@ -110,6 +115,11 @@ public class DataflowError extends AbstractTruffleException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean isNull() {
|
||||
return payload == null;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
RuntimeException throwException() throws UnsupportedMessageException {
|
||||
return this;
|
||||
|
@ -8,6 +8,7 @@ import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{
|
||||
Scope => AliasScope
|
||||
}
|
||||
import org.enso.compiler.pass.analyse.{AliasAnalysis, DataflowAnalysis}
|
||||
import org.enso.interpreter.runtime.error.DataflowError
|
||||
import org.enso.interpreter.runtime.scope.LocalScope.{
|
||||
internalSlots,
|
||||
monadicStateSlotName
|
||||
@ -162,6 +163,7 @@ class LocalScope(
|
||||
)
|
||||
assert(localFrameSlotIdxs(definition.id) == returnedFrameIdx)
|
||||
}
|
||||
descriptorBuilder.defaultValue(DataflowError.UNINITIALIZED)
|
||||
val frameDescriptor = descriptorBuilder.build()
|
||||
assert(
|
||||
internalSlots.length + localFrameSlotIdxs.size == frameDescriptor.getNumberOfSlots
|
||||
|
@ -6,9 +6,12 @@ import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.PolyglotException;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ExecCompilerTest {
|
||||
private static Context ctx;
|
||||
@ -66,6 +69,37 @@ public class ExecCompilerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelfAssignment() throws Exception {
|
||||
var module = ctx.eval("enso", """
|
||||
from Standard.Base.Errors.Common import all
|
||||
run value =
|
||||
meta1 = meta1
|
||||
meta1
|
||||
""");
|
||||
var run = module.invokeMember("eval_expression", "run");
|
||||
var error = run.execute(-1);
|
||||
assertTrue("We get an error value back", error.isException());
|
||||
assertTrue("The error value also represents null", error.isNull());
|
||||
assertEquals("(Error: Uninitialized value)", error.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursiveDefinition() throws Exception {
|
||||
var module = ctx.eval("enso", """
|
||||
from Standard.Base import all
|
||||
|
||||
run prefix =
|
||||
op = if False then 42 else prefix+op
|
||||
op
|
||||
""");
|
||||
var run = module.invokeMember("eval_expression", "run");
|
||||
var error = run.execute("Nope: ");
|
||||
assertTrue("We get an error value back", error.isException());
|
||||
assertTrue("The error value also represents null", error.isNull());
|
||||
assertEquals("(Error: Uninitialized value)", error.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidEnsoProjectRef() throws Exception {
|
||||
var module =
|
||||
|
Loading…
Reference in New Issue
Block a user