mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 17:41:53 +03:00
WithWarnings uses EnsoHashMap to speed things up (#10555)
Majority of warnings handling is now done via newly introduced nodes. Moreover, the underlying representation of warnings storage in `WithWarnings` was changed from `Warning[]` to `EnsoHashMap`. # Important Notes - Remove `ArrayRope`.
This commit is contained in:
parent
3a4b942aae
commit
c2c6712b77
@ -1422,6 +1422,7 @@ lazy val `interpreter-dsl-test` =
|
||||
)
|
||||
.dependsOn(`interpreter-dsl`)
|
||||
.dependsOn(`runtime`)
|
||||
.dependsOn(`test-utils`)
|
||||
|
||||
// ============================================================================
|
||||
// === Sub-Projects ===========================================================
|
||||
|
@ -255,36 +255,6 @@ type Warning
|
||||
origin : Vector Stack_Trace_Element
|
||||
origin self = @Builtin_Method "Warning.origin"
|
||||
|
||||
## PRIVATE
|
||||
ADVANCED
|
||||
|
||||
A list of locations where the warning was reassigned in the order of
|
||||
latest-first.
|
||||
|
||||
Warnings are reassigned whenever they interact with specific language
|
||||
elements:
|
||||
- When pattern matching, the warnings of the scrutinee will be reassigned
|
||||
to the `case` expression result.
|
||||
- When calling a method, warnings assigned to `self` will be reassigned to
|
||||
the method return value.
|
||||
- When calling a polyglot function or method, warnings assigned to any
|
||||
arguments will be accumulated in the return value.
|
||||
- The standard library methods reassign warnings such that their dataflow
|
||||
nature is preserved.
|
||||
reassignments : Vector Stack_Trace_Element
|
||||
reassignments self =
|
||||
Vector.from_polyglot_array self.get_reassignments . map r->
|
||||
loc = case Polyglot.has_source_location r of
|
||||
False -> Nothing
|
||||
True -> Source_Location.Value (Polyglot.get_source_location r)
|
||||
Stack_Trace_Element.Value (Polyglot.get_executable_name r) loc
|
||||
|
||||
## PRIVATE
|
||||
|
||||
Builtin method for getting the list of locations where the warnings was reassigned.
|
||||
Should use `Warning.reassignments` instead.
|
||||
get_reassignments : Array Any
|
||||
get_reassignments self = @Builtin_Method "Warning.get_reassignments"
|
||||
|
||||
## PRIVATE
|
||||
|
||||
|
@ -8,6 +8,7 @@ import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||
import com.oracle.truffle.api.nodes.RootNode;
|
||||
import org.enso.interpreter.node.InlineableNode;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.test.utils.ContextUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
public class InliningBuiltinsTest {
|
||||
@ -17,26 +18,33 @@ public class InliningBuiltinsTest {
|
||||
*/
|
||||
@Test
|
||||
public void executeWithoutVirtualFrame() {
|
||||
var fn = InliningBuiltinsInMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
var call = root.createInlineableNode();
|
||||
var clazz = call.getClass();
|
||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||
assertEquals(
|
||||
"org.enso.interpreter.node.InlineableNode$Root",
|
||||
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||
ContextUtils.executeInContext(
|
||||
ctx,
|
||||
() -> {
|
||||
var fn = InliningBuiltinsInMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
var call = root.createInlineableNode();
|
||||
var clazz = call.getClass();
|
||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||
assertEquals(
|
||||
"org.enso.interpreter.node.InlineableNode$Root",
|
||||
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
frame,
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 5L, 7L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
} else {
|
||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
frame,
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 5L, 7L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
} else {
|
||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,22 +53,29 @@ public class InliningBuiltinsTest {
|
||||
*/
|
||||
@Test
|
||||
public void executeWithVirtualFrame() {
|
||||
var fn = InliningBuiltinsOutMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode());
|
||||
} else {
|
||||
var call = DirectCallNode.create(fn.getCallTarget());
|
||||
var clazz = call.getClass().getSuperclass();
|
||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
||||
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||
ContextUtils.executeInContext(
|
||||
ctx,
|
||||
() -> {
|
||||
var fn = InliningBuiltinsOutMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode());
|
||||
} else {
|
||||
var call = DirectCallNode.create(fn.getCallTarget());
|
||||
var clazz = call.getClass().getSuperclass();
|
||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
||||
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 3L, 9L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 3L, 9L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,22 +84,29 @@ public class InliningBuiltinsTest {
|
||||
*/
|
||||
@Test
|
||||
public void executeWhenNeedsVirtualFrame() {
|
||||
var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode());
|
||||
} else {
|
||||
var call = DirectCallNode.create(fn.getCallTarget());
|
||||
var clazz = call.getClass().getSuperclass();
|
||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
||||
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||
ContextUtils.executeInContext(
|
||||
ctx,
|
||||
() -> {
|
||||
var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode());
|
||||
} else {
|
||||
var call = DirectCallNode.create(fn.getCallTarget());
|
||||
var clazz = call.getClass().getSuperclass();
|
||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
||||
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 3L, 9L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 3L, 9L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,26 +115,33 @@ public class InliningBuiltinsTest {
|
||||
*/
|
||||
@Test
|
||||
public void executeWhenNeedNotVirtualFrame() {
|
||||
var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
var call = root.createInlineableNode();
|
||||
var clazz = call.getClass();
|
||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||
assertEquals(
|
||||
"org.enso.interpreter.node.InlineableNode$Root",
|
||||
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||
ContextUtils.executeInContext(
|
||||
ctx,
|
||||
() -> {
|
||||
var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null);
|
||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||
var call = root.createInlineableNode();
|
||||
var clazz = call.getClass();
|
||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||
assertEquals(
|
||||
"org.enso.interpreter.node.InlineableNode$Root",
|
||||
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
frame,
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 5L, 7L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
} else {
|
||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||
var res =
|
||||
WithFrame.invoke(
|
||||
(frame) -> {
|
||||
return call.call(
|
||||
frame,
|
||||
Function.ArgumentsHelper.buildArguments(
|
||||
null, null, new Object[] {null, 5L, 7L}));
|
||||
});
|
||||
assertEquals(12L, res);
|
||||
} else {
|
||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ public final class Utils {
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.INFO.getName())
|
||||
.option(RuntimeOptions.DISABLE_IR_CACHES, "true")
|
||||
.option(RuntimeOptions.STRICT_ERRORS, "true")
|
||||
.option("engine.CompilationFailureAction", "Print")
|
||||
|
@ -73,29 +73,34 @@ public class WarningBenchmarks {
|
||||
|
||||
benchmarkName = SrcUtil.findName(params);
|
||||
|
||||
var code =
|
||||
new StringBuilder(
|
||||
"""
|
||||
var benchCode =
|
||||
"""
|
||||
from Standard.Base import all
|
||||
|
||||
vec_sum_bench : Vector Integer -> Integer
|
||||
vec_sum_bench vec =
|
||||
vec.fold 0 (x->y->x+y)
|
||||
""";
|
||||
|
||||
create_vec size elem =
|
||||
var setupCode =
|
||||
new StringBuilder(
|
||||
"""
|
||||
from Standard.Base import all
|
||||
|
||||
create_vec size elem = Runtime.no_inline <|
|
||||
Vector.fill size elem
|
||||
|
||||
elem =
|
||||
42
|
||||
|
||||
elem_const_with_warning =
|
||||
elem_const_with_warning = Runtime.no_inline <|
|
||||
x = 42
|
||||
Warning.attach "Foo!" x
|
||||
|
||||
elem_with_warning v =
|
||||
elem_with_warning v = Runtime.no_inline <|
|
||||
Warning.attach "Foo!" v
|
||||
|
||||
map_vector_with_warnings vec =
|
||||
map_vector_with_warnings vec = Runtime.no_inline <|
|
||||
vec.map (e-> elem_with_warning e)
|
||||
""");
|
||||
|
||||
@ -103,31 +108,37 @@ public class WarningBenchmarks {
|
||||
var randomIntVectorName = "vector_with_random_values";
|
||||
var vectorWithRandomValues =
|
||||
generateRandomVector(random, randomIntVectorName, INPUT_DIFF_VEC_SIZE, 3_000);
|
||||
code.append(vectorWithRandomValues.repr());
|
||||
setupCode.append(vectorWithRandomValues.repr());
|
||||
randomVectorSum = vectorWithRandomValues.sum();
|
||||
|
||||
var src = SrcUtil.source(benchmarkName, code.toString());
|
||||
Value module = ctx.eval(src);
|
||||
vecSumBench =
|
||||
Objects.requireNonNull(
|
||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "vec_sum_bench"));
|
||||
var setupSrc = SrcUtil.source(benchmarkName + "_Setup", setupCode.toString());
|
||||
Value setupModule = ctx.eval(setupSrc);
|
||||
createVec =
|
||||
Objects.requireNonNull(
|
||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create_vec"));
|
||||
setupModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create_vec"));
|
||||
mapVecWithWarnings =
|
||||
Objects.requireNonNull(
|
||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "map_vector_with_warnings"));
|
||||
setupModule.invokeMember(
|
||||
MethodNames.Module.EVAL_EXPRESSION, "map_vector_with_warnings"));
|
||||
constElem =
|
||||
Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem"));
|
||||
Objects.requireNonNull(
|
||||
setupModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem"));
|
||||
constElemWithWarning =
|
||||
Objects.requireNonNull(
|
||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem_const_with_warning"));
|
||||
setupModule.invokeMember(
|
||||
MethodNames.Module.EVAL_EXPRESSION, "elem_const_with_warning"));
|
||||
noWarningsVec = createVec.execute(INPUT_VEC_SIZE, constElem);
|
||||
sameWarningVec = createVec.execute(INPUT_VEC_SIZE, constElemWithWarning);
|
||||
randomVec =
|
||||
Objects.requireNonNull(
|
||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, randomIntVectorName));
|
||||
setupModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, randomIntVectorName));
|
||||
randomElemsWithWarningsVec = mapVecWithWarnings.execute(randomVec);
|
||||
|
||||
var benchSrc = SrcUtil.source(benchmarkName + "_Bench", benchCode);
|
||||
Value benchModule = ctx.eval(benchSrc);
|
||||
vecSumBench =
|
||||
Objects.requireNonNull(
|
||||
benchModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "vec_sum_bench"));
|
||||
}
|
||||
|
||||
@TearDown
|
||||
|
@ -5,7 +5,7 @@ import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
|
||||
public final class VisualizationResult {
|
||||
private VisualizationResult() {}
|
||||
|
@ -22,12 +22,7 @@ import org.enso.interpreter.runtime.`type`.{Types, TypesGen}
|
||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor
|
||||
import org.enso.interpreter.runtime.callable.function.Function
|
||||
import org.enso.interpreter.runtime.control.ThreadInterruptedException
|
||||
import org.enso.interpreter.runtime.error.{
|
||||
DataflowError,
|
||||
PanicSentinel,
|
||||
WarningsLibrary,
|
||||
WithWarnings
|
||||
}
|
||||
import org.enso.interpreter.runtime.error.{DataflowError, PanicSentinel}
|
||||
import org.enso.interpreter.service.ExecutionService.{
|
||||
ExpressionCall,
|
||||
ExpressionValue,
|
||||
@ -41,6 +36,11 @@ import org.enso.interpreter.service.error.{
|
||||
VisualizationException
|
||||
}
|
||||
import org.enso.common.LanguageInfo
|
||||
import org.enso.interpreter.runtime.warning.{
|
||||
Warning,
|
||||
WarningsLibrary,
|
||||
WithWarnings
|
||||
}
|
||||
import org.enso.polyglot.debugger.ExecutedVisualization
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.polyglot.runtime.Runtime.Api.{ContextId, ExecutionResult}
|
||||
@ -419,12 +419,9 @@ object ProgramExecutionSupport {
|
||||
value.getValue
|
||||
)
|
||||
) {
|
||||
val warnings =
|
||||
WarningsLibrary.getUncached.getWarnings(
|
||||
value.getValue,
|
||||
null,
|
||||
false
|
||||
)
|
||||
val warnsMap =
|
||||
WarningsLibrary.getUncached.getWarnings(value.getValue, false)
|
||||
val warnings = Warning.fromMapToArray(warnsMap)
|
||||
val warningsCount = warnings.length
|
||||
val warning =
|
||||
if (warningsCount > 0) {
|
||||
|
@ -6,12 +6,11 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.enso.common.LanguageInfo;
|
||||
import org.enso.common.MethodNames;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.Warning;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
import org.enso.test.utils.ContextUtils;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.PolyglotException;
|
||||
@ -33,11 +32,7 @@ public class WarningsTest {
|
||||
public static void initEnsoContext() {
|
||||
ctx = ContextUtils.createDefaultContext();
|
||||
generator = ValuesGenerator.create(ctx, ValuesGenerator.Language.ENSO);
|
||||
ensoContext =
|
||||
(EnsoContext)
|
||||
ctx.getBindings(LanguageInfo.ID)
|
||||
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
|
||||
.asHostObject();
|
||||
ensoContext = ContextUtils.leakContext(ctx);
|
||||
var module =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
@ -57,19 +52,22 @@ public class WarningsTest {
|
||||
|
||||
@Test
|
||||
public void doubleWithWarningsWrap() {
|
||||
var warn1 = Warning.create(ensoContext, "w1", this);
|
||||
var warn2 = Warning.create(ensoContext, "w2", this);
|
||||
var value = 42L;
|
||||
ContextUtils.executeInContext(
|
||||
ctx,
|
||||
() -> {
|
||||
var warn1 = Warning.create(ensoContext, "w1", this);
|
||||
var warn2 = Warning.create(ensoContext, "w2", this);
|
||||
var value = 42L;
|
||||
|
||||
var with1 = WithWarnings.wrap(ensoContext, value, warn1);
|
||||
var with2 = WithWarnings.wrap(ensoContext, with1, warn2);
|
||||
var with1 = AppendWarningNode.getUncached().executeAppend(null, value, warn1);
|
||||
var with2 = AppendWarningNode.getUncached().executeAppend(null, with1, warn2);
|
||||
|
||||
assertEquals(value, with1.getValue());
|
||||
assertEquals(value, with2.getValue());
|
||||
Assert.assertArrayEquals(
|
||||
new Object[] {warn1}, with1.getWarningsArray(WarningsLibrary.getUncached(), false));
|
||||
Assert.assertArrayEquals(
|
||||
new Object[] {warn1, warn2}, with2.getWarningsArray(WarningsLibrary.getUncached(), false));
|
||||
assertEquals(value, with1.getValue());
|
||||
assertEquals(value, with2.getValue());
|
||||
Assert.assertArrayEquals(new Object[] {warn1}, with1.getWarningsArray(false));
|
||||
Assert.assertArrayEquals(new Object[] {warn1, warn2}, with2.getWarningsArray(false));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -77,7 +75,7 @@ public class WarningsTest {
|
||||
var value = 42;
|
||||
WithWarnings without;
|
||||
try {
|
||||
without = WithWarnings.wrap(ensoContext, 42, new Warning[0]);
|
||||
without = AppendWarningNode.getUncached().executeAppend(null, 42, new Warning[0]);
|
||||
} catch (AssertionError e) {
|
||||
// OK
|
||||
return;
|
||||
|
@ -22,10 +22,9 @@ import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/**
|
||||
* Invokes any callable with given arguments.
|
||||
@ -74,7 +73,8 @@ public abstract class IndirectInvokeCallableNode extends Node {
|
||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||
BaseNode.TailStatus isTail,
|
||||
@Cached IndirectInvokeCallableNode invokeCallableNode,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached AppendWarningNode appendWarningNode) {
|
||||
try {
|
||||
var result =
|
||||
invokeCallableNode.execute(
|
||||
@ -87,8 +87,8 @@ public abstract class IndirectInvokeCallableNode extends Node {
|
||||
argumentsExecutionMode,
|
||||
isTail);
|
||||
|
||||
Warning[] extracted = warnings.getWarnings(warning, null, false);
|
||||
return WithWarnings.wrap(EnsoContext.get(this), result, extracted);
|
||||
var extracted = warnings.getWarnings(warning, false);
|
||||
return appendWarningNode.executeAppend(null, result, extracted);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
var ctx = EnsoContext.get(this);
|
||||
throw ctx.raiseAssertionPanic(this, null, e);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.enso.interpreter.node.callable;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
@ -19,15 +20,16 @@ import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
|
||||
@GenerateUncached
|
||||
@ReportPolymorphism
|
||||
@ -157,9 +159,16 @@ abstract class IndirectInvokeConversionNode extends Node {
|
||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||
BaseNode.TailStatus isTail,
|
||||
int thatArgumentPosition,
|
||||
@Cached IndirectInvokeConversionNode childDispatch) {
|
||||
@Cached IndirectInvokeConversionNode childDispatch,
|
||||
@Cached AppendWarningNode appendWarningNode,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnsLib) {
|
||||
arguments[thatArgumentPosition] = that.getValue();
|
||||
ArrayRope<Warning> warnings = that.getReassignedWarningsAsRope(this, false);
|
||||
EnsoHashMap warnings;
|
||||
try {
|
||||
warnings = warnsLib.getWarnings(that, false);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
}
|
||||
Object result =
|
||||
childDispatch.execute(
|
||||
frame,
|
||||
@ -173,7 +182,7 @@ abstract class IndirectInvokeConversionNode extends Node {
|
||||
argumentsExecutionMode,
|
||||
isTail,
|
||||
thatArgumentPosition);
|
||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
||||
return appendWarningNode.executeAppend(null, result, warnings);
|
||||
}
|
||||
|
||||
@Specialization(guards = "interop.isString(that)")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.enso.interpreter.node.callable;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Bind;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
@ -24,14 +25,15 @@ import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
|
||||
@GenerateUncached
|
||||
@ReportPolymorphism
|
||||
@ -129,9 +131,16 @@ public abstract class IndirectInvokeMethodNode extends Node {
|
||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||
BaseNode.TailStatus isTail,
|
||||
int thisArgumentPosition,
|
||||
@Cached IndirectInvokeMethodNode childDispatch) {
|
||||
@Cached IndirectInvokeMethodNode childDispatch,
|
||||
@Cached AppendWarningNode appendWarningNode,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnsLib) {
|
||||
arguments[thisArgumentPosition] = self.getValue();
|
||||
ArrayRope<Warning> warnings = self.getReassignedWarningsAsRope(this, false);
|
||||
EnsoHashMap warnings;
|
||||
try {
|
||||
warnings = warnsLib.getWarnings(self, false);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
}
|
||||
Object result =
|
||||
childDispatch.execute(
|
||||
frame,
|
||||
@ -144,7 +153,7 @@ public abstract class IndirectInvokeMethodNode extends Node {
|
||||
argumentsExecutionMode,
|
||||
isTail,
|
||||
thisArgumentPosition);
|
||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
||||
return appendWarningNode.executeAppend(null, result, warnings);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
|
@ -19,7 +19,6 @@ import java.util.UUID;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.node.BaseNode;
|
||||
import org.enso.interpreter.node.BaseNode.TailStatus;
|
||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
@ -31,14 +30,14 @@ import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.control.TailCallException;
|
||||
import org.enso.interpreter.runtime.data.atom.Atom;
|
||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/**
|
||||
* This class is responsible for performing the actual invocation of a given callable with its
|
||||
@ -287,12 +286,12 @@ public abstract class InvokeCallableNode extends BaseNode {
|
||||
VirtualFrame callerFrame,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
@Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
||||
|
||||
Warning[] extracted;
|
||||
@Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached AppendWarningNode appendWarningNode) {
|
||||
EnsoHashMap extracted;
|
||||
Object callable;
|
||||
try {
|
||||
extracted = warnings.getWarnings(warning, null, false);
|
||||
extracted = warnings.getWarnings(warning, false);
|
||||
callable = warnings.removeWarnings(warning);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
var ctx = EnsoContext.get(this);
|
||||
@ -325,7 +324,7 @@ public abstract class InvokeCallableNode extends BaseNode {
|
||||
if (result instanceof DataflowError) {
|
||||
return result;
|
||||
} else {
|
||||
return WithWarnings.wrap(EnsoContext.get(this), result, extracted);
|
||||
return appendWarningNode.executeAppend(null, result, extracted);
|
||||
}
|
||||
} catch (TailCallException e) {
|
||||
throw new TailCallException(e, extracted);
|
||||
|
@ -20,17 +20,18 @@ import org.enso.interpreter.runtime.callable.UnresolvedConversion;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.control.TailCallException;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.data.EnsoMultiValue;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
|
||||
public abstract class InvokeConversionNode extends BaseNode {
|
||||
private @Child InvokeFunctionNode invokeFunctionNode;
|
||||
@ -198,7 +199,9 @@ public abstract class InvokeConversionNode extends BaseNode {
|
||||
UnresolvedConversion conversion,
|
||||
Object self,
|
||||
WithWarnings that,
|
||||
Object[] arguments) {
|
||||
Object[] arguments,
|
||||
@Cached AppendWarningNode appendWarningNode,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnsLib) {
|
||||
// Cannot use @Cached for childDispatch, because we need to call notifyInserted.
|
||||
if (childDispatch == null) {
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
@ -223,12 +226,17 @@ public abstract class InvokeConversionNode extends BaseNode {
|
||||
}
|
||||
Object value = that.getValue();
|
||||
arguments[thatArgumentPosition] = value;
|
||||
ArrayRope<Warning> warnings = that.getReassignedWarningsAsRope(this, false);
|
||||
EnsoHashMap warnings;
|
||||
try {
|
||||
warnings = warnsLib.getWarnings(that, false);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
}
|
||||
try {
|
||||
Object result = childDispatch.execute(frame, state, conversion, self, value, arguments);
|
||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
||||
return appendWarningNode.executeAppend(null, result, warnings);
|
||||
} catch (TailCallException e) {
|
||||
throw new TailCallException(e, warnings.toArray(Warning[]::new));
|
||||
throw new TailCallException(e, warnings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@ import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.control.TailCallException;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.data.EnsoDate;
|
||||
import org.enso.interpreter.runtime.data.EnsoDateTime;
|
||||
import org.enso.interpreter.runtime.data.EnsoDuration;
|
||||
@ -51,15 +50,16 @@ import org.enso.interpreter.runtime.data.EnsoMultiValue;
|
||||
import org.enso.interpreter.runtime.data.EnsoTimeOfDay;
|
||||
import org.enso.interpreter.runtime.data.EnsoTimeZone;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
||||
public abstract class InvokeMethodNode extends BaseNode {
|
||||
@ -436,12 +436,13 @@ public abstract class InvokeMethodNode extends BaseNode {
|
||||
UnresolvedSymbol symbol,
|
||||
Object self,
|
||||
Object[] arguments,
|
||||
@Shared("warnings") @CachedLibrary(limit = "10") WarningsLibrary warnings) {
|
||||
@Shared("warnings") @CachedLibrary(limit = "10") WarningsLibrary warnings,
|
||||
@Shared @Cached AppendWarningNode appendWarningNode) {
|
||||
Object selfWithoutWarnings;
|
||||
Warning[] arrOfWarnings;
|
||||
EnsoHashMap warnsMap;
|
||||
try {
|
||||
selfWithoutWarnings = warnings.removeWarnings(self);
|
||||
arrOfWarnings = warnings.getWarnings(self, this, false);
|
||||
warnsMap = warnings.getWarnings(self, false);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
var ctx = EnsoContext.get(this);
|
||||
throw ctx.raiseAssertionPanic(this, null, e);
|
||||
@ -475,9 +476,10 @@ public abstract class InvokeMethodNode extends BaseNode {
|
||||
|
||||
try {
|
||||
Object result = childDispatch.execute(frame, state, symbol, selfWithoutWarnings, arguments);
|
||||
return WithWarnings.appendTo(EnsoContext.get(this), result, arrOfWarnings);
|
||||
return appendWarningNode.executeAppend(null, result, warnsMap);
|
||||
} catch (TailCallException e) {
|
||||
throw new TailCallException(e, arrOfWarnings);
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
throw new TailCallException(e, warnsMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,10 +507,13 @@ public abstract class InvokeMethodNode extends BaseNode {
|
||||
@Cached(value = "buildProfiles()", dimensions = 1) BranchProfile[] profiles,
|
||||
@Cached(value = "buildProfiles()", dimensions = 1) BranchProfile[] warningProfiles,
|
||||
@Cached BranchProfile anyWarningsProfile,
|
||||
@Cached HostMethodCallNode hostMethodCallNode) {
|
||||
@Cached HostMethodCallNode hostMethodCallNode,
|
||||
@Shared @Cached AppendWarningNode appendWarningNode,
|
||||
@Cached HashMapInsertAllNode mapInsertAllNode) {
|
||||
Object[] args = new Object[argExecutors.length];
|
||||
boolean anyWarnings = false;
|
||||
ArrayRope<Warning> accumulatedWarnings = new ArrayRope<>();
|
||||
var accumulatedWarnings = EnsoHashMap.empty();
|
||||
var maxWarnings = EnsoContext.get(this).getWarningsLimit();
|
||||
for (int i = 0; i < argExecutors.length; i++) {
|
||||
var r = argExecutors[i].executeThunk(frame, arguments[i + 1], state, TailStatus.NOT_TAIL);
|
||||
if (r instanceof DataflowError) {
|
||||
@ -518,7 +523,9 @@ public abstract class InvokeMethodNode extends BaseNode {
|
||||
warningProfiles[i].enter();
|
||||
anyWarnings = true;
|
||||
try {
|
||||
accumulatedWarnings = accumulatedWarnings.append(warnings.getWarnings(r, this, false));
|
||||
EnsoHashMap rWarnsMap = warnings.getWarnings(r, false);
|
||||
accumulatedWarnings =
|
||||
mapInsertAllNode.executeInsertAll(frame, accumulatedWarnings, rWarnsMap, maxWarnings);
|
||||
args[i] = warnings.removeWarnings(r);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
var ctx = EnsoContext.get(this);
|
||||
@ -531,7 +538,7 @@ public abstract class InvokeMethodNode extends BaseNode {
|
||||
Object res = hostMethodCallNode.execute(polyglotCallType, symbol.getName(), self, args);
|
||||
if (anyWarnings) {
|
||||
anyWarningsProfile.enter();
|
||||
res = WithWarnings.appendTo(EnsoContext.get(this), res, accumulatedWarnings);
|
||||
res = appendWarningNode.executeAppend(null, res, accumulatedWarnings);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
|
||||
/**
|
||||
@ -43,5 +43,5 @@ public abstract class CallOptimiserNode extends Node {
|
||||
CallerInfo callerInfo,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
Warning[] warnings);
|
||||
EnsoHashMap warnings);
|
||||
}
|
||||
|
@ -17,13 +17,12 @@ import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import com.oracle.truffle.api.nodes.RepeatingNode;
|
||||
import org.enso.interpreter.node.callable.ExecuteCallNode;
|
||||
import org.enso.interpreter.node.callable.ExecuteCallNodeGen;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.control.TailCallException;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
|
||||
/**
|
||||
* A version of {@link CallOptimiserNode} that is fully prepared to handle tail calls. Tail calls
|
||||
@ -65,7 +64,7 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
||||
CallerInfo callerInfo,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
Warning[] warnings,
|
||||
EnsoHashMap warnings,
|
||||
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode) {
|
||||
return dispatch(function, callerInfo, state, arguments, loopNode);
|
||||
}
|
||||
@ -76,10 +75,11 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
||||
CallerInfo callerInfo,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
Warning[] warnings,
|
||||
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode) {
|
||||
EnsoHashMap warnings,
|
||||
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode,
|
||||
@Shared @Cached AppendWarningNode appendWarningNode) {
|
||||
Object result = dispatch(function, callerInfo, state, arguments, loopNode);
|
||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
||||
return appendWarningNode.executeAppend(null, result, warnings);
|
||||
}
|
||||
|
||||
private Object dispatch(
|
||||
@ -104,7 +104,7 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
||||
CallerInfo callerInfo,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
Warning[] warnings,
|
||||
EnsoHashMap warnings,
|
||||
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode) {
|
||||
return loopUntilCompletion(frame, function, callerInfo, state, arguments, executeCallNode);
|
||||
}
|
||||
@ -117,11 +117,12 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
||||
CallerInfo callerInfo,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
Warning[] warnings,
|
||||
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode) {
|
||||
EnsoHashMap warnings,
|
||||
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode,
|
||||
@Shared @Cached AppendWarningNode appendWarningNode) {
|
||||
Object result =
|
||||
loopUntilCompletion(frame, function, callerInfo, state, arguments, executeCallNode);
|
||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
||||
return appendWarningNode.executeAppend(null, result, warnings);
|
||||
}
|
||||
|
||||
private Object loopUntilCompletion(
|
||||
|
@ -9,7 +9,7 @@ import org.enso.interpreter.node.callable.ExecuteCallNodeGen;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.control.TailCallException;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
|
||||
/**
|
||||
@ -51,7 +51,7 @@ public class SimpleCallOptimiserNode extends CallOptimiserNode {
|
||||
CallerInfo callerInfo,
|
||||
State state,
|
||||
Object[] arguments,
|
||||
Warning[] warnings) {
|
||||
EnsoHashMap warnings) {
|
||||
try {
|
||||
return executeCallNode.executeCall(frame, function, callerInfo, state, arguments);
|
||||
} catch (TailCallException e) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.enso.interpreter.node.controlflow.caseexpr;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.dsl.NodeChild;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
@ -16,6 +17,8 @@ import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.error.*;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/**
|
||||
* A node representing a pattern match on an arbitrary runtime value.
|
||||
@ -82,12 +85,12 @@ public abstract class CaseNode extends ExpressionNode {
|
||||
Object doWarning(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached AppendWarningNode appendWarningNode) {
|
||||
try {
|
||||
EnsoContext ctx = EnsoContext.get(this);
|
||||
Warning[] ws = warnings.getWarnings(object, this, false);
|
||||
var ws = warnings.getWarnings(object, false);
|
||||
Object result = doMatch(frame, warnings.removeWarnings(object), warnings);
|
||||
return WithWarnings.wrap(ctx, result, ws);
|
||||
return appendWarningNode.executeAppend(null, result, ws);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/**
|
||||
* Converts a value returned by a polyglot call back to a value that can be further used within Enso
|
||||
@ -75,13 +75,14 @@ public abstract class HostValueToEnsoNode extends Node {
|
||||
Object value,
|
||||
@CachedLibrary(limit = "3") InteropLibrary iop,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warningsLibrary,
|
||||
@Cached CountingConditionProfile nullWarningProfile) {
|
||||
@Cached CountingConditionProfile nullWarningProfile,
|
||||
@Cached AppendWarningNode appendWarningNode) {
|
||||
var ctx = EnsoContext.get(this);
|
||||
var nothing = ctx.getBuiltins().nothing();
|
||||
if (nothing != value && nullWarningProfile.profile(warningsLibrary.hasWarnings(value))) {
|
||||
try {
|
||||
var attachedWarnings = warningsLibrary.getWarnings(value, null, false);
|
||||
return WithWarnings.wrap(ctx, nothing, attachedWarnings);
|
||||
var attachedWarnings = warningsLibrary.getWarnings(value, false);
|
||||
return appendWarningNode.executeAppend(null, nothing, attachedWarnings);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
return nothing;
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "IO",
|
||||
|
@ -27,9 +27,9 @@ import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.data.EnsoFile;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.atom.Atom;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@GenerateUncached
|
||||
public abstract class EqualsComplexNode extends Node {
|
||||
|
@ -21,8 +21,8 @@ import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.data.atom.Atom;
|
||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
||||
|
||||
@GenerateUncached
|
||||
|
@ -45,11 +45,11 @@ import org.enso.interpreter.runtime.data.atom.Atom;
|
||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.data.atom.StructsLibrary;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
||||
|
||||
/**
|
||||
|
@ -21,8 +21,8 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Default_Comparator",
|
||||
|
@ -39,12 +39,13 @@ import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.Warning;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
|
||||
/**
|
||||
* Sorts a vector with elements that have only Default_Comparator, thus, only elements with a
|
||||
@ -66,7 +67,7 @@ public abstract class SortVectorNode extends Node {
|
||||
* @param self Vector that has elements with only Default_Comparator, that are elements with
|
||||
* builtin types.
|
||||
* @param ascending -1 for descending, 1 for ascending
|
||||
* @param comparators Vector of comparators, with the same length of self. This is gather in the
|
||||
* @param comparators Vector of comparators, with the same length of self. This is gathered in the
|
||||
* Enso code, because doing that in this builtin would be difficult. If {@code onFunc}
|
||||
* parameter is not {@code Nothing}, comparators are gathered from the result of {@code
|
||||
* onFunc} projection.
|
||||
@ -354,7 +355,8 @@ public abstract class SortVectorNode extends Node {
|
||||
.map(text -> Warning.create(ctx, text, this))
|
||||
.limit(MAX_SORT_WARNINGS)
|
||||
.toArray(Warning[]::new);
|
||||
return WithWarnings.appendTo(ctx, vector, warnArray.length < warnings.size(), warnArray);
|
||||
var reachedMaxCount = warnArray.length < warnings.size();
|
||||
return WithWarnings.create(vector, MAX_SORT_WARNINGS, reachedMaxCount, warnArray);
|
||||
}
|
||||
|
||||
private Object attachDifferentComparatorsWarning(Object vector, List<Group> groups) {
|
||||
@ -366,8 +368,13 @@ public abstract class SortVectorNode extends Node {
|
||||
.collect(Collectors.joining(", "));
|
||||
var text = Text.create("Different comparators: [" + diffCompsMsg + "]");
|
||||
var ctx = EnsoContext.get(this);
|
||||
var warn = Warning.create(ctx, text, this);
|
||||
return WithWarnings.appendTo(ctx, vector, false, warn);
|
||||
var warnsLib = WarningsLibrary.getUncached();
|
||||
if (warnsLib.hasWarnings(vector) && warnsLib.isLimitReached(vector)) {
|
||||
return vector;
|
||||
} else {
|
||||
var warn = Warning.create(ctx, text, this);
|
||||
return AppendWarningNode.getUncached().executeAppend(null, vector, warn);
|
||||
}
|
||||
} else {
|
||||
return vector;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import org.enso.interpreter.runtime.builtin.Builtins;
|
||||
import org.enso.interpreter.runtime.data.atom.Atom;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
public abstract class ExpectStringNode extends Node {
|
||||
private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(10);
|
||||
|
@ -3,7 +3,7 @@ package org.enso.interpreter.runtime.control;
|
||||
import com.oracle.truffle.api.nodes.ControlFlowException;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
|
||||
/**
|
||||
* Used to model the switch of control-flow from standard stack-based execution to looping.
|
||||
@ -14,7 +14,13 @@ public class TailCallException extends ControlFlowException {
|
||||
private final Function function;
|
||||
private final CallerInfo callerInfo;
|
||||
private final Object[] arguments;
|
||||
private final Warning[] warnings;
|
||||
|
||||
/**
|
||||
* May be null.
|
||||
*
|
||||
* @see org.enso.interpreter.runtime.warning.WithWarnings#warnings
|
||||
*/
|
||||
private final EnsoHashMap warnings;
|
||||
|
||||
/**
|
||||
* Creates a new exception containing the necessary data to continue computation.
|
||||
@ -31,7 +37,7 @@ public class TailCallException extends ControlFlowException {
|
||||
}
|
||||
|
||||
private TailCallException(
|
||||
Function function, CallerInfo callerInfo, Object[] arguments, Warning[] warnings) {
|
||||
Function function, CallerInfo callerInfo, Object[] arguments, EnsoHashMap warnings) {
|
||||
this.function = function;
|
||||
this.callerInfo = callerInfo;
|
||||
this.arguments = arguments;
|
||||
@ -44,7 +50,7 @@ public class TailCallException extends ControlFlowException {
|
||||
* @param origin the original tail call exception
|
||||
* @param warnings warnings to be associated with the tail call exception
|
||||
*/
|
||||
public TailCallException(TailCallException origin, Warning[] warnings) {
|
||||
public TailCallException(TailCallException origin, EnsoHashMap warnings) {
|
||||
this(origin.getFunction(), origin.getCallerInfo(), origin.getArguments(), warnings);
|
||||
}
|
||||
|
||||
@ -80,7 +86,7 @@ public class TailCallException extends ControlFlowException {
|
||||
*
|
||||
* @return the warnings to be appended to the result of the call, or null if empty
|
||||
*/
|
||||
public Warning[] getWarnings() {
|
||||
public EnsoHashMap getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
}
|
||||
|
@ -1,123 +0,0 @@
|
||||
package org.enso.interpreter.runtime.data;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class ArrayRope<T> {
|
||||
private final ArrayRopeSegment<T> segment;
|
||||
|
||||
private ArrayRope(ArrayRopeSegment<T> segment) {
|
||||
this.segment = segment;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public ArrayRope(T... elements) {
|
||||
segment = new ArraySegment<>(elements);
|
||||
}
|
||||
|
||||
public ArrayRope<T> append(ArrayRope<T> that) {
|
||||
return new ArrayRope<>(new ConcatSegment<>(this.segment, that.segment));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public final ArrayRope<T> append(T... items) {
|
||||
return new ArrayRope<>(new ConcatSegment<>(this.segment, new ArraySegment<>(items)));
|
||||
}
|
||||
|
||||
public ArrayRope<T> prepend(ArrayRope<T> that) {
|
||||
return new ArrayRope<>(new ConcatSegment<>(that.segment, this.segment));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public final ArrayRope<T> prepend(T... items) {
|
||||
return new ArrayRope<>(new ConcatSegment<>(new ArraySegment<>(items), this.segment));
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public T[] toArray(Function<Integer, T[]> genArray) {
|
||||
T[] res = genArray.apply(size());
|
||||
writeArray(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void writeArray(T[] arr) {
|
||||
segment.appendTo(arr, 0);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return segment.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArrayRope{" + "segment=" + segment + '}';
|
||||
}
|
||||
|
||||
private interface ArrayRopeSegment<T> {
|
||||
void appendTo(T[] builder, int start);
|
||||
|
||||
int size();
|
||||
}
|
||||
|
||||
private static final class ArraySegment<T> implements ArrayRopeSegment<T> {
|
||||
private final T[] elements;
|
||||
|
||||
public ArraySegment(T[] elements) {
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(T[] builder, int start) {
|
||||
System.arraycopy(elements, 0, builder, start, elements.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return elements.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArraySegment{" + "elements=" + Arrays.toString(elements) + '}';
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConcatSegment<T> implements ArrayRopeSegment<T> {
|
||||
private final ArrayRopeSegment<T> left;
|
||||
private final ArrayRopeSegment<T> right;
|
||||
private int cachedSize = UNKNOWN;
|
||||
private static final int UNKNOWN = -1;
|
||||
|
||||
public ConcatSegment(ArrayRopeSegment<T> left, ArrayRopeSegment<T> right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(T[] builder, int start) {
|
||||
left.appendTo(builder, start);
|
||||
right.appendTo(builder, start + left.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
if (cachedSize == UNKNOWN) {
|
||||
cachedSize = left.size() + right.size();
|
||||
}
|
||||
return cachedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConcatSegment{"
|
||||
+ "left="
|
||||
+ left
|
||||
+ ", right="
|
||||
+ right
|
||||
+ ", cachedSize="
|
||||
+ cachedSize
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
}
|
@ -26,9 +26,9 @@ import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/** A runtime representation of an Atom in Enso. */
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
|
@ -11,11 +11,11 @@ import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
||||
import org.enso.interpreter.node.ExpressionNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/**
|
||||
* A node instantiating a constant {@link AtomConstructor} with values computed based on the
|
||||
@ -66,10 +66,13 @@ abstract class InstantiateNode extends ExpressionNode {
|
||||
@ExplodeLoop
|
||||
Object doExecute(
|
||||
VirtualFrame frame,
|
||||
@Cached(parameters = {"constructor"}) AtomConstructorInstanceNode createInstanceNode) {
|
||||
@Cached(parameters = {"constructor"}) AtomConstructorInstanceNode createInstanceNode,
|
||||
@Cached AppendWarningNode appendWarningNode,
|
||||
@Cached HashMapInsertAllNode mapInsertAllNode) {
|
||||
Object[] argumentValues = new Object[arguments.length];
|
||||
boolean anyWarnings = false;
|
||||
ArrayRope<Warning> accumulatedWarnings = new ArrayRope<>();
|
||||
var accumulatedWarnings = EnsoHashMap.empty();
|
||||
var maxWarnings = EnsoContext.get(this).getWarningsLimit();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
CountingConditionProfile profile = profiles[i];
|
||||
CountingConditionProfile warningProfile = warningProfiles[i];
|
||||
@ -80,8 +83,10 @@ abstract class InstantiateNode extends ExpressionNode {
|
||||
} else if (warningProfile.profile(warnings.hasWarnings(argument))) {
|
||||
anyWarnings = true;
|
||||
try {
|
||||
var argumentWarnsMap = warnings.getWarnings(argument, false);
|
||||
accumulatedWarnings =
|
||||
accumulatedWarnings.append(warnings.getWarnings(argument, this, false));
|
||||
mapInsertAllNode.executeInsertAll(
|
||||
frame, accumulatedWarnings, argumentWarnsMap, maxWarnings);
|
||||
argumentValues[i] = warnings.removeWarnings(argument);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||
@ -94,8 +99,8 @@ abstract class InstantiateNode extends ExpressionNode {
|
||||
}
|
||||
}
|
||||
if (anyWarningsProfile.profile(anyWarnings)) {
|
||||
return WithWarnings.appendTo(
|
||||
EnsoContext.get(this), createInstanceNode.execute(argumentValues), accumulatedWarnings);
|
||||
return appendWarningNode.executeAppend(
|
||||
frame, createInstanceNode.execute(argumentValues), accumulatedWarnings);
|
||||
} else {
|
||||
return createInstanceNode.execute(argumentValues);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ public final class EnsoHashMap implements EnsoObject {
|
||||
}
|
||||
}
|
||||
|
||||
/** Slow version of {@link #getCachedVectorRepresentation(ConditionProfile)}. */
|
||||
Object getCachedVectorRepresentation() {
|
||||
return getCachedVectorRepresentation(ConditionProfile.getUncached());
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.enso.interpreter.runtime.data.hash;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import org.enso.interpreter.node.expression.builtin.meta.EqualsNode;
|
||||
import org.enso.interpreter.node.expression.builtin.meta.HashCodeNode;
|
||||
|
||||
@ -48,17 +49,22 @@ final class EnsoHashMapBuilder {
|
||||
}
|
||||
|
||||
/** Create a new builder with default size being {@code 11}. */
|
||||
public static EnsoHashMapBuilder create() {
|
||||
static EnsoHashMapBuilder create() {
|
||||
return new EnsoHashMapBuilder(11);
|
||||
}
|
||||
|
||||
static EnsoHashMapBuilder createWithCapacity(int capacity) {
|
||||
assert capacity > 0;
|
||||
return new EnsoHashMapBuilder(capacity);
|
||||
}
|
||||
|
||||
/** Returns count of elements in the storage. */
|
||||
public int generation() {
|
||||
int generation() {
|
||||
return generation;
|
||||
}
|
||||
|
||||
/** Returns the actual number of visible elements in current generation. */
|
||||
public int size() {
|
||||
int size() {
|
||||
return actualSize;
|
||||
}
|
||||
|
||||
@ -66,7 +72,7 @@ final class EnsoHashMapBuilder {
|
||||
* Provides access to all {@code StorageEntry} in this builder at given {@code atGeneration}.
|
||||
* Classical usage is to {@code for (var e : this) if (e.isVisible(atGeneration) operation(e))}.
|
||||
*/
|
||||
public StorageEntry[] getEntries(int atGeneration, int size) {
|
||||
StorageEntry[] getEntries(int atGeneration, int size) {
|
||||
var arr = new StorageEntry[size];
|
||||
var at = 0;
|
||||
for (var i = 0; i < byHash.length; i++) {
|
||||
@ -82,12 +88,57 @@ final class EnsoHashMapBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
record Entry(Object key, Object value) {}
|
||||
|
||||
Iterator<Entry> getEntriesIterator(int atGeneration) {
|
||||
return new EntriesIterator(atGeneration);
|
||||
}
|
||||
|
||||
final class EntriesIterator implements Iterator<Entry> {
|
||||
private final int atGeneration;
|
||||
private int nextVisibleEntryIdx = -1;
|
||||
|
||||
EntriesIterator(int atGeneration) {
|
||||
this.atGeneration = atGeneration;
|
||||
skipToNextVisibleEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (nextVisibleEntryIdx >= byHash.length) {
|
||||
return false;
|
||||
}
|
||||
var entry = byHash[nextVisibleEntryIdx];
|
||||
return entry != null && entry.isVisible(atGeneration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry next() {
|
||||
var entry = byHash[nextVisibleEntryIdx];
|
||||
skipToNextVisibleEntry();
|
||||
return new Entry(entry.key(), entry.value());
|
||||
}
|
||||
|
||||
private void skipToNextVisibleEntry() {
|
||||
while (true) {
|
||||
nextVisibleEntryIdx++;
|
||||
if (nextVisibleEntryIdx == byHash.length) {
|
||||
break;
|
||||
}
|
||||
var entry = byHash[nextVisibleEntryIdx];
|
||||
if (entry != null && entry.isVisible(atGeneration)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a builder ready for modification at given generation. It may return {@code this} if
|
||||
* the {@code atGeneration == this.generation} and the {@code byHash} array is less than 75% full.
|
||||
* Otherwise it may return new builder suitable for additions.
|
||||
*/
|
||||
public EnsoHashMapBuilder asModifiable(
|
||||
EnsoHashMapBuilder asModifiable(
|
||||
VirtualFrame frame, int atGeneration, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
||||
if (atGeneration != generation || generation * 4 > byHash.length * 3) {
|
||||
var newSize = Math.max(actualSize * 2, byHash.length);
|
||||
@ -103,7 +154,7 @@ final class EnsoHashMapBuilder {
|
||||
* equal key, it marks it as removed, if it hasn't been removed yet. Once it finds an empty slot,
|
||||
* it puts there a new entry with the next generation.
|
||||
*/
|
||||
public void put(
|
||||
void put(
|
||||
VirtualFrame frame,
|
||||
Object key,
|
||||
Object value,
|
||||
@ -139,7 +190,7 @@ final class EnsoHashMapBuilder {
|
||||
* Finds storage entry for given key or {@code null}. Searches only entries that are visible for
|
||||
* given {@code generation}.
|
||||
*/
|
||||
public StorageEntry get(
|
||||
StorageEntry get(
|
||||
VirtualFrame frame,
|
||||
Object key,
|
||||
int generation,
|
||||
@ -175,8 +226,7 @@ final class EnsoHashMapBuilder {
|
||||
*
|
||||
* @return true if the removal was successful false otherwise.
|
||||
*/
|
||||
public boolean remove(
|
||||
VirtualFrame frame, Object key, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
||||
boolean remove(VirtualFrame frame, Object key, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
||||
assert actualSize <= generation;
|
||||
var at = findWhereToStart(key, hashCodeNode);
|
||||
var nextGeneration = ++generation;
|
||||
@ -225,11 +275,11 @@ final class EnsoHashMapBuilder {
|
||||
* are in the storage as of this moment, i.e., all the entries with their indexes lesser than
|
||||
* {@code generation}.
|
||||
*
|
||||
* <p>Should be called where most once for a particular {@code generation}.
|
||||
* <p>Should be called at most once for a particular {@code generation}.
|
||||
*
|
||||
* @return A new hash map snapshot.
|
||||
*/
|
||||
public EnsoHashMap build() {
|
||||
EnsoHashMap build() {
|
||||
return EnsoHashMap.createWithBuilder(this);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
package org.enso.interpreter.runtime.data.hash;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.common.LanguageInfo;
|
||||
import org.enso.interpreter.node.expression.builtin.meta.EqualsNode;
|
||||
import org.enso.interpreter.node.expression.builtin.meta.HashCodeNode;
|
||||
|
||||
@GenerateUncached
|
||||
@NodeInfo(
|
||||
shortName = "MapInsertAll",
|
||||
description = "Inserts all elements from the given container into a hash map",
|
||||
language = LanguageInfo.ID)
|
||||
public abstract class HashMapInsertAllNode extends Node {
|
||||
|
||||
public static HashMapInsertAllNode build() {
|
||||
return HashMapInsertAllNodeGen.create();
|
||||
}
|
||||
|
||||
public static HashMapInsertAllNode getUncached() {
|
||||
return HashMapInsertAllNodeGen.getUncached();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all the elements from the given container into the given map.
|
||||
*
|
||||
* @param self A map to insert into.
|
||||
* @param container Either a map, or a list of pairs to insert into the map.
|
||||
* @param maxItems Maximum number of items to insert into the map from the container.
|
||||
*/
|
||||
public abstract EnsoHashMap executeInsertAll(
|
||||
VirtualFrame frame, EnsoHashMap self, EnsoHashMap container, int maxItems);
|
||||
|
||||
@Specialization
|
||||
EnsoHashMap doEnsoHashMaps(
|
||||
VirtualFrame frame,
|
||||
EnsoHashMap self,
|
||||
EnsoHashMap other,
|
||||
int maxItems,
|
||||
@Cached HashCodeNode hashCodeNode,
|
||||
@Cached EqualsNode equalsNode) {
|
||||
assert maxItems > 0;
|
||||
var selfSize = self.getHashSize();
|
||||
var otherSize = other.getHashSize();
|
||||
if (otherSize == 0) {
|
||||
return self;
|
||||
}
|
||||
var mapBuilder = EnsoHashMapBuilder.createWithCapacity(selfSize + otherSize);
|
||||
|
||||
var selfMapBuilder = self.getMapBuilder(frame, true, hashCodeNode, equalsNode);
|
||||
var selfEntriesIt = selfMapBuilder.getEntriesIterator(selfMapBuilder.generation());
|
||||
while (selfEntriesIt.hasNext()) {
|
||||
var selfEntry = selfEntriesIt.next();
|
||||
mapBuilder.put(frame, selfEntry.key(), selfEntry.value(), hashCodeNode, equalsNode);
|
||||
}
|
||||
var otherMapBuilder = other.getMapBuilder(frame, true, hashCodeNode, equalsNode);
|
||||
var otherEntriesIt = otherMapBuilder.getEntriesIterator(otherMapBuilder.generation());
|
||||
var itemsInserted = 0;
|
||||
while (otherEntriesIt.hasNext()) {
|
||||
if (itemsInserted >= maxItems) {
|
||||
break;
|
||||
}
|
||||
var entry = otherEntriesIt.next();
|
||||
mapBuilder.put(frame, entry.key(), entry.value(), hashCodeNode, equalsNode);
|
||||
itemsInserted++;
|
||||
}
|
||||
return mapBuilder.build();
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package org.enso.interpreter.runtime.data.hash;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
@ -25,6 +26,7 @@ import org.enso.interpreter.runtime.error.PanicException;
|
||||
Returns newly created hash map with the given key value mapping.
|
||||
""",
|
||||
autoRegister = false)
|
||||
@GenerateUncached
|
||||
public abstract class HashMapInsertNode extends Node {
|
||||
|
||||
public static HashMapInsertNode build() {
|
||||
@ -41,6 +43,7 @@ public abstract class HashMapInsertNode extends Node {
|
||||
Object value,
|
||||
@Shared("hash") @Cached HashCodeNode hashCodeNode,
|
||||
@Shared("equals") @Cached EqualsNode equalsNode) {
|
||||
assert value != null;
|
||||
var mapBuilder = hashMap.getMapBuilder(frame, false, hashCodeNode, equalsNode);
|
||||
mapBuilder.put(frame, key, value, hashCodeNode, equalsNode);
|
||||
var newMap = mapBuilder.build();
|
||||
@ -61,6 +64,7 @@ public abstract class HashMapInsertNode extends Node {
|
||||
@CachedLibrary(limit = "3") InteropLibrary iteratorInterop,
|
||||
@Shared("hash") @Cached HashCodeNode hashCodeNode,
|
||||
@Shared("equals") @Cached EqualsNode equalsNode) {
|
||||
assert valueToInsert != null;
|
||||
var mapBuilder = EnsoHashMapBuilder.create();
|
||||
try {
|
||||
Object entriesIterator = mapInterop.getHashEntriesIterator(foreignMap);
|
||||
|
@ -23,6 +23,10 @@ public abstract class HashMapSizeNode extends Node {
|
||||
return HashMapSizeNodeGen.create();
|
||||
}
|
||||
|
||||
public static HashMapSizeNode getUncached() {
|
||||
return HashMapSizeNodeGen.getUncached();
|
||||
}
|
||||
|
||||
public abstract long execute(Object self);
|
||||
|
||||
@Specialization(guards = "interop.hasHashEntries(hashMap)", limit = "3")
|
||||
|
@ -13,15 +13,19 @@ import com.oracle.truffle.api.library.ExportMessage;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import org.enso.interpreter.dsl.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.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertNode;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapSizeNode;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.graalvm.collections.EconomicSet;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.Warning;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/** A primitive boxed array type for use in the runtime. */
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
@ -30,9 +34,13 @@ import org.graalvm.collections.EconomicSet;
|
||||
@Builtin(pkg = "mutable", stdlibName = "Standard.Base.Data.Array.Array")
|
||||
final class Array implements EnsoObject {
|
||||
private final Object[] items;
|
||||
|
||||
/** If true, some elements contain warning, and thus, this Array contains warning. */
|
||||
private Boolean withWarnings;
|
||||
private Warning[] cachedWarningsWrapped;
|
||||
private Warning[] cachedWarningsUnwrapped;
|
||||
|
||||
private EnsoHashMap cachedWarningsWrapped;
|
||||
|
||||
private EnsoHashMap cachedWarningsUnwrapped;
|
||||
|
||||
/**
|
||||
* Creates a new array
|
||||
@ -91,7 +99,12 @@ final class Array implements EnsoObject {
|
||||
long index,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached BranchProfile errProfile,
|
||||
@Cached BranchProfile hasWarningsProfile)
|
||||
@Cached BranchProfile hasWarningsProfile,
|
||||
@Cached HashMapInsertNode mapInsertNode,
|
||||
@Cached AppendWarningNode appendWarningNode,
|
||||
@Cached BranchProfile shouldWrapProfile,
|
||||
@Cached HashMapSizeNode mapSizeNode,
|
||||
@Cached HashMapInsertAllNode mapInsertAllNode)
|
||||
throws InvalidArrayIndexException, UnsupportedMessageException {
|
||||
if (index >= items.length || index < 0) {
|
||||
errProfile.enter();
|
||||
@ -101,11 +114,13 @@ final class Array implements EnsoObject {
|
||||
var v = items[(int) index];
|
||||
if (this.hasWarnings(warnings)) {
|
||||
hasWarningsProfile.enter();
|
||||
Warning[] extracted = this.getWarnings(null, false, warnings);
|
||||
var extractedWarnsMap =
|
||||
this.getWarnings(
|
||||
false, warnings, mapInsertNode, shouldWrapProfile, mapSizeNode, mapInsertAllNode);
|
||||
if (warnings.hasWarnings(v)) {
|
||||
v = warnings.removeWarnings(v);
|
||||
}
|
||||
return WithWarnings.wrap(EnsoContext.get(warnings), v, extracted);
|
||||
return appendWarningNode.executeAppend(null, v, extractedWarnsMap);
|
||||
}
|
||||
|
||||
return v;
|
||||
@ -180,48 +195,81 @@ final class Array implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(
|
||||
Node location,
|
||||
EnsoHashMap getWarnings(
|
||||
boolean shouldWrap,
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Shared("mapInsertNode") @Cached HashMapInsertNode mapInsertNode,
|
||||
@Shared @Cached BranchProfile shouldWrapProfile,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode,
|
||||
@Shared @Cached HashMapInsertAllNode mapInsertAllNode)
|
||||
throws UnsupportedMessageException {
|
||||
Warning[] cache = shouldWrap ? cachedWarningsWrapped : cachedWarningsUnwrapped;
|
||||
var cache = shouldWrap ? cachedWarningsWrapped : cachedWarningsUnwrapped;
|
||||
if (cache == null) {
|
||||
cache = Warning.fromSetToArray(collectAllWarnings(warnings, location, shouldWrap));
|
||||
var warnLimit = EnsoContext.get(warnings).getWarningsLimit();
|
||||
var allWarnsMap =
|
||||
collectAllWarnings(
|
||||
warnings,
|
||||
mapInsertNode,
|
||||
shouldWrap,
|
||||
mapInsertAllNode,
|
||||
warnLimit,
|
||||
shouldWrapProfile,
|
||||
mapSizeNode);
|
||||
if (shouldWrap) {
|
||||
cachedWarningsWrapped = cache;
|
||||
cachedWarningsWrapped = allWarnsMap;
|
||||
cache = cachedWarningsWrapped;
|
||||
} else {
|
||||
cachedWarningsUnwrapped = cache;
|
||||
cachedWarningsUnwrapped = allWarnsMap;
|
||||
cache = cachedWarningsUnwrapped;
|
||||
}
|
||||
}
|
||||
assert cache != null;
|
||||
return cache;
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private EconomicSet<Warning> collectAllWarnings(
|
||||
WarningsLibrary warningsLib, Node location, boolean shouldWrap)
|
||||
private EnsoHashMap collectAllWarnings(
|
||||
WarningsLibrary warningsLib,
|
||||
HashMapInsertNode mapInsertNode,
|
||||
boolean shouldWrap,
|
||||
HashMapInsertAllNode mapInsertAllNode,
|
||||
int warnLimit,
|
||||
BranchProfile shouldWrapProfile,
|
||||
HashMapSizeNode mapSizeNode)
|
||||
throws UnsupportedMessageException {
|
||||
EconomicSet<Warning> setOfWarnings = EconomicSet.create(new WithWarnings.WarningEquivalence());
|
||||
for (int i = 0; i < this.items.length; i++) {
|
||||
final int finalIndex = i;
|
||||
Object item = this.items[i];
|
||||
var warnsSet = EnsoHashMap.empty();
|
||||
for (int itemIdx = 0; itemIdx < this.items.length; itemIdx++) {
|
||||
Object item = this.items[itemIdx];
|
||||
var warnsCnt = (int) mapSizeNode.execute(warnsSet);
|
||||
if (warnsCnt == warnLimit) {
|
||||
break;
|
||||
}
|
||||
if (warningsLib.hasWarnings(item)) {
|
||||
Warning[] warnings = warningsLib.getWarnings(item, location, shouldWrap);
|
||||
Warning[] wrappedWarningsMaybe;
|
||||
var itemWarnsMap = warningsLib.getWarnings(item, shouldWrap);
|
||||
assert mapSizeNode.execute(itemWarnsMap) <= warnLimit;
|
||||
|
||||
if (shouldWrap) {
|
||||
wrappedWarningsMaybe =
|
||||
Arrays.stream(warnings)
|
||||
.map(warning -> Warning.wrapMapError(warningsLib, warning, finalIndex))
|
||||
.toArray(Warning[]::new);
|
||||
if (!shouldWrap) {
|
||||
warnsSet =
|
||||
mapInsertAllNode.executeInsertAll(null, warnsSet, itemWarnsMap, warnLimit - warnsCnt);
|
||||
} else {
|
||||
wrappedWarningsMaybe = warnings;
|
||||
shouldWrapProfile.enter();
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
// warnings need to be sorted such that at the first index, there is the oldest warning.
|
||||
// This is because we are creating new warnings by wrapping the previous one, and we need
|
||||
// to
|
||||
// do that in the same creation order.
|
||||
var warnings = Warning.fromMapToArray(itemWarnsMap);
|
||||
Arrays.sort(warnings, Comparator.comparing(Warning::getSequenceId));
|
||||
for (int i = 0; i < Math.min(warnings.length, warnLimit); i++) {
|
||||
var warn = warnings[i];
|
||||
var wrappedWarn = Warning.wrapMapError(warningsLib, warn, itemIdx);
|
||||
warnsSet =
|
||||
mapInsertNode.execute(null, warnsSet, wrappedWarn.getSequenceId(), wrappedWarn);
|
||||
}
|
||||
}
|
||||
|
||||
setOfWarnings.addAll(Arrays.asList(wrappedWarningsMaybe));
|
||||
}
|
||||
}
|
||||
return setOfWarnings;
|
||||
assert mapSizeNode.execute(warnsSet) <= warnLimit;
|
||||
return warnsSet;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@ -239,10 +287,18 @@ final class Array implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean isLimitReached(@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
||||
boolean isLimitReached(
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnsLib,
|
||||
@Shared("mapInsertNode") @Cached HashMapInsertNode mapInsertNode,
|
||||
@Shared @Cached HashMapInsertAllNode mapInsertAllNode,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode,
|
||||
@Shared @Cached BranchProfile shouldWrapProfile) {
|
||||
try {
|
||||
int limit = EnsoContext.get(warnings).getWarningsLimit();
|
||||
return getWarnings(null, false, warnings).length >= limit;
|
||||
int limit = EnsoContext.get(warnsLib).getWarningsLimit();
|
||||
var ourWarnings =
|
||||
getWarnings(
|
||||
false, warnsLib, mapInsertNode, shouldWrapProfile, mapSizeNode, mapInsertAllNode);
|
||||
return (int) mapSizeNode.execute(ourWarnings) >= limit;
|
||||
} catch (UnsupportedMessageException e) {
|
||||
return false;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import com.oracle.truffle.api.library.ExportMessage;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import java.util.Arrays;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
final class ArrayBuilder implements EnsoObject {
|
||||
@ -142,14 +142,31 @@ final class ArrayBuilder implements EnsoObject {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkArraySize(boolean mustBeExact, int real, int expected) {
|
||||
if (real == expected) {
|
||||
return true;
|
||||
} else {
|
||||
if (mustBeExact) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the current array of the builder. */
|
||||
private Object toArray() {
|
||||
private Object toArray(boolean mustBeExact) {
|
||||
if (objectArray != null) {
|
||||
return objectArray.length == size ? objectArray : Arrays.copyOf(objectArray, size);
|
||||
return checkArraySize(mustBeExact, objectArray.length, size)
|
||||
? objectArray
|
||||
: Arrays.copyOf(objectArray, size);
|
||||
} else if (primitiveArray instanceof long[] longArray) {
|
||||
return longArray.length == size ? longArray : Arrays.copyOf(longArray, size);
|
||||
return checkArraySize(mustBeExact, longArray.length, size)
|
||||
? longArray
|
||||
: Arrays.copyOf(longArray, size);
|
||||
} else if (primitiveArray instanceof double[] doubleArray) {
|
||||
return doubleArray.length == size ? doubleArray : Arrays.copyOf(doubleArray, size);
|
||||
return checkArraySize(mustBeExact, doubleArray.length, size)
|
||||
? doubleArray
|
||||
: Arrays.copyOf(doubleArray, size);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -195,7 +212,7 @@ final class ArrayBuilder implements EnsoObject {
|
||||
yield get(index, iop);
|
||||
}
|
||||
case "getSize" -> getSize();
|
||||
case "toArray" -> asVector();
|
||||
case "toArray" -> asVector(false);
|
||||
default -> throw UnknownIdentifierException.create(name);
|
||||
};
|
||||
}
|
||||
@ -225,8 +242,8 @@ final class ArrayBuilder implements EnsoObject {
|
||||
return "Array_Builder";
|
||||
}
|
||||
|
||||
Object asVector() {
|
||||
var res = toArray();
|
||||
Object asVector(boolean mustBeExact) {
|
||||
var res = toArray(mustBeExact);
|
||||
if (res instanceof long[] longs) {
|
||||
return Vector.fromLongArray(longs);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.enso.interpreter.runtime.data.vector;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.NeverDefault;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.exception.AbstractTruffleException;
|
||||
@ -10,8 +11,10 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@GenerateUncached
|
||||
public abstract class ArrayLikeAtNode extends Node {
|
||||
public abstract Object executeAt(Object arrayLike, long index) throws InvalidArrayIndexException;
|
||||
|
||||
@ -57,10 +60,11 @@ public abstract class ArrayLikeAtNode extends Node {
|
||||
long index,
|
||||
@Cached.Exclusive @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@Cached.Exclusive @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached.Exclusive @Cached HostValueToEnsoNode convert)
|
||||
@Cached.Exclusive @Cached HostValueToEnsoNode convert,
|
||||
@Cached AppendWarningNode appendWarningNode)
|
||||
throws InvalidArrayIndexException {
|
||||
try {
|
||||
return self.readArrayElement(index, interop, warnings, convert);
|
||||
return self.readArrayElement(index, interop, warnings, convert, appendWarningNode);
|
||||
} catch (UnsupportedMessageException ex) {
|
||||
throw ArrayPanics.notAnArrayPanic(this, self);
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
/** Publicly available operations on array-like classes. */
|
||||
@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Internal.Array_Like_Helpers")
|
||||
@ -97,7 +97,7 @@ public final class ArrayLikeHelpers {
|
||||
}
|
||||
target.add(value, warnings);
|
||||
}
|
||||
return target.asVector();
|
||||
return target.asVector(true);
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
|
@ -2,6 +2,7 @@ package org.enso.interpreter.runtime.data.vector;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Cached.Exclusive;
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.NeverDefault;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
@ -9,6 +10,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
|
||||
@GenerateUncached
|
||||
public abstract class ArrayLikeLengthNode extends Node {
|
||||
public abstract long executeLength(Object arrayLike);
|
||||
|
||||
|
@ -15,10 +15,10 @@ import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEn
|
||||
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.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
@ -91,7 +91,8 @@ final class ArraySlice implements EnsoObject {
|
||||
long index,
|
||||
@Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached HostValueToEnsoNode toEnso)
|
||||
@Cached HostValueToEnsoNode toEnso,
|
||||
@Cached AppendWarningNode appendWarningNode)
|
||||
throws InvalidArrayIndexException, UnsupportedMessageException {
|
||||
if (index < 0 || index >= getArraySize(interop)) {
|
||||
throw InvalidArrayIndexException.create(index);
|
||||
@ -99,11 +100,11 @@ final class ArraySlice implements EnsoObject {
|
||||
|
||||
var v = interop.readArrayElement(storage, start + index);
|
||||
if (this.hasWarnings(warnings)) {
|
||||
Warning[] extracted = this.getWarnings(null, false, warnings);
|
||||
var extracted = this.getWarnings(false, warnings);
|
||||
if (warnings.hasWarnings(v)) {
|
||||
v = warnings.removeWarnings(v);
|
||||
}
|
||||
return WithWarnings.wrap(EnsoContext.get(warnings), toEnso.execute(v), extracted);
|
||||
return appendWarningNode.executeAppend(null, toEnso.execute(v), extracted);
|
||||
}
|
||||
return toEnso.execute(v);
|
||||
}
|
||||
@ -155,12 +156,10 @@ final class ArraySlice implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(
|
||||
Node location,
|
||||
boolean shouldWrap,
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||
EnsoHashMap getWarnings(
|
||||
boolean shouldWrap, @Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||
throws UnsupportedMessageException {
|
||||
return warnings.getWarnings(this.storage, location, shouldWrap);
|
||||
return warnings.getWarnings(this.storage, shouldWrap);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
|
@ -15,10 +15,10 @@ import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEn
|
||||
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.error.Warning;
|
||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
@ -178,8 +178,8 @@ abstract class Vector implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(Node location, boolean shouldWrap) throws UnsupportedMessageException {
|
||||
return new Warning[0];
|
||||
EnsoHashMap getWarnings(boolean shouldWrap) {
|
||||
return EnsoHashMap.empty();
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@ -249,15 +249,16 @@ abstract class Vector implements EnsoObject {
|
||||
long index,
|
||||
@Cached.Shared(value = "interop") @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||
@Cached HostValueToEnsoNode toEnso)
|
||||
@Cached HostValueToEnsoNode toEnso,
|
||||
@Cached AppendWarningNode appendWarningNode)
|
||||
throws InvalidArrayIndexException, UnsupportedMessageException {
|
||||
var v = interop.readArrayElement(this.storage, index);
|
||||
if (warnings.hasWarnings(this.storage)) {
|
||||
Warning[] extracted = warnings.getWarnings(this.storage, null, false);
|
||||
var extracted = warnings.getWarnings(this.storage, false);
|
||||
if (warnings.hasWarnings(v)) {
|
||||
v = warnings.removeWarnings(v);
|
||||
}
|
||||
return WithWarnings.wrap(EnsoContext.get(interop), toEnso.execute(v), extracted);
|
||||
return appendWarningNode.executeAppend(null, toEnso.execute(v), extracted);
|
||||
}
|
||||
return toEnso.execute(v);
|
||||
}
|
||||
@ -287,12 +288,11 @@ abstract class Vector implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(
|
||||
Node location,
|
||||
EnsoHashMap getWarnings(
|
||||
boolean shouldWrap,
|
||||
@Cached.Shared(value = "warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||
throws UnsupportedMessageException {
|
||||
return warnings.getWarnings(this.storage, location, shouldWrap);
|
||||
return warnings.getWarnings(this.storage, shouldWrap);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@ -357,8 +357,8 @@ abstract class Vector implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(Node location, boolean shouldWrap) throws UnsupportedMessageException {
|
||||
return new Warning[0];
|
||||
EnsoHashMap getWarnings(boolean shouldWrap) {
|
||||
return EnsoHashMap.empty();
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@ -407,8 +407,8 @@ abstract class Vector implements EnsoObject {
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(Node location, boolean shouldWrap) throws UnsupportedMessageException {
|
||||
return new Warning[0];
|
||||
EnsoHashMap getWarnings(boolean shouldWrap) {
|
||||
return EnsoHashMap.empty();
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
|
@ -1,258 +0,0 @@
|
||||
package org.enso.interpreter.runtime.error;
|
||||
|
||||
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.InvalidArrayIndexException;
|
||||
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 com.oracle.truffle.api.nodes.RootNode;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import org.enso.interpreter.dsl.Builtin;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.graalvm.collections.EconomicSet;
|
||||
|
||||
@Builtin(pkg = "error", stdlibName = "Standard.Base.Warning.Warning")
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
public final class Warning implements EnsoObject {
|
||||
private final Object value;
|
||||
private final Object origin;
|
||||
private final ArrayRope<Reassignment> reassignments;
|
||||
private final long sequenceId;
|
||||
|
||||
private Warning(Object value, Object origin, long sequenceId) {
|
||||
this(value, origin, sequenceId, new ArrayRope<>());
|
||||
}
|
||||
|
||||
private Warning(
|
||||
Object value, Object origin, long sequenceId, ArrayRope<Reassignment> reassignments) {
|
||||
this.value = value;
|
||||
this.origin = origin;
|
||||
this.reassignments = reassignments;
|
||||
this.sequenceId = sequenceId;
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "value", description = "Gets the payload of the warning.")
|
||||
@SuppressWarnings("generic-enso-builtin-type")
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "origin", description = "Gets the payload of the warning.")
|
||||
@SuppressWarnings("generic-enso-builtin-type")
|
||||
public Object getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "create",
|
||||
description = "Creates a new instance of the primitive warning value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
public static Warning create(EnsoContext ctx, Object payload, Object origin) {
|
||||
return new Warning(payload, origin, ctx.nextSequenceId());
|
||||
}
|
||||
|
||||
@Builtin.Method(description = "Gets the list of locations where the warnings was reassigned.")
|
||||
public EnsoObject getReassignments() {
|
||||
Warning.Reassignment[] reassignmentsArray = reassignments.toArray(Warning.Reassignment[]::new);
|
||||
return ArrayLikeHelpers.wrapEnsoObjects(reassignmentsArray);
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "attach_with_stacktrace",
|
||||
description = "Attaches the given warning to the value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
public static WithWarnings attach(
|
||||
EnsoContext ctx, WithWarnings value, Object warning, Object origin) {
|
||||
return value.append(ctx, new Warning(warning, origin, ctx.nextSequenceId()));
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "attach_with_stacktrace",
|
||||
description = "Attaches the given warning to the value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize(fallback = true)
|
||||
public static WithWarnings attach(EnsoContext ctx, Object value, Object warning, Object origin) {
|
||||
return WithWarnings.wrap(ctx, value, new Warning(warning, origin, ctx.nextSequenceId()));
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "get_all_vector",
|
||||
description = "Gets all the warnings associated with the value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static EnsoObject getAll(
|
||||
WithWarnings value, boolean shouldWrap, WarningsLibrary warningsLib) {
|
||||
Warning[] warnings = value.getWarningsArray(warningsLib, shouldWrap);
|
||||
sortArray(warnings);
|
||||
return ArrayLikeHelpers.asVectorEnsoObjects(warnings);
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "get_all_vector",
|
||||
description = "Gets all the warnings associated with the value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize(fallback = true)
|
||||
public static EnsoObject getAll(Object value, boolean shouldWrap, WarningsLibrary warningsLib) {
|
||||
if (warningsLib.hasWarnings(value)) {
|
||||
try {
|
||||
Warning[] warnings = warningsLib.getWarnings(value, null, shouldWrap);
|
||||
sortArray(warnings);
|
||||
return ArrayLikeHelpers.asVectorEnsoObjects(warnings);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(warningsLib).raiseAssertionPanic(warningsLib, null, e);
|
||||
}
|
||||
} else {
|
||||
return ArrayLikeHelpers.asVectorEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
description =
|
||||
"Returns `true` if the maximal number of warnings has been reached, `false` otherwise.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
public static boolean limitReached(WithWarnings value, WarningsLibrary warnings) {
|
||||
return value.isLimitReached();
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
description =
|
||||
"Returns `true` if the maximal number of warnings has been reached, `false` otherwise.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize(fallback = true)
|
||||
public static boolean limitReached(Object value, WarningsLibrary warnings) {
|
||||
return warnings.hasWarnings(value) ? warnings.isLimitReached(value) : false;
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private static void sortArray(Warning[] arr) {
|
||||
Arrays.sort(arr, Comparator.comparing(Warning::getSequenceId).reversed());
|
||||
}
|
||||
|
||||
/** Converts set to an array behing a truffle boundary. */
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static Warning[] fromSetToArray(EconomicSet<Warning> set) {
|
||||
return set.toArray(new Warning[set.size()]);
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "set_array",
|
||||
description = "Sets all the warnings associated with the value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
@SuppressWarnings("generic-enso-builtin-type")
|
||||
public static Object set(
|
||||
EnsoContext ctx, WithWarnings value, Object warnings, InteropLibrary interop) {
|
||||
return setGeneric(ctx, value.getValue(), interop, warnings);
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "set_array",
|
||||
description = "Sets all the warnings associated with the value.",
|
||||
autoRegister = false)
|
||||
@SuppressWarnings("generic-enso-builtin-type")
|
||||
@Builtin.Specialize(fallback = true)
|
||||
public static Object set(EnsoContext ctx, Object value, Object warnings, InteropLibrary interop) {
|
||||
return setGeneric(ctx, value, interop, warnings);
|
||||
}
|
||||
|
||||
private static Object setGeneric(
|
||||
EnsoContext ctx, Object value, InteropLibrary interop, Object warnings) {
|
||||
try {
|
||||
var size = interop.getArraySize(warnings);
|
||||
if (size == 0) {
|
||||
return value;
|
||||
}
|
||||
Warning[] warningsCast = new Warning[(int) size];
|
||||
for (int i = 0; i < warningsCast.length; i++) {
|
||||
warningsCast[i] = (Warning) interop.readArrayElement(warnings, i);
|
||||
}
|
||||
return WithWarnings.wrap(ctx, value, warningsCast);
|
||||
} catch (UnsupportedMessageException | InvalidArrayIndexException ex) {
|
||||
throw EnsoContext.get(interop).raiseAssertionPanic(interop, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@Override
|
||||
public String toString() {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
public static final class Reassignment implements EnsoObject {
|
||||
private final String methodName;
|
||||
private final SourceSection location;
|
||||
|
||||
public Reassignment(String methodName, SourceSection location) {
|
||||
this.methodName = methodName;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasExecutableName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
String getExecutableName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasSourceLocation() {
|
||||
return location != null;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
SourceSection getSourceLocation() throws UnsupportedMessageException {
|
||||
if (location == null) {
|
||||
throw UnsupportedMessageException.create();
|
||||
}
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
public long getSequenceId() {
|
||||
return sequenceId;
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public Warning reassign(Node location) {
|
||||
RootNode root = location.getRootNode();
|
||||
SourceSection section = location.getEncapsulatingSourceSection();
|
||||
Reassignment reassignment = new Reassignment(root == null ? "" : root.getName(), section);
|
||||
return new Warning(value, origin, sequenceId, reassignments.prepend(reassignment));
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Type getType(@Bind("$node") Node node) {
|
||||
return EnsoContext.get(node).getBuiltins().warning();
|
||||
}
|
||||
|
||||
public static Warning wrapMapError(WarningsLibrary warningsLib, Warning warning, long index) {
|
||||
var ctx = EnsoContext.get(warningsLib);
|
||||
var error = warning.getValue();
|
||||
var wrappedError = ctx.getBuiltins().error().makeMapError(index, error);
|
||||
var wrappedWarning = Warning.create(ctx, wrappedError, warning.getOrigin());
|
||||
return wrappedWarning;
|
||||
}
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
package org.enso.interpreter.runtime.error;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Bind;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.interop.ArityException;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.TruffleObject;
|
||||
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.library.Message;
|
||||
import com.oracle.truffle.api.library.ReflectionLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.node.callable.InteropMethodCallNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
import org.graalvm.collections.EconomicSet;
|
||||
import org.graalvm.collections.Equivalence;
|
||||
|
||||
/**
|
||||
* Represents a typical Enso <em>value with warnings</em>. As much of care as possible is taken to
|
||||
* delegate all operations to the underlaying {@code value}. Warnings are considered {@link
|
||||
* InteropLibrary#isException exceptional values} - e.g. one can check for them in Java polyglot
|
||||
* code as:
|
||||
*
|
||||
* <pre>
|
||||
* Value value = ...;
|
||||
* if (value.fitsInLong() && value.isException()) {
|
||||
* // probably an Integer with a warning
|
||||
* try {
|
||||
* warningMulti.throwException();
|
||||
* } catch (PolyglotException ex) {
|
||||
* System.out.println("Warnings attached to " + value.asLong() + " are " + ex.getMessage());
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
@ExportLibrary(WarningsLibrary.class)
|
||||
@ExportLibrary(ReflectionLibrary.class)
|
||||
@ExportLibrary(value = InteropLibrary.class, delegateTo = "value")
|
||||
public final class WithWarnings implements EnsoObject {
|
||||
final Object value;
|
||||
private final EconomicSet<Warning> warnings;
|
||||
|
||||
private final boolean limitReached;
|
||||
private final int maxWarnings;
|
||||
|
||||
/**
|
||||
* Creates a new instance of value wrapped in warnings. `limitReached` parameter allows for
|
||||
* indicating if some custom warnings filtering on `warnings` have already been performed.
|
||||
*
|
||||
* @param value value to be wrapped in warnings
|
||||
* @param maxWarnings maximal number of warnings allowed to be attached to the value
|
||||
* @param limitReached if `true`, indicates that `warnings` have already been limited for a
|
||||
* custom-method, `false` otherwise
|
||||
* @param warnings non-empty warnings to be attached to a value
|
||||
*/
|
||||
private WithWarnings(Object value, int maxWarnings, boolean limitReached, Warning... warnings) {
|
||||
assert isAcceptableValue(value);
|
||||
this.warnings = createSetFromArray(maxWarnings, warnings);
|
||||
assert this.warnings.size() > 0;
|
||||
this.value = value;
|
||||
this.limitReached = limitReached || this.warnings.size() >= maxWarnings;
|
||||
this.maxWarnings = maxWarnings;
|
||||
}
|
||||
|
||||
private WithWarnings(Object value, int maxWarnings, Warning... warnings) {
|
||||
this(value, maxWarnings, false, warnings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of value wrapped in warnings. `limitReached` parameter allows for
|
||||
* indicating if some custom warnings filtering on `additionalWarnings` have already been
|
||||
* performed.
|
||||
*
|
||||
* @param value value to be wrapped in warnings
|
||||
* @param maxWarnings maximal number of warnings allowed to be attached to the value
|
||||
* @param warnings warnings originally attached to a value
|
||||
* @param limitReached if `true`, indicates that `warnings` have already been limited for a
|
||||
* custom-method, `false` otherwise
|
||||
* @param additionalWarnings additional warnings to be appended to the list of `warnings`
|
||||
*/
|
||||
private WithWarnings(
|
||||
Object value,
|
||||
int maxWarnings,
|
||||
EconomicSet<Warning> warnings,
|
||||
boolean limitReached,
|
||||
Warning... additionalWarnings) {
|
||||
assert isAcceptableValue(value);
|
||||
this.warnings = cloneSetAndAppend(maxWarnings, warnings, additionalWarnings);
|
||||
assert this.warnings.size() > 0;
|
||||
this.value = value;
|
||||
this.limitReached = limitReached || this.warnings.size() >= maxWarnings;
|
||||
this.maxWarnings = maxWarnings;
|
||||
}
|
||||
|
||||
private WithWarnings(
|
||||
Object value, int maxWarnings, EconomicSet<Warning> warnings, Warning... additionalWarnings) {
|
||||
this(value, maxWarnings, warnings, false, additionalWarnings);
|
||||
}
|
||||
|
||||
private static boolean isAcceptableValue(Object value) {
|
||||
assert value != null;
|
||||
assert !(value instanceof WithWarnings) : "Trying to double wrap WithWarnings " + value;
|
||||
boolean goodValue =
|
||||
value instanceof TruffleObject
|
||||
|| value instanceof Long
|
||||
|| value instanceof Double
|
||||
|| value instanceof Boolean;
|
||||
assert goodValue : "Unexpected value floating around " + value + " type: " + value.getClass();
|
||||
return goodValue;
|
||||
}
|
||||
|
||||
public static WithWarnings wrap(EnsoContext ctx, Object value, Warning... warnings) {
|
||||
if (value instanceof WithWarnings with) {
|
||||
return with.append(ctx, warnings);
|
||||
} else {
|
||||
return new WithWarnings(value, ctx.getWarningsLimit(), warnings);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public WithWarnings append(EnsoContext ctx, boolean limitReached, Warning... newWarnings) {
|
||||
return new WithWarnings(value, ctx.getWarningsLimit(), warnings, limitReached, newWarnings);
|
||||
}
|
||||
|
||||
public WithWarnings append(EnsoContext ctx, Warning... newWarnings) {
|
||||
return new WithWarnings(value, ctx.getWarningsLimit(), warnings, newWarnings);
|
||||
}
|
||||
|
||||
public WithWarnings append(EnsoContext ctx, ArrayRope<Warning> newWarnings) {
|
||||
return new WithWarnings(
|
||||
value, ctx.getWarningsLimit(), warnings, newWarnings.toArray(Warning[]::new));
|
||||
}
|
||||
|
||||
// Ignore the warnings cache in .value and re-fetch them using the WarningsLibrary.
|
||||
// This is only used for shouldWrap=true.
|
||||
private Warning[] getWarningsNoCache(WarningsLibrary warningsLibrary) {
|
||||
if (warningsLibrary != null && warningsLibrary.hasWarnings(value)) {
|
||||
try {
|
||||
return warningsLibrary.getWarnings(value, null, true);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(warningsLibrary).raiseAssertionPanic(warningsLibrary, null, e);
|
||||
}
|
||||
} else {
|
||||
return Warning.fromSetToArray(warnings);
|
||||
}
|
||||
}
|
||||
|
||||
public Warning[] getWarningsArray(WarningsLibrary warningsLibrary, boolean shouldWrap) {
|
||||
Warning[] allWarnings;
|
||||
if (warningsLibrary != null && warningsLibrary.hasWarnings(value)) {
|
||||
try {
|
||||
Warning[] valueWarnings = warningsLibrary.getWarnings(value, null, shouldWrap);
|
||||
EconomicSet<Warning> tmp = cloneSetAndAppend(maxWarnings, warnings, valueWarnings);
|
||||
allWarnings = Warning.fromSetToArray(tmp);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(warningsLibrary).raiseAssertionPanic(warningsLibrary, null, e);
|
||||
}
|
||||
} else {
|
||||
allWarnings = Warning.fromSetToArray(warnings);
|
||||
}
|
||||
return allWarnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of warnings.
|
||||
*/
|
||||
public int getWarningsCount() {
|
||||
return warnings.size();
|
||||
}
|
||||
|
||||
public ArrayRope<Warning> getReassignedWarningsAsRope(Node location, boolean shouldWrap) {
|
||||
return new ArrayRope<>(getReassignedWarnings(location, shouldWrap, null));
|
||||
}
|
||||
|
||||
public Warning[] getReassignedWarnings(
|
||||
Node location, boolean shouldWrap, WarningsLibrary warningsLibrary) {
|
||||
Warning[] warnings = getWarningsArray(warningsLibrary, shouldWrap);
|
||||
for (int i = 0; i < warnings.length; i++) {
|
||||
warnings[i] = warnings[i].reassign(location);
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
|
||||
public static WithWarnings appendTo(EnsoContext ctx, Object target, ArrayRope<Warning> warnings) {
|
||||
if (target instanceof WithWarnings) {
|
||||
return ((WithWarnings) target).append(ctx, warnings.toArray(Warning[]::new));
|
||||
} else {
|
||||
return new WithWarnings(target, ctx.getWarningsLimit(), warnings.toArray(Warning[]::new));
|
||||
}
|
||||
}
|
||||
|
||||
public static WithWarnings appendTo(EnsoContext ctx, Object target, Warning... warnings) {
|
||||
return appendTo(ctx, target, false, warnings);
|
||||
}
|
||||
|
||||
public static WithWarnings appendTo(
|
||||
EnsoContext ctx, Object target, boolean reachedMaxCount, Warning... warnings) {
|
||||
if (target instanceof WithWarnings) {
|
||||
return ((WithWarnings) target).append(ctx, reachedMaxCount, warnings);
|
||||
} else {
|
||||
return new WithWarnings(target, ctx.getWarningsLimit(), reachedMaxCount, warnings);
|
||||
}
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private PanicException asException(Node where) {
|
||||
var rawWarn = this.getWarnings(where, false, WarningsLibrary.getUncached());
|
||||
var ctx = EnsoContext.get(where);
|
||||
var scopeOfAny = ctx.getBuiltins().any().getDefinitionScope();
|
||||
var toText = UnresolvedSymbol.build("to_text", scopeOfAny);
|
||||
var node = InteropMethodCallNode.getUncached();
|
||||
var state = State.create(ctx);
|
||||
|
||||
var text = Text.empty();
|
||||
for (var w : rawWarn) {
|
||||
try {
|
||||
var wText = node.execute(toText, state, new Object[] {w});
|
||||
if (wText instanceof Text t) {
|
||||
text = text.add(t);
|
||||
}
|
||||
} catch (ArityException e) {
|
||||
throw ctx.raiseAssertionPanic(where, null, e);
|
||||
}
|
||||
}
|
||||
return new PanicException(text, where);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Object send(Message message, Object[] args, @CachedLibrary(limit = "3") ReflectionLibrary lib)
|
||||
throws Exception {
|
||||
return lib.send(value, message, args);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasWarnings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Warning[] getWarnings(
|
||||
Node location,
|
||||
boolean shouldWrap,
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warningsLibrary) {
|
||||
if (location != null) {
|
||||
return getReassignedWarnings(location, shouldWrap, warningsLibrary);
|
||||
} else {
|
||||
if (shouldWrap) {
|
||||
// In the wrapping case, we don't use the local cache in .values, since
|
||||
// it contains unwrapped warnings. Instead, we fetch them again.
|
||||
return getWarningsNoCache(warningsLibrary);
|
||||
} else {
|
||||
return Warning.fromSetToArray(warnings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Object removeWarnings(@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||
throws UnsupportedMessageException {
|
||||
if (warnings.hasWarnings(value)) {
|
||||
return warnings.removeWarnings(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
public boolean isLimitReached() {
|
||||
return limitReached;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasType(@Shared("typesLib") @CachedLibrary(limit = "3") TypesLibrary types) {
|
||||
return types.hasType(value);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Type getType(@Shared("typesLib") @CachedLibrary(limit = "3") TypesLibrary types) {
|
||||
return types.getType(value);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasSpecialDispatch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean isException() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
RuntimeException throwException(@Bind("$node") Node node) throws UnsupportedMessageException {
|
||||
throw asException(node);
|
||||
}
|
||||
|
||||
public static class WarningEquivalence extends Equivalence {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object a, Object b) {
|
||||
if (a instanceof Warning thisObj && b instanceof Warning thatObj) {
|
||||
return thisObj.getSequenceId() == thatObj.getSequenceId();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object o) {
|
||||
return (int) ((Warning) o).getSequenceId();
|
||||
}
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private EconomicSet<Warning> createSetFromArray(int maxWarnings, Warning[] entries) {
|
||||
EconomicSet<Warning> set = EconomicSet.create(new WarningEquivalence());
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
if (set.size() == maxWarnings) {
|
||||
return set;
|
||||
}
|
||||
set.add(entries[i]);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private EconomicSet<Warning> cloneSetAndAppend(
|
||||
int maxWarnings, EconomicSet<Warning> initial, Warning[] entries) {
|
||||
return initial.size() == maxWarnings
|
||||
? initial
|
||||
: cloneSetAndAppendSlow(maxWarnings, initial, entries);
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private EconomicSet<Warning> cloneSetAndAppendSlow(
|
||||
int maxWarnings, EconomicSet<Warning> initial, Warning[] entries) {
|
||||
EconomicSet<Warning> set = EconomicSet.create(new WarningEquivalence());
|
||||
for (Warning warning : initial) {
|
||||
if (set.size() == maxWarnings) {
|
||||
return set;
|
||||
}
|
||||
set.add(warning);
|
||||
}
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
if (set.size() == maxWarnings) {
|
||||
return set;
|
||||
}
|
||||
set.add(entries[i]);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WithWarnings{"
|
||||
+ value
|
||||
+ " has "
|
||||
+ warnings.size()
|
||||
+ " warnings"
|
||||
+ (limitReached ? " (warnings limit reached)}" : "}");
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
|
||||
@GenerateUncached
|
||||
public abstract class TypeOfNode extends Node {
|
||||
@ -70,8 +70,8 @@ public abstract class TypeOfNode extends Node {
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doWarning(WithWarnings value) {
|
||||
return execute(value.getValue());
|
||||
Object doWarning(WithWarnings value, @Cached TypeOfNode withoutWarning) {
|
||||
return withoutWarning.execute(value.getValue());
|
||||
}
|
||||
|
||||
static boolean isWithoutType(Object value, TypesLibrary types) {
|
||||
|
@ -22,9 +22,11 @@ import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.DataflowError;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.error.Warning;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.warning.Warning;
|
||||
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||
import org.enso.polyglot.data.TypeGraph;
|
||||
|
||||
/**
|
||||
@ -57,6 +59,8 @@ import org.enso.polyglot.data.TypeGraph;
|
||||
PanicSentinel.class,
|
||||
EnsoHashMap.class,
|
||||
Warning.class,
|
||||
WithWarnings.class,
|
||||
WarningsLibrary.class,
|
||||
EnsoFile.class,
|
||||
EnsoDate.class,
|
||||
EnsoDateTime.class,
|
||||
|
@ -0,0 +1,209 @@
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.ConditionProfile;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertNode;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapSizeNode;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
|
||||
|
||||
@GenerateUncached
|
||||
public abstract class AppendWarningNode extends Node {
|
||||
|
||||
public static AppendWarningNode build() {
|
||||
return AppendWarningNodeGen.create();
|
||||
}
|
||||
|
||||
public static AppendWarningNode getUncached() {
|
||||
return AppendWarningNodeGen.getUncached();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a warning to the given object.
|
||||
*
|
||||
* @param object Object that will have the warning appended
|
||||
* @param warnings Either an array-like object containing warnings to append, or a single warning.
|
||||
* It is expected that all the elements in the container are of {@link Warning} class.
|
||||
* @return A wrapped object with warnings
|
||||
*/
|
||||
public abstract WithWarnings executeAppend(VirtualFrame frame, Object object, Object warnings);
|
||||
|
||||
@Specialization
|
||||
WithWarnings doSingleWarning(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
Warning warning,
|
||||
@Shared @Cached HashMapInsertNode mapInsertNode,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode,
|
||||
@Shared @Cached ConditionProfile isWithWarnsProfile) {
|
||||
EnsoHashMap warnsMap;
|
||||
int warnsLimit;
|
||||
Object value;
|
||||
if (isWithWarnsProfile.profile(object instanceof WithWarnings)) {
|
||||
warnsMap = ((WithWarnings) object).warnings;
|
||||
value = ((WithWarnings) object).value;
|
||||
warnsLimit = ((WithWarnings) object).maxWarnings;
|
||||
} else {
|
||||
warnsMap = EnsoHashMap.empty();
|
||||
value = object;
|
||||
warnsLimit = EnsoContext.get(this).getWarningsLimit();
|
||||
}
|
||||
boolean isLimitReached;
|
||||
if ((int) mapSizeNode.execute(warnsMap) < warnsLimit) {
|
||||
warnsMap = mapInsertNode.execute(frame, warnsMap, warning.getSequenceId(), warning);
|
||||
isLimitReached = false;
|
||||
} else {
|
||||
isLimitReached = true;
|
||||
}
|
||||
return new WithWarnings(value, warnsLimit, isLimitReached, warnsMap);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
WithWarnings doMultipleWarningsArray(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
Warning[] warnings,
|
||||
@Shared @Cached HashMapInsertNode mapInsertNode,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode,
|
||||
@Shared @Cached ConditionProfile isWithWarnsProfile) {
|
||||
EnsoHashMap warnsMap;
|
||||
int warnsLimit;
|
||||
Object value;
|
||||
if (isWithWarnsProfile.profile(object instanceof WithWarnings)) {
|
||||
warnsMap = ((WithWarnings) object).warnings;
|
||||
warnsLimit = ((WithWarnings) object).maxWarnings;
|
||||
value = ((WithWarnings) object).value;
|
||||
} else {
|
||||
warnsMap = EnsoHashMap.empty();
|
||||
warnsLimit = EnsoContext.get(this).getWarningsLimit();
|
||||
value = object;
|
||||
}
|
||||
var isLimitReached = false;
|
||||
for (var warn : warnings) {
|
||||
if (mapSizeNode.execute(warnsMap) < warnsLimit) {
|
||||
warnsMap = mapInsertNode.execute(frame, warnsMap, warn.getSequenceId(), warn);
|
||||
} else {
|
||||
isLimitReached = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new WithWarnings(value, warnsLimit, isLimitReached, warnsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* This specialization should be the most frequent - just wrapping the given {@code object} with
|
||||
* warnings hash map
|
||||
*/
|
||||
@Specialization(guards = {"!isWithWarns(object)"})
|
||||
WithWarnings doObjectMultipleWarningsHashMap(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
EnsoHashMap newWarnsMap,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode) {
|
||||
assert !(object instanceof WithWarnings);
|
||||
int warnsLimit = EnsoContext.get(this).getWarningsLimit();
|
||||
var limitReached = mapSizeNode.execute(newWarnsMap) >= warnsLimit;
|
||||
return new WithWarnings(object, warnsLimit, limitReached, newWarnsMap);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
WithWarnings doWithWarnMultipleWarningsHashMap(
|
||||
VirtualFrame frame,
|
||||
WithWarnings withWarnings,
|
||||
EnsoHashMap newWarnsMap,
|
||||
@Cached HashMapInsertAllNode mapInsertAllNode,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode) {
|
||||
if (withWarnings.isLimitReached()) {
|
||||
return withWarnings;
|
||||
}
|
||||
var maxWarns = withWarnings.maxWarnings;
|
||||
var warnsMap = withWarnings.warnings;
|
||||
var curWarnsCnt = (int) mapSizeNode.execute(warnsMap);
|
||||
warnsMap =
|
||||
mapInsertAllNode.executeInsertAll(frame, warnsMap, newWarnsMap, maxWarns - curWarnsCnt);
|
||||
var isLimitReached =
|
||||
mapSizeNode.execute(withWarnings.warnings) + mapSizeNode.execute(newWarnsMap) >= maxWarns;
|
||||
return new WithWarnings(withWarnings.value, withWarnings.maxWarnings, isLimitReached, warnsMap);
|
||||
}
|
||||
|
||||
@Specialization(guards = {"interop.hasArrayElements(warnings)", "!isWarnArray(warnings)"})
|
||||
WithWarnings doMultipleWarningsInterop(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
Object warnings,
|
||||
@CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@Shared @Cached HashMapInsertNode mapInsertNode,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
@Cached ArrayLikeLengthNode lengthNode,
|
||||
@Shared @Cached HashMapSizeNode mapSizeNode,
|
||||
@Shared @Cached ConditionProfile isWithWarnsProfile) {
|
||||
assert !(warnings instanceof Warning[]);
|
||||
EnsoHashMap warnsMap;
|
||||
int warnsLimit;
|
||||
Object value;
|
||||
if (isWithWarnsProfile.profile(object instanceof WithWarnings)) {
|
||||
value = ((WithWarnings) object).value;
|
||||
warnsLimit = ((WithWarnings) object).maxWarnings;
|
||||
warnsMap = ((WithWarnings) object).warnings;
|
||||
} else {
|
||||
value = object;
|
||||
warnsLimit = EnsoContext.get(this).getWarningsLimit();
|
||||
warnsMap = EnsoHashMap.empty();
|
||||
}
|
||||
var currWarnsCnt = mapSizeNode.execute(warnsMap);
|
||||
var resWarningMap =
|
||||
insertToWarningMap(
|
||||
frame, warnsMap, warnings, warnsLimit, lengthNode, atNode, mapInsertNode, mapSizeNode);
|
||||
var newWarnsCnt = lengthNode.executeLength(warnings);
|
||||
var isLimitReached = currWarnsCnt + newWarnsCnt >= warnsLimit;
|
||||
return new WithWarnings(value, warnsLimit, isLimitReached, resWarningMap);
|
||||
}
|
||||
|
||||
/** Inserts all {@code warnings} to the {@code initialWarningMap}. */
|
||||
private EnsoHashMap insertToWarningMap(
|
||||
VirtualFrame frame,
|
||||
EnsoHashMap initialWarningMap,
|
||||
Object warnings,
|
||||
int warnsLimit,
|
||||
ArrayLikeLengthNode lengthNode,
|
||||
ArrayLikeAtNode atNode,
|
||||
HashMapInsertNode mapInsertNode,
|
||||
HashMapSizeNode mapSizeNode) {
|
||||
EnsoHashMap resWarningMap = initialWarningMap;
|
||||
for (long i = 0; i < lengthNode.executeLength(warnings); i++) {
|
||||
Warning warn;
|
||||
try {
|
||||
warn = (Warning) atNode.executeAt(warnings, i);
|
||||
} catch (InvalidArrayIndexException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
} catch (ClassCastException e) {
|
||||
throw EnsoContext.get(this).raiseAssertionPanic(this, "Expected warning object", e);
|
||||
}
|
||||
if (mapSizeNode.execute(resWarningMap) >= warnsLimit) {
|
||||
return resWarningMap;
|
||||
}
|
||||
resWarningMap = mapInsertNode.execute(frame, resWarningMap, warn.getSequenceId(), warn);
|
||||
}
|
||||
return resWarningMap;
|
||||
}
|
||||
|
||||
protected static boolean isWarnArray(Object obj) {
|
||||
return obj instanceof Warning[];
|
||||
}
|
||||
|
||||
protected static boolean isWithWarns(Object obj) {
|
||||
return obj instanceof WithWarnings;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
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.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import org.enso.interpreter.dsl.AcceptsWarning;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Warning",
|
||||
name = "get_all_vector",
|
||||
description = "Gets all the warnings associated with the value.",
|
||||
autoRegister = false)
|
||||
public abstract class GetAllWarningsNode extends Node {
|
||||
|
||||
public static GetAllWarningsNode build() {
|
||||
return GetAllWarningsNodeGen.create();
|
||||
}
|
||||
|
||||
public abstract Object execute(@AcceptsWarning Object value, boolean shouldWrap);
|
||||
|
||||
@Specialization
|
||||
Object doWithWarn(
|
||||
WithWarnings value,
|
||||
boolean shouldWrap,
|
||||
@Shared @CachedLibrary(limit = "3") WarningsLibrary warningsLib,
|
||||
@Shared @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@Cached HashMapInsertAllNode mapInsertAllNode) {
|
||||
var warns = value.getWarningsArray(shouldWrap, warningsLib, mapInsertAllNode, interop);
|
||||
sortArray(warns);
|
||||
return ArrayLikeHelpers.asVectorEnsoObjects(warns);
|
||||
}
|
||||
|
||||
@Fallback
|
||||
Object doGeneric(
|
||||
Object value,
|
||||
boolean shouldWrap,
|
||||
@Shared @CachedLibrary(limit = "3") WarningsLibrary warningsLib,
|
||||
@Shared @CachedLibrary(limit = "3") InteropLibrary interop) {
|
||||
assert !(value instanceof WithWarnings);
|
||||
if (warningsLib.hasWarnings(value)) {
|
||||
try {
|
||||
var warnsMap = warningsLib.getWarnings(value, shouldWrap);
|
||||
var warnings = Warning.fromMapToArray(warnsMap, interop);
|
||||
sortArray(warnings);
|
||||
return ArrayLikeHelpers.asVectorEnsoObjects(warnings);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(warningsLib).raiseAssertionPanic(warningsLib, null, e);
|
||||
}
|
||||
} else {
|
||||
return ArrayLikeHelpers.asVectorEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private static void sortArray(Warning[] arr) {
|
||||
Arrays.sort(arr, Comparator.comparing(Warning::getSequenceId).reversed());
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.AcceptsWarning;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Warning",
|
||||
name = "limit_reached",
|
||||
description =
|
||||
"Returns `true` if the maximal number of warnings has been reached, `false` otherwise.",
|
||||
autoRegister = false)
|
||||
public abstract class LimitReachedNode extends Node {
|
||||
public static LimitReachedNode build() {
|
||||
return LimitReachedNodeGen.create();
|
||||
}
|
||||
|
||||
public abstract boolean execute(@AcceptsWarning Object value);
|
||||
|
||||
@Specialization
|
||||
boolean doWithWarns(WithWarnings withWarns) {
|
||||
return withWarns.isLimitReached();
|
||||
}
|
||||
|
||||
@Fallback
|
||||
boolean doGeneric(Object value, @CachedLibrary(limit = "3") WarningsLibrary warnsLib) {
|
||||
return warnsLib.hasWarnings(value) && warnsLib.isLimitReached(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.ConditionProfile;
|
||||
import org.enso.interpreter.dsl.AcceptsWarning;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertNode;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Warning",
|
||||
name = "set_array",
|
||||
description = "Sets all the warnings associated with the value.",
|
||||
autoRegister = false)
|
||||
@GenerateUncached
|
||||
public abstract class SetWarningsNode extends Node {
|
||||
|
||||
public static SetWarningsNode build() {
|
||||
return SetWarningsNodeGen.create();
|
||||
}
|
||||
|
||||
public abstract Object execute(VirtualFrame frame, @AcceptsWarning Object value, Object warnings);
|
||||
|
||||
@Specialization(guards = "isEmpty(warnings, interop)")
|
||||
Object doEmpty(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
Object warnings,
|
||||
@Shared @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@Shared @Cached ConditionProfile isWithWarnsProfile) {
|
||||
if (isWithWarnsProfile.profile(object instanceof WithWarnings)) {
|
||||
return ((WithWarnings) object).value;
|
||||
} else {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization(guards = "!isEmpty(warnings, interop)")
|
||||
Object doSetArray(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
Warning[] warnings,
|
||||
@Shared @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@Shared @Cached HashMapInsertNode mapInsertNode,
|
||||
@Shared @Cached ConditionProfile isWithWarnsProfile) {
|
||||
var warnMap = EnsoHashMap.empty();
|
||||
for (var warn : warnings) {
|
||||
warnMap = mapInsertNode.execute(frame, warnMap, warn.getSequenceId(), warn);
|
||||
}
|
||||
var maxWarns = EnsoContext.get(this).getWarningsLimit();
|
||||
var isLimitReached = warnings.length >= maxWarns;
|
||||
if (isWithWarnsProfile.profile(object instanceof WithWarnings)) {
|
||||
return new WithWarnings(((WithWarnings) object).value, maxWarns, isLimitReached, warnMap);
|
||||
} else {
|
||||
return new WithWarnings(object, maxWarns, isLimitReached, warnMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization(guards = {"!isEmpty(warnings, interop)", "!isWarnArray(warnings)"})
|
||||
Object doSetInteropArray(
|
||||
VirtualFrame frame,
|
||||
Object object,
|
||||
Object warnings,
|
||||
@Shared @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||
@Shared @Cached HashMapInsertNode mapInsertNode,
|
||||
@Shared @Cached ConditionProfile isWithWarnsProfile) {
|
||||
assert !(warnings instanceof Warning[]);
|
||||
var warnMap = EnsoHashMap.empty();
|
||||
var ctx = EnsoContext.get(this);
|
||||
try {
|
||||
var size = interop.getArraySize(warnings);
|
||||
for (long i = 0; i < interop.getArraySize(warnings); i++) {
|
||||
var warn = (Warning) interop.readArrayElement(warnings, i);
|
||||
warnMap = mapInsertNode.execute(frame, warnMap, warn.getSequenceId(), warn);
|
||||
}
|
||||
var maxWarns = ctx.getWarningsLimit();
|
||||
var isLimitReached = size >= maxWarns;
|
||||
if (isWithWarnsProfile.profile(object instanceof WithWarnings)) {
|
||||
return new WithWarnings(((WithWarnings) object).value, maxWarns, isLimitReached, warnMap);
|
||||
} else {
|
||||
return new WithWarnings(object, maxWarns, isLimitReached, warnMap);
|
||||
}
|
||||
} catch (UnsupportedMessageException | InvalidArrayIndexException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
} catch (ClassCastException e) {
|
||||
throw ctx.raiseAssertionPanic(this, "Expected Warning, got something else", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isEmpty(Object warns, InteropLibrary interop) {
|
||||
if (warns instanceof Warning[] warnsArray) {
|
||||
return warnsArray.length == 0;
|
||||
}
|
||||
if (interop.hasArrayElements(warns)) {
|
||||
try {
|
||||
return interop.getArraySize(warns) == 0;
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean isWarnArray(Object obj) {
|
||||
return obj instanceof Warning[];
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.Bind;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.StopIterationException;
|
||||
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.dsl.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.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertNode;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
|
||||
@Builtin(pkg = "error", stdlibName = "Standard.Base.Warning.Warning")
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
public final class Warning implements EnsoObject {
|
||||
private final Object value;
|
||||
private final Object origin;
|
||||
private final long sequenceId;
|
||||
|
||||
private Warning(Object value, Object origin, long sequenceId) {
|
||||
this.value = value;
|
||||
this.origin = origin;
|
||||
this.sequenceId = sequenceId;
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "value", description = "Gets the payload of the warning.")
|
||||
@SuppressWarnings("generic-enso-builtin-type")
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "origin", description = "Gets the payload of the warning.")
|
||||
@SuppressWarnings("generic-enso-builtin-type")
|
||||
public Object getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "create",
|
||||
description = "Creates a new instance of the primitive warning value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
public static Warning create(EnsoContext ctx, Object payload, Object origin) {
|
||||
return new Warning(payload, origin, ctx.nextSequenceId());
|
||||
}
|
||||
|
||||
@Builtin.Method(
|
||||
name = "attach_with_stacktrace",
|
||||
description = "Attaches the given warning to the value.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
public static WithWarnings attach(
|
||||
EnsoContext ctx,
|
||||
Object value,
|
||||
Object warning,
|
||||
Object origin,
|
||||
@Cached AppendWarningNode appendWarningNode) {
|
||||
var warn = new Warning(warning, origin, ctx.nextSequenceId());
|
||||
return appendWarningNode.executeAppend(null, value, warn);
|
||||
}
|
||||
|
||||
/** Slow version of {@link #fromMapToArray(EnsoHashMap, InteropLibrary)}. */
|
||||
@TruffleBoundary
|
||||
public static Warning[] fromMapToArray(EnsoHashMap map) {
|
||||
return fromMapToArray(map, InteropLibrary.getUncached());
|
||||
}
|
||||
|
||||
public static Warning[] fromMapToArray(EnsoHashMap map, InteropLibrary interop) {
|
||||
assert interop.hasHashEntries(map);
|
||||
Warning[] warns = null;
|
||||
try {
|
||||
long mapSize = interop.getHashSize(map);
|
||||
assert mapSize < Integer.MAX_VALUE;
|
||||
warns = new Warning[(int) mapSize];
|
||||
var hashValuesIt = interop.getHashValuesIterator(map);
|
||||
assert interop.isIterator(hashValuesIt);
|
||||
int warnsIdx = 0;
|
||||
while (interop.hasIteratorNextElement(hashValuesIt)) {
|
||||
var value = interop.getIteratorNextElement(hashValuesIt);
|
||||
warns[warnsIdx] = (Warning) value;
|
||||
warnsIdx++;
|
||||
}
|
||||
return warns;
|
||||
} catch (UnsupportedMessageException | ClassCastException | ArrayIndexOutOfBoundsException e) {
|
||||
throw CompilerDirectives.shouldNotReachHere(e);
|
||||
} catch (StopIterationException e) {
|
||||
assert warns != null;
|
||||
return warns;
|
||||
}
|
||||
}
|
||||
|
||||
public static EnsoHashMap fromArrayToMap(Warning[] warnings, HashMapInsertNode mapInsertNode) {
|
||||
var map = EnsoHashMap.empty();
|
||||
for (var warn : warnings) {
|
||||
map = mapInsertNode.execute(null, map, warn.getSequenceId(), warn);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@Override
|
||||
public String toString() {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public long getSequenceId() {
|
||||
return sequenceId;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Type getType(@Bind("$node") Node node) {
|
||||
return EnsoContext.get(node).getBuiltins().warning();
|
||||
}
|
||||
|
||||
public static Warning wrapMapError(WarningsLibrary warningsLib, Warning warning, long index) {
|
||||
var ctx = EnsoContext.get(warningsLib);
|
||||
var error = warning.getValue();
|
||||
var wrappedError = ctx.getBuiltins().error().makeMapError(index, error);
|
||||
return Warning.create(ctx, wrappedError, warning.getOrigin());
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package org.enso.interpreter.runtime.error;
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.GenerateLibrary;
|
||||
import com.oracle.truffle.api.library.Library;
|
||||
import com.oracle.truffle.api.library.LibraryFactory;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
|
||||
@GenerateLibrary
|
||||
public abstract class WarningsLibrary extends Library {
|
||||
@ -44,15 +44,14 @@ public abstract class WarningsLibrary extends Library {
|
||||
/**
|
||||
* Returns all unique warnings associated with the receiver.
|
||||
*
|
||||
* @param receiver the receiver to analyze
|
||||
* @param location optional parameter specifying the node to which the warnings should be
|
||||
* reassigned to
|
||||
* @param receiver the receiver to get the warnings from
|
||||
* @param shouldWrap if true, warnings attached to elements in array-likes are wrapped in
|
||||
* Map_Error
|
||||
* @return the associated warnings
|
||||
* @return the associated warnings as map - keys are {@code sequenceId} and values are warnings.
|
||||
* Not null
|
||||
*/
|
||||
@GenerateLibrary.Abstract(ifExported = {"hasWarnings"})
|
||||
public Warning[] getWarnings(Object receiver, Node location, boolean shouldWrap)
|
||||
public EnsoHashMap getWarnings(Object receiver, boolean shouldWrap)
|
||||
throws UnsupportedMessageException {
|
||||
throw UnsupportedMessageException.create();
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
package org.enso.interpreter.runtime.warning;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Bind;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||
import com.oracle.truffle.api.interop.ArityException;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.TruffleObject;
|
||||
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.library.Message;
|
||||
import com.oracle.truffle.api.library.ReflectionLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.node.callable.InteropMethodCallNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapInsertNodeGen;
|
||||
import org.enso.interpreter.runtime.data.hash.HashMapSizeNode;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNodeGen;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNodeGen;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
|
||||
/**
|
||||
* Represents a typical Enso <em>value with warnings</em>. As much of care as possible is taken to
|
||||
* delegate all operations to the underlaying {@code value}. Warnings are considered {@link
|
||||
* InteropLibrary#isException exceptional values} - e.g. one can check for them in Java polyglot
|
||||
* code as:
|
||||
*
|
||||
* <pre>
|
||||
* Value value = ...;
|
||||
* if (value.fitsInLong() && value.isException()) {
|
||||
* // probably an Integer with a warning
|
||||
* try {
|
||||
* warningMulti.throwException();
|
||||
* } catch (PolyglotException ex) {
|
||||
* System.out.println("Warnings attached to " + value.asLong() + " are " + ex.getMessage());
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@ExportLibrary(TypesLibrary.class)
|
||||
@ExportLibrary(WarningsLibrary.class)
|
||||
@ExportLibrary(ReflectionLibrary.class)
|
||||
@ExportLibrary(value = InteropLibrary.class, delegateTo = "value")
|
||||
public final class WithWarnings implements EnsoObject {
|
||||
final Object value;
|
||||
|
||||
/**
|
||||
* Internal storage for warnings is a PE-friendly hash map. The key is a sequence ID (gathered
|
||||
* from {@link EnsoContext#nextSequenceId()} and the value is the warning itself. Note that it is
|
||||
* essential that sequenceId is the key so that the warnings are not duplicated.
|
||||
*/
|
||||
final EnsoHashMap warnings;
|
||||
|
||||
private final boolean limitReached;
|
||||
final int maxWarnings;
|
||||
|
||||
/**
|
||||
* Creates a new instance of value wrapped in warnings.
|
||||
*
|
||||
* @param value value to be wrapped in warnings
|
||||
* @param maxWarnings maximal number of warnings allowed to be attached to the value
|
||||
* @param warningsMap warnings originally attached to a value
|
||||
* @param limitReached if `true`, indicates that `warnings` have already been limited for a
|
||||
* custom-method, `false` otherwise
|
||||
*/
|
||||
WithWarnings(Object value, int maxWarnings, boolean limitReached, EnsoHashMap warningsMap) {
|
||||
assert isAcceptableValue(value);
|
||||
var mapSizeNode = HashMapSizeNode.getUncached();
|
||||
assert mapSizeNode.execute(warningsMap) <= maxWarnings;
|
||||
if (limitReached) {
|
||||
assert mapSizeNode.execute(warningsMap) == maxWarnings;
|
||||
}
|
||||
this.value = value;
|
||||
this.maxWarnings = maxWarnings;
|
||||
this.limitReached = limitReached || mapSizeNode.execute(warningsMap) >= maxWarnings;
|
||||
this.warnings = warningsMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicit creation of WithWarnings. Allows to set a specific {@code maxWarnings} count, which
|
||||
* cannot be achieved by using warning-handling nodes like {@link AppendWarningNode}. If {@code
|
||||
* maxWarnings} does not need to be set explicitly, use nodes to create WithWarning objects
|
||||
* instead.
|
||||
*
|
||||
* @param value value to be wrapped in warnings
|
||||
* @param maxWarnings maximal number of warnings allowed to be attached to the value
|
||||
* @param limitReached if `true`, no other warnings will be attached to the {@code value}.
|
||||
* @param warnings array of warnings to be attached to the {@code value}
|
||||
*/
|
||||
public static WithWarnings create(
|
||||
Object value, int maxWarnings, boolean limitReached, Warning[] warnings) {
|
||||
assert warnings.length <= maxWarnings;
|
||||
if (limitReached) {
|
||||
assert warnings.length == maxWarnings;
|
||||
}
|
||||
var warnMap = Warning.fromArrayToMap(warnings, HashMapInsertNodeGen.getUncached());
|
||||
return new WithWarnings(value, maxWarnings, limitReached, warnMap);
|
||||
}
|
||||
|
||||
private static boolean isAcceptableValue(Object value) {
|
||||
assert value != null;
|
||||
assert !(value instanceof WithWarnings) : "Trying to double wrap WithWarnings " + value;
|
||||
boolean goodValue =
|
||||
value instanceof TruffleObject
|
||||
|| value instanceof Long
|
||||
|| value instanceof Double
|
||||
|| value instanceof Boolean;
|
||||
assert goodValue : "Unexpected value floating around " + value + " type: " + value.getClass();
|
||||
return goodValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Ignore the warnings cache in .value and re-fetch them using the WarningsLibrary.
|
||||
// This is only used for shouldWrap=true.
|
||||
private EnsoHashMap getWarningsNoCache(
|
||||
WarningsLibrary warningsLibrary, ArrayLikeLengthNode lengthNode, ArrayLikeAtNode atNode) {
|
||||
assert warningsLibrary != null;
|
||||
if (warningsLibrary.hasWarnings(value)) {
|
||||
try {
|
||||
return warningsLibrary.getWarnings(value, true);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(warningsLibrary).raiseAssertionPanic(warningsLibrary, null, e);
|
||||
}
|
||||
} else {
|
||||
return warnings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Slow version of {@link #getWarningsArray(boolean, WarningsLibrary, HashMapInsertAllNode,
|
||||
* InteropLibrary)} that uses uncached version of nodes and libraries parameters.
|
||||
*/
|
||||
public Warning[] getWarningsArray(boolean shouldWrap) {
|
||||
return getWarningsArray(
|
||||
shouldWrap,
|
||||
WarningsLibrary.getUncached(),
|
||||
HashMapInsertAllNode.getUncached(),
|
||||
InteropLibrary.getUncached());
|
||||
}
|
||||
|
||||
public Warning[] getWarningsArray(
|
||||
boolean shouldWrap,
|
||||
WarningsLibrary warningsLibrary,
|
||||
HashMapInsertAllNode mapInsertAllNode,
|
||||
InteropLibrary interop) {
|
||||
Warning[] allWarnsArray;
|
||||
if (warningsLibrary != null && warningsLibrary.hasWarnings(value)) {
|
||||
try {
|
||||
var valueWarnings = warningsLibrary.getWarnings(value, shouldWrap);
|
||||
var allWarns =
|
||||
mapInsertAllNode.executeInsertAll(null, warnings, valueWarnings, maxWarnings);
|
||||
allWarnsArray = Warning.fromMapToArray(allWarns, interop);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
throw EnsoContext.get(warningsLibrary).raiseAssertionPanic(warningsLibrary, null, e);
|
||||
}
|
||||
} else {
|
||||
allWarnsArray = Warning.fromMapToArray(warnings, interop);
|
||||
}
|
||||
return allWarnsArray;
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private PanicException asException(Node where) {
|
||||
var warnsMap =
|
||||
this.getWarnings(
|
||||
false,
|
||||
WarningsLibrary.getUncached(),
|
||||
ArrayLikeAtNodeGen.getUncached(),
|
||||
ArrayLikeLengthNodeGen.getUncached());
|
||||
var warns = Warning.fromMapToArray(warnsMap);
|
||||
var ctx = EnsoContext.get(where);
|
||||
var scopeOfAny = ctx.getBuiltins().any().getDefinitionScope();
|
||||
var toText = UnresolvedSymbol.build("to_text", scopeOfAny);
|
||||
var node = InteropMethodCallNode.getUncached();
|
||||
var state = State.create(ctx);
|
||||
|
||||
var text = Text.empty();
|
||||
for (var w : warns) {
|
||||
try {
|
||||
var wText = node.execute(toText, state, new Object[] {w});
|
||||
if (wText instanceof Text t) {
|
||||
text = text.add(t);
|
||||
}
|
||||
} catch (ArityException e) {
|
||||
throw ctx.raiseAssertionPanic(where, null, e);
|
||||
}
|
||||
}
|
||||
return new PanicException(text, where);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Object send(Message message, Object[] args, @CachedLibrary(limit = "3") ReflectionLibrary lib)
|
||||
throws Exception {
|
||||
return lib.send(value, message, args);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasWarnings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
EnsoHashMap getWarnings(
|
||||
boolean shouldWrap,
|
||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warningsLibrary,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
@Cached ArrayLikeLengthNode lengthNode) {
|
||||
if (shouldWrap) {
|
||||
// In the wrapping case, we don't use the local cache in .values, since
|
||||
// it contains unwrapped warnings. Instead, we fetch them again.
|
||||
return getWarningsNoCache(warningsLibrary, lengthNode, atNode);
|
||||
} else {
|
||||
return warnings;
|
||||
}
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Object removeWarnings(@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||
throws UnsupportedMessageException {
|
||||
if (warnings.hasWarnings(value)) {
|
||||
return warnings.removeWarnings(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
public boolean isLimitReached() {
|
||||
return limitReached;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasType(@Shared("typesLib") @CachedLibrary(limit = "3") TypesLibrary types) {
|
||||
return types.hasType(value);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Type getType(@Shared("typesLib") @CachedLibrary(limit = "3") TypesLibrary types) {
|
||||
return types.getType(value);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasSpecialDispatch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean isException() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
RuntimeException throwException(@Bind("$node") Node node) {
|
||||
throw asException(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WithWarnings{"
|
||||
+ value
|
||||
+ " has "
|
||||
+ HashMapSizeNode.getUncached().execute(warnings)
|
||||
+ " warnings"
|
||||
+ (limitReached ? " (warnings limit reached)}" : "}");
|
||||
}
|
||||
}
|
@ -5,7 +5,11 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/** An interface marking an argument as allowing it to accept a WithWarnings. */
|
||||
/**
|
||||
* An interface marking an argument as allowing it to accept a WithWarnings. Parameters annotated
|
||||
* with this annotation will not have their warnings stripped, so if it is of type {@link
|
||||
* org.enso.interpreter.runtime.warning.WithWarnings} it will not be unwrapped.
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface AcceptsWarning {}
|
||||
|
@ -16,7 +16,7 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface BuiltinMethod {
|
||||
/**
|
||||
* @return the language-level type of {@code self} argument.
|
||||
* @return the language-level type of {@code self} argument. Not a fully-qualified name.
|
||||
*/
|
||||
String type();
|
||||
|
||||
|
@ -130,6 +130,8 @@ public class MethodProcessor
|
||||
"com.oracle.truffle.api.CompilerDirectives",
|
||||
"com.oracle.truffle.api.dsl.UnsupportedSpecializationException",
|
||||
"com.oracle.truffle.api.frame.VirtualFrame",
|
||||
"com.oracle.truffle.api.interop.InteropLibrary",
|
||||
"com.oracle.truffle.api.interop.UnsupportedMessageException",
|
||||
"com.oracle.truffle.api.nodes.ControlFlowException",
|
||||
"com.oracle.truffle.api.nodes.Node",
|
||||
"com.oracle.truffle.api.nodes.NodeInfo",
|
||||
@ -146,14 +148,18 @@ public class MethodProcessor
|
||||
"org.enso.interpreter.runtime.callable.function.FunctionSchema",
|
||||
"org.enso.interpreter.runtime.EnsoContext",
|
||||
"org.enso.interpreter.runtime.builtin.Builtins",
|
||||
"org.enso.interpreter.runtime.data.ArrayRope",
|
||||
"org.enso.interpreter.runtime.data.hash.EnsoHashMap",
|
||||
"org.enso.interpreter.runtime.data.hash.HashMapInsertNode",
|
||||
"org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode",
|
||||
"org.enso.interpreter.runtime.data.text.Text",
|
||||
"org.enso.interpreter.runtime.error.DataflowError",
|
||||
"org.enso.interpreter.runtime.error.PanicException",
|
||||
"org.enso.interpreter.runtime.error.Warning",
|
||||
"org.enso.interpreter.runtime.error.WithWarnings",
|
||||
"org.enso.interpreter.runtime.state.State",
|
||||
"org.enso.interpreter.runtime.type.TypesGen");
|
||||
"org.enso.interpreter.runtime.type.TypesGen",
|
||||
"org.enso.interpreter.runtime.warning.Warning",
|
||||
"org.enso.interpreter.runtime.warning.WarningsLibrary",
|
||||
"org.enso.interpreter.runtime.warning.WithWarnings",
|
||||
"org.enso.interpreter.runtime.warning.AppendWarningNode");
|
||||
|
||||
/** List of exception types that should be caught from the builtin's execute method. */
|
||||
private static final List<String> handleExceptionTypes =
|
||||
@ -190,6 +196,13 @@ public class MethodProcessor
|
||||
+ " extends BuiltinRootNode implements InlineableNode.Root {");
|
||||
}
|
||||
out.println(" private @Child " + methodDefinition.getOriginalClassName() + " bodyNode;");
|
||||
out.println(
|
||||
" private @Child AppendWarningNode appendWarningNode = AppendWarningNode.build();");
|
||||
out.println(
|
||||
" private @Child WarningsLibrary warnLib ="
|
||||
+ " WarningsLibrary.getFactory().createDispatched(5);");
|
||||
out.println(
|
||||
" private @Child HashMapInsertAllNode mapInsertAllNode = HashMapInsertAllNode.build();");
|
||||
out.println();
|
||||
out.println(" private static final class Internals {");
|
||||
out.println(" Internals(boolean s) {");
|
||||
@ -282,27 +295,44 @@ public class MethodProcessor
|
||||
+ " body = "
|
||||
+ methodDefinition.getConstructorExpression()
|
||||
+ ";");
|
||||
out.println(
|
||||
" private @Child AppendWarningNode appendWarningNode ="
|
||||
+ " AppendWarningNode.build();");
|
||||
out.println(
|
||||
" private @Child WarningsLibrary warnLib ="
|
||||
+ " WarningsLibrary.getFactory().createDispatched(5);");
|
||||
out.println(
|
||||
" private @Child HashMapInsertAllNode mapInsertAllNode ="
|
||||
+ " HashMapInsertAllNode.build();");
|
||||
out.println();
|
||||
out.println(" @Override");
|
||||
out.println(" public Object call(VirtualFrame frame, Object[] args) {");
|
||||
out.println(" return handleExecute(frame, extra, body, args);");
|
||||
out.println(
|
||||
" return handleExecute(frame, extra, body, appendWarningNode, warnLib,"
|
||||
+ " mapInsertAllNode, args);");
|
||||
out.println(" }");
|
||||
out.println(" }");
|
||||
out.println();
|
||||
out.println(" return new Inlineable();");
|
||||
out.println(" }");
|
||||
}
|
||||
|
||||
out.println();
|
||||
|
||||
out.println(" @Override");
|
||||
out.println(" public Object execute(VirtualFrame frame) {");
|
||||
if (methodDefinition.needsFrame()) {
|
||||
out.println(" var args = frame.getArguments();");
|
||||
} else {
|
||||
out.println(
|
||||
" return handleExecute(frame, this.internals, bodyNode, frame.getArguments());");
|
||||
" return handleExecute(frame, this.internals, bodyNode, this.appendWarningNode,"
|
||||
+ " this.warnLib, this.mapInsertAllNode, frame.getArguments());");
|
||||
out.println(" }");
|
||||
out.println(
|
||||
" private static Object handleExecute(VirtualFrame frame, Internals internals, "
|
||||
+ methodDefinition.getOriginalClassName()
|
||||
+ " bodyNode, Object[] args) {");
|
||||
+ " bodyNode, AppendWarningNode appendWarningNode, WarningsLibrary warnLib,"
|
||||
+ " HashMapInsertAllNode mapInsertAllNode, Object[] args) {");
|
||||
}
|
||||
out.println(" var prefix = internals.staticOfInstanceMethod ? 1 : 0;");
|
||||
out.println(" State state = Function.ArgumentsHelper.getState(args);");
|
||||
@ -346,8 +376,8 @@ public class MethodProcessor
|
||||
out.println(" internals.anyWarningsProfile.enter();");
|
||||
out.println(" Object result;");
|
||||
out.println(wrapInTryCatch("result = " + executeCall + ";", 6));
|
||||
out.println(" EnsoContext ctx = EnsoContext.get(bodyNode);");
|
||||
out.println(" return WithWarnings.appendTo(ctx, result, gatheredWarnings);");
|
||||
out.println(
|
||||
" return appendWarningNode.executeAppend(frame, result, gatheredWarnings);");
|
||||
out.println(" } else {");
|
||||
out.println(wrapInTryCatch("return " + executeCall + ";", 6));
|
||||
out.println(" }");
|
||||
@ -598,28 +628,27 @@ public class MethodProcessor
|
||||
return false;
|
||||
} else {
|
||||
out.println(" boolean anyWarnings = false;");
|
||||
out.println(" ArrayRope<Warning> gatheredWarnings = new ArrayRope<>();");
|
||||
out.println(" int maxWarnings = EnsoContext.get(bodyNode).getWarningsLimit();");
|
||||
out.println(" EnsoHashMap gatheredWarnings = EnsoHashMap.empty();");
|
||||
for (var arg : argsToCheck) {
|
||||
String argCode = arrayRead(argumentsArray, arg.getPosition());
|
||||
out.println(
|
||||
" if ("
|
||||
+ arrayRead(argumentsArray, arg.getPosition())
|
||||
+ " instanceof WithWarnings) {");
|
||||
+ " instanceof WithWarnings withWarnings) {");
|
||||
out.println(
|
||||
" internals." + mkArgumentInternalVarName(arg) + WARNING_PROFILE + ".enter();");
|
||||
out.println(" anyWarnings = true;");
|
||||
out.println(" try {"); // begin try
|
||||
out.println(" var warns = warnLib.getWarnings(withWarnings, false);");
|
||||
out.println(" " + argCode + " = withWarnings.getValue();");
|
||||
out.println(
|
||||
" WithWarnings withWarnings = (WithWarnings) "
|
||||
+ arrayRead(argumentsArray, arg.getPosition())
|
||||
+ ";");
|
||||
out.println(
|
||||
" "
|
||||
+ arrayRead(argumentsArray, arg.getPosition())
|
||||
+ " = withWarnings.getValue();");
|
||||
out.print(
|
||||
"""
|
||||
gatheredWarnings = gatheredWarnings.prepend(withWarnings.getReassignedWarningsAsRope(bodyNode, false));
|
||||
""");
|
||||
out.println(" }");
|
||||
" gatheredWarnings = mapInsertAllNode.executeInsertAll(frame, gatheredWarnings,"
|
||||
+ " warns, maxWarnings);");
|
||||
out.println(" } catch (UnsupportedMessageException e) {"); // end try
|
||||
out.println(" throw CompilerDirectives.shouldNotReachHere(e);");
|
||||
out.println(" }"); // end catch
|
||||
out.println(" }"); // end hasWarnings
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class CachedLibraryMethodParameter extends SpecializedMethodParameter {
|
||||
|
||||
public static final String INTEROP_LIBRARY = "com.oracle.truffle.api.interop.InteropLibrary";
|
||||
public static final String WARNINGS_LIBRARY =
|
||||
"org.enso.interpreter.runtime.error.WarningsLibrary";
|
||||
"org.enso.interpreter.runtime.warning.WarningsLibrary";
|
||||
}
|
||||
|
||||
class InjectedMethodParameter extends SpecializedMethodParameter {
|
||||
|
@ -14,6 +14,7 @@ import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.enso.interpreter.dsl.AcceptsWarning;
|
||||
import org.enso.interpreter.dsl.Builtin;
|
||||
@ -160,12 +161,16 @@ public final class SpecializedMethodsGenerator extends MethodGenerator {
|
||||
paramss.forEach(
|
||||
(k, v) -> {
|
||||
if (v.size() != elements.size()) {
|
||||
throw new RuntimeException(
|
||||
"Restriction: Specialized methods have to have equal number of parameters.\n"
|
||||
+ "Expected "
|
||||
+ elements.size()
|
||||
+ ", got "
|
||||
+ v.size());
|
||||
processingEnv
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Kind.ERROR,
|
||||
"Restriction: Specialized methods have to have equal number of parameters.\n"
|
||||
+ "Expected "
|
||||
+ elements.size()
|
||||
+ ", got "
|
||||
+ v.size(),
|
||||
elements.get(0));
|
||||
}
|
||||
|
||||
MethodParameter p = v.get(0);
|
||||
|
@ -46,16 +46,6 @@ get_foo x = x.foo
|
||||
|
||||
unwrap x = Integer.from x
|
||||
|
||||
reassign_test x =
|
||||
consed = Wrap.Value x
|
||||
reconsed = rewrap consed
|
||||
i = unwrap reconsed
|
||||
rereconsed = Wrap.Value i
|
||||
x1 = get_foo rereconsed
|
||||
prim_sum = 1 + x1
|
||||
r = poly_sum prim_sum 1
|
||||
r
|
||||
|
||||
baz value = Warning.attach value "I have warned you"
|
||||
bar value = baz value
|
||||
foo value = bar value
|
||||
@ -165,21 +155,6 @@ add_specs suite_builder = suite_builder.group "Dataflow Warnings" group_builder-
|
||||
relevant = warning_stack . drop (..Last current.length)
|
||||
relevant.map .name . should_equal (['baz', 'bar', 'foo'].map ('Warnings_Spec.'+))
|
||||
|
||||
group_builder.specify "should attach reassignment info in the last-reassigned-first order" <|
|
||||
x = Warning.attach "warn!" 1
|
||||
r = reassign_test x
|
||||
warn = Warning.get_all r . first
|
||||
reassignments = warn.reassignments.map .name
|
||||
expected_stack = []
|
||||
+ [ 'Warnings_Spec.poly_sum' ]
|
||||
+ [ 'Integer.+' ]
|
||||
+ [ 'Warnings_Spec.get_foo' ]
|
||||
+ [ 'Wrap.Value' ]
|
||||
+ [ 'Integer.from' ]
|
||||
+ [ 'Warnings_Spec.rewrap' ]
|
||||
+ [ 'Wrap.Value' ]
|
||||
reassignments.should_equal expected_stack.to_vector
|
||||
|
||||
group_builder.specify "should allow to set all warnings" <|
|
||||
warned = Warning.attach 1 <| Warning.attach 2 <| Warning.attach 3 <| Warning.attach 4 "foo"
|
||||
warnings = Warning.get_all warned
|
||||
|
Loading…
Reference in New Issue
Block a user