Skip to content

Commit

Permalink
Better error when unknown language is used with foreign in binary m…
Browse files Browse the repository at this point in the history
…ode (#12104)

Small improvement based on the #10121 discussion. Improving error messages for `foreign` statement when running in _native image_ build and requested language isn't available.
  • Loading branch information
JaroslavTulach authored Jan 24, 2025
1 parent 00bde82 commit 78febd5
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package org.enso.interpreter.test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.Executors;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
import org.junit.BeforeClass;
Expand All @@ -31,10 +35,10 @@ public static void disposeCtx() {
}

@Test
public void testForeignFunctionParseFailure() {
public void testForeignFunctionParseFailure() throws Exception {
// python is not a permitted language, therefore, invoking `py_array` method
// should fail with a Polyglot_Error, rather than crashing whole engine.
String source =
var code =
"""
from Standard.Base import all
Expand All @@ -45,16 +49,24 @@ public void testForeignFunctionParseFailure() {
Panic.recover Any py_array
"""
.trim();
Value module = ctx.eval("enso", source);
var src = Source.newBuilder("enso", code, "TryPython.enso").build();
Value module = ctx.eval(src);
Value res = module.invokeMember("eval_expression", "main");
assertTrue("Invoking non-installed foreign function should recover", res.isException());
try {
throw res.throwException();
} catch (RuntimeException e) {
assertTrue(
"Wrong error message",
e.getMessage()
.matches("Cannot parse foreign python method. Only available languages are .+"));
var sw = new StringWriter();
var pw = new PrintWriter(sw);
e.printStackTrace(pw);
var text = sw.toString().replace(System.getProperty("line.separator"), "\n");
var lines = text.split("\n");
assertThat(
"Expecting message at first line: " + lines[0],
lines[0].matches("Cannot parse.*foreign python.*method.*languages are .+"));
assertThat(
"First error line comes from TryPython file: " + lines[1],
lines[1].matches(".*at <enso> TryPython\\.py_array\\(TryPython:3.*\\)"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.oracle.truffle.api.source.Source;
import java.util.Arrays;
import java.util.List;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
Expand All @@ -29,6 +30,11 @@ static ForeignEvalNode parse(EpbLanguage epb, Source langAndCode, List<String> a
return node;
}

@Override
public boolean isInternal() {
return true;
}

private String truffleId(Source langAndCode) {
var seq = langAndCode.getCharacters();
var langAndLine = seq.subSequence(0, splitAt(seq, '#'));
Expand Down Expand Up @@ -74,11 +80,12 @@ public Object execute(VirtualFrame frame) {
CompilerDirectives.transferToInterpreterAndInvalidate();
var id = truffleId(langAndCode);
var context = EpbContext.get(this);
var installedLanguages = context.getEnv().getInternalLanguages();
var installedLanguages = context.getEnv().getPublicLanguages();
var node =
switch (installedLanguages.containsKey(id) ? 1 : 0) {
case 0 -> {
var ex = new ForeignParsingException(id, installedLanguages.keySet(), this);
var sortedLangs = new TreeSet<>(installedLanguages.keySet());
var ex = new ForeignParsingException(id, sortedLangs, this);
yield new ExceptionForeignNode(ex);
}
default -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.enso.interpreter.epb;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleOptions;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.Node;
import java.util.Set;
import java.util.SortedSet;

/**
* This exception is thrown once a foreign method cannot be parsed because the associated foreign
Expand All @@ -23,24 +24,28 @@ class ForeignParsingException extends AbstractTruffleException {
* distribution.
* @param location Location node passed to {@link AbstractTruffleException}.
*/
public ForeignParsingException(String truffleLangId, Set<String> installedLangs, Node location) {
ForeignParsingException(String truffleLangId, SortedSet<String> installedLangs, Node location) {
this(createMessage(truffleLangId, installedLangs), location);
}

/**
* @param msg message of the exception
* @param location Location node passed to {@link AbstractTruffleException}.
*/
public ForeignParsingException(String msg, Node location) {
ForeignParsingException(String msg, Node location) {
super(msg, location);
this.message = msg;
}

@TruffleBoundary
private static String createMessage(String truffleLangId, Set<String> installedLangs) {
return String.format(
"Cannot parse foreign %s method. Only available languages are %s",
truffleLangId, installedLangs);
private static String createMessage(String truffleLangId, Iterable<String> installedLangs) {
var allLangs = String.join(", ", installedLangs);
var format = "Cannot parse `foreign %s` method. Only available languages are %s. %s";
var extraInfo = "";
if (TruffleOptions.AOT) {
extraInfo = "\nMore languages may be available in JVM mode. Try running with --jvm option.";
}
return String.format(format, truffleLangId, allLangs, extraInfo);
}

@Override
Expand Down

0 comments on commit 78febd5

Please sign in to comment.