mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 00:01:35 +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(`interpreter-dsl`)
|
||||||
.dependsOn(`runtime`)
|
.dependsOn(`runtime`)
|
||||||
|
.dependsOn(`test-utils`)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// === Sub-Projects ===========================================================
|
// === Sub-Projects ===========================================================
|
||||||
|
@ -255,36 +255,6 @@ type Warning
|
|||||||
origin : Vector Stack_Trace_Element
|
origin : Vector Stack_Trace_Element
|
||||||
origin self = @Builtin_Method "Warning.origin"
|
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
|
## PRIVATE
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import com.oracle.truffle.api.nodes.DirectCallNode;
|
|||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import org.enso.interpreter.node.InlineableNode;
|
import org.enso.interpreter.node.InlineableNode;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
|
import org.enso.test.utils.ContextUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class InliningBuiltinsTest {
|
public class InliningBuiltinsTest {
|
||||||
@ -17,26 +18,33 @@ public class InliningBuiltinsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWithoutVirtualFrame() {
|
public void executeWithoutVirtualFrame() {
|
||||||
var fn = InliningBuiltinsInMethodGen.makeFunction(null);
|
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
ContextUtils.executeInContext(
|
||||||
var call = root.createInlineableNode();
|
ctx,
|
||||||
var clazz = call.getClass();
|
() -> {
|
||||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
var fn = InliningBuiltinsInMethodGen.makeFunction(null);
|
||||||
assertEquals(
|
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||||
"org.enso.interpreter.node.InlineableNode$Root",
|
var call = root.createInlineableNode();
|
||||||
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
var clazz = call.getClass();
|
||||||
|
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||||
|
assertEquals(
|
||||||
|
"org.enso.interpreter.node.InlineableNode$Root",
|
||||||
|
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||||
|
|
||||||
var res =
|
var res =
|
||||||
WithFrame.invoke(
|
WithFrame.invoke(
|
||||||
(frame) -> {
|
(frame) -> {
|
||||||
return call.call(
|
return call.call(
|
||||||
frame,
|
frame,
|
||||||
Function.ArgumentsHelper.buildArguments(
|
Function.ArgumentsHelper.buildArguments(
|
||||||
null, null, new Object[] {null, 5L, 7L}));
|
null, null, new Object[] {null, 5L, 7L}));
|
||||||
});
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
} else {
|
} else {
|
||||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,22 +53,29 @@ public class InliningBuiltinsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWithVirtualFrame() {
|
public void executeWithVirtualFrame() {
|
||||||
var fn = InliningBuiltinsOutMethodGen.makeFunction(null);
|
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
ContextUtils.executeInContext(
|
||||||
fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode());
|
ctx,
|
||||||
} else {
|
() -> {
|
||||||
var call = DirectCallNode.create(fn.getCallTarget());
|
var fn = InliningBuiltinsOutMethodGen.makeFunction(null);
|
||||||
var clazz = call.getClass().getSuperclass();
|
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
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 =
|
var res =
|
||||||
WithFrame.invoke(
|
WithFrame.invoke(
|
||||||
(frame) -> {
|
(frame) -> {
|
||||||
return call.call(
|
return call.call(
|
||||||
Function.ArgumentsHelper.buildArguments(
|
Function.ArgumentsHelper.buildArguments(
|
||||||
null, null, new Object[] {null, 3L, 9L}));
|
null, null, new Object[] {null, 3L, 9L}));
|
||||||
});
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,22 +84,29 @@ public class InliningBuiltinsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWhenNeedsVirtualFrame() {
|
public void executeWhenNeedsVirtualFrame() {
|
||||||
var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null);
|
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
ContextUtils.executeInContext(
|
||||||
fail("The node isn't inlineable: " + fn.getCallTarget().getRootNode());
|
ctx,
|
||||||
} else {
|
() -> {
|
||||||
var call = DirectCallNode.create(fn.getCallTarget());
|
var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null);
|
||||||
var clazz = call.getClass().getSuperclass();
|
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
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 =
|
var res =
|
||||||
WithFrame.invoke(
|
WithFrame.invoke(
|
||||||
(frame) -> {
|
(frame) -> {
|
||||||
return call.call(
|
return call.call(
|
||||||
Function.ArgumentsHelper.buildArguments(
|
Function.ArgumentsHelper.buildArguments(
|
||||||
null, null, new Object[] {null, 3L, 9L}));
|
null, null, new Object[] {null, 3L, 9L}));
|
||||||
});
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,26 +115,33 @@ public class InliningBuiltinsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWhenNeedNotVirtualFrame() {
|
public void executeWhenNeedNotVirtualFrame() {
|
||||||
var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null);
|
try (var ctx = ContextUtils.createDefaultContext()) {
|
||||||
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
ContextUtils.executeInContext(
|
||||||
var call = root.createInlineableNode();
|
ctx,
|
||||||
var clazz = call.getClass();
|
() -> {
|
||||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null);
|
||||||
assertEquals(
|
if (fn.getCallTarget().getRootNode() instanceof InlineableNode.Root root) {
|
||||||
"org.enso.interpreter.node.InlineableNode$Root",
|
var call = root.createInlineableNode();
|
||||||
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
var clazz = call.getClass();
|
||||||
|
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||||
|
assertEquals(
|
||||||
|
"org.enso.interpreter.node.InlineableNode$Root",
|
||||||
|
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||||
|
|
||||||
var res =
|
var res =
|
||||||
WithFrame.invoke(
|
WithFrame.invoke(
|
||||||
(frame) -> {
|
(frame) -> {
|
||||||
return call.call(
|
return call.call(
|
||||||
frame,
|
frame,
|
||||||
Function.ArgumentsHelper.buildArguments(
|
Function.ArgumentsHelper.buildArguments(
|
||||||
null, null, new Object[] {null, 5L, 7L}));
|
null, null, new Object[] {null, 5L, 7L}));
|
||||||
});
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
} else {
|
} else {
|
||||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ public final class Utils {
|
|||||||
.option(
|
.option(
|
||||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
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.DISABLE_IR_CACHES, "true")
|
||||||
.option(RuntimeOptions.STRICT_ERRORS, "true")
|
.option(RuntimeOptions.STRICT_ERRORS, "true")
|
||||||
.option("engine.CompilationFailureAction", "Print")
|
.option("engine.CompilationFailureAction", "Print")
|
||||||
|
@ -73,29 +73,34 @@ public class WarningBenchmarks {
|
|||||||
|
|
||||||
benchmarkName = SrcUtil.findName(params);
|
benchmarkName = SrcUtil.findName(params);
|
||||||
|
|
||||||
var code =
|
var benchCode =
|
||||||
new StringBuilder(
|
"""
|
||||||
"""
|
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
vec_sum_bench : Vector Integer -> Integer
|
vec_sum_bench : Vector Integer -> Integer
|
||||||
vec_sum_bench vec =
|
vec_sum_bench vec =
|
||||||
vec.fold 0 (x->y->x+y)
|
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
|
Vector.fill size elem
|
||||||
|
|
||||||
elem =
|
elem =
|
||||||
42
|
42
|
||||||
|
|
||||||
elem_const_with_warning =
|
elem_const_with_warning = Runtime.no_inline <|
|
||||||
x = 42
|
x = 42
|
||||||
Warning.attach "Foo!" x
|
Warning.attach "Foo!" x
|
||||||
|
|
||||||
elem_with_warning v =
|
elem_with_warning v = Runtime.no_inline <|
|
||||||
Warning.attach "Foo!" v
|
Warning.attach "Foo!" v
|
||||||
|
|
||||||
map_vector_with_warnings vec =
|
map_vector_with_warnings vec = Runtime.no_inline <|
|
||||||
vec.map (e-> elem_with_warning e)
|
vec.map (e-> elem_with_warning e)
|
||||||
""");
|
""");
|
||||||
|
|
||||||
@ -103,31 +108,37 @@ public class WarningBenchmarks {
|
|||||||
var randomIntVectorName = "vector_with_random_values";
|
var randomIntVectorName = "vector_with_random_values";
|
||||||
var vectorWithRandomValues =
|
var vectorWithRandomValues =
|
||||||
generateRandomVector(random, randomIntVectorName, INPUT_DIFF_VEC_SIZE, 3_000);
|
generateRandomVector(random, randomIntVectorName, INPUT_DIFF_VEC_SIZE, 3_000);
|
||||||
code.append(vectorWithRandomValues.repr());
|
setupCode.append(vectorWithRandomValues.repr());
|
||||||
randomVectorSum = vectorWithRandomValues.sum();
|
randomVectorSum = vectorWithRandomValues.sum();
|
||||||
|
|
||||||
var src = SrcUtil.source(benchmarkName, code.toString());
|
var setupSrc = SrcUtil.source(benchmarkName + "_Setup", setupCode.toString());
|
||||||
Value module = ctx.eval(src);
|
Value setupModule = ctx.eval(setupSrc);
|
||||||
vecSumBench =
|
|
||||||
Objects.requireNonNull(
|
|
||||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "vec_sum_bench"));
|
|
||||||
createVec =
|
createVec =
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create_vec"));
|
setupModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create_vec"));
|
||||||
mapVecWithWarnings =
|
mapVecWithWarnings =
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "map_vector_with_warnings"));
|
setupModule.invokeMember(
|
||||||
|
MethodNames.Module.EVAL_EXPRESSION, "map_vector_with_warnings"));
|
||||||
constElem =
|
constElem =
|
||||||
Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem"));
|
Objects.requireNonNull(
|
||||||
|
setupModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem"));
|
||||||
constElemWithWarning =
|
constElemWithWarning =
|
||||||
Objects.requireNonNull(
|
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);
|
noWarningsVec = createVec.execute(INPUT_VEC_SIZE, constElem);
|
||||||
sameWarningVec = createVec.execute(INPUT_VEC_SIZE, constElemWithWarning);
|
sameWarningVec = createVec.execute(INPUT_VEC_SIZE, constElemWithWarning);
|
||||||
randomVec =
|
randomVec =
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, randomIntVectorName));
|
setupModule.invokeMember(MethodNames.Module.EVAL_EXPRESSION, randomIntVectorName));
|
||||||
randomElemsWithWarningsVec = mapVecWithWarnings.execute(randomVec);
|
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
|
@TearDown
|
||||||
|
@ -5,7 +5,7 @@ import com.oracle.truffle.api.interop.InteropLibrary;
|
|||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
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 {
|
public final class VisualizationResult {
|
||||||
private 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.data.atom.AtomConstructor
|
||||||
import org.enso.interpreter.runtime.callable.function.Function
|
import org.enso.interpreter.runtime.callable.function.Function
|
||||||
import org.enso.interpreter.runtime.control.ThreadInterruptedException
|
import org.enso.interpreter.runtime.control.ThreadInterruptedException
|
||||||
import org.enso.interpreter.runtime.error.{
|
import org.enso.interpreter.runtime.error.{DataflowError, PanicSentinel}
|
||||||
DataflowError,
|
|
||||||
PanicSentinel,
|
|
||||||
WarningsLibrary,
|
|
||||||
WithWarnings
|
|
||||||
}
|
|
||||||
import org.enso.interpreter.service.ExecutionService.{
|
import org.enso.interpreter.service.ExecutionService.{
|
||||||
ExpressionCall,
|
ExpressionCall,
|
||||||
ExpressionValue,
|
ExpressionValue,
|
||||||
@ -41,6 +36,11 @@ import org.enso.interpreter.service.error.{
|
|||||||
VisualizationException
|
VisualizationException
|
||||||
}
|
}
|
||||||
import org.enso.common.LanguageInfo
|
import org.enso.common.LanguageInfo
|
||||||
|
import org.enso.interpreter.runtime.warning.{
|
||||||
|
Warning,
|
||||||
|
WarningsLibrary,
|
||||||
|
WithWarnings
|
||||||
|
}
|
||||||
import org.enso.polyglot.debugger.ExecutedVisualization
|
import org.enso.polyglot.debugger.ExecutedVisualization
|
||||||
import org.enso.polyglot.runtime.Runtime.Api
|
import org.enso.polyglot.runtime.Runtime.Api
|
||||||
import org.enso.polyglot.runtime.Runtime.Api.{ContextId, ExecutionResult}
|
import org.enso.polyglot.runtime.Runtime.Api.{ContextId, ExecutionResult}
|
||||||
@ -419,12 +419,9 @@ object ProgramExecutionSupport {
|
|||||||
value.getValue
|
value.getValue
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
val warnings =
|
val warnsMap =
|
||||||
WarningsLibrary.getUncached.getWarnings(
|
WarningsLibrary.getUncached.getWarnings(value.getValue, false)
|
||||||
value.getValue,
|
val warnings = Warning.fromMapToArray(warnsMap)
|
||||||
null,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
val warningsCount = warnings.length
|
val warningsCount = warnings.length
|
||||||
val warning =
|
val warning =
|
||||||
if (warningsCount > 0) {
|
if (warningsCount > 0) {
|
||||||
|
@ -6,12 +6,11 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import org.enso.common.LanguageInfo;
|
|
||||||
import org.enso.common.MethodNames;
|
import org.enso.common.MethodNames;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.error.Warning;
|
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
import org.enso.interpreter.runtime.warning.Warning;
|
||||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||||
import org.enso.test.utils.ContextUtils;
|
import org.enso.test.utils.ContextUtils;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.PolyglotException;
|
import org.graalvm.polyglot.PolyglotException;
|
||||||
@ -33,11 +32,7 @@ public class WarningsTest {
|
|||||||
public static void initEnsoContext() {
|
public static void initEnsoContext() {
|
||||||
ctx = ContextUtils.createDefaultContext();
|
ctx = ContextUtils.createDefaultContext();
|
||||||
generator = ValuesGenerator.create(ctx, ValuesGenerator.Language.ENSO);
|
generator = ValuesGenerator.create(ctx, ValuesGenerator.Language.ENSO);
|
||||||
ensoContext =
|
ensoContext = ContextUtils.leakContext(ctx);
|
||||||
(EnsoContext)
|
|
||||||
ctx.getBindings(LanguageInfo.ID)
|
|
||||||
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
|
|
||||||
.asHostObject();
|
|
||||||
var module =
|
var module =
|
||||||
ctx.eval(
|
ctx.eval(
|
||||||
"enso",
|
"enso",
|
||||||
@ -57,19 +52,22 @@ public class WarningsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doubleWithWarningsWrap() {
|
public void doubleWithWarningsWrap() {
|
||||||
var warn1 = Warning.create(ensoContext, "w1", this);
|
ContextUtils.executeInContext(
|
||||||
var warn2 = Warning.create(ensoContext, "w2", this);
|
ctx,
|
||||||
var value = 42L;
|
() -> {
|
||||||
|
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 with1 = AppendWarningNode.getUncached().executeAppend(null, value, warn1);
|
||||||
var with2 = WithWarnings.wrap(ensoContext, with1, warn2);
|
var with2 = AppendWarningNode.getUncached().executeAppend(null, with1, warn2);
|
||||||
|
|
||||||
assertEquals(value, with1.getValue());
|
assertEquals(value, with1.getValue());
|
||||||
assertEquals(value, with2.getValue());
|
assertEquals(value, with2.getValue());
|
||||||
Assert.assertArrayEquals(
|
Assert.assertArrayEquals(new Object[] {warn1}, with1.getWarningsArray(false));
|
||||||
new Object[] {warn1}, with1.getWarningsArray(WarningsLibrary.getUncached(), false));
|
Assert.assertArrayEquals(new Object[] {warn1, warn2}, with2.getWarningsArray(false));
|
||||||
Assert.assertArrayEquals(
|
return null;
|
||||||
new Object[] {warn1, warn2}, with2.getWarningsArray(WarningsLibrary.getUncached(), false));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -77,7 +75,7 @@ public class WarningsTest {
|
|||||||
var value = 42;
|
var value = 42;
|
||||||
WithWarnings without;
|
WithWarnings without;
|
||||||
try {
|
try {
|
||||||
without = WithWarnings.wrap(ensoContext, 42, new Warning[0]);
|
without = AppendWarningNode.getUncached().executeAppend(null, 42, new Warning[0]);
|
||||||
} catch (AssertionError e) {
|
} catch (AssertionError e) {
|
||||||
// OK
|
// OK
|
||||||
return;
|
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.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.state.State;
|
||||||
|
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes any callable with given arguments.
|
* Invokes any callable with given arguments.
|
||||||
@ -74,7 +73,8 @@ public abstract class IndirectInvokeCallableNode extends Node {
|
|||||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||||
BaseNode.TailStatus isTail,
|
BaseNode.TailStatus isTail,
|
||||||
@Cached IndirectInvokeCallableNode invokeCallableNode,
|
@Cached IndirectInvokeCallableNode invokeCallableNode,
|
||||||
@CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
|
@Cached AppendWarningNode appendWarningNode) {
|
||||||
try {
|
try {
|
||||||
var result =
|
var result =
|
||||||
invokeCallableNode.execute(
|
invokeCallableNode.execute(
|
||||||
@ -87,8 +87,8 @@ public abstract class IndirectInvokeCallableNode extends Node {
|
|||||||
argumentsExecutionMode,
|
argumentsExecutionMode,
|
||||||
isTail);
|
isTail);
|
||||||
|
|
||||||
Warning[] extracted = warnings.getWarnings(warning, null, false);
|
var extracted = warnings.getWarnings(warning, false);
|
||||||
return WithWarnings.wrap(EnsoContext.get(this), result, extracted);
|
return appendWarningNode.executeAppend(null, result, extracted);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
throw ctx.raiseAssertionPanic(this, null, e);
|
throw ctx.raiseAssertionPanic(this, null, e);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.enso.interpreter.node.callable;
|
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;
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
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.UnresolvedConversion;
|
||||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
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.Type;
|
||||||
|
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.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
|
@GenerateUncached
|
||||||
@ReportPolymorphism
|
@ReportPolymorphism
|
||||||
@ -157,9 +159,16 @@ abstract class IndirectInvokeConversionNode extends Node {
|
|||||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||||
BaseNode.TailStatus isTail,
|
BaseNode.TailStatus isTail,
|
||||||
int thatArgumentPosition,
|
int thatArgumentPosition,
|
||||||
@Cached IndirectInvokeConversionNode childDispatch) {
|
@Cached IndirectInvokeConversionNode childDispatch,
|
||||||
|
@Cached AppendWarningNode appendWarningNode,
|
||||||
|
@CachedLibrary(limit = "3") WarningsLibrary warnsLib) {
|
||||||
arguments[thatArgumentPosition] = that.getValue();
|
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 =
|
Object result =
|
||||||
childDispatch.execute(
|
childDispatch.execute(
|
||||||
frame,
|
frame,
|
||||||
@ -173,7 +182,7 @@ abstract class IndirectInvokeConversionNode extends Node {
|
|||||||
argumentsExecutionMode,
|
argumentsExecutionMode,
|
||||||
isTail,
|
isTail,
|
||||||
thatArgumentPosition);
|
thatArgumentPosition);
|
||||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
return appendWarningNode.executeAppend(null, result, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "interop.isString(that)")
|
@Specialization(guards = "interop.isString(that)")
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.enso.interpreter.node.callable;
|
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.Bind;
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
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.UnresolvedSymbol;
|
||||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
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.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
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
|
@GenerateUncached
|
||||||
@ReportPolymorphism
|
@ReportPolymorphism
|
||||||
@ -129,9 +131,16 @@ public abstract class IndirectInvokeMethodNode extends Node {
|
|||||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||||
BaseNode.TailStatus isTail,
|
BaseNode.TailStatus isTail,
|
||||||
int thisArgumentPosition,
|
int thisArgumentPosition,
|
||||||
@Cached IndirectInvokeMethodNode childDispatch) {
|
@Cached IndirectInvokeMethodNode childDispatch,
|
||||||
|
@Cached AppendWarningNode appendWarningNode,
|
||||||
|
@CachedLibrary(limit = "3") WarningsLibrary warnsLib) {
|
||||||
arguments[thisArgumentPosition] = self.getValue();
|
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 =
|
Object result =
|
||||||
childDispatch.execute(
|
childDispatch.execute(
|
||||||
frame,
|
frame,
|
||||||
@ -144,7 +153,7 @@ public abstract class IndirectInvokeMethodNode extends Node {
|
|||||||
argumentsExecutionMode,
|
argumentsExecutionMode,
|
||||||
isTail,
|
isTail,
|
||||||
thisArgumentPosition);
|
thisArgumentPosition);
|
||||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
return appendWarningNode.executeAppend(null, result, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
|
@ -19,7 +19,6 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import org.enso.interpreter.Constants;
|
import org.enso.interpreter.Constants;
|
||||||
import org.enso.interpreter.node.BaseNode;
|
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.dispatch.InvokeFunctionNode;
|
||||||
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
|
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
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.control.TailCallException;
|
||||||
import org.enso.interpreter.runtime.data.atom.Atom;
|
import org.enso.interpreter.runtime.data.atom.Atom;
|
||||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
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.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
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
|
* 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,
|
VirtualFrame callerFrame,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
@Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
@Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
|
@Cached AppendWarningNode appendWarningNode) {
|
||||||
Warning[] extracted;
|
EnsoHashMap extracted;
|
||||||
Object callable;
|
Object callable;
|
||||||
try {
|
try {
|
||||||
extracted = warnings.getWarnings(warning, null, false);
|
extracted = warnings.getWarnings(warning, false);
|
||||||
callable = warnings.removeWarnings(warning);
|
callable = warnings.removeWarnings(warning);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
@ -325,7 +324,7 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
if (result instanceof DataflowError) {
|
if (result instanceof DataflowError) {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
return WithWarnings.wrap(EnsoContext.get(this), result, extracted);
|
return appendWarningNode.executeAppend(null, result, extracted);
|
||||||
}
|
}
|
||||||
} catch (TailCallException e) {
|
} catch (TailCallException e) {
|
||||||
throw new TailCallException(e, extracted);
|
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.argument.CallArgumentInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
import org.enso.interpreter.runtime.control.TailCallException;
|
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.EnsoMultiValue;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
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.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.library.dispatch.TypeOfNode;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
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 {
|
public abstract class InvokeConversionNode extends BaseNode {
|
||||||
private @Child InvokeFunctionNode invokeFunctionNode;
|
private @Child InvokeFunctionNode invokeFunctionNode;
|
||||||
@ -198,7 +199,9 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
UnresolvedConversion conversion,
|
UnresolvedConversion conversion,
|
||||||
Object self,
|
Object self,
|
||||||
WithWarnings that,
|
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.
|
// Cannot use @Cached for childDispatch, because we need to call notifyInserted.
|
||||||
if (childDispatch == null) {
|
if (childDispatch == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
@ -223,12 +226,17 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
}
|
}
|
||||||
Object value = that.getValue();
|
Object value = that.getValue();
|
||||||
arguments[thatArgumentPosition] = value;
|
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 {
|
try {
|
||||||
Object result = childDispatch.execute(frame, state, conversion, self, value, arguments);
|
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) {
|
} 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.Function;
|
||||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||||
import org.enso.interpreter.runtime.control.TailCallException;
|
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.EnsoDate;
|
||||||
import org.enso.interpreter.runtime.data.EnsoDateTime;
|
import org.enso.interpreter.runtime.data.EnsoDateTime;
|
||||||
import org.enso.interpreter.runtime.data.EnsoDuration;
|
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.EnsoTimeOfDay;
|
||||||
import org.enso.interpreter.runtime.data.EnsoTimeZone;
|
import org.enso.interpreter.runtime.data.EnsoTimeZone;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
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.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
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})
|
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
||||||
public abstract class InvokeMethodNode extends BaseNode {
|
public abstract class InvokeMethodNode extends BaseNode {
|
||||||
@ -436,12 +436,13 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
UnresolvedSymbol symbol,
|
UnresolvedSymbol symbol,
|
||||||
Object self,
|
Object self,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
@Shared("warnings") @CachedLibrary(limit = "10") WarningsLibrary warnings) {
|
@Shared("warnings") @CachedLibrary(limit = "10") WarningsLibrary warnings,
|
||||||
|
@Shared @Cached AppendWarningNode appendWarningNode) {
|
||||||
Object selfWithoutWarnings;
|
Object selfWithoutWarnings;
|
||||||
Warning[] arrOfWarnings;
|
EnsoHashMap warnsMap;
|
||||||
try {
|
try {
|
||||||
selfWithoutWarnings = warnings.removeWarnings(self);
|
selfWithoutWarnings = warnings.removeWarnings(self);
|
||||||
arrOfWarnings = warnings.getWarnings(self, this, false);
|
warnsMap = warnings.getWarnings(self, false);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
throw ctx.raiseAssertionPanic(this, null, e);
|
throw ctx.raiseAssertionPanic(this, null, e);
|
||||||
@ -475,9 +476,10 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Object result = childDispatch.execute(frame, state, symbol, selfWithoutWarnings, arguments);
|
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) {
|
} 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[] profiles,
|
||||||
@Cached(value = "buildProfiles()", dimensions = 1) BranchProfile[] warningProfiles,
|
@Cached(value = "buildProfiles()", dimensions = 1) BranchProfile[] warningProfiles,
|
||||||
@Cached BranchProfile anyWarningsProfile,
|
@Cached BranchProfile anyWarningsProfile,
|
||||||
@Cached HostMethodCallNode hostMethodCallNode) {
|
@Cached HostMethodCallNode hostMethodCallNode,
|
||||||
|
@Shared @Cached AppendWarningNode appendWarningNode,
|
||||||
|
@Cached HashMapInsertAllNode mapInsertAllNode) {
|
||||||
Object[] args = new Object[argExecutors.length];
|
Object[] args = new Object[argExecutors.length];
|
||||||
boolean anyWarnings = false;
|
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++) {
|
for (int i = 0; i < argExecutors.length; i++) {
|
||||||
var r = argExecutors[i].executeThunk(frame, arguments[i + 1], state, TailStatus.NOT_TAIL);
|
var r = argExecutors[i].executeThunk(frame, arguments[i + 1], state, TailStatus.NOT_TAIL);
|
||||||
if (r instanceof DataflowError) {
|
if (r instanceof DataflowError) {
|
||||||
@ -518,7 +523,9 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
warningProfiles[i].enter();
|
warningProfiles[i].enter();
|
||||||
anyWarnings = true;
|
anyWarnings = true;
|
||||||
try {
|
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);
|
args[i] = warnings.removeWarnings(r);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
@ -531,7 +538,7 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
Object res = hostMethodCallNode.execute(polyglotCallType, symbol.getName(), self, args);
|
Object res = hostMethodCallNode.execute(polyglotCallType, symbol.getName(), self, args);
|
||||||
if (anyWarnings) {
|
if (anyWarnings) {
|
||||||
anyWarningsProfile.enter();
|
anyWarningsProfile.enter();
|
||||||
res = WithWarnings.appendTo(EnsoContext.get(this), res, accumulatedWarnings);
|
res = appendWarningNode.executeAppend(null, res, accumulatedWarnings);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import com.oracle.truffle.api.nodes.Node;
|
|||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
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;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,5 +43,5 @@ public abstract class CallOptimiserNode extends Node {
|
|||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
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 com.oracle.truffle.api.nodes.RepeatingNode;
|
||||||
import org.enso.interpreter.node.callable.ExecuteCallNode;
|
import org.enso.interpreter.node.callable.ExecuteCallNode;
|
||||||
import org.enso.interpreter.node.callable.ExecuteCallNodeGen;
|
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.CallerInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
import org.enso.interpreter.runtime.control.TailCallException;
|
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.error.WithWarnings;
|
|
||||||
import org.enso.interpreter.runtime.state.State;
|
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
|
* 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,
|
CallerInfo callerInfo,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
Warning[] warnings,
|
EnsoHashMap warnings,
|
||||||
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode) {
|
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode) {
|
||||||
return dispatch(function, callerInfo, state, arguments, loopNode);
|
return dispatch(function, callerInfo, state, arguments, loopNode);
|
||||||
}
|
}
|
||||||
@ -76,10 +75,11 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
|||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
Warning[] warnings,
|
EnsoHashMap warnings,
|
||||||
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode) {
|
@Shared("loopNode") @Cached(value = "createLoopNode()") LoopNode loopNode,
|
||||||
|
@Shared @Cached AppendWarningNode appendWarningNode) {
|
||||||
Object result = dispatch(function, callerInfo, state, arguments, loopNode);
|
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(
|
private Object dispatch(
|
||||||
@ -104,7 +104,7 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
|||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
Warning[] warnings,
|
EnsoHashMap warnings,
|
||||||
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode) {
|
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode) {
|
||||||
return loopUntilCompletion(frame, function, callerInfo, state, arguments, executeCallNode);
|
return loopUntilCompletion(frame, function, callerInfo, state, arguments, executeCallNode);
|
||||||
}
|
}
|
||||||
@ -117,11 +117,12 @@ public abstract class LoopingCallOptimiserNode extends CallOptimiserNode {
|
|||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
Warning[] warnings,
|
EnsoHashMap warnings,
|
||||||
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode) {
|
@Shared("executeCallNode") @Cached ExecuteCallNode executeCallNode,
|
||||||
|
@Shared @Cached AppendWarningNode appendWarningNode) {
|
||||||
Object result =
|
Object result =
|
||||||
loopUntilCompletion(frame, function, callerInfo, state, arguments, executeCallNode);
|
loopUntilCompletion(frame, function, callerInfo, state, arguments, executeCallNode);
|
||||||
return WithWarnings.appendTo(EnsoContext.get(this), result, warnings);
|
return appendWarningNode.executeAppend(null, result, warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object loopUntilCompletion(
|
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.CallerInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
import org.enso.interpreter.runtime.control.TailCallException;
|
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;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +51,7 @@ public class SimpleCallOptimiserNode extends CallOptimiserNode {
|
|||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
State state,
|
State state,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
Warning[] warnings) {
|
EnsoHashMap warnings) {
|
||||||
try {
|
try {
|
||||||
return executeCallNode.executeCall(frame, function, callerInfo, state, arguments);
|
return executeCallNode.executeCall(frame, function, callerInfo, state, arguments);
|
||||||
} catch (TailCallException e) {
|
} catch (TailCallException e) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.enso.interpreter.node.controlflow.caseexpr;
|
package org.enso.interpreter.node.controlflow.caseexpr;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
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.Cached.Shared;
|
||||||
import com.oracle.truffle.api.dsl.NodeChild;
|
import com.oracle.truffle.api.dsl.NodeChild;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
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.error.*;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
import org.enso.interpreter.runtime.type.TypesGen;
|
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.
|
* A node representing a pattern match on an arbitrary runtime value.
|
||||||
@ -82,12 +85,12 @@ public abstract class CaseNode extends ExpressionNode {
|
|||||||
Object doWarning(
|
Object doWarning(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
Object object,
|
Object object,
|
||||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
|
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
|
@Cached AppendWarningNode appendWarningNode) {
|
||||||
try {
|
try {
|
||||||
EnsoContext ctx = EnsoContext.get(this);
|
var ws = warnings.getWarnings(object, false);
|
||||||
Warning[] ws = warnings.getWarnings(object, this, false);
|
|
||||||
Object result = doMatch(frame, warnings.removeWarnings(object), warnings);
|
Object result = doMatch(frame, warnings.removeWarnings(object), warnings);
|
||||||
return WithWarnings.wrap(ctx, result, ws);
|
return appendWarningNode.executeAppend(null, result, ws);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, 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 com.oracle.truffle.api.profiles.CountingConditionProfile;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
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
|
* 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,
|
Object value,
|
||||||
@CachedLibrary(limit = "3") InteropLibrary iop,
|
@CachedLibrary(limit = "3") InteropLibrary iop,
|
||||||
@CachedLibrary(limit = "3") WarningsLibrary warningsLibrary,
|
@CachedLibrary(limit = "3") WarningsLibrary warningsLibrary,
|
||||||
@Cached CountingConditionProfile nullWarningProfile) {
|
@Cached CountingConditionProfile nullWarningProfile,
|
||||||
|
@Cached AppendWarningNode appendWarningNode) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var nothing = ctx.getBuiltins().nothing();
|
var nothing = ctx.getBuiltins().nothing();
|
||||||
if (nothing != value && nullWarningProfile.profile(warningsLibrary.hasWarnings(value))) {
|
if (nothing != value && nullWarningProfile.profile(warningsLibrary.hasWarnings(value))) {
|
||||||
try {
|
try {
|
||||||
var attachedWarnings = warningsLibrary.getWarnings(value, null, false);
|
var attachedWarnings = warningsLibrary.getWarnings(value, false);
|
||||||
return WithWarnings.wrap(ctx, nothing, attachedWarnings);
|
return appendWarningNode.executeAppend(null, nothing, attachedWarnings);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ import org.enso.interpreter.node.callable.InvokeCallableNode;
|
|||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
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.state.State;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "IO",
|
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.EnsoFile;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.data.atom.Atom;
|
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.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
@GenerateUncached
|
@GenerateUncached
|
||||||
public abstract class EqualsComplexNode extends Node {
|
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.Atom;
|
||||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
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.number.EnsoBigInteger;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
||||||
|
|
||||||
@GenerateUncached
|
@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.AtomConstructor;
|
||||||
import org.enso.interpreter.runtime.data.atom.StructsLibrary;
|
import org.enso.interpreter.runtime.data.atom.StructsLibrary;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
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.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
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.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
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.number.EnsoBigInteger;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Default_Comparator",
|
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.data.vector.ArrayLikeLengthNode;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
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.TypeOfNode;
|
||||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
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
|
* 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
|
* @param self Vector that has elements with only Default_Comparator, that are elements with
|
||||||
* builtin types.
|
* builtin types.
|
||||||
* @param ascending -1 for descending, 1 for ascending
|
* @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}
|
* 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
|
* parameter is not {@code Nothing}, comparators are gathered from the result of {@code
|
||||||
* onFunc} projection.
|
* onFunc} projection.
|
||||||
@ -354,7 +355,8 @@ public abstract class SortVectorNode extends Node {
|
|||||||
.map(text -> Warning.create(ctx, text, this))
|
.map(text -> Warning.create(ctx, text, this))
|
||||||
.limit(MAX_SORT_WARNINGS)
|
.limit(MAX_SORT_WARNINGS)
|
||||||
.toArray(Warning[]::new);
|
.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) {
|
private Object attachDifferentComparatorsWarning(Object vector, List<Group> groups) {
|
||||||
@ -366,8 +368,13 @@ public abstract class SortVectorNode extends Node {
|
|||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
var text = Text.create("Different comparators: [" + diffCompsMsg + "]");
|
var text = Text.create("Different comparators: [" + diffCompsMsg + "]");
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var warn = Warning.create(ctx, text, this);
|
var warnsLib = WarningsLibrary.getUncached();
|
||||||
return WithWarnings.appendTo(ctx, vector, false, warn);
|
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 {
|
} else {
|
||||||
return vector;
|
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.atom.Atom;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
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 {
|
public abstract class ExpectStringNode extends Node {
|
||||||
private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(10);
|
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 com.oracle.truffle.api.nodes.ControlFlowException;
|
||||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
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.
|
* 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 Function function;
|
||||||
private final CallerInfo callerInfo;
|
private final CallerInfo callerInfo;
|
||||||
private final Object[] arguments;
|
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.
|
* Creates a new exception containing the necessary data to continue computation.
|
||||||
@ -31,7 +37,7 @@ public class TailCallException extends ControlFlowException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TailCallException(
|
private TailCallException(
|
||||||
Function function, CallerInfo callerInfo, Object[] arguments, Warning[] warnings) {
|
Function function, CallerInfo callerInfo, Object[] arguments, EnsoHashMap warnings) {
|
||||||
this.function = function;
|
this.function = function;
|
||||||
this.callerInfo = callerInfo;
|
this.callerInfo = callerInfo;
|
||||||
this.arguments = arguments;
|
this.arguments = arguments;
|
||||||
@ -44,7 +50,7 @@ public class TailCallException extends ControlFlowException {
|
|||||||
* @param origin the original tail call exception
|
* @param origin the original tail call exception
|
||||||
* @param warnings warnings to be associated with the 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);
|
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
|
* @return the warnings to be appended to the result of the call, or null if empty
|
||||||
*/
|
*/
|
||||||
public Warning[] getWarnings() {
|
public EnsoHashMap getWarnings() {
|
||||||
return warnings;
|
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.text.Text;
|
||||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
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.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.type.TypesGen;
|
import org.enso.interpreter.runtime.type.TypesGen;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
/** A runtime representation of an Atom in Enso. */
|
/** A runtime representation of an Atom in Enso. */
|
||||||
@ExportLibrary(InteropLibrary.class)
|
@ExportLibrary(InteropLibrary.class)
|
||||||
|
@ -11,11 +11,11 @@ import com.oracle.truffle.api.profiles.BranchProfile;
|
|||||||
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
||||||
import org.enso.interpreter.node.ExpressionNode;
|
import org.enso.interpreter.node.ExpressionNode;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.ArrayRope;
|
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||||
import org.enso.interpreter.runtime.error.Warning;
|
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
|
||||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
|
||||||
import org.enso.interpreter.runtime.type.TypesGen;
|
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
|
* A node instantiating a constant {@link AtomConstructor} with values computed based on the
|
||||||
@ -66,10 +66,13 @@ abstract class InstantiateNode extends ExpressionNode {
|
|||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
Object doExecute(
|
Object doExecute(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
@Cached(parameters = {"constructor"}) AtomConstructorInstanceNode createInstanceNode) {
|
@Cached(parameters = {"constructor"}) AtomConstructorInstanceNode createInstanceNode,
|
||||||
|
@Cached AppendWarningNode appendWarningNode,
|
||||||
|
@Cached HashMapInsertAllNode mapInsertAllNode) {
|
||||||
Object[] argumentValues = new Object[arguments.length];
|
Object[] argumentValues = new Object[arguments.length];
|
||||||
boolean anyWarnings = false;
|
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++) {
|
for (int i = 0; i < arguments.length; i++) {
|
||||||
CountingConditionProfile profile = profiles[i];
|
CountingConditionProfile profile = profiles[i];
|
||||||
CountingConditionProfile warningProfile = warningProfiles[i];
|
CountingConditionProfile warningProfile = warningProfiles[i];
|
||||||
@ -80,8 +83,10 @@ abstract class InstantiateNode extends ExpressionNode {
|
|||||||
} else if (warningProfile.profile(warnings.hasWarnings(argument))) {
|
} else if (warningProfile.profile(warnings.hasWarnings(argument))) {
|
||||||
anyWarnings = true;
|
anyWarnings = true;
|
||||||
try {
|
try {
|
||||||
|
var argumentWarnsMap = warnings.getWarnings(argument, false);
|
||||||
accumulatedWarnings =
|
accumulatedWarnings =
|
||||||
accumulatedWarnings.append(warnings.getWarnings(argument, this, false));
|
mapInsertAllNode.executeInsertAll(
|
||||||
|
frame, accumulatedWarnings, argumentWarnsMap, maxWarnings);
|
||||||
argumentValues[i] = warnings.removeWarnings(argument);
|
argumentValues[i] = warnings.removeWarnings(argument);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||||
@ -94,8 +99,8 @@ abstract class InstantiateNode extends ExpressionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anyWarningsProfile.profile(anyWarnings)) {
|
if (anyWarningsProfile.profile(anyWarnings)) {
|
||||||
return WithWarnings.appendTo(
|
return appendWarningNode.executeAppend(
|
||||||
EnsoContext.get(this), createInstanceNode.execute(argumentValues), accumulatedWarnings);
|
frame, createInstanceNode.execute(argumentValues), accumulatedWarnings);
|
||||||
} else {
|
} else {
|
||||||
return createInstanceNode.execute(argumentValues);
|
return createInstanceNode.execute(argumentValues);
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ public final class EnsoHashMap implements EnsoObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Slow version of {@link #getCachedVectorRepresentation(ConditionProfile)}. */
|
||||||
Object getCachedVectorRepresentation() {
|
Object getCachedVectorRepresentation() {
|
||||||
return getCachedVectorRepresentation(ConditionProfile.getUncached());
|
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.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import java.util.Arrays;
|
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.EqualsNode;
|
||||||
import org.enso.interpreter.node.expression.builtin.meta.HashCodeNode;
|
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}. */
|
/** Create a new builder with default size being {@code 11}. */
|
||||||
public static EnsoHashMapBuilder create() {
|
static EnsoHashMapBuilder create() {
|
||||||
return new EnsoHashMapBuilder(11);
|
return new EnsoHashMapBuilder(11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EnsoHashMapBuilder createWithCapacity(int capacity) {
|
||||||
|
assert capacity > 0;
|
||||||
|
return new EnsoHashMapBuilder(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns count of elements in the storage. */
|
/** Returns count of elements in the storage. */
|
||||||
public int generation() {
|
int generation() {
|
||||||
return generation;
|
return generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the actual number of visible elements in current generation. */
|
/** Returns the actual number of visible elements in current generation. */
|
||||||
public int size() {
|
int size() {
|
||||||
return actualSize;
|
return actualSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +72,7 @@ final class EnsoHashMapBuilder {
|
|||||||
* Provides access to all {@code StorageEntry} in this builder at given {@code atGeneration}.
|
* 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))}.
|
* 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 arr = new StorageEntry[size];
|
||||||
var at = 0;
|
var at = 0;
|
||||||
for (var i = 0; i < byHash.length; i++) {
|
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
|
* 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.
|
* the {@code atGeneration == this.generation} and the {@code byHash} array is less than 75% full.
|
||||||
* Otherwise it may return new builder suitable for additions.
|
* Otherwise it may return new builder suitable for additions.
|
||||||
*/
|
*/
|
||||||
public EnsoHashMapBuilder asModifiable(
|
EnsoHashMapBuilder asModifiable(
|
||||||
VirtualFrame frame, int atGeneration, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
VirtualFrame frame, int atGeneration, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
||||||
if (atGeneration != generation || generation * 4 > byHash.length * 3) {
|
if (atGeneration != generation || generation * 4 > byHash.length * 3) {
|
||||||
var newSize = Math.max(actualSize * 2, byHash.length);
|
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,
|
* 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.
|
* it puts there a new entry with the next generation.
|
||||||
*/
|
*/
|
||||||
public void put(
|
void put(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
Object key,
|
Object key,
|
||||||
Object value,
|
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
|
* Finds storage entry for given key or {@code null}. Searches only entries that are visible for
|
||||||
* given {@code generation}.
|
* given {@code generation}.
|
||||||
*/
|
*/
|
||||||
public StorageEntry get(
|
StorageEntry get(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
Object key,
|
Object key,
|
||||||
int generation,
|
int generation,
|
||||||
@ -175,8 +226,7 @@ final class EnsoHashMapBuilder {
|
|||||||
*
|
*
|
||||||
* @return true if the removal was successful false otherwise.
|
* @return true if the removal was successful false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean remove(
|
boolean remove(VirtualFrame frame, Object key, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
||||||
VirtualFrame frame, Object key, HashCodeNode hashCodeNode, EqualsNode equalsNode) {
|
|
||||||
assert actualSize <= generation;
|
assert actualSize <= generation;
|
||||||
var at = findWhereToStart(key, hashCodeNode);
|
var at = findWhereToStart(key, hashCodeNode);
|
||||||
var nextGeneration = ++generation;
|
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
|
* are in the storage as of this moment, i.e., all the entries with their indexes lesser than
|
||||||
* {@code generation}.
|
* {@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.
|
* @return A new hash map snapshot.
|
||||||
*/
|
*/
|
||||||
public EnsoHashMap build() {
|
EnsoHashMap build() {
|
||||||
return EnsoHashMap.createWithBuilder(this);
|
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.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
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.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
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.
|
Returns newly created hash map with the given key value mapping.
|
||||||
""",
|
""",
|
||||||
autoRegister = false)
|
autoRegister = false)
|
||||||
|
@GenerateUncached
|
||||||
public abstract class HashMapInsertNode extends Node {
|
public abstract class HashMapInsertNode extends Node {
|
||||||
|
|
||||||
public static HashMapInsertNode build() {
|
public static HashMapInsertNode build() {
|
||||||
@ -41,6 +43,7 @@ public abstract class HashMapInsertNode extends Node {
|
|||||||
Object value,
|
Object value,
|
||||||
@Shared("hash") @Cached HashCodeNode hashCodeNode,
|
@Shared("hash") @Cached HashCodeNode hashCodeNode,
|
||||||
@Shared("equals") @Cached EqualsNode equalsNode) {
|
@Shared("equals") @Cached EqualsNode equalsNode) {
|
||||||
|
assert value != null;
|
||||||
var mapBuilder = hashMap.getMapBuilder(frame, false, hashCodeNode, equalsNode);
|
var mapBuilder = hashMap.getMapBuilder(frame, false, hashCodeNode, equalsNode);
|
||||||
mapBuilder.put(frame, key, value, hashCodeNode, equalsNode);
|
mapBuilder.put(frame, key, value, hashCodeNode, equalsNode);
|
||||||
var newMap = mapBuilder.build();
|
var newMap = mapBuilder.build();
|
||||||
@ -61,6 +64,7 @@ public abstract class HashMapInsertNode extends Node {
|
|||||||
@CachedLibrary(limit = "3") InteropLibrary iteratorInterop,
|
@CachedLibrary(limit = "3") InteropLibrary iteratorInterop,
|
||||||
@Shared("hash") @Cached HashCodeNode hashCodeNode,
|
@Shared("hash") @Cached HashCodeNode hashCodeNode,
|
||||||
@Shared("equals") @Cached EqualsNode equalsNode) {
|
@Shared("equals") @Cached EqualsNode equalsNode) {
|
||||||
|
assert valueToInsert != null;
|
||||||
var mapBuilder = EnsoHashMapBuilder.create();
|
var mapBuilder = EnsoHashMapBuilder.create();
|
||||||
try {
|
try {
|
||||||
Object entriesIterator = mapInterop.getHashEntriesIterator(foreignMap);
|
Object entriesIterator = mapInterop.getHashEntriesIterator(foreignMap);
|
||||||
|
@ -23,6 +23,10 @@ public abstract class HashMapSizeNode extends Node {
|
|||||||
return HashMapSizeNodeGen.create();
|
return HashMapSizeNodeGen.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HashMapSizeNode getUncached() {
|
||||||
|
return HashMapSizeNodeGen.getUncached();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract long execute(Object self);
|
public abstract long execute(Object self);
|
||||||
|
|
||||||
@Specialization(guards = "interop.hasHashEntries(hashMap)", limit = "3")
|
@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.nodes.Node;
|
||||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import org.enso.interpreter.dsl.Builtin;
|
import org.enso.interpreter.dsl.Builtin;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.error.Warning;
|
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
import org.enso.interpreter.runtime.data.hash.HashMapInsertAllNode;
|
||||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
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.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. */
|
/** A primitive boxed array type for use in the runtime. */
|
||||||
@ExportLibrary(InteropLibrary.class)
|
@ExportLibrary(InteropLibrary.class)
|
||||||
@ -30,9 +34,13 @@ import org.graalvm.collections.EconomicSet;
|
|||||||
@Builtin(pkg = "mutable", stdlibName = "Standard.Base.Data.Array.Array")
|
@Builtin(pkg = "mutable", stdlibName = "Standard.Base.Data.Array.Array")
|
||||||
final class Array implements EnsoObject {
|
final class Array implements EnsoObject {
|
||||||
private final Object[] items;
|
private final Object[] items;
|
||||||
|
|
||||||
|
/** If true, some elements contain warning, and thus, this Array contains warning. */
|
||||||
private Boolean withWarnings;
|
private Boolean withWarnings;
|
||||||
private Warning[] cachedWarningsWrapped;
|
|
||||||
private Warning[] cachedWarningsUnwrapped;
|
private EnsoHashMap cachedWarningsWrapped;
|
||||||
|
|
||||||
|
private EnsoHashMap cachedWarningsUnwrapped;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new array
|
* Creates a new array
|
||||||
@ -91,7 +99,12 @@ final class Array implements EnsoObject {
|
|||||||
long index,
|
long index,
|
||||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
@Cached BranchProfile errProfile,
|
@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 {
|
throws InvalidArrayIndexException, UnsupportedMessageException {
|
||||||
if (index >= items.length || index < 0) {
|
if (index >= items.length || index < 0) {
|
||||||
errProfile.enter();
|
errProfile.enter();
|
||||||
@ -101,11 +114,13 @@ final class Array implements EnsoObject {
|
|||||||
var v = items[(int) index];
|
var v = items[(int) index];
|
||||||
if (this.hasWarnings(warnings)) {
|
if (this.hasWarnings(warnings)) {
|
||||||
hasWarningsProfile.enter();
|
hasWarningsProfile.enter();
|
||||||
Warning[] extracted = this.getWarnings(null, false, warnings);
|
var extractedWarnsMap =
|
||||||
|
this.getWarnings(
|
||||||
|
false, warnings, mapInsertNode, shouldWrapProfile, mapSizeNode, mapInsertAllNode);
|
||||||
if (warnings.hasWarnings(v)) {
|
if (warnings.hasWarnings(v)) {
|
||||||
v = warnings.removeWarnings(v);
|
v = warnings.removeWarnings(v);
|
||||||
}
|
}
|
||||||
return WithWarnings.wrap(EnsoContext.get(warnings), v, extracted);
|
return appendWarningNode.executeAppend(null, v, extractedWarnsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
@ -180,48 +195,81 @@ final class Array implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Warning[] getWarnings(
|
EnsoHashMap getWarnings(
|
||||||
Node location,
|
|
||||||
boolean shouldWrap,
|
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 {
|
throws UnsupportedMessageException {
|
||||||
Warning[] cache = shouldWrap ? cachedWarningsWrapped : cachedWarningsUnwrapped;
|
var cache = shouldWrap ? cachedWarningsWrapped : cachedWarningsUnwrapped;
|
||||||
if (cache == null) {
|
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) {
|
if (shouldWrap) {
|
||||||
cachedWarningsWrapped = cache;
|
cachedWarningsWrapped = allWarnsMap;
|
||||||
|
cache = cachedWarningsWrapped;
|
||||||
} else {
|
} else {
|
||||||
cachedWarningsUnwrapped = cache;
|
cachedWarningsUnwrapped = allWarnsMap;
|
||||||
|
cache = cachedWarningsUnwrapped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert cache != null;
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CompilerDirectives.TruffleBoundary
|
private EnsoHashMap collectAllWarnings(
|
||||||
private EconomicSet<Warning> collectAllWarnings(
|
WarningsLibrary warningsLib,
|
||||||
WarningsLibrary warningsLib, Node location, boolean shouldWrap)
|
HashMapInsertNode mapInsertNode,
|
||||||
|
boolean shouldWrap,
|
||||||
|
HashMapInsertAllNode mapInsertAllNode,
|
||||||
|
int warnLimit,
|
||||||
|
BranchProfile shouldWrapProfile,
|
||||||
|
HashMapSizeNode mapSizeNode)
|
||||||
throws UnsupportedMessageException {
|
throws UnsupportedMessageException {
|
||||||
EconomicSet<Warning> setOfWarnings = EconomicSet.create(new WithWarnings.WarningEquivalence());
|
var warnsSet = EnsoHashMap.empty();
|
||||||
for (int i = 0; i < this.items.length; i++) {
|
for (int itemIdx = 0; itemIdx < this.items.length; itemIdx++) {
|
||||||
final int finalIndex = i;
|
Object item = this.items[itemIdx];
|
||||||
Object item = this.items[i];
|
var warnsCnt = (int) mapSizeNode.execute(warnsSet);
|
||||||
|
if (warnsCnt == warnLimit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (warningsLib.hasWarnings(item)) {
|
if (warningsLib.hasWarnings(item)) {
|
||||||
Warning[] warnings = warningsLib.getWarnings(item, location, shouldWrap);
|
var itemWarnsMap = warningsLib.getWarnings(item, shouldWrap);
|
||||||
Warning[] wrappedWarningsMaybe;
|
assert mapSizeNode.execute(itemWarnsMap) <= warnLimit;
|
||||||
|
|
||||||
if (shouldWrap) {
|
if (!shouldWrap) {
|
||||||
wrappedWarningsMaybe =
|
warnsSet =
|
||||||
Arrays.stream(warnings)
|
mapInsertAllNode.executeInsertAll(null, warnsSet, itemWarnsMap, warnLimit - warnsCnt);
|
||||||
.map(warning -> Warning.wrapMapError(warningsLib, warning, finalIndex))
|
|
||||||
.toArray(Warning[]::new);
|
|
||||||
} else {
|
} 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
|
@ExportMessage
|
||||||
@ -239,10 +287,18 @@ final class Array implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@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 {
|
try {
|
||||||
int limit = EnsoContext.get(warnings).getWarningsLimit();
|
int limit = EnsoContext.get(warnsLib).getWarningsLimit();
|
||||||
return getWarnings(null, false, warnings).length >= limit;
|
var ourWarnings =
|
||||||
|
getWarnings(
|
||||||
|
false, warnsLib, mapInsertNode, shouldWrapProfile, mapSizeNode, mapInsertAllNode);
|
||||||
|
return (int) mapSizeNode.execute(ourWarnings) >= limit;
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import com.oracle.truffle.api.library.ExportMessage;
|
|||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
@ExportLibrary(InteropLibrary.class)
|
@ExportLibrary(InteropLibrary.class)
|
||||||
final class ArrayBuilder implements EnsoObject {
|
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. */
|
/** Returns the current array of the builder. */
|
||||||
private Object toArray() {
|
private Object toArray(boolean mustBeExact) {
|
||||||
if (objectArray != null) {
|
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) {
|
} 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) {
|
} 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 {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -195,7 +212,7 @@ final class ArrayBuilder implements EnsoObject {
|
|||||||
yield get(index, iop);
|
yield get(index, iop);
|
||||||
}
|
}
|
||||||
case "getSize" -> getSize();
|
case "getSize" -> getSize();
|
||||||
case "toArray" -> asVector();
|
case "toArray" -> asVector(false);
|
||||||
default -> throw UnknownIdentifierException.create(name);
|
default -> throw UnknownIdentifierException.create(name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -225,8 +242,8 @@ final class ArrayBuilder implements EnsoObject {
|
|||||||
return "Array_Builder";
|
return "Array_Builder";
|
||||||
}
|
}
|
||||||
|
|
||||||
Object asVector() {
|
Object asVector(boolean mustBeExact) {
|
||||||
var res = toArray();
|
var res = toArray(mustBeExact);
|
||||||
if (res instanceof long[] longs) {
|
if (res instanceof long[] longs) {
|
||||||
return Vector.fromLongArray(longs);
|
return Vector.fromLongArray(longs);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.enso.interpreter.runtime.data.vector;
|
package org.enso.interpreter.runtime.data.vector;
|
||||||
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
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.NeverDefault;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.exception.AbstractTruffleException;
|
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.library.CachedLibrary;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
|
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 class ArrayLikeAtNode extends Node {
|
||||||
public abstract Object executeAt(Object arrayLike, long index) throws InvalidArrayIndexException;
|
public abstract Object executeAt(Object arrayLike, long index) throws InvalidArrayIndexException;
|
||||||
|
|
||||||
@ -57,10 +60,11 @@ public abstract class ArrayLikeAtNode extends Node {
|
|||||||
long index,
|
long index,
|
||||||
@Cached.Exclusive @CachedLibrary(limit = "3") InteropLibrary interop,
|
@Cached.Exclusive @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||||
@Cached.Exclusive @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
@Cached.Exclusive @CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
@Cached.Exclusive @Cached HostValueToEnsoNode convert)
|
@Cached.Exclusive @Cached HostValueToEnsoNode convert,
|
||||||
|
@Cached AppendWarningNode appendWarningNode)
|
||||||
throws InvalidArrayIndexException {
|
throws InvalidArrayIndexException {
|
||||||
try {
|
try {
|
||||||
return self.readArrayElement(index, interop, warnings, convert);
|
return self.readArrayElement(index, interop, warnings, convert, appendWarningNode);
|
||||||
} catch (UnsupportedMessageException ex) {
|
} catch (UnsupportedMessageException ex) {
|
||||||
throw ArrayPanics.notAnArrayPanic(this, self);
|
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.callable.function.Function;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
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.state.State;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
/** Publicly available operations on array-like classes. */
|
/** Publicly available operations on array-like classes. */
|
||||||
@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Internal.Array_Like_Helpers")
|
@Builtin(pkg = "immutable", stdlibName = "Standard.Base.Internal.Array_Like_Helpers")
|
||||||
@ -97,7 +97,7 @@ public final class ArrayLikeHelpers {
|
|||||||
}
|
}
|
||||||
target.add(value, warnings);
|
target.add(value, warnings);
|
||||||
}
|
}
|
||||||
return target.asVector();
|
return target.asVector(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Builtin.Method(
|
@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.Cached.Exclusive;
|
||||||
import com.oracle.truffle.api.dsl.Fallback;
|
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.NeverDefault;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
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.library.CachedLibrary;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
|
||||||
|
@GenerateUncached
|
||||||
public abstract class ArrayLikeLengthNode extends Node {
|
public abstract class ArrayLikeLengthNode extends Node {
|
||||||
public abstract long executeLength(Object arrayLike);
|
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.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.error.Warning;
|
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||||
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.library.dispatch.TypesLibrary;
|
||||||
|
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
@ExportLibrary(TypesLibrary.class)
|
@ExportLibrary(TypesLibrary.class)
|
||||||
@ExportLibrary(InteropLibrary.class)
|
@ExportLibrary(InteropLibrary.class)
|
||||||
@ -91,7 +91,8 @@ final class ArraySlice implements EnsoObject {
|
|||||||
long index,
|
long index,
|
||||||
@Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop,
|
@Shared("interop") @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
@Cached HostValueToEnsoNode toEnso)
|
@Cached HostValueToEnsoNode toEnso,
|
||||||
|
@Cached AppendWarningNode appendWarningNode)
|
||||||
throws InvalidArrayIndexException, UnsupportedMessageException {
|
throws InvalidArrayIndexException, UnsupportedMessageException {
|
||||||
if (index < 0 || index >= getArraySize(interop)) {
|
if (index < 0 || index >= getArraySize(interop)) {
|
||||||
throw InvalidArrayIndexException.create(index);
|
throw InvalidArrayIndexException.create(index);
|
||||||
@ -99,11 +100,11 @@ final class ArraySlice implements EnsoObject {
|
|||||||
|
|
||||||
var v = interop.readArrayElement(storage, start + index);
|
var v = interop.readArrayElement(storage, start + index);
|
||||||
if (this.hasWarnings(warnings)) {
|
if (this.hasWarnings(warnings)) {
|
||||||
Warning[] extracted = this.getWarnings(null, false, warnings);
|
var extracted = this.getWarnings(false, warnings);
|
||||||
if (warnings.hasWarnings(v)) {
|
if (warnings.hasWarnings(v)) {
|
||||||
v = warnings.removeWarnings(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);
|
return toEnso.execute(v);
|
||||||
}
|
}
|
||||||
@ -155,12 +156,10 @@ final class ArraySlice implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Warning[] getWarnings(
|
EnsoHashMap getWarnings(
|
||||||
Node location,
|
boolean shouldWrap, @Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||||
boolean shouldWrap,
|
|
||||||
@Shared("warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
|
||||||
throws UnsupportedMessageException {
|
throws UnsupportedMessageException {
|
||||||
return warnings.getWarnings(this.storage, location, shouldWrap);
|
return warnings.getWarnings(this.storage, shouldWrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@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.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.error.Warning;
|
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||||
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.library.dispatch.TypesLibrary;
|
||||||
|
import org.enso.interpreter.runtime.warning.AppendWarningNode;
|
||||||
|
import org.enso.interpreter.runtime.warning.WarningsLibrary;
|
||||||
|
|
||||||
@ExportLibrary(InteropLibrary.class)
|
@ExportLibrary(InteropLibrary.class)
|
||||||
@ExportLibrary(TypesLibrary.class)
|
@ExportLibrary(TypesLibrary.class)
|
||||||
@ -178,8 +178,8 @@ abstract class Vector implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Warning[] getWarnings(Node location, boolean shouldWrap) throws UnsupportedMessageException {
|
EnsoHashMap getWarnings(boolean shouldWrap) {
|
||||||
return new Warning[0];
|
return EnsoHashMap.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
@ -249,15 +249,16 @@ abstract class Vector implements EnsoObject {
|
|||||||
long index,
|
long index,
|
||||||
@Cached.Shared(value = "interop") @CachedLibrary(limit = "3") InteropLibrary interop,
|
@Cached.Shared(value = "interop") @CachedLibrary(limit = "3") InteropLibrary interop,
|
||||||
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
@CachedLibrary(limit = "3") WarningsLibrary warnings,
|
||||||
@Cached HostValueToEnsoNode toEnso)
|
@Cached HostValueToEnsoNode toEnso,
|
||||||
|
@Cached AppendWarningNode appendWarningNode)
|
||||||
throws InvalidArrayIndexException, UnsupportedMessageException {
|
throws InvalidArrayIndexException, UnsupportedMessageException {
|
||||||
var v = interop.readArrayElement(this.storage, index);
|
var v = interop.readArrayElement(this.storage, index);
|
||||||
if (warnings.hasWarnings(this.storage)) {
|
if (warnings.hasWarnings(this.storage)) {
|
||||||
Warning[] extracted = warnings.getWarnings(this.storage, null, false);
|
var extracted = warnings.getWarnings(this.storage, false);
|
||||||
if (warnings.hasWarnings(v)) {
|
if (warnings.hasWarnings(v)) {
|
||||||
v = warnings.removeWarnings(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);
|
return toEnso.execute(v);
|
||||||
}
|
}
|
||||||
@ -287,12 +288,11 @@ abstract class Vector implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Warning[] getWarnings(
|
EnsoHashMap getWarnings(
|
||||||
Node location,
|
|
||||||
boolean shouldWrap,
|
boolean shouldWrap,
|
||||||
@Cached.Shared(value = "warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
@Cached.Shared(value = "warnsLib") @CachedLibrary(limit = "3") WarningsLibrary warnings)
|
||||||
throws UnsupportedMessageException {
|
throws UnsupportedMessageException {
|
||||||
return warnings.getWarnings(this.storage, location, shouldWrap);
|
return warnings.getWarnings(this.storage, shouldWrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
@ -357,8 +357,8 @@ abstract class Vector implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Warning[] getWarnings(Node location, boolean shouldWrap) throws UnsupportedMessageException {
|
EnsoHashMap getWarnings(boolean shouldWrap) {
|
||||||
return new Warning[0];
|
return EnsoHashMap.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
@ -407,8 +407,8 @@ abstract class Vector implements EnsoObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Warning[] getWarnings(Node location, boolean shouldWrap) throws UnsupportedMessageException {
|
EnsoHashMap getWarnings(boolean shouldWrap) {
|
||||||
return new Warning[0];
|
return EnsoHashMap.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@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.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.number.EnsoBigInteger;
|
||||||
|
import org.enso.interpreter.runtime.warning.WithWarnings;
|
||||||
|
|
||||||
@GenerateUncached
|
@GenerateUncached
|
||||||
public abstract class TypeOfNode extends Node {
|
public abstract class TypeOfNode extends Node {
|
||||||
@ -70,8 +70,8 @@ public abstract class TypeOfNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
Object doWarning(WithWarnings value) {
|
Object doWarning(WithWarnings value, @Cached TypeOfNode withoutWarning) {
|
||||||
return execute(value.getValue());
|
return withoutWarning.execute(value.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isWithoutType(Object value, TypesLibrary types) {
|
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.DataflowError;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
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.number.EnsoBigInteger;
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
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;
|
import org.enso.polyglot.data.TypeGraph;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +59,8 @@ import org.enso.polyglot.data.TypeGraph;
|
|||||||
PanicSentinel.class,
|
PanicSentinel.class,
|
||||||
EnsoHashMap.class,
|
EnsoHashMap.class,
|
||||||
Warning.class,
|
Warning.class,
|
||||||
|
WithWarnings.class,
|
||||||
|
WarningsLibrary.class,
|
||||||
EnsoFile.class,
|
EnsoFile.class,
|
||||||
EnsoDate.class,
|
EnsoDate.class,
|
||||||
EnsoDateTime.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.interop.UnsupportedMessageException;
|
||||||
import com.oracle.truffle.api.library.GenerateLibrary;
|
import com.oracle.truffle.api.library.GenerateLibrary;
|
||||||
import com.oracle.truffle.api.library.Library;
|
import com.oracle.truffle.api.library.Library;
|
||||||
import com.oracle.truffle.api.library.LibraryFactory;
|
import com.oracle.truffle.api.library.LibraryFactory;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import org.enso.interpreter.runtime.data.hash.EnsoHashMap;
|
||||||
|
|
||||||
@GenerateLibrary
|
@GenerateLibrary
|
||||||
public abstract class WarningsLibrary extends Library {
|
public abstract class WarningsLibrary extends Library {
|
||||||
@ -44,15 +44,14 @@ public abstract class WarningsLibrary extends Library {
|
|||||||
/**
|
/**
|
||||||
* Returns all unique warnings associated with the receiver.
|
* Returns all unique warnings associated with the receiver.
|
||||||
*
|
*
|
||||||
* @param receiver the receiver to analyze
|
* @param receiver the receiver to get the warnings from
|
||||||
* @param location optional parameter specifying the node to which the warnings should be
|
|
||||||
* reassigned to
|
|
||||||
* @param shouldWrap if true, warnings attached to elements in array-likes are wrapped in
|
* @param shouldWrap if true, warnings attached to elements in array-likes are wrapped in
|
||||||
* Map_Error
|
* 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"})
|
@GenerateLibrary.Abstract(ifExported = {"hasWarnings"})
|
||||||
public Warning[] getWarnings(Object receiver, Node location, boolean shouldWrap)
|
public EnsoHashMap getWarnings(Object receiver, boolean shouldWrap)
|
||||||
throws UnsupportedMessageException {
|
throws UnsupportedMessageException {
|
||||||
throw UnsupportedMessageException.create();
|
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.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
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)
|
@Target(ElementType.PARAMETER)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface AcceptsWarning {}
|
public @interface AcceptsWarning {}
|
||||||
|
@ -16,7 +16,7 @@ import java.lang.annotation.Target;
|
|||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface BuiltinMethod {
|
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();
|
String type();
|
||||||
|
|
||||||
|
@ -130,6 +130,8 @@ public class MethodProcessor
|
|||||||
"com.oracle.truffle.api.CompilerDirectives",
|
"com.oracle.truffle.api.CompilerDirectives",
|
||||||
"com.oracle.truffle.api.dsl.UnsupportedSpecializationException",
|
"com.oracle.truffle.api.dsl.UnsupportedSpecializationException",
|
||||||
"com.oracle.truffle.api.frame.VirtualFrame",
|
"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.ControlFlowException",
|
||||||
"com.oracle.truffle.api.nodes.Node",
|
"com.oracle.truffle.api.nodes.Node",
|
||||||
"com.oracle.truffle.api.nodes.NodeInfo",
|
"com.oracle.truffle.api.nodes.NodeInfo",
|
||||||
@ -146,14 +148,18 @@ public class MethodProcessor
|
|||||||
"org.enso.interpreter.runtime.callable.function.FunctionSchema",
|
"org.enso.interpreter.runtime.callable.function.FunctionSchema",
|
||||||
"org.enso.interpreter.runtime.EnsoContext",
|
"org.enso.interpreter.runtime.EnsoContext",
|
||||||
"org.enso.interpreter.runtime.builtin.Builtins",
|
"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.data.text.Text",
|
||||||
"org.enso.interpreter.runtime.error.DataflowError",
|
"org.enso.interpreter.runtime.error.DataflowError",
|
||||||
"org.enso.interpreter.runtime.error.PanicException",
|
"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.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. */
|
/** List of exception types that should be caught from the builtin's execute method. */
|
||||||
private static final List<String> handleExceptionTypes =
|
private static final List<String> handleExceptionTypes =
|
||||||
@ -190,6 +196,13 @@ public class MethodProcessor
|
|||||||
+ " extends BuiltinRootNode implements InlineableNode.Root {");
|
+ " extends BuiltinRootNode implements InlineableNode.Root {");
|
||||||
}
|
}
|
||||||
out.println(" private @Child " + methodDefinition.getOriginalClassName() + " bodyNode;");
|
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();
|
||||||
out.println(" private static final class Internals {");
|
out.println(" private static final class Internals {");
|
||||||
out.println(" Internals(boolean s) {");
|
out.println(" Internals(boolean s) {");
|
||||||
@ -282,27 +295,44 @@ public class MethodProcessor
|
|||||||
+ " body = "
|
+ " body = "
|
||||||
+ methodDefinition.getConstructorExpression()
|
+ 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(" @Override");
|
||||||
out.println(" public Object call(VirtualFrame frame, Object[] args) {");
|
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(" }");
|
||||||
|
out.println();
|
||||||
out.println(" return new Inlineable();");
|
out.println(" return new Inlineable();");
|
||||||
out.println(" }");
|
out.println(" }");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.println();
|
||||||
|
|
||||||
out.println(" @Override");
|
out.println(" @Override");
|
||||||
out.println(" public Object execute(VirtualFrame frame) {");
|
out.println(" public Object execute(VirtualFrame frame) {");
|
||||||
if (methodDefinition.needsFrame()) {
|
if (methodDefinition.needsFrame()) {
|
||||||
out.println(" var args = frame.getArguments();");
|
out.println(" var args = frame.getArguments();");
|
||||||
} else {
|
} else {
|
||||||
out.println(
|
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(" }");
|
||||||
out.println(
|
out.println(
|
||||||
" private static Object handleExecute(VirtualFrame frame, Internals internals, "
|
" private static Object handleExecute(VirtualFrame frame, Internals internals, "
|
||||||
+ methodDefinition.getOriginalClassName()
|
+ methodDefinition.getOriginalClassName()
|
||||||
+ " bodyNode, Object[] args) {");
|
+ " bodyNode, AppendWarningNode appendWarningNode, WarningsLibrary warnLib,"
|
||||||
|
+ " HashMapInsertAllNode mapInsertAllNode, Object[] args) {");
|
||||||
}
|
}
|
||||||
out.println(" var prefix = internals.staticOfInstanceMethod ? 1 : 0;");
|
out.println(" var prefix = internals.staticOfInstanceMethod ? 1 : 0;");
|
||||||
out.println(" State state = Function.ArgumentsHelper.getState(args);");
|
out.println(" State state = Function.ArgumentsHelper.getState(args);");
|
||||||
@ -346,8 +376,8 @@ public class MethodProcessor
|
|||||||
out.println(" internals.anyWarningsProfile.enter();");
|
out.println(" internals.anyWarningsProfile.enter();");
|
||||||
out.println(" Object result;");
|
out.println(" Object result;");
|
||||||
out.println(wrapInTryCatch("result = " + executeCall + ";", 6));
|
out.println(wrapInTryCatch("result = " + executeCall + ";", 6));
|
||||||
out.println(" EnsoContext ctx = EnsoContext.get(bodyNode);");
|
out.println(
|
||||||
out.println(" return WithWarnings.appendTo(ctx, result, gatheredWarnings);");
|
" return appendWarningNode.executeAppend(frame, result, gatheredWarnings);");
|
||||||
out.println(" } else {");
|
out.println(" } else {");
|
||||||
out.println(wrapInTryCatch("return " + executeCall + ";", 6));
|
out.println(wrapInTryCatch("return " + executeCall + ";", 6));
|
||||||
out.println(" }");
|
out.println(" }");
|
||||||
@ -598,28 +628,27 @@ public class MethodProcessor
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
out.println(" boolean anyWarnings = false;");
|
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) {
|
for (var arg : argsToCheck) {
|
||||||
|
String argCode = arrayRead(argumentsArray, arg.getPosition());
|
||||||
out.println(
|
out.println(
|
||||||
" if ("
|
" if ("
|
||||||
+ arrayRead(argumentsArray, arg.getPosition())
|
+ arrayRead(argumentsArray, arg.getPosition())
|
||||||
+ " instanceof WithWarnings) {");
|
+ " instanceof WithWarnings withWarnings) {");
|
||||||
out.println(
|
out.println(
|
||||||
" internals." + mkArgumentInternalVarName(arg) + WARNING_PROFILE + ".enter();");
|
" internals." + mkArgumentInternalVarName(arg) + WARNING_PROFILE + ".enter();");
|
||||||
out.println(" anyWarnings = true;");
|
out.println(" anyWarnings = true;");
|
||||||
|
out.println(" try {"); // begin try
|
||||||
|
out.println(" var warns = warnLib.getWarnings(withWarnings, false);");
|
||||||
|
out.println(" " + argCode + " = withWarnings.getValue();");
|
||||||
out.println(
|
out.println(
|
||||||
" WithWarnings withWarnings = (WithWarnings) "
|
" gatheredWarnings = mapInsertAllNode.executeInsertAll(frame, gatheredWarnings,"
|
||||||
+ arrayRead(argumentsArray, arg.getPosition())
|
+ " warns, maxWarnings);");
|
||||||
+ ";");
|
out.println(" } catch (UnsupportedMessageException e) {"); // end try
|
||||||
out.println(
|
out.println(" throw CompilerDirectives.shouldNotReachHere(e);");
|
||||||
" "
|
out.println(" }"); // end catch
|
||||||
+ arrayRead(argumentsArray, arg.getPosition())
|
out.println(" }"); // end hasWarnings
|
||||||
+ " = withWarnings.getValue();");
|
|
||||||
out.print(
|
|
||||||
"""
|
|
||||||
gatheredWarnings = gatheredWarnings.prepend(withWarnings.getReassignedWarningsAsRope(bodyNode, false));
|
|
||||||
""");
|
|
||||||
out.println(" }");
|
|
||||||
}
|
}
|
||||||
return true;
|
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 INTEROP_LIBRARY = "com.oracle.truffle.api.interop.InteropLibrary";
|
||||||
public static final String WARNINGS_LIBRARY =
|
public static final String WARNINGS_LIBRARY =
|
||||||
"org.enso.interpreter.runtime.error.WarningsLibrary";
|
"org.enso.interpreter.runtime.warning.WarningsLibrary";
|
||||||
}
|
}
|
||||||
|
|
||||||
class InjectedMethodParameter extends SpecializedMethodParameter {
|
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.Modifier;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.tools.Diagnostic;
|
import javax.tools.Diagnostic;
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.enso.interpreter.dsl.AcceptsWarning;
|
import org.enso.interpreter.dsl.AcceptsWarning;
|
||||||
import org.enso.interpreter.dsl.Builtin;
|
import org.enso.interpreter.dsl.Builtin;
|
||||||
@ -160,12 +161,16 @@ public final class SpecializedMethodsGenerator extends MethodGenerator {
|
|||||||
paramss.forEach(
|
paramss.forEach(
|
||||||
(k, v) -> {
|
(k, v) -> {
|
||||||
if (v.size() != elements.size()) {
|
if (v.size() != elements.size()) {
|
||||||
throw new RuntimeException(
|
processingEnv
|
||||||
"Restriction: Specialized methods have to have equal number of parameters.\n"
|
.getMessager()
|
||||||
+ "Expected "
|
.printMessage(
|
||||||
+ elements.size()
|
Kind.ERROR,
|
||||||
+ ", got "
|
"Restriction: Specialized methods have to have equal number of parameters.\n"
|
||||||
+ v.size());
|
+ "Expected "
|
||||||
|
+ elements.size()
|
||||||
|
+ ", got "
|
||||||
|
+ v.size(),
|
||||||
|
elements.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodParameter p = v.get(0);
|
MethodParameter p = v.get(0);
|
||||||
|
@ -46,16 +46,6 @@ get_foo x = x.foo
|
|||||||
|
|
||||||
unwrap x = Integer.from x
|
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"
|
baz value = Warning.attach value "I have warned you"
|
||||||
bar value = baz value
|
bar value = baz value
|
||||||
foo value = bar 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 = warning_stack . drop (..Last current.length)
|
||||||
relevant.map .name . should_equal (['baz', 'bar', 'foo'].map ('Warnings_Spec.'+))
|
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" <|
|
group_builder.specify "should allow to set all warnings" <|
|
||||||
warned = Warning.attach 1 <| Warning.attach 2 <| Warning.attach 3 <| Warning.attach 4 "foo"
|
warned = Warning.attach 1 <| Warning.attach 2 <| Warning.attach 3 <| Warning.attach 4 "foo"
|
||||||
warnings = Warning.get_all warned
|
warnings = Warning.get_all warned
|
||||||
|
Loading…
Reference in New Issue
Block a user