Execute foreign function and check autoscoped constructor result (#10187)

Fixes #10151 and also fixes #10180 and fixes #10186.
This commit is contained in:
Jaroslav Tulach 2024-06-06 15:16:27 +02:00 committed by GitHub
parent d21140e422
commit 396d70ddc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 112 additions and 25 deletions

View File

@ -1307,7 +1307,7 @@ class RuntimeServerTest
)
}
it should "send method pointer updates of partially applied autoscope constructors" in {
it should "send error updates for partially applied autoscope constructors" in {
val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID()
val moduleName = "Enso_Test.Test.Main"
@ -1361,7 +1361,7 @@ class RuntimeServerTest
)
)
)
context.receiveN(4) should contain theSameElementsAs Seq(
context.receiveN(3) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)),
TestMessages.update(
contextId,
@ -1382,26 +1382,31 @@ class RuntimeServerTest
)
)
),
TestMessages.update(
contextId,
id_x_1,
ConstantsGen.FUNCTION_BUILTIN,
methodCall = Some(
Api.MethodCall(
Api.MethodPointer(moduleName, s"$moduleName.T", "A"),
Vector(1)
)
),
payload = Api.ExpressionUpdate.Payload.Value(
functionSchema = Some(
Api.FunctionSchema(
Api.MethodPointer(moduleName, s"$moduleName.T", "A"),
Vector(1)
Api.Response(
Api.ExecutionFailed(
contextId,
Api.ExecutionResult.Diagnostic.error(
"Type_Error.Error",
Some(mainFile),
Some(model.Range(model.Position(8, 0), model.Position(8, 12))),
None,
Vector(
Api.StackTraceElement(
"Main.test",
Some(mainFile),
Some(model.Range(model.Position(8, 0), model.Position(8, 12))),
None
),
Api.StackTraceElement(
"Main.main",
Some(mainFile),
Some(model.Range(model.Position(4, 10), model.Position(4, 18))),
None
)
)
)
)
),
context.executionComplete(contextId)
)
)
}

View File

@ -42,6 +42,7 @@ public abstract class EnsoRootNode extends RootNode {
super(language, buildFrameDescriptor(localScope));
Objects.requireNonNull(language);
Objects.requireNonNull(localScope);
Objects.requireNonNull(moduleScope);
this.name = name;
this.localScope = localScope;
this.moduleScope = moduleScope;

View File

@ -1,10 +1,15 @@
package org.enso.interpreter.node.callable;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.SourceSection;
@ -12,6 +17,7 @@ import java.util.UUID;
import java.util.concurrent.locks.Lock;
import org.enso.interpreter.Constants;
import org.enso.interpreter.node.BaseNode;
import org.enso.interpreter.node.BaseNode.TailStatus;
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.EnsoContext;
@ -29,6 +35,7 @@ import org.enso.interpreter.runtime.error.PanicSentinel;
import org.enso.interpreter.runtime.error.Warning;
import org.enso.interpreter.runtime.error.WarningsLibrary;
import org.enso.interpreter.runtime.error.WithWarnings;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.state.State;
/**
@ -278,7 +285,7 @@ public abstract class InvokeCallableNode extends BaseNode {
VirtualFrame callerFrame,
State state,
Object[] arguments,
@CachedLibrary(limit = "3") WarningsLibrary warnings) {
@Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
Warning[] extracted;
Object callable;
@ -323,6 +330,42 @@ public abstract class InvokeCallableNode extends BaseNode {
}
}
@Specialization(
guards = {
"!warnings.hasWarnings(self)",
"!types.hasType(self)",
"!types.hasSpecialDispatch(self)",
"iop.isExecutable(self)",
})
Object doPolyglot(
Object self,
VirtualFrame frame,
State state,
Object[] arguments,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings,
@CachedLibrary(limit = "3") TypesLibrary types,
@Cached ThunkExecutorNode thunkNode) {
var errors = EnsoContext.get(this).getBuiltins().error();
try {
for (int i = 0; i < arguments.length; i++) {
arguments[i] = thunkNode.executeThunk(frame, arguments[i], state, TailStatus.NOT_TAIL);
}
return iop.execute(self, arguments);
} catch (UnsupportedTypeException ex) {
var err = errors.makeUnsupportedArgumentsError(ex.getSuppliedValues(), ex.getMessage());
throw new PanicException(err, this);
} catch (ArityException ex) {
var err =
errors.makeArityError(
ex.getExpectedMinArity(), ex.getExpectedMaxArity(), arguments.length);
throw new PanicException(err, this);
} catch (UnsupportedMessageException ex) {
var err = errors.makeNotInvokable(self);
throw new PanicException(err, this);
}
}
@Fallback
public Object invokeGeneric(
Object callable, VirtualFrame callerFrame, State state, Object[] arguments) {

View File

@ -30,9 +30,10 @@ import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.data.atom.Atom;
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.State;
/**
@ -171,7 +172,8 @@ public final class UnresolvedConstructor implements EnsoObject {
static DirectCallNode buildApplication(UnresolvedConstructor prototype) {
UUID id = null;
SourceSection section = null;
ModuleScope scope = null;
var scope =
prototype.where.getRootNode() instanceof EnsoRootNode root ? root.getModuleScope() : null;
for (var where = prototype.where; where != null; where = where.getParent()) {
if (where instanceof ExpressionNode withId && withId.getId() != null) {
id = withId.getId();
@ -235,7 +237,7 @@ public final class UnresolvedConstructor implements EnsoObject {
return invokeConstructor(c, unresolved.asPrototype(), unresolved, state, callNode);
}
private static Object invokeConstructor(
private Object invokeConstructor(
AtomConstructor c,
UnresolvedConstructor prototype,
UnresolvedConstructor unresolved,
@ -254,7 +256,13 @@ public final class UnresolvedConstructor implements EnsoObject {
args[0] = fn;
var helper = Function.ArgumentsHelper.buildArguments(fn, null, state, args);
var r = callNode.call(helper);
return r;
if (r instanceof Atom) {
return r;
} else {
var ctx = EnsoContext.get(this);
var err = ctx.getBuiltins().error().makeTypeError(c.getType(), r, prototype.toString());
throw new PanicException(err, this);
}
}
private static Object checkSingleton(Type c, UnresolvedConstructor unresolved) {

View File

@ -1,5 +1,5 @@
from Standard.Base import all
import Standard.Base.Errors.Common.Not_Invokable
from Standard.Test import all
@ -34,6 +34,18 @@ add_specs suite_builder = suite_builder.group "Polyglot" group_builder->
group_builder.specify "access Integer field from Polyglot object" <|
js_meaning.meaning . should_equal 42
group_builder.specify "Execute JavaScript function" <|
js_plus 3 5 . should_equal 8
group_builder.specify "Execute JavaScript with insufficient number of arguments" <|
r = js_plus 3
r.is_nan . should_be_true
group_builder.specify "Cannot Execute JavaScript number" <|
fourty_two = js_meaning.meaning
Test.expect_panic Not_Invokable <|
fourty_two "Cannot invoke"
group_builder.specify "use Integer obtained from a call" <|
Java_Integer.parseInt "42" . should_equal 42
@ -50,6 +62,9 @@ add_specs suite_builder = suite_builder.group "Polyglot" group_builder->
foreign js js_meaning = """
return { meaning : 6 * 7 };
foreign js js_plus = """
return (a, b) => a + b;
main filter=Nothing =
suite = Test.build suite_builder->
add_specs suite_builder

View File

@ -448,6 +448,21 @@ add_specs suite_builder =
foo = v:Foo
Foo.Value 10 . should_equal foo
group_builder.specify "Foo.Value constructor is not autoscoped" <|
v = ..Value
err = Test.expect_panic Type_Error <|
f = v:Foo
f
msg = err.to_text
msg . should_contain "Type error:"
msg . should_contain "Expected `..Value` to be Foo"
msg . should_contain "got Foo.Value["
msg . should_contain "foo=_"
msg . should_contain "Try to apply foo argument"
group_builder.specify "..False can be autoscoped" <|
bool b:Boolean = b