diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala index aa95f01b454..d1631f99d6a 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala @@ -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) + ) ) } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/EnsoRootNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/EnsoRootNode.java index 91152fe7248..b202ac95262 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/EnsoRootNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/EnsoRootNode.java @@ -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; 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 255cc17e42f..1ecd1e02845 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 @@ -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) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java index c2084cf5c2d..78c8b15611f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedConstructor.java @@ -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) { diff --git a/test/Base_Tests/src/Data/Polyglot_Spec.enso b/test/Base_Tests/src/Data/Polyglot_Spec.enso index bd569cd0e46..6591e92fac9 100644 --- a/test/Base_Tests/src/Data/Polyglot_Spec.enso +++ b/test/Base_Tests/src/Data/Polyglot_Spec.enso @@ -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 diff --git a/test/Base_Tests/src/Semantic/Conversion_Spec.enso b/test/Base_Tests/src/Semantic/Conversion_Spec.enso index 43e9f5345d8..b42d5bd1426 100644 --- a/test/Base_Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Base_Tests/src/Semantic/Conversion_Spec.enso @@ -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