From c6790f1e9cad8bbefe924637314f2dbc43ea1bac Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 28 Apr 2023 09:16:00 +0200 Subject: [PATCH] Report only unique warnings (#6372) This change makes sure that reported warnings are unique, based on the value of internal clock tick and ignoring differences in reassignments. Before: ![Screenshot from 2023-04-20 15-42-55](https://user-images.githubusercontent.com/292128/233415710-925c1045-37c7-49f5-9bc3-bfbfd30270a3.png) After: ![Screenshot from 2023-04-20 15-27-27](https://user-images.githubusercontent.com/292128/233415807-8cb67bc2-ac37-4db7-924e-ae7619074b5b.png) On the positive side, no further changes, like in LS, have to be done. Closes #6257. --- CHANGELOG.md | 8 +- .../semantic/WarningBenchmarks.java | 101 ++++++++++++++++++ .../IndirectInvokeConversionNode.java | 4 +- .../callable/IndirectInvokeMethodNode.java | 4 +- .../node/callable/InvokeCallableNode.java | 2 +- .../node/callable/InvokeConversionNode.java | 4 +- .../node/callable/InvokeMethodNode.java | 4 +- .../enso/interpreter/runtime/EnsoContext.java | 2 +- .../enso/interpreter/runtime/data/Array.java | 17 ++- .../interpreter/runtime/data/ArrayRope.java | 3 + .../interpreter/runtime/error/Warning.java | 46 +++++--- .../runtime/error/WarningsLibrary.java | 2 +- .../runtime/error/WithWarnings.java | 96 ++++++++++------- .../org/enso/interpreter/test/ArrayTest.java | 37 +++---- .../enso/interpreter/test/BigNumberTest.java | 37 +++---- .../test/ForeignMethodInvokeTest.java | 36 ++----- .../interpreter/test/LazyAtomFieldTest.java | 36 +++---- .../org/enso/interpreter/test/ListTest.java | 27 ++--- .../enso/interpreter/test/MetaObjectTest.java | 14 +-- .../interpreter/test/PolyglotErrorTest.java | 27 ++--- .../org/enso/interpreter/test/PrintTest.java | 25 ++--- .../org/enso/interpreter/test/TestBase.java | 30 ++++-- .../interpreter/test/TypeMembersTest.java | 25 ++--- .../org/enso/interpreter/test/VectorTest.java | 37 +++---- .../enso/interpreter/test/WarningsTest.java | 33 +++++- .../enso/interpreter/dsl/MethodProcessor.java | 2 +- .../Table_Tests/src/Database/SQLite_Spec.enso | 7 ++ test/Tests/src/Semantic/Warnings_Spec.enso | 19 ++++ 28 files changed, 406 insertions(+), 279 deletions(-) create mode 100644 engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 52042f1786f3..c5bc858c6b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -691,7 +691,7 @@ - [Optimize Atom storage layouts][3862] - [Make instance methods callable like statics for builtin types][4077] - [Convert large longs to doubles, safely, for host calls][4099] -- [Consistent ordering with comparators](4067) +- [Consistent ordering with comparators][4067] - [Profile engine startup][4110] - [Report type of polyglot values][4111] - [Engine can now recover from serialization failures][5591] @@ -709,6 +709,7 @@ - [Vector.sort handles incomparable types][5998] - [Removing need for asynchronous thread to execute ResourceManager finalizers][6335] +- [Warning.get_all returns only unique warnings][6372] [3227]: https://github.com/enso-org/enso/pull/3227 [3248]: https://github.com/enso-org/enso/pull/3248 @@ -797,9 +798,9 @@ [4048]: https://github.com/enso-org/enso/pull/4048 [4049]: https://github.com/enso-org/enso/pull/4049 [4056]: https://github.com/enso-org/enso/pull/4056 +[4067]: https://github.com/enso-org/enso/pull/4067 [4077]: https://github.com/enso-org/enso/pull/4077 [4099]: https://github.com/enso-org/enso/pull/4099 -[4067]: https://github.com/enso-org/enso/pull/4067 [4110]: https://github.com/enso-org/enso/pull/4110 [4111]: https://github.com/enso-org/enso/pull/4111 [5591]: https://github.com/enso-org/enso/pull/5591 @@ -811,11 +812,12 @@ [5791]: https://github.com/enso-org/enso/pull/5791 [5900]: https://github.com/enso-org/enso/pull/5900 [5966]: https://github.com/enso-org/enso/pull/5966 +[5998]: https://github.com/enso-org/enso/pull/5998 [6067]: https://github.com/enso-org/enso/pull/6067 [6151]: https://github.com/enso-org/enso/pull/6151 [6171]: https://github.com/enso-org/enso/pull/6171 -[5998]: https://github.com/enso-org/enso/pull/5998 [6335]: https://github.com/enso-org/enso/pull/6335 +[6372]: https://github.com/enso-org/enso/pull/6372 # Enso 2.0.0-alpha.18 (2021-10-12) diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java new file mode 100644 index 000000000000..da08d9e081b6 --- /dev/null +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java @@ -0,0 +1,101 @@ +package org.enso.interpreter.bench.benchmarks.semantic; + +import org.enso.interpreter.test.TestBase; +import org.enso.polyglot.MethodNames; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.BenchmarkParams; + +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Fork(1) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 3, time = 3) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +public class WarningBenchmarks extends TestBase { + private static final int INPUT_VEC_SIZE = 10000; + private Context ctx; + private Value vecSumBench; + + private Value createVec; + private Value noWarningsVec; + private Value sameWarningVec; + + private Value elem; + + private Value elemWithWarning; + + private String benchmarkName; + + @Setup + public void initializeBench(BenchmarkParams params) throws IOException { + ctx = createDefaultContext(); + + benchmarkName = params.getBenchmark().replaceFirst(".*\\.", ""); + + var code = """ + from Standard.Base import all + + vec_sum_bench : Vector Integer -> Integer + vec_sum_bench vec = + vec.fold 0 (x->y->x+y) + + create_vec size elem = + Vector.fill size elem + + elem = + 42 + + elem_with_warning = + x = 42 + Warning.attach "Foo!" x + """; + var src = SrcUtil.source(benchmarkName, code); + Value module = ctx.eval(src); + vecSumBench = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "vec_sum_bench")); + createVec = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create_vec")); + elem = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem")); + elemWithWarning = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem_with_warning")); + noWarningsVec = createVec.execute(INPUT_VEC_SIZE, elem); + sameWarningVec = createVec.execute(INPUT_VEC_SIZE, elemWithWarning); + } + + @TearDown + public void cleanup() { + ctx.close(true); + } + + @Benchmark + public void noWarningsVecSum() { + Value res = vecSumBench.execute(noWarningsVec); + checkResult(res); + } + + @Benchmark + public void sameWarningVecSum() { + Value res = vecSumBench.execute(sameWarningVec); + checkResult(res); + } + + private static void checkResult(Value res) { + if (res.asInt() != INPUT_VEC_SIZE*42) { + throw new AssertionError("Expected result: " + INPUT_VEC_SIZE*42 + ", got: " + res.asInt()); + } + } + +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeConversionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeConversionNode.java index 0f397f0871ba..d497adeee9d8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeConversionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeConversionNode.java @@ -142,7 +142,7 @@ Object doWarning( int thatArgumentPosition, @Cached IndirectInvokeConversionNode childDispatch) { arguments[thatArgumentPosition] = that.getValue(); - ArrayRope warnings = that.getReassignedWarnings(this); + ArrayRope warnings = that.getReassignedWarningsAsRope(this); Object result = childDispatch.execute( frame, @@ -156,7 +156,7 @@ Object doWarning( argumentsExecutionMode, isTail, thatArgumentPosition); - return WithWarnings.prependTo(result, warnings); + return WithWarnings.appendTo(result, warnings); } @Specialization(guards = "interop.isString(that)") diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java index 6a22a01234e8..79fafca1515c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java @@ -121,7 +121,7 @@ Object doWarning( int thisArgumentPosition, @Cached IndirectInvokeMethodNode childDispatch) { arguments[thisArgumentPosition] = self.getValue(); - ArrayRope warnings = self.getReassignedWarnings(this); + ArrayRope warnings = self.getReassignedWarningsAsRope(this); Object result = childDispatch.execute( frame, @@ -134,7 +134,7 @@ Object doWarning( argumentsExecutionMode, isTail, thisArgumentPosition); - return WithWarnings.prependTo(result, warnings); + return WithWarnings.appendTo(result, warnings); } @Specialization diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java index 8916c6a26f29..f12789694ad5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeCallableNode.java @@ -297,7 +297,7 @@ public Object invokeWarnings( if (result instanceof DataflowError) { return result; } else if (result instanceof WithWarnings withWarnings) { - return withWarnings.prepend(extracted); + return withWarnings.append(extracted); } else { return WithWarnings.wrap(result, extracted); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java index 6af3ce73ee8d..3df215b17fb4 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java @@ -172,10 +172,10 @@ Object doWarning( } } arguments[thatArgumentPosition] = that.getValue(); - ArrayRope warnings = that.getReassignedWarnings(this); + ArrayRope warnings = that.getReassignedWarningsAsRope(this); Object result = childDispatch.execute(frame, state, conversion, self, that.getValue(), arguments); - return WithWarnings.prependTo(result, warnings); + return WithWarnings.appendTo(result, warnings); } @Specialization(guards = "interop.isString(that)") diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java index 74a672bd9fa8..fa58b5875a5f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java @@ -275,7 +275,7 @@ Object doWarning( arguments[thisArgumentPosition] = selfWithoutWarnings; Object result = childDispatch.execute(frame, state, symbol, selfWithoutWarnings, arguments); - return WithWarnings.prependTo(result, arrOfWarnings); + return WithWarnings.appendTo(result, arrOfWarnings); } @ExplodeLoop @@ -327,7 +327,7 @@ Object doPolyglot( Object res = hostMethodCallNode.execute(polyglotCallType, symbol.getName(), self, args); if (anyWarnings) { anyWarningsProfile.enter(); - res = WithWarnings.prependTo(res, accumulatedWarnings); + res = WithWarnings.appendTo(res, accumulatedWarnings); } return res; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java index d0bf6a65a6bb..1cff5992521e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java @@ -504,7 +504,7 @@ public TruffleLogger getLogger(Class klass) { * *

The counter is used to track the creation time of warnings. */ - public long clockTick() { + public long nextSequenceId() { return clock.getAndIncrement(); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java index 87601a4dbe00..6417441ddc3d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/Array.java @@ -19,6 +19,7 @@ import java.util.Arrays; import org.enso.interpreter.runtime.error.WithWarnings; +import org.graalvm.collections.EconomicSet; /** A primitive boxed array type for use in the runtime. */ @ExportLibrary(InteropLibrary.class) @@ -28,6 +29,7 @@ public final class Array implements TruffleObject { private final Object[] items; private Boolean withWarnings; + private Warning[] cachedWarnings; /** * Creates a new array @@ -203,13 +205,22 @@ boolean hasWarnings(@CachedLibrary(limit = "3") WarningsLibrary warnings) { @ExportMessage Warning[] getWarnings(Node location, @CachedLibrary(limit = "3") WarningsLibrary warnings) throws UnsupportedMessageException { - ArrayRope ropeOfWarnings = new ArrayRope<>(); + if (cachedWarnings == null) { + cachedWarnings = Warning.fromSetToArray(collectAllWarnings(warnings, location)); + } + return cachedWarnings; + } + + @CompilerDirectives.TruffleBoundary + private EconomicSet collectAllWarnings(WarningsLibrary warnings, Node location) + throws UnsupportedMessageException { + EconomicSet setOfWarnings = EconomicSet.create(new WithWarnings.WarningEquivalence()); for (int i = 0; i < items.length; i++) { if (warnings.hasWarnings(items[i])) { - ropeOfWarnings = ropeOfWarnings.prepend(warnings.getWarnings(items[i], location)); + setOfWarnings.addAll(Arrays.asList(warnings.getWarnings(items[i], location))); } } - return ropeOfWarnings.toArray(Warning[]::new); + return setOfWarnings; } @ExportMessage diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayRope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayRope.java index 9ee3a1c5c815..9b0c0be6329a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayRope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/ArrayRope.java @@ -1,5 +1,7 @@ package org.enso.interpreter.runtime.data; +import com.oracle.truffle.api.CompilerDirectives; + import java.util.Arrays; import java.util.function.Function; @@ -33,6 +35,7 @@ public final ArrayRope prepend(T... items) { return new ArrayRope<>(new ConcatSegment<>(new ArraySegment<>(items), this.segment)); } + @CompilerDirectives.TruffleBoundary public T[] toArray(Function genArray) { T[] res = genArray.apply(size()); writeArray(res); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java index 82e7d690d4cc..41716e1cbb33 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java @@ -17,6 +17,7 @@ import org.enso.interpreter.runtime.data.ArrayRope; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; +import org.graalvm.collections.EconomicSet; import java.util.Arrays; import java.util.Comparator; @@ -27,18 +28,18 @@ public final class Warning implements TruffleObject { private final Object value; private final Object origin; private final ArrayRope reassignments; - private final long creationTime; + private final long sequenceId; - public Warning(Object value, Object origin, long creationTime) { - this(value, origin, creationTime, new ArrayRope<>()); + private Warning(Object value, Object origin, long sequenceId) { + this(value, origin, sequenceId, new ArrayRope<>()); } - public Warning( - Object value, Object origin, long creationTime, ArrayRope reassignments) { + private Warning( + Object value, Object origin, long sequenceId, ArrayRope reassignments) { this.value = value; this.origin = origin; this.reassignments = reassignments; - this.creationTime = creationTime; + this.sequenceId = sequenceId; } @Builtin.Method(name = "value", description = "Gets the payload of the warning.") @@ -57,7 +58,7 @@ public Object getOrigin() { autoRegister = false) @Builtin.Specialize public static Warning create(EnsoContext ctx, Object payload, Object origin) { - return new Warning(payload, origin, ctx.clockTick()); + return new Warning(payload, origin, ctx.nextSequenceId()); } @Builtin.Method(description = "Gets the list of locations where the warnings was reassigned.") @@ -73,7 +74,7 @@ public Array getReassignments() { @Builtin.Specialize public static WithWarnings attach( EnsoContext ctx, WithWarnings value, Object warning, Object origin) { - return value.prepend(new Warning(warning, origin, ctx.clockTick())); + return value.append(new Warning(warning, origin, ctx.nextSequenceId())); } @Builtin.Method( @@ -82,7 +83,7 @@ public static WithWarnings attach( autoRegister = false) @Builtin.Specialize(fallback = true) public static WithWarnings attach(EnsoContext ctx, Object value, Object warning, Object origin) { - return WithWarnings.wrap(value, new Warning(warning, origin, ctx.clockTick())); + return WithWarnings.wrap(value, new Warning(warning, origin, ctx.nextSequenceId())); } @Builtin.Method( @@ -93,10 +94,8 @@ public static WithWarnings attach(EnsoContext ctx, Object value, Object warning, @CompilerDirectives.TruffleBoundary public static Array getAll(WithWarnings value, WarningsLibrary warningsLib) { Warning[] warnings = value.getWarningsArray(warningsLib); - Arrays.sort(warnings, Comparator.comparing(Warning::getCreationTime).reversed()); - Object[] result = new Object[warnings.length]; - System.arraycopy(warnings, 0, result, 0, warnings.length); - return new Array(result); + sortArray(warnings); + return new Array((Object[]) warnings); } @Builtin.Method( @@ -107,7 +106,9 @@ public static Array getAll(WithWarnings value, WarningsLibrary warningsLib) { public static Array getAll(Object value, WarningsLibrary warnings) { if (warnings.hasWarnings(value)) { try { - return new Array((Object[]) warnings.getWarnings(value, null)); + Warning[] arr = warnings.getWarnings(value, null); + sortArray(arr); + return new Array((Object[]) arr); } catch (UnsupportedMessageException e) { throw new IllegalStateException(e); } @@ -116,6 +117,17 @@ public static Array getAll(Object value, WarningsLibrary warnings) { } } + @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 set) { + return set.toArray(new Warning[set.size()]); + } + @Builtin.Method( name = "set_array", description = "Sets all the warnings associated with the value.", @@ -185,8 +197,8 @@ SourceSection getSourceLocation() throws UnsupportedMessageException { } } - public long getCreationTime() { - return creationTime; + public long getSequenceId() { + return sequenceId; } @CompilerDirectives.TruffleBoundary @@ -194,7 +206,7 @@ public Warning reassign(Node location) { RootNode root = location.getRootNode(); SourceSection section = location.getEncapsulatingSourceSection(); Reassignment reassignment = new Reassignment(root.getName(), section); - return new Warning(value, origin, creationTime, reassignments.prepend(reassignment)); + return new Warning(value, origin, sequenceId, reassignments.prepend(reassignment)); } @ExportMessage diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WarningsLibrary.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WarningsLibrary.java index dd079a317d11..31fc820d917d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WarningsLibrary.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WarningsLibrary.java @@ -42,7 +42,7 @@ public boolean hasWarnings(Object receiver) { } /** - * Returns all warnings associated with the receiver. + * Returns all unique warnings associated with the receiver. * * @param receiver the receiver to analyze * @param location optional parameter specifying the node to which the warnings should be diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java index dc6c17d40cef..d80981d4058a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java @@ -1,5 +1,6 @@ package org.enso.interpreter.runtime.error; +import com.oracle.truffle.api.CompilerDirectives; import org.enso.interpreter.runtime.data.ArrayRope; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @@ -11,22 +12,27 @@ import com.oracle.truffle.api.library.Message; import com.oracle.truffle.api.library.ReflectionLibrary; import com.oracle.truffle.api.nodes.Node; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; + +import java.util.Arrays; @ExportLibrary(TypesLibrary.class) @ExportLibrary(WarningsLibrary.class) @ExportLibrary(ReflectionLibrary.class) public final class WithWarnings implements TruffleObject { - private final ArrayRope warnings; + private final EconomicSet warnings; private final Object value; private WithWarnings(Object value, Warning... warnings) { assert !(value instanceof WithWarnings); - this.warnings = new ArrayRope<>(warnings); + this.warnings = createSetFromArray(warnings); this.value = value; } - private WithWarnings(Object value, ArrayRope warnings) { - this.warnings = warnings; + private WithWarnings(Object value, EconomicSet warnings, Warning... additionalWarnings) { + assert !(value instanceof WithWarnings); + this.warnings = cloneSetAndAppend(warnings, additionalWarnings); this.value = value; } @@ -43,36 +49,25 @@ public Object getValue() { } public WithWarnings append(Warning... newWarnings) { - return new WithWarnings(value, warnings.append(newWarnings)); + return new WithWarnings(value, warnings, newWarnings); } public WithWarnings append(ArrayRope newWarnings) { - return new WithWarnings(value, warnings.append(newWarnings)); - } - - public WithWarnings prepend(Warning... newWarnings) { - return new WithWarnings(value, warnings.prepend(newWarnings)); - } - - public WithWarnings prepend(ArrayRope newWarnings) { - return new WithWarnings(value, warnings.prepend(newWarnings)); + return new WithWarnings(value, warnings, newWarnings.toArray(Warning[]::new)); } public Warning[] getWarningsArray(WarningsLibrary warningsLibrary) { - Warning[] warningsArr = warnings.toArray(Warning[]::new); Warning[] allWarnings; - if (warningsLibrary != null && warningsLibrary.hasWarnings(value)) { try { - Warning[] valuesWarnings = warningsLibrary.getWarnings(value, null); - allWarnings = new Warning[valuesWarnings.length + warningsArr.length]; - System.arraycopy(warningsArr, 0, allWarnings, 0, warningsArr.length); - System.arraycopy(valuesWarnings, 0, allWarnings, warningsArr.length, valuesWarnings.length); + Warning[] valueWarnings = warningsLibrary.getWarnings(value, null); + EconomicSet tmp = cloneSetAndAppend(warnings, valueWarnings); + allWarnings = Warning.fromSetToArray(tmp); } catch (UnsupportedMessageException e) { throw new IllegalStateException(e); } } else { - allWarnings = warningsArr; + allWarnings = Warning.fromSetToArray(warnings); } return allWarnings; } @@ -82,37 +77,29 @@ public int getWarningsCount() { return warnings.size(); } - public ArrayRope getReassignedWarnings(Node location) { - return getReassignedWarnings(location, null); + public ArrayRope getReassignedWarningsAsRope(Node location) { + return new ArrayRope<>(getReassignedWarnings(location, null)); } - public ArrayRope getReassignedWarnings(Node location, WarningsLibrary warningsLibrary) { + public Warning[] getReassignedWarnings(Node location, WarningsLibrary warningsLibrary) { Warning[] warnings = getWarningsArray(warningsLibrary); for (int i = 0; i < warnings.length; i++) { warnings[i] = warnings[i].reassign(location); } - return new ArrayRope<>(warnings); + return warnings; } public static WithWarnings appendTo(Object target, ArrayRope warnings) { if (target instanceof WithWarnings) { - return ((WithWarnings) target).append(warnings); + return ((WithWarnings) target).append(warnings.toArray(Warning[]::new)); } else { - return new WithWarnings(target, warnings); + return new WithWarnings(target, warnings.toArray(Warning[]::new)); } } - public static WithWarnings prependTo(Object target, ArrayRope warnings) { + public static WithWarnings appendTo(Object target, Warning[] warnings) { if (target instanceof WithWarnings) { - return ((WithWarnings) target).prepend(warnings); - } else { - return new WithWarnings(target, warnings); - } - } - - public static WithWarnings prependTo(Object target, Warning[] warnings) { - if (target instanceof WithWarnings) { - return ((WithWarnings) target).prepend(warnings); + return ((WithWarnings) target).append(warnings); } else { return new WithWarnings(target, warnings); } @@ -133,9 +120,9 @@ boolean hasWarnings() { Warning[] getWarnings( Node location, @CachedLibrary(limit = "3") WarningsLibrary warningsLibrary) { if (location != null) { - return getReassignedWarnings(location, warningsLibrary).toArray(Warning[]::new); + return getReassignedWarnings(location, warningsLibrary); } else { - return warnings.toArray(Warning[]::new); + return Warning.fromSetToArray(warnings); } } @@ -154,6 +141,37 @@ boolean hasSpecialDispatch() { return true; } + 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 createSetFromArray(Warning[] entries) { + EconomicSet set = EconomicSet.create(new WarningEquivalence()); + set.addAll(Arrays.stream(entries).iterator()); + return set; + } + + @CompilerDirectives.TruffleBoundary + private EconomicSet cloneSetAndAppend(EconomicSet initial, Warning[] entries) { + EconomicSet set = EconomicSet.create(new WarningEquivalence()); + set.addAll(initial.iterator()); + set.addAll(Arrays.stream(entries).iterator()); + return set; + } + @Override public String toString() { return "WithWarnings{" + value + " + " + warnings.size() + " warnings}"; diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/ArrayTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/ArrayTest.java index d1e26773c463..d9ef270d68bb 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/ArrayTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/ArrayTest.java @@ -1,34 +1,25 @@ package org.enso.interpreter.test; -import java.io.ByteArrayOutputStream; import java.net.URI; -import java.nio.file.Paths; -import java.util.Map; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.Before; + +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; -public class ArrayTest { - private Context ctx; - - @Before - public void prepareCtx() { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); +public class ArrayTest extends TestBase { + private static Context ctx; + + @BeforeClass + public static void prepareCtx() { + ctx = createDefaultContext(); + } + + @AfterClass + public static void disposeCtx() { + ctx.close(); } @Test diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/BigNumberTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/BigNumberTest.java index a5d824366439..668b6c5acca1 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/BigNumberTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/BigNumberTest.java @@ -1,42 +1,35 @@ package org.enso.interpreter.test; -import java.io.ByteArrayOutputStream; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; -import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Map; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.Before; + +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; -public class BigNumberTest { - private Context ctx; - - @Before - public void prepareCtx() { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); +public class BigNumberTest extends TestBase { + private static Context ctx; + + @BeforeClass + public static void prepareCtx() { + ctx = createDefaultContext(); } + @AfterClass + public static void disposeCtx() { + ctx.close(); + } + + @Test public void evaluation() throws Exception { final String code = """ diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java index 000e87f4104d..6e7af79eb8d1 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java @@ -1,40 +1,24 @@ package org.enso.interpreter.test; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeNotNull; -import java.io.ByteArrayOutputStream; -import java.nio.file.Paths; -import java.util.Map; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Value; -import org.junit.After; -import org.junit.Before; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; -public class ForeignMethodInvokeTest { - private Context ctx; +public class ForeignMethodInvokeTest extends TestBase { + private static Context ctx; - @Before - public void prepareCtx() { - this.ctx = Context.newBuilder("enso") - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assumeNotNull("Enso not found: " + langs, langs.get("enso")); + @BeforeClass + public static void prepareCtx() { + ctx = createDefaultContext(); } - @After - public void disposeCtx() { - this.ctx.close(); + @AfterClass + public static void disposeCtx() { + ctx.close(); } @Test diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/LazyAtomFieldTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/LazyAtomFieldTest.java index bc28cd100313..49290373aa40 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/LazyAtomFieldTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/LazyAtomFieldTest.java @@ -4,41 +4,37 @@ import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.Map; import java.util.stream.Collectors; import org.enso.polyglot.MethodNames; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; + +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; -public class LazyAtomFieldTest { +public class LazyAtomFieldTest extends TestBase { private static final ByteArrayOutputStream out = new ByteArrayOutputStream(); - private Context ctx; + private static Context ctx; + + @BeforeClass + public static void prepareCtx() { + ctx = createDefaultContext(out); + } @Before - public void prepareCtx() { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .out(out) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); + public void resetOut() { out.reset(); } + @AfterClass + public static void disposeCtx() { + ctx.close(); + } + @Test public void evaluation() throws Exception { final String code = """ diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/ListTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/ListTest.java index fbe01302cab5..2ddb17a140d2 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/ListTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/ListTest.java @@ -1,24 +1,21 @@ package org.enso.interpreter.test; -import java.io.ByteArrayOutputStream; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; -import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Map; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; + +import org.junit.After; import org.junit.Before; import org.junit.Test; -public class ListTest { +public class ListTest extends TestBase { private Context ctx; private final int size = 100_000; private Value generator; @@ -31,18 +28,7 @@ public class ListTest { @Before public void prepareCtx() throws Exception { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); + this.ctx = createDefaultContext(); final String code = """ from Standard.Base.Data.List.List import Cons, Nil @@ -74,6 +60,11 @@ public void prepareCtx() throws Exception { asText = evalCode(code, "as_text"); } + @After + public void disposeCtx() { + this.ctx.close(); + } + @Test public void mapPlusOneAndIterate() throws Exception { var list = generator.execute(size); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/MetaObjectTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/MetaObjectTest.java index 142c43bc23a6..d317e453eacb 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/MetaObjectTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/MetaObjectTest.java @@ -16,20 +16,20 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import org.junit.After; -import org.junit.Before; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; public class MetaObjectTest extends TestBase { - private Context ctx; + private static Context ctx; - @Before - public void prepareCtx() { + @BeforeClass + public static void prepareCtx() { ctx = createDefaultContext(); } - @After - public void disposeCtx() { + @AfterClass + public static void disposeCtx() { ctx.close(); } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/PolyglotErrorTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/PolyglotErrorTest.java index 415bdf75d13e..f67ebfcf27d0 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/PolyglotErrorTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/PolyglotErrorTest.java @@ -1,20 +1,16 @@ package org.enso.interpreter.test; -import java.io.ByteArrayOutputStream; -import java.nio.file.Paths; -import java.util.Map; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; + +import org.junit.After; import org.junit.Before; import org.junit.Test; -public class PolyglotErrorTest { +public class PolyglotErrorTest extends TestBase { private Context ctx; private Value panic; @@ -24,17 +20,7 @@ public static String bar(Object o) { @Before public void prepareCtx() throws Exception { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); + this.ctx = createDefaultContext(); var code = """ import Standard.Base.Panic.Panic @@ -102,6 +88,11 @@ Panic.catch Illegal_State (PolyglotErrorTest.bar (TypeCc.Cc 'z')) caught_panic-> assertTrue("It is a function", this.panic.canExecute()); } + @After + public void disposeCtx() { + this.ctx.close(); + } + @Test public void panic1() { var v = panic.execute(1); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/PrintTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/PrintTest.java index a896d6a77d8d..a8f90659eed0 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/PrintTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/PrintTest.java @@ -1,11 +1,10 @@ package org.enso.interpreter.test; import org.enso.polyglot.MethodNames; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -13,32 +12,24 @@ import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.Map; import static org.junit.Assert.*; -public class PrintTest { +public class PrintTest extends TestBase { private static final ByteArrayOutputStream out = new ByteArrayOutputStream(); private Context ctx; @Before public void prepareCtx() { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .out(out) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); + ctx = createDefaultContext(out); out.reset(); } + @After + public void disposeCtx() { + ctx.close(); + } + private void checkPrint(String code, String expected) throws Exception { Value result = evalCode(code, "test"); assertTrue("should return Nothing", result.isNull()); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java b/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java index 4394b4959136..e67f6fa07f6b 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java @@ -10,6 +10,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import java.io.ByteArrayOutputStream; +import java.io.OutputStream; import java.nio.file.Paths; import java.util.Map; import java.util.concurrent.Callable; @@ -24,21 +25,30 @@ public abstract class TestBase { protected static Context createDefaultContext() { - var context = - Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath()) - .build(); + var context = defaultContextBuilder().build(); final Map langs = context.getEngine().getLanguages(); assertNotNull("Enso found: " + langs, langs.get("enso")); return context; } + protected static Context createDefaultContext(OutputStream out) { + var context = defaultContextBuilder().out(out).build(); + final Map langs = context.getEngine().getLanguages(); + assertNotNull("Enso found: " + langs, langs.get("enso")); + return context; + } + + private static Context.Builder defaultContextBuilder() { + return Context.newBuilder() + .allowExperimentalOptions(true) + .allowIO(true) + .allowAllAccess(true) + .logHandler(new ByteArrayOutputStream()) + .option( + RuntimeOptions.LANGUAGE_HOME_OVERRIDE, + Paths.get("../../distribution/component").toFile().getAbsolutePath()); + } + /** * Executes the given callable in the given context. A necessity for executing artificially * created Truffle ASTs. diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/TypeMembersTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/TypeMembersTest.java index f1e13ed129d3..699d9c21e3a6 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/TypeMembersTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/TypeMembersTest.java @@ -1,13 +1,8 @@ package org.enso.interpreter.test; -import java.io.ByteArrayOutputStream; import java.net.URI; -import java.nio.file.Paths; -import java.util.Map; import java.util.Set; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; @@ -16,27 +11,23 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + +import org.junit.After; import org.junit.Before; import org.junit.Test; -public class TypeMembersTest { +public class TypeMembersTest extends TestBase { private Context ctx; @Before public void prepareCtx() { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); + ctx = createDefaultContext(); } + @After + public void disposeCtx() { + ctx.close(); + } @Test public void checkAtomMembers() throws Exception { diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/VectorTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/VectorTest.java index 7546b60eee83..7479ab9f9eef 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/VectorTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/VectorTest.java @@ -1,40 +1,31 @@ package org.enso.interpreter.test; -import java.io.ByteArrayOutputStream; import java.net.URI; -import java.nio.file.Paths; import java.util.BitSet; import java.util.List; -import java.util.Map; import java.util.function.Consumer; -import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Language; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; import org.graalvm.polyglot.proxy.ProxyArray; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import org.junit.Before; + +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; -public class VectorTest { - private Context ctx; - - @Before - public void prepareCtx() { - this.ctx = Context.newBuilder() - .allowExperimentalOptions(true) - .allowIO(true) - .allowAllAccess(true) - .logHandler(new ByteArrayOutputStream()) - .option( - RuntimeOptions.LANGUAGE_HOME_OVERRIDE, - Paths.get("../../distribution/component").toFile().getAbsolutePath() - ).build(); - final Map langs = ctx.getEngine().getLanguages(); - assertNotNull("Enso found: " + langs, langs.get("enso")); +public class VectorTest extends TestBase { + private static Context ctx; + + @BeforeClass + public static void prepareCtx() { + ctx = createDefaultContext(); + } + + @AfterClass + public static void disposeCtx() { + ctx.close(); } @Test diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/WarningsTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/WarningsTest.java index fbbe272005cc..32a267a77b3e 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/WarningsTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/WarningsTest.java @@ -1,17 +1,42 @@ package org.enso.interpreter.test; +import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.Warning; import org.enso.interpreter.runtime.error.WarningsLibrary; import org.enso.interpreter.runtime.error.WithWarnings; +import org.enso.polyglot.LanguageInfo; +import org.enso.polyglot.MethodNames; +import org.graalvm.polyglot.Context; +import org.junit.AfterClass; import org.junit.Assert; -import static org.junit.Assert.assertEquals; +import org.junit.BeforeClass; import org.junit.Test; -public class WarningsTest { +import static org.junit.Assert.assertEquals; + +public class WarningsTest extends TestBase { + + private static Context ctx; + + @BeforeClass + public static void initEnsoContext() { + ctx = createDefaultContext(); + } + + @AfterClass + public static void disposeContext() { + ctx.close(); + } + @Test public void doubleWithWarningsWrap() { - var warn1 = new Warning("w1", this, 1L); - var warn2 = new Warning("w2", this, 2L); + var ensoContext = + (EnsoContext) + ctx.getBindings(LanguageInfo.ID) + .invokeMember(MethodNames.TopScope.LEAK_CONTEXT) + .asHostObject(); + var warn1 = Warning.create(ensoContext, "w1", this); + var warn2 = Warning.create(ensoContext, "w2", this); var value = 42; var with1 = WithWarnings.wrap(42, warn1); diff --git a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java index 734a644484ee..7e09c3b7c474 100644 --- a/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java +++ b/lib/scala/interpreter-dsl/src/main/java/org/enso/interpreter/dsl/MethodProcessor.java @@ -502,7 +502,7 @@ private boolean generateWarningsCheck( + arrayRead(argumentsArray, arg.getPosition()) + " = withWarnings.getValue();"); out.println( - " gatheredWarnings = gatheredWarnings.prepend(withWarnings.getReassignedWarnings(bodyNode));"); + " gatheredWarnings = gatheredWarnings.prepend(withWarnings.getReassignedWarningsAsRope(bodyNode));"); out.println(" }"); } return true; diff --git a/test/Table_Tests/src/Database/SQLite_Spec.enso b/test/Table_Tests/src/Database/SQLite_Spec.enso index 0d7634759829..ead9985511b1 100644 --- a/test/Table_Tests/src/Database/SQLite_Spec.enso +++ b/test/Table_Tests/src/Database/SQLite_Spec.enso @@ -177,4 +177,11 @@ spec = file.delete_if_exists + Test.specify 'should not duplicate warnings' <| + c = Database.connect (SQLite In_Memory) + t0 = Table.new [["X", ["a", "bc", "def"]]] + t1 = c.upload_table "Tabela" t0 + t2 = t1.cast "X" (Value_Type.Char size=1) + Warning.get_all t2 . length . should_equal 1 + main = Test_Suite.run_main spec diff --git a/test/Tests/src/Semantic/Warnings_Spec.enso b/test/Tests/src/Semantic/Warnings_Spec.enso index 7cd337b7ab36..2d399139c5b6 100644 --- a/test/Tests/src/Semantic/Warnings_Spec.enso +++ b/test/Tests/src/Semantic/Warnings_Spec.enso @@ -19,6 +19,8 @@ My_Type.my_method self = self.a + self.b + self.c type Wrap Value foo +f x _ = Warning.attach "Baz!" x + type My_Fancy_Collection Value (x:Integer) @@ -388,5 +390,22 @@ spec = Test.group "Dataflow Warnings" <| Problems.assume_no_problems <| condition_1 False x3 Problems.assume_no_problems <| condition_2 False x3 + Test.specify "should only report unique warnings" <| + a = 1 + b = Warning.attach "Foo!" a + c = Warning.attach "Bar!" b + d = Warning.attach "Foo!" b + + result_1 = b + c + Warning.get_all result_1 . map (x-> x.value.to_text) . should_equal ["Bar!", "Foo!"] + + result_2 = b + b + b + Warning.get_all result_2 . length . should_equal 1 + + result_3 = b + b + d + Warning.get_all result_3 . map (x-> x.value.to_text) . should_equal ["Foo!", "Foo!"] + + result_4 = f a 1 + f a 2 + f a 3 + Warning.get_all result_4 . map (x-> x.value.to_text) . should_equal ["Baz!", "Baz!", "Baz!"] main = Test_Suite.run_main spec