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 contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()
val moduleName = "Enso_Test.Test.Main" 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)), Api.Response(requestId, Api.PushContextResponse(contextId)),
TestMessages.update( TestMessages.update(
contextId, contextId,
@ -1382,26 +1382,31 @@ class RuntimeServerTest
) )
) )
), ),
TestMessages.update( Api.Response(
Api.ExecutionFailed(
contextId, contextId,
id_x_1, Api.ExecutionResult.Diagnostic.error(
ConstantsGen.FUNCTION_BUILTIN, "Type_Error.Error",
methodCall = Some( Some(mainFile),
Api.MethodCall( Some(model.Range(model.Position(8, 0), model.Position(8, 12))),
Api.MethodPointer(moduleName, s"$moduleName.T", "A"), None,
Vector(1) Vector(
) Api.StackTraceElement(
"Main.test",
Some(mainFile),
Some(model.Range(model.Position(8, 0), model.Position(8, 12))),
None
), ),
payload = Api.ExpressionUpdate.Payload.Value( Api.StackTraceElement(
functionSchema = Some( "Main.main",
Api.FunctionSchema( Some(mainFile),
Api.MethodPointer(moduleName, s"$moduleName.T", "A"), Some(model.Range(model.Position(4, 10), model.Position(4, 18))),
Vector(1) None
)
)
) )
) )
) )
),
context.executionComplete(contextId)
) )
} }

View File

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

View File

@ -1,10 +1,15 @@
package org.enso.interpreter.node.callable; package org.enso.interpreter.node.callable;
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.Fallback; import com.oracle.truffle.api.dsl.Fallback;
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.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException; 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.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.source.SourceSection;
@ -12,6 +17,7 @@ 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;
@ -29,6 +35,7 @@ import org.enso.interpreter.runtime.error.PanicSentinel;
import org.enso.interpreter.runtime.error.Warning; import org.enso.interpreter.runtime.error.Warning;
import org.enso.interpreter.runtime.error.WarningsLibrary; import org.enso.interpreter.runtime.error.WarningsLibrary;
import org.enso.interpreter.runtime.error.WithWarnings; import org.enso.interpreter.runtime.error.WithWarnings;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.state.State; import org.enso.interpreter.runtime.state.State;
/** /**
@ -278,7 +285,7 @@ public abstract class InvokeCallableNode extends BaseNode {
VirtualFrame callerFrame, VirtualFrame callerFrame,
State state, State state,
Object[] arguments, Object[] arguments,
@CachedLibrary(limit = "3") WarningsLibrary warnings) { @Shared("warnings") @CachedLibrary(limit = "3") WarningsLibrary warnings) {
Warning[] extracted; Warning[] extracted;
Object callable; 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 @Fallback
public Object invokeGeneric( public Object invokeGeneric(
Object callable, VirtualFrame callerFrame, State state, Object[] arguments) { 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.callable.function.Function;
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.data.atom.Atom;
import org.enso.interpreter.runtime.data.atom.AtomConstructor; 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.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.State; import org.enso.interpreter.runtime.state.State;
/** /**
@ -171,7 +172,8 @@ public final class UnresolvedConstructor implements EnsoObject {
static DirectCallNode buildApplication(UnresolvedConstructor prototype) { static DirectCallNode buildApplication(UnresolvedConstructor prototype) {
UUID id = null; UUID id = null;
SourceSection section = 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()) { for (var where = prototype.where; where != null; where = where.getParent()) {
if (where instanceof ExpressionNode withId && withId.getId() != null) { if (where instanceof ExpressionNode withId && withId.getId() != null) {
id = withId.getId(); id = withId.getId();
@ -235,7 +237,7 @@ public final class UnresolvedConstructor implements EnsoObject {
return invokeConstructor(c, unresolved.asPrototype(), unresolved, state, callNode); return invokeConstructor(c, unresolved.asPrototype(), unresolved, state, callNode);
} }
private static Object invokeConstructor( private Object invokeConstructor(
AtomConstructor c, AtomConstructor c,
UnresolvedConstructor prototype, UnresolvedConstructor prototype,
UnresolvedConstructor unresolved, UnresolvedConstructor unresolved,
@ -254,7 +256,13 @@ public final class UnresolvedConstructor implements EnsoObject {
args[0] = fn; args[0] = fn;
var helper = Function.ArgumentsHelper.buildArguments(fn, null, state, args); var helper = Function.ArgumentsHelper.buildArguments(fn, null, state, args);
var r = callNode.call(helper); var r = callNode.call(helper);
if (r instanceof Atom) {
return r; 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) { private static Object checkSingleton(Type c, UnresolvedConstructor unresolved) {

View File

@ -1,5 +1,5 @@
from Standard.Base import all from Standard.Base import all
import Standard.Base.Errors.Common.Not_Invokable
from Standard.Test import all 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" <| group_builder.specify "access Integer field from Polyglot object" <|
js_meaning.meaning . should_equal 42 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" <| group_builder.specify "use Integer obtained from a call" <|
Java_Integer.parseInt "42" . should_equal 42 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 = """ foreign js js_meaning = """
return { meaning : 6 * 7 }; return { meaning : 6 * 7 };
foreign js js_plus = """
return (a, b) => a + b;
main filter=Nothing = main filter=Nothing =
suite = Test.build suite_builder-> suite = Test.build suite_builder->
add_specs suite_builder add_specs suite_builder

View File

@ -448,6 +448,21 @@ add_specs suite_builder =
foo = v:Foo foo = v:Foo
Foo.Value 10 . should_equal 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" <| group_builder.specify "..False can be autoscoped" <|
bool b:Boolean = b bool b:Boolean = b