Invoke Warning.getValue().to_text and use it from ReplDebuggerInstrument (#11591)

Fixes #11569 by using `.to_text` on the right _warning's value_ (as introduced by #10842) and sharing the code with the instrument.
This commit is contained in:
Jaroslav Tulach 2024-11-20 18:31:33 +01:00 committed by GitHub
parent f0a04b4e52
commit afe4203f6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 23 deletions

View File

@ -15,7 +15,6 @@ import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
import com.oracle.truffle.api.interop.ExceptionType;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
@ -41,12 +40,10 @@ import org.enso.interpreter.node.expression.debug.EvalNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.CallerInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.hash.HashMapToVectorNode;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode;
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
import org.enso.interpreter.runtime.state.State;
import org.enso.interpreter.runtime.warning.WarningsLibrary;
import org.enso.interpreter.runtime.warning.WithWarnings;
import org.graalvm.options.OptionDescriptor;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.options.OptionKey;
@ -222,26 +219,15 @@ public final class ReplDebuggerInstrument extends TruffleInstrument {
}
private Object formatObject(Object raw) {
if (raw instanceof Text) {
return toJavaStringNode.execute((Text) raw);
if (raw instanceof Text txt) {
return toJavaStringNode.execute(txt);
}
if (WarningsLibrary.getUncached().hasWarnings(raw)) {
try {
var sb = new StringBuilder();
sb.append(WarningsLibrary.getUncached().removeWarnings(raw));
var value = Text.create(WarningsLibrary.getUncached().removeWarnings(raw).toString());
var mappedWarnings = WarningsLibrary.getUncached().getWarnings(raw, true);
var pairs = HashMapToVectorNode.getUncached().execute(mappedWarnings);
var size = ArrayLikeLengthNode.getUncached().executeLength(pairs);
for (var i = 0L; i < size; i++) {
try {
var pair = ArrayLikeAtNode.getUncached().executeAt(pairs, i);
var value = ArrayLikeAtNode.getUncached().executeAt(pair, 1);
sb.append("\n ! ").append(value);
} catch (InvalidArrayIndexException ex) {
// go on
}
}
return sb.toString();
var txt = WithWarnings.warningsToText(mappedWarnings, this, Text.create("\n ! "));
return value.add(txt);
} catch (UnsupportedMessageException e) {
// go on
}

View File

@ -150,6 +150,33 @@ public class WarningsTest {
}
}
@Test
public void toDisplayText() throws Exception {
var code =
"""
from Standard.Base import Integer, Warning, Error, Text
type My_Warning
private Value msg
to_display_text self -> Text = Error.throw "Don't call me!"
to_text self -> Text = "My_Warning to_text: "+self.msg
fn =
Warning.attach (My_Warning.Value "ONE") 1
""";
var module = ctx.eval(LanguageInfo.ID, code);
var ownWarning = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn");
assertTrue("Warning is seen as exception", ownWarning.isException());
try {
throw ownWarning.throwException();
} catch (PolyglotException ex) {
assertEquals("My_Warning to_text: ONE", ex.getMessage());
}
}
private void assertWarningsForAType(Value v) {
var type = v.getMetaObject();

View File

@ -141,4 +141,37 @@ public class DebugServerInspectTest {
err.toString(),
AllOf.allOf(containsString("d = Error:2"), not(containsString("j = 1"))));
}
@Test
public void toTextIsCalledForListings() throws Exception {
var code =
"""
from Standard.Base import all
type My_Warning
Value msg
to_text self -> Text = "Beware of "+self.msg
inspect =
one = Warning.attach (My_Warning.Value "ONE") 1
half = Warning.attach (My_Warning.Value "HALF") 2
two = Warning.attach (My_Warning.Value "TWO") half
[one, half, two]
""";
var r = ContextUtils.evalModule(ctx, code, "ScriptTest.enso", "inspect");
assertTrue("Got array back: " + r, r.hasArrayElements());
assertEquals("Got three elements", 3, r.getArraySize());
assertEquals("One", 1, r.getArrayElement(0).asInt());
assertEquals("Half", 2, r.getArrayElement(1).asInt());
assertEquals("Two", 2, r.getArrayElement(2).asInt());
assertEquals("No output printed", "", out.toString());
assertThat(
"Stderr contains some warnings",
err.toString(),
AllOf.allOf(
containsString("half = 2\n ! Beware of HALF"),
containsString("one = 1\n ! Beware of ONE"),
containsString("two = 2\n ! Beware of TWO\n ! Beware of HALF"),
containsString("two = 2")));
}
}

View File

@ -184,25 +184,34 @@ public final class WithWarnings extends EnsoObject {
WarningsLibrary.getUncached(),
ArrayLikeAtNodeGen.getUncached(),
ArrayLikeLengthNodeGen.getUncached());
var text = warningsToText(warnsMap, where, null);
return new PanicException(text, where);
}
@CompilerDirectives.TruffleBoundary
public static Text warningsToText(EnsoHashMap warnsMap, Node where, Text prefix)
throws PanicException {
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});
var wText = node.execute(toText, state, new Object[] {w.getValue()});
if (wText instanceof Text t) {
if (prefix != null) {
text = text.add(prefix);
}
text = text.add(t);
}
} catch (ArityException e) {
throw ctx.raiseAssertionPanic(where, null, e);
}
}
return new PanicException(text, where);
return text;
}
@ExportMessage