From 2a161e83672cd3c224aa31b20109114f5768a784 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 12 Sep 2023 09:55:51 +0200 Subject: [PATCH 01/21] Checking ascribed expression types for existance --- .../pass/analyse/GatherDiagnostics.scala | 14 ++++++++++++-- .../enso/compiler/pass/resolve/TypeNames.scala | 14 ++++++++++---- .../enso/interpreter/test/SignatureTest.java | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala index 282186835cc2..6a13e61448ed 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala @@ -6,7 +6,8 @@ import org.enso.compiler.core.ir.{ DefinitionArgument, Diagnostic, Expression, - Module + Module, + Name } import org.enso.compiler.core.ir.module.scope.definition import org.enso.compiler.core.ir.MetadataStorage._ @@ -81,7 +82,16 @@ case object GatherDiagnostics extends IRPass { }) .getOrElse(Nil) typeSignatureDiagnostics ++ x.diagnostics.toList - case x => x.diagnostics.toList + case x: Name.Literal => + val typeSignatureDiagnostics = + x.getMetadata(TypeSignatures) + .map(_.signature.preorder.collect { case err: Diagnostic => + err + }) + .getOrElse(Nil) + typeSignatureDiagnostics ++ x.diagnostics.toList + case x => + x.diagnostics.toList }.flatten DiagnosticsMeta( diagnostics.distinctBy(d => new DiagnosticKeys(d)) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeNames.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeNames.scala index 078c5a0d9fb7..cbe5b92f3743 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeNames.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeNames.scala @@ -45,9 +45,14 @@ case object TypeNames extends IRPass { val bindingsMap = ir.unsafeGetMetadata(BindingAnalysis, "bindings analysis did not run") ir.copy(bindings = ir.bindings.map { d => - val mapped = d.mapExpressions(resolveExpression(bindingsMap, _)) + val typeParams = d match { + case t: Definition.Type => t.params.map(_.name) + case _ => Nil + } + val mapped = + d.mapExpressions(resolveExpression(typeParams, bindingsMap, _)) doResolveType( - Nil, + typeParams, bindingsMap, mapped match { case typ: Definition.Type => @@ -64,6 +69,7 @@ case object TypeNames extends IRPass { } private def resolveExpression( + typeParams: List[Name], bindingsMap: BindingsMap, ir: Expression ): Expression = { @@ -71,11 +77,11 @@ case object TypeNames extends IRPass { val processedIr = ir match { case fn: Function.Lambda => fn.copy(arguments = - fn.arguments.map(doResolveType(Nil, bindingsMap, _)) + fn.arguments.map(doResolveType(typeParams, bindingsMap, _)) ) case x => x } - doResolveType(Nil, bindingsMap, processedIr.mapExpressions(go)) + doResolveType(typeParams, bindingsMap, processedIr.mapExpressions(go)) } go(ir) } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java index 23740c4337c2..9bde97b9c2af 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java @@ -49,6 +49,24 @@ public void wrongFunctionSignature() throws Exception { } } + @Test + public void wrongExpressionSignature() throws Exception { + final URI uri = new URI("memory://neg.enso"); + final Source src = Source.newBuilder("enso", """ + neg a = 0 - a:Xyz + """,uri.getAuthority()) + .uri(uri) + .buildLiteral(); + + try { + var module = ctx.eval(src); + var neg = module.invokeMember("eval_expression", "neg").execute(-1); + fail("Expecting an exception from compilation, not: " + neg); + } catch (PolyglotException e) { + assertTrue("It is a syntax error exception", e.isSyntaxError()); + } + } + @Test public void wrongAscribedTypeSignature() throws Exception { final URI uri = new URI("memory://neg.enso"); From b4652b799e79f743caa14cfbdaccffcc5ae9b4da Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 12 Sep 2023 10:07:30 +0200 Subject: [PATCH 02/21] Allow ascriptions of any expression --- .../pass/analyse/GatherDiagnostics.scala | 5 ++--- .../enso/interpreter/test/SignatureTest.java | 22 +++++++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala index 6a13e61448ed..39a11697e6ad 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/GatherDiagnostics.scala @@ -6,8 +6,7 @@ import org.enso.compiler.core.ir.{ DefinitionArgument, Diagnostic, Expression, - Module, - Name + Module } import org.enso.compiler.core.ir.module.scope.definition import org.enso.compiler.core.ir.MetadataStorage._ @@ -82,7 +81,7 @@ case object GatherDiagnostics extends IRPass { }) .getOrElse(Nil) typeSignatureDiagnostics ++ x.diagnostics.toList - case x: Name.Literal => + case x: Expression => val typeSignatureDiagnostics = x.getMetadata(TypeSignatures) .map(_.signature.preorder.collect { case err: Diagnostic => diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java index 9bde97b9c2af..28c202cb4b1f 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java @@ -50,8 +50,8 @@ public void wrongFunctionSignature() throws Exception { } @Test - public void wrongExpressionSignature() throws Exception { - final URI uri = new URI("memory://neg.enso"); + public void wrongLiteralSignature() throws Exception { + final URI uri = new URI("memory://literal_signature.enso"); final Source src = Source.newBuilder("enso", """ neg a = 0 - a:Xyz """,uri.getAuthority()) @@ -67,6 +67,24 @@ public void wrongExpressionSignature() throws Exception { } } + @Test + public void wrongExpressionSignature() throws Exception { + final URI uri = new URI("memory://exp_signature.enso"); + final Source src = Source.newBuilder("enso", """ + neg a = (0 - a):Xyz + """,uri.getAuthority()) + .uri(uri) + .buildLiteral(); + + try { + var module = ctx.eval(src); + var neg = module.invokeMember("eval_expression", "neg").execute(-1); + fail("Expecting an exception from compilation, not: " + neg); + } catch (PolyglotException e) { + assertTrue("It is a syntax error exception", e.isSyntaxError()); + } + } + @Test public void wrongAscribedTypeSignature() throws Exception { final URI uri = new URI("memory://neg.enso"); From 11b98eaa3d804d7000a3392e6b7b04250a070a5a Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 12 Sep 2023 12:14:21 +0200 Subject: [PATCH 03/21] Requesting explicit runtime conversions with p:Plus & co. --- .../argument/ReadArgumentCheckNode.java | 65 +++++++++++--- .../enso/compiler/codegen/IrToTruffle.scala | 84 +++++++++++-------- .../interpreter/test/DebuggingEnsoTest.java | 49 +++++------ .../enso/interpreter/test/SignatureTest.java | 5 +- 4 files changed, 130 insertions(+), 73 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java index 1464fbd4e1b1..120015fdbc48 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/argument/ReadArgumentCheckNode.java @@ -9,6 +9,7 @@ import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.node.BaseNode.TailStatus; import org.enso.interpreter.node.EnsoRootNode; +import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.callable.ApplicationNode; import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode; import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode; @@ -55,6 +56,13 @@ public abstract class ReadArgumentCheckNode extends Node { this.name = name; } + /** + * + */ + public static ExpressionNode wrap(ExpressionNode original, ReadArgumentCheckNode check) { + return new TypeCheckExpressionNode(original, check); + } + /** Executes check or conversion of the value.abstract * @param frame frame requesting the conversion * @param value the value to convert @@ -289,16 +297,28 @@ private Pair findConversion(Type from) { ApplicationNode findConversionNode(Type from) { var convAndType = findConversion(from); - if (convAndType != null && NodeUtil.findParent(this, ReadArgumentNode.class) instanceof ReadArgumentNode ran) { - CompilerAsserts.neverPartOfCompilation(); - var convNode = LiteralNode.build(convAndType.getLeft()); - var intoNode = LiteralNode.build(convAndType.getRight()); - var valueNode = ran.plainRead(); - var args = new CallArgument[]{ - new CallArgument(null, intoNode), - new CallArgument(null, valueNode) - }; - return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE); + if (convAndType != null) { + if (NodeUtil.findParent(this, ReadArgumentNode.class) instanceof ReadArgumentNode ran) { + CompilerAsserts.neverPartOfCompilation(); + var convNode = LiteralNode.build(convAndType.getLeft()); + var intoNode = LiteralNode.build(convAndType.getRight()); + var valueNode = ran.plainRead(); + var args = new CallArgument[]{ + new CallArgument(null, intoNode), + new CallArgument(null, valueNode) + }; + return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE); + } else if (NodeUtil.findParent(this, TypeCheckExpressionNode.class) instanceof TypeCheckExpressionNode tcen) { + CompilerAsserts.neverPartOfCompilation(); + var convNode = LiteralNode.build(convAndType.getLeft()); + var intoNode = LiteralNode.build(convAndType.getRight()); + var valueNode = tcen.original; + var args = new CallArgument[]{ + new CallArgument(null, intoNode), + new CallArgument(null, valueNode) + }; + return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE); + } } return null; } @@ -378,4 +398,29 @@ public Object execute(VirtualFrame frame) { return result; } } + + private static final class TypeCheckExpressionNode extends ExpressionNode { + @Child + private ExpressionNode original; + @Child + private ReadArgumentCheckNode check; + + TypeCheckExpressionNode(ExpressionNode original, ReadArgumentCheckNode check) { + this.check = check; + this.original = original; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + var value = original.executeGeneric(frame); + var result = check.handleCheckOrConversion(frame, value); + return result; + } + + @Override + public boolean isInstrumentable() { + return false; + } + } + } diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index da1476fc3808..48b9bb897fb9 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -680,43 +680,46 @@ class IrToTruffle( // === Utility Functions ==================================================== // ========================================================================== - private def checkRuntimeTypes( - arg: DefinitionArgument - ): ReadArgumentCheckNode = { - def extractAscribedType(t: Expression): ReadArgumentCheckNode = t match { - case u: `type`.Set.Union => - ReadArgumentCheckNode.oneOf( - arg.name, - u.operands.map(extractAscribedType).asJava - ) - case i: `type`.Set.Intersection => - ReadArgumentCheckNode.allOf( - arg.name, - extractAscribedType(i.left), - extractAscribedType(i.right) - ) - case p: Application.Prefix => extractAscribedType(p.function) - case _: Tpe.Function => - ReadArgumentCheckNode.build( - arg.name, - context.getTopScope().getBuiltins().function() - ) - case t => { - t.getMetadata(TypeNames) match { - case Some( - BindingsMap - .Resolution(BindingsMap.ResolvedType(mod, tpe)) - ) => - ReadArgumentCheckNode.build( - arg.name, - mod.unsafeAsModule().getScope.getTypes.get(tpe.name) - ) - case _ => null - } + private def extractAscribedType( + name: Name, + t: Expression + ): ReadArgumentCheckNode = t match { + case u: `type`.Set.Union => + ReadArgumentCheckNode.oneOf( + name, + u.operands.map(extractAscribedType(name, _)).asJava + ) + case i: `type`.Set.Intersection => + ReadArgumentCheckNode.allOf( + name, + extractAscribedType(name, i.left), + extractAscribedType(name, i.right) + ) + case p: Application.Prefix => extractAscribedType(name, p.function) + case _: Tpe.Function => + ReadArgumentCheckNode.build( + name, + context.getTopScope().getBuiltins().function() + ) + case t => { + t.getMetadata(TypeNames) match { + case Some( + BindingsMap + .Resolution(BindingsMap.ResolvedType(mod, tpe)) + ) => + ReadArgumentCheckNode.build( + name, + mod.unsafeAsModule().getScope.getTypes.get(tpe.name) + ) + case _ => null } } + } - arg.ascribedType.map(extractAscribedType).getOrElse(null) + private def checkRuntimeTypes( + arg: DefinitionArgument + ): ReadArgumentCheckNode = { + arg.ascribedType.map(extractAscribedType(arg.name, _)).getOrElse(null) } /** Checks if the expression has a @Builtin_Method annotation @@ -984,7 +987,7 @@ class IrToTruffle( binding: Boolean, subjectToInstrumentation: Boolean ): RuntimeExpression = { - val runtimeExpression = ir match { + var runtimeExpression = ir match { case block: Expression.Block => processBlock(block) case literal: Literal => processLiteral(literal) case app: Application => @@ -1009,8 +1012,17 @@ class IrToTruffle( s"Foreign expressions not yet implemented: $ir." ) } - runtimeExpression.setTailStatus(getTailStatus(ir)) + + val types = ir.getMetadata(TypeSignatures) + if (types.isDefined) { + val checkNode = extractAscribedType(null, types.get.signature); + if (checkNode != null) { + runtimeExpression = + ReadArgumentCheckNode.wrap(runtimeExpression, checkNode) + } + } + runtimeExpression } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index d2c38b342d01..bd7be358f515 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -1,20 +1,5 @@ package org.enso.interpreter.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; - -import com.oracle.truffle.api.debug.DebugException; -import com.oracle.truffle.api.debug.DebugScope; -import com.oracle.truffle.api.debug.DebugStackFrame; -import com.oracle.truffle.api.debug.DebugValue; -import com.oracle.truffle.api.debug.Debugger; -import com.oracle.truffle.api.debug.DebuggerSession; -import com.oracle.truffle.api.debug.SuspendedCallback; -import com.oracle.truffle.api.debug.SuspendedEvent; -import com.oracle.truffle.api.nodes.LanguageInfo; import java.io.OutputStream; import java.net.URI; import java.nio.file.Paths; @@ -29,6 +14,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; + import org.enso.polyglot.MethodNames.Module; import org.enso.polyglot.RuntimeOptions; import org.graalvm.polyglot.Context; @@ -39,9 +25,24 @@ import org.graalvm.polyglot.io.IOAccess; import org.junit.After; import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import com.oracle.truffle.api.debug.DebugException; +import com.oracle.truffle.api.debug.DebugScope; +import com.oracle.truffle.api.debug.DebugStackFrame; +import com.oracle.truffle.api.debug.DebugValue; +import com.oracle.truffle.api.debug.Debugger; +import com.oracle.truffle.api.debug.DebuggerSession; +import com.oracle.truffle.api.debug.SuspendedCallback; +import com.oracle.truffle.api.debug.SuspendedEvent; +import com.oracle.truffle.api.nodes.LanguageInfo; + public class DebuggingEnsoTest { private Context context; private Engine engine; @@ -118,8 +119,8 @@ private Value createEnsoMethod(String source, String methodName) { @Test public void recursiveFactorialCall() { final Value facFn = createEnsoMethod(""" - from Standard.Base.Data.Ordering import all - + from Standard.Base import all + fac : Number -> Number fac n = facacc : Number -> Number -> Number @@ -156,7 +157,7 @@ public void callerVariablesAreVisibleOnPreviousStackFrame() { bar arg_bar = loc_bar = arg_bar + 1 loc_bar - + foo x = loc_foo = 1 bar loc_foo @@ -195,7 +196,7 @@ public void testHostValues() { Value fooFunc = createEnsoMethod(""" polyglot java import java.nio.file.Path polyglot java import java.util.ArrayList - + foo x = path = Path.of 'blaaaaa' list = ArrayList.new @@ -231,7 +232,7 @@ public void testHostValues() { public void testHostValueAsAtomField() { Value fooFunc = createEnsoMethod(""" from Standard.Base import Vector - + foo x = vec_builder = Vector.new_builder end = 42 @@ -256,7 +257,7 @@ public void testHostValueAsAtomField() { public void testEvaluateExpression() { Value fooFunc = createEnsoMethod(""" polyglot java import java.nio.file.Path - + foo x = a = 10 b = 20 @@ -323,7 +324,7 @@ public void testRewriteVariableInCallerStackFrame() { Value fooFunc = createEnsoMethod(""" bar = loc_bar = 42 - + foo x = a = 10 # Will get modified to 1 b = 20 # Will get modified to 2 @@ -480,10 +481,10 @@ public void testSteppingOver() { public void testSteppingOverUseStdLib() { Source src = createEnsoSource(""" from Standard.Base import Vector - + bar vec num_elems = vec.slice 0 num_elems - + foo x = vec_builder = Vector.new_builder vec_builder.append 1 diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java index 28c202cb4b1f..031f5f6c9019 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/SignatureTest.java @@ -657,10 +657,9 @@ public void andConversions() throws Exception { self.dict.mul self.value that.value compute (a : Plus & Mul) (b : Plus & Mul) = - add (x:Plus) (y:Plus) = x+y - p = add a b + p = a+b m = a*b - add p m + p:Plus + m:Plus type BooleanPlus plus a:Boolean b:Boolean = a || b From 2dd35b077979d159d41149af39e29ca79959a8d0 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 12 Sep 2023 16:54:07 +0200 Subject: [PATCH 04/21] Avoid checking Expression.Binding signatures --- .../enso/compiler/codegen/IrToTruffle.scala | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index 48b9bb897fb9..3cb5cf10bb08 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -1014,15 +1014,18 @@ class IrToTruffle( } runtimeExpression.setTailStatus(getTailStatus(ir)) - val types = ir.getMetadata(TypeSignatures) - if (types.isDefined) { - val checkNode = extractAscribedType(null, types.get.signature); - if (checkNode != null) { - runtimeExpression = - ReadArgumentCheckNode.wrap(runtimeExpression, checkNode) - } + ir match { + case _: Expression.Binding => + case _ => + val types = ir.getMetadata(TypeSignatures) + if (types.isDefined) { + val checkNode = extractAscribedType(null, types.get.signature); + if (checkNode != null) { + runtimeExpression = + ReadArgumentCheckNode.wrap(runtimeExpression, checkNode) + } + } } - runtimeExpression } From a9424a964a0b15af6a54b86e844ad36d4a6c428b Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 12 Sep 2023 17:15:10 +0200 Subject: [PATCH 05/21] Note in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f117d9342f35..f689fab40b7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -947,6 +947,7 @@ projects next to each other][7634] - [Support runtime checks of intersection types][7769] - [Merge `Small_Integer` and `Big_Integer` types][7636] +- [Inline type ascriptions][7796] [3227]: https://github.com/enso-org/enso/pull/3227 [3248]: https://github.com/enso-org/enso/pull/3248 @@ -1086,6 +1087,7 @@ [7634]: https://github.com/enso-org/enso/pull/7634 [7769]: https://github.com/enso-org/enso/pull/7769 [7636]: https://github.com/enso-org/enso/pull/7636 +[7796]: https://github.com/enso-org/enso/pull/7796 # Enso 2.0.0-alpha.18 (2021-10-12) From 2bc7dd360ba53089db2f46ed85535993699edc4b Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 10:57:44 +0200 Subject: [PATCH 06/21] Methods of Any are dispatched for the whole EnsoMultiValue object --- .../callable/IndirectInvokeMethodNode.java | 3 ++- .../node/callable/InvokeConversionNode.java | 22 ++++++++++++++++++ .../node/callable/InvokeMethodNode.java | 13 ++++++----- .../callable/resolver/MethodResolverNode.java | 18 ++++++++++----- .../builtin/meta/GetAnnotationNode.java | 3 ++- .../runtime/callable/UnresolvedSymbol.java | 8 ++++--- .../runtime/data/EnsoMultiValue.java | 14 +++++++---- .../interpreter/test/DebuggingEnsoTest.java | 2 ++ test/Tests/src/Semantic/Conversion_Spec.enso | 23 +++++++++++++++++++ 9 files changed, 85 insertions(+), 21 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java index b7200fd46f25..f0ad4ea80dbc 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/IndirectInvokeMethodNode.java @@ -99,7 +99,8 @@ Object doDataflowError( @Shared("indirectInvokeFunctionNode") @Cached IndirectInvokeFunctionNode invokeFunctionNode, @Cached ConditionProfile profile) { Function function = - methodResolverNode.execute(EnsoContext.get(this).getBuiltins().dataflowError(), symbol); + methodResolverNode.executeResolution( + EnsoContext.get(this).getBuiltins().dataflowError(), symbol); if (profile.profile(function == null)) { return self; } else { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java index 55cc8241a166..56082732cba2 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeConversionNode.java @@ -12,6 +12,7 @@ import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.control.TailCallException; import org.enso.interpreter.runtime.data.ArrayRope; +import org.enso.interpreter.runtime.data.EnsoMultiValue; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.data.text.Text; import org.enso.interpreter.runtime.error.DataflowError; @@ -152,6 +153,27 @@ Object doPanicSentinel( throw that; } + @Specialization + Object doMultiValue( + VirtualFrame frame, + State state, + UnresolvedConversion conversion, + Object self, + EnsoMultiValue that, + Object[] arguments) { + var type = extractType(self); + var result = that.castTo(type); + if (result == null) { + throw new PanicException( + EnsoContext.get(this) + .getBuiltins() + .error() + .makeNoSuchConversion(type, self, conversion), + this); + } + return result; + } + @Specialization Object doWarning( VirtualFrame frame, diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java index d171e90fda8a..b274e947420e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java @@ -162,7 +162,7 @@ Object doFunctionalDispatchCachedSymbol( Function resolveFunction( UnresolvedSymbol symbol, Type selfTpe, MethodResolverNode methodResolverNode) { - Function function = methodResolverNode.execute(selfTpe, symbol); + Function function = methodResolverNode.executeResolution(selfTpe, symbol); if (function == null) { return null; } @@ -288,10 +288,11 @@ Object doMultiValue( var fnAndType = self.resolveSymbol(methodResolverNode, symbol); if (fnAndType != null) { var unwrapSelf = self.castTo(fnAndType.getRight()); - assert unwrapSelf != null; - assert arguments[0] == self; - arguments[0] = unwrapSelf; - return execute(frame, state, symbol, unwrapSelf, arguments); + if (unwrapSelf != null) { + assert arguments[0] == self; + arguments[0] = unwrapSelf; + } + return invokeFunctionNode.execute(fnAndType.getLeft(), frame, state, arguments); } throw methodNotFound(symbol, self); } @@ -305,7 +306,7 @@ Object doDataflowError( Object[] arguments, @Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) { Function function = - methodResolverNode.execute(EnsoContext.get(this).getBuiltins().dataflowError(), symbol); + methodResolverNode.executeResolution(EnsoContext.get(this).getBuiltins().dataflowError(), symbol); if (errorReceiverProfile.profile(function == null)) { return self; } else { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java index 3e8b4dde42bb..40536bcc6ee1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java @@ -11,6 +11,7 @@ import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.error.PanicException; +import org.graalvm.collections.Pair; @GenerateUncached @ReportPolymorphism @@ -22,15 +23,20 @@ EnsoContext getContext() { return EnsoContext.get(this); } - public abstract Function execute(Type type, UnresolvedSymbol symbol); + public abstract Pair execute(Type type, UnresolvedSymbol symbol); - public Function expectNonNull(Object self, Type type, UnresolvedSymbol symbol) { + public final Function executeResolution(Type type, UnresolvedSymbol symbol) { + var pair = execute(type, symbol); + return pair == null ? null : pair.getLeft(); + } + + public final Function expectNonNull(Object self, Type type, UnresolvedSymbol symbol) { var result = execute(type, symbol); if (result == null) { throw new PanicException( EnsoContext.get(this).getBuiltins().error().makeNoSuchMethod(self, symbol), this); } - return result; + return result.getLeft(); } @Specialization( @@ -40,17 +46,17 @@ public Function expectNonNull(Object self, Type type, UnresolvedSymbol symbol) { "cachedType == type" }, limit = "CACHE_SIZE") - Function resolveCached( + Pair resolveCached( Type type, UnresolvedSymbol symbol, @Cached("symbol") UnresolvedSymbol cachedSymbol, @Cached("type") Type cachedType, - @Cached("resolveUncached(cachedType, cachedSymbol)") Function function) { + @Cached("resolveUncached(cachedType, cachedSymbol)") Pair function) { return function; } @Specialization(replaces = "resolveCached") - Function resolveUncached(Type self, UnresolvedSymbol symbol) { + Pair resolveUncached(Type self, UnresolvedSymbol symbol) { return symbol.resolveFor(this, self); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java index da3ec5454fce..4c9f463f2219 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/GetAnnotationNode.java @@ -46,7 +46,8 @@ Object doExecute( if (targetTypeResult instanceof Type targetType) { Function methodFunction; if (method instanceof UnresolvedSymbol symbol) { - methodFunction = symbol.resolveFor(this, targetType); + var pair = symbol.resolveFor(this, targetType); + methodFunction = pair == null ? null : pair.getLeft(); } else { CompilerDirectives.transferToInterpreter(); var ctx = EnsoContext.get(this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java index 1788b413b236..10a7d35a28a8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java @@ -17,6 +17,7 @@ import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.scope.ModuleScope; +import org.graalvm.collections.Pair; /** Simple runtime value representing a yet-unresolved by-name symbol. */ @ExportLibrary(InteropLibrary.class) @@ -56,14 +57,15 @@ public ModuleScope getScope() { * is returned. This is useful for certain subtyping relations, such as "any constructor is a * subtype of Any" or "Nat is a subtype of Int, is a subtype of Number". * + * @param node the node that performs the query * @param type the type for which this symbol should be resolved - * @return the resolved function definition, or null if not found + * @return the resolved function definition and type it was resolved in, or null if not found */ - public Function resolveFor(Node node, Type type) { + public Pair resolveFor(Node node, Type type) { for (var current : type.allTypes(EnsoContext.get(node))) { Function candidate = scope.lookupMethodDefinition(current, name); if (candidate != null) { - return candidate; + return Pair.create(candidate, current); } } return null; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java index 94ddf41bdfed..ee42373b2222 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.stream.Collectors; import org.enso.interpreter.node.callable.resolver.MethodResolverNode; +import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.callable.UnresolvedSymbol; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @@ -82,12 +83,17 @@ public final Object castTo(Type type) { */ public final Pair resolveSymbol( MethodResolverNode node, UnresolvedSymbol symbol) { + var ctx = EnsoContext.get(node); + Pair foundAnyMethod = null; for (Type t : types) { - var fn = node.execute(t, symbol); - if (fn != null) { - return Pair.create(fn, t); + var fnAndType = node.execute(t, symbol); + if (fnAndType != null) { + if (fnAndType.getRight() != ctx.getBuiltins().any()) { + return Pair.create(fnAndType.getLeft(), t); + } + foundAnyMethod = fnAndType; } } - return null; + return foundAnyMethod; } } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java index bd7be358f515..39356a709bde 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/DebuggingEnsoTest.java @@ -108,6 +108,8 @@ private static Source createEnsoSource(String srcCode) { } private Value createEnsoMethod(String source, String methodName) { + Value m = context.eval(createEnsoSource("from Standard.Base import all\n\n" + methodName + " = 10")); + m.invokeMember(Module.EVAL_EXPRESSION, methodName); Value module = context.eval(createEnsoSource(source)); return module.invokeMember(Module.EVAL_EXPRESSION, methodName); } diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index 6a7aee345687..8638dca16c28 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -55,6 +55,16 @@ foreign js call_function fn arg_1 = """ Number.foo self = "foo called" +from Standard.Base import all + +type Fool + Value fool + + to_text : Text + to_text self = "{FOOL " + self.fool.to_text + "}" + +Fool.from (that : Integer) = Fool.Value that + spec = Test.group "Conversion" <| Test.specify "should be able to convert atoms" <| @@ -202,6 +212,19 @@ spec = to_6 (v : Number & Decimal & Integer) = v to_6 m . should_equal 1.5 + Test.specify "Requesting Integer & Fool" <| + do_stuff (x : Integer & Fool) = + x.foo . should_equal "foo called" + x.fool . should_equal 42 + x==x . should_be_true + (x:Integer)==42 . should_be_true + 42==(x.to Integer) . should_be_true + 100+(x:Integer) . should_equal 142 + x.to_text . should_equal "{FOOL 42}" + (x:Fool).to_text . should_equal "{FOOL 42}" + (x:Integer).to_text . should_equal "42" + + do_stuff 42 Hello.from (that:Foo) suffix=" " = Hello.Say <| (that.foo.to_case Case.Upper) + suffix Hello.from (that:Bar) suffix="!" = Hello.Say <| (that.bar.to_case Case.Lower) + suffix From caf4427a2ebc1b31a6d911fc77333acc98562ee8 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 13:01:20 +0200 Subject: [PATCH 07/21] Support == for TruffleObjects wrapping numbers --- .../expression/builtin/meta/EqualsNode.java | 130 +++++++++++-- .../org/enso/interpreter/test/EqualsTest.java | 176 ++++++++++++++++++ 2 files changed, 292 insertions(+), 14 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java index 4dc5c7ac3686..bd18ad4bcd64 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java @@ -1,26 +1,29 @@ package org.enso.interpreter.node.expression.builtin.meta; -import com.ibm.icu.text.Normalizer; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.GenerateUncached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.nodes.Node; import java.math.BigInteger; + import org.enso.interpreter.dsl.AcceptsError; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.callable.atom.Atom; import org.enso.interpreter.runtime.callable.atom.AtomConstructor; +import org.enso.interpreter.runtime.data.EnsoMultiValue; import org.enso.interpreter.runtime.data.text.Text; import org.enso.interpreter.runtime.error.WarningsLibrary; import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.polyglot.common_utils.Core_Text_Utils; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; + @BuiltinMethod( type = "Any", name = "==", @@ -72,6 +75,18 @@ boolean equalsBoolText(boolean self, Text other) { return false; } + @Specialization(guards="interop.isBoolean(other)") + boolean equalsBoolInterop( + boolean self, Object other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop + ) { + try { + return self == interop.asBoolean(other); + } catch (UnsupportedMessageException ex) { + return false; + } + } + @Specialization boolean equalsLongLong(long self, long other) { return self == other; @@ -92,6 +107,18 @@ boolean equalsLongText(long self, Text other) { return false; } + @Specialization(guards="interop.fitsInLong(other)") + boolean equalsLongInterop( + long self, Object other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop + ) { + try { + return self == interop.asLong(other); + } catch (UnsupportedMessageException ex) { + return false; + } + } + @Specialization boolean equalsDoubleDouble(double self, double other) { if (Double.isNaN(self) || Double.isNaN(other)) { @@ -117,6 +144,18 @@ boolean equalsDoubleBigInt(double self, EnsoBigInteger other) { return self == other.asDouble(); } + @Specialization(guards="interop.fitsInDouble(other)") + boolean equalsDoubleInterop( + double self, Object other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop + ) { + try { + return self == interop.asDouble(other); + } catch (UnsupportedMessageException ex) { + return false; + } + } + @Specialization boolean equalsDoubleText(double self, Text other) { return false; @@ -154,6 +193,23 @@ boolean equalsBigIntText(EnsoBigInteger self, Text other) { return false; } + @TruffleBoundary + @Specialization(guards={ + "!isPrimitiveValue(other)", + "interop.fitsInBigInteger(other)" + }) + boolean equalsBigIntInterop( + EnsoBigInteger self, Object other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop + ) { + try { + var otherBigInteger = InteropLibrary.getUncached().asBigInteger(other); + return self.asBigInteger().equals(otherBigInteger); + } catch (UnsupportedMessageException ex) { + return false; + } + } + @Specialization @TruffleBoundary boolean equalsLongBigInt(long self, EnsoBigInteger other) { @@ -236,6 +292,43 @@ boolean equalsAtoms( return isSameObjectNode.execute(self, other) || equalsAtomNode.execute(self, other); } + + @Specialization + boolean equalsReverseBoolean( + TruffleObject self, boolean other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop, + @Shared("reverse") @Cached EqualsNode reverse + ) { + return reverse.execute(other, self); + } + + @Specialization + boolean equalsReverseLong( + TruffleObject self, long other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop, + @Shared("reverse") @Cached EqualsNode reverse + ) { + return reverse.execute(other, self); + } + + @Specialization + boolean equalsReverseDouble( + TruffleObject self, double other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop, + @Shared("reverse") @Cached EqualsNode reverse + ) { + return reverse.execute(other, self); + } + + @Specialization + boolean equalsReverseBigInt( + TruffleObject self, EnsoBigInteger other, + @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop, + @Shared("reverse") @Cached EqualsNode reverse + ) { + return reverse.execute(other, self); + } + @Specialization(guards = "isNotPrimitive(self, other, interop, warnings)") boolean equalsComplex( Object self, @@ -258,6 +351,9 @@ static boolean isNotPrimitive( if (warnings.hasWarnings(a) || warnings.hasWarnings(b)) { return true; } + if (a instanceof EnsoMultiValue || b instanceof EnsoMultiValue) { + return true; + } return !isPrimitive(a, interop) && !isPrimitive(b, interop); } @@ -269,11 +365,17 @@ static boolean isNotPrimitive( * org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode}. */ static boolean isPrimitive(Object object, InteropLibrary interop) { - return object instanceof Boolean - || object instanceof Long - || object instanceof Double + return isPrimitiveValue(object) || object instanceof EnsoBigInteger || object instanceof Text - || interop.isString(object); + || interop.isString(object) + || interop.isNumber(object) + || interop.isBoolean(object); + } + + static boolean isPrimitiveValue(Object object) { + return object instanceof Boolean + || object instanceof Long + || object instanceof Double; } } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java index 18d3af3ecf9c..c50935864409 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java @@ -3,6 +3,12 @@ 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.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import java.math.BigInteger; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; @@ -111,6 +117,9 @@ public void equalsNodeCachedIsConsistentWithUncached(Object firstVal, Object sec () -> { Object uncachedRes = EqualsNodeGen.getUncached().execute(firstVal, secondVal); Object cachedRes = equalsNode.execute(firstVal, secondVal); + if (uncachedRes != cachedRes) { + Thread.dumpStack(); + } assertEquals( "Result from uncached EqualsNode should be the same as result from its cached variant", uncachedRes, @@ -189,4 +198,171 @@ public void testVectorsEquality() { return null; }); } + + @ExportLibrary(InteropLibrary.class) + static final class WrappedPrimitive implements TruffleObject { + private final Object value; + + WrappedPrimitive(long value) { + this.value = value; + } + + WrappedPrimitive(boolean value) { + this.value = value; + } + + WrappedPrimitive(double value) { + this.value = value; + } + + WrappedPrimitive(BigInteger value) { + this.value = value; + } + + @ExportMessage + boolean isNumber() { + return value instanceof Number; + } + + @ExportMessage + boolean isBoolean() { + return value instanceof Boolean; + } + + @ExportMessage + boolean asBoolean() { + return (Boolean) value; + } + + @ExportMessage + boolean fitsInByte() { + return false; + } + + @ExportMessage + boolean fitsInShort() { + return false; + } + + @ExportMessage + boolean fitsInInt() { + return false; + } + + @ExportMessage + boolean fitsInLong() { + return value instanceof Long; + } + + @ExportMessage + boolean fitsInFloat() { + return false; + } + + @ExportMessage + boolean fitsInDouble() { + return value instanceof Double; + } + + @ExportMessage + byte asByte() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + short asShort() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + int asInt() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + long asLong() throws UnsupportedMessageException { + return (Long) value; + } + + @ExportMessage + float asFloat() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + double asDouble() throws UnsupportedMessageException { + return (Double) value; + } + + @ExportMessage + boolean fitsInBigInteger() { + return value instanceof BigInteger; + } + + @ExportMessage + BigInteger asBigInteger() throws UnsupportedMessageException { + return (BigInteger) value; + } + + Object asDirect() { + return value; + } + } + + @Test + public void testTruffleNumberLong() { + var ensoNumber = unwrapValue(context, createValue(context, "1", "")); + var foreignNumber = new WrappedPrimitive(1); + executeInContext( + context, + () -> { + assertTrue(equalsNode.execute(ensoNumber, foreignNumber.asDirect())); + assertTrue(equalsNode.execute(ensoNumber, foreignNumber)); + assertTrue(equalsNode.execute(foreignNumber, ensoNumber)); + return null; + }); + } + + @Test + public void testTruffleNumberDouble() { + var ensoNumber = unwrapValue(context, createValue(context, "1.0", "")); + var foreignNumber = new WrappedPrimitive(1.0); + executeInContext( + context, + () -> { + assertTrue(equalsNode.execute(ensoNumber, foreignNumber.asDirect())); + assertTrue(equalsNode.execute(ensoNumber, foreignNumber)); + assertTrue(equalsNode.execute(foreignNumber, ensoNumber)); + return null; + }); + } + + @Test + public void testTruffleNumberBigInt() { + var value = new BigInteger("43207431473298432194374819743291479009431478329"); + var ensoNumber = unwrapValue(context, createValue(context, value.toString(), "")); + var foreignNumber = new WrappedPrimitive(value); + executeInContext( + context, + () -> { + assertTrue(equalsNode.execute(ensoNumber, foreignNumber)); + assertTrue(equalsNode.execute(foreignNumber, ensoNumber)); + return null; + }); + } + + @Test + public void testTruffleBoolean() { + var ensoBoolean = + unwrapValue(context, createValue(context, "True", "from Standard.Base import True")); + var foreignBoolean = new WrappedPrimitive(true); + executeInContext( + context, + () -> { + assertTrue(equalsNode.execute(ensoBoolean, foreignBoolean.asDirect())); + assertTrue(equalsNode.execute(ensoBoolean, foreignBoolean)); + assertTrue(equalsNode.execute(foreignBoolean, ensoBoolean)); + return null; + }); + } } From 97fc8ef0456b12d5c3dad3006b1ba7f01797c42c Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 13:02:13 +0200 Subject: [PATCH 08/21] Number interop for multi values --- .../runtime/data/EnsoMultiValue.java | 162 ++++++++++++++++++ test/Tests/src/Semantic/Conversion_Spec.enso | 6 + 2 files changed, 168 insertions(+) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java index ee42373b2222..09ad5e8306ae 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java @@ -2,9 +2,13 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; +import java.math.BigInteger; import java.util.Arrays; import java.util.stream.Collectors; import org.enso.interpreter.node.callable.resolver.MethodResolverNode; @@ -17,6 +21,7 @@ @ExportLibrary(TypesLibrary.class) @ExportLibrary(InteropLibrary.class) public final class EnsoMultiValue implements EnsoObject { + @CompilationFinal(dimensions = 1) private final Type[] types; @@ -53,6 +58,163 @@ String toDisplayString(boolean ignore) { return toString(); } + @ExportMessage + boolean isNumber(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isNumber(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean fitsInByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInByte(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean fitsInShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInShort(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean fitsInInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInShort(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean fitsInLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInLong(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean fitsInFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInFloat(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean fitsInDouble(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInDouble(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + byte asByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInByte(values[i])) { + return iop.asByte(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + short asShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInShort(values[i])) { + return iop.asShort(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + int asInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInInt(values[i])) { + return iop.asInt(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + long asLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInLong(values[i])) { + return iop.asLong(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + float asFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInFloat(values[i])) { + return iop.asFloat(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + double asDouble(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInDouble(values[i])) { + return iop.asDouble(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + boolean fitsInBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInBigInteger(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + BigInteger asBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.fitsInBigInteger(values[i])) { + return iop.asBigInteger(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + @TruffleBoundary @Override public String toString() { diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index 8638dca16c28..eeab7ef3eebd 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -218,8 +218,14 @@ spec = x.fool . should_equal 42 x==x . should_be_true (x:Integer)==42 . should_be_true + (x:Fool)==42 . should_be_false + x==42 . should_be_true 42==(x.to Integer) . should_be_true + 42==(x.to Fool) . should_be_false + 42==x . should_be_true 100+(x:Integer) . should_equal 142 + (x:Integer)+100 . should_equal 142 + x+100 . should_equal 142 x.to_text . should_equal "{FOOL 42}" (x:Fool).to_text . should_equal "{FOOL 42}" (x:Integer).to_text . should_equal "42" From 824ea0a477d4d6af10a73162a4c07f4915a39318 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 13:23:15 +0200 Subject: [PATCH 09/21] Supporting boolean interop for multi values --- .../runtime/data/EnsoMultiValue.java | 21 ++++++++++++++++++ project/DistributionPackage.scala | 2 +- test/Tests/src/Semantic/Conversion_Spec.enso | 22 +++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java index 09ad5e8306ae..40eaed99ddc1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java @@ -58,6 +58,27 @@ String toDisplayString(boolean ignore) { return toString(); } + @ExportMessage + boolean isBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isBoolean(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + boolean asBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.isBoolean(values[i])) { + return iop.asBoolean(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + @ExportMessage boolean isNumber(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { for (var i = 0; i < values.length; i++) { diff --git a/project/DistributionPackage.scala b/project/DistributionPackage.scala index 3d00e4e8752d..25778ff686bf 100644 --- a/project/DistributionPackage.scala +++ b/project/DistributionPackage.scala @@ -246,7 +246,7 @@ object DistributionPackage { throw new RuntimeException(s"Cannot compile $libMajor.$libName.") } } else { - log.info(s"No modified files. Not generating index for ${libName} ") + log.debug(s"No modified files. Not generating index for ${libName}.") } } } diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index eeab7ef3eebd..c0935db4aab4 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -64,6 +64,7 @@ type Fool to_text self = "{FOOL " + self.fool.to_text + "}" Fool.from (that : Integer) = Fool.Value that +Fool.from (that : Boolean) = Fool.Value that spec = Test.group "Conversion" <| @@ -213,7 +214,7 @@ spec = to_6 m . should_equal 1.5 Test.specify "Requesting Integer & Fool" <| - do_stuff (x : Integer & Fool) = + do_number (x : Integer & Fool) = x.foo . should_equal "foo called" x.fool . should_equal 42 x==x . should_be_true @@ -230,7 +231,24 @@ spec = (x:Fool).to_text . should_equal "{FOOL 42}" (x:Integer).to_text . should_equal "42" - do_stuff 42 + do_number 42 + + Test.specify "Requesting Boolean & Fool" <| + do_boolean (x : Boolean & Fool) = + x.fool . should_equal True + x==x . should_be_true + (x:Boolean) . should_be_true + (x:Fool)==True . should_be_false + x==True . should_be_true + True==(x:Boolean) . should_be_true + True==(x:Fool) . should_be_false + True==x . should_be_true + x.to_text . should_equal "{FOOL True}" + (x:Fool).to_text . should_equal "{FOOL True}" + (x:Boolean).to_text . should_equal "True" + Panic.recover Any (x:Integer).to_text . should_fail_with Type_Error + + do_boolean True Hello.from (that:Foo) suffix=" " = Hello.Say <| (that.foo.to_case Case.Upper) + suffix Hello.from (that:Bar) suffix="!" = Hello.Say <| (that.bar.to_case Case.Lower) + suffix From e415c91f27cdb3300b03770c11f82b7123e4451d Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 13:33:04 +0200 Subject: [PATCH 10/21] Supporting string interop for multi values --- .../runtime/data/EnsoMultiValue.java | 21 ++++++++++++++ .../org/enso/interpreter/test/EqualsTest.java | 28 +++++++++++++++++++ test/Tests/src/Semantic/Conversion_Spec.enso | 20 +++++++++++-- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java index 40eaed99ddc1..789172a52002 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java @@ -79,6 +79,27 @@ boolean asBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary throw UnsupportedMessageException.create(); } + @ExportMessage + boolean isString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isString(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + String asString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.isString(values[i])) { + return iop.asString(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + @ExportMessage boolean isNumber(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { for (var i = 0; i < values.length; i++) { diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java index c50935864409..00af526916ee 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java @@ -219,6 +219,20 @@ static final class WrappedPrimitive implements TruffleObject { this.value = value; } + WrappedPrimitive(String value) { + this.value = value; + } + + @ExportMessage + boolean isString() { + return value instanceof String; + } + + @ExportMessage + String asString() { + return (String) value; + } + @ExportMessage boolean isNumber() { return value instanceof Number; @@ -365,4 +379,18 @@ public void testTruffleBoolean() { return null; }); } + + @Test + public void testTruffleString() { + var ensoText = unwrapValue(context, createValue(context, "'Hello'", "")); + var foreignString = new WrappedPrimitive("Hello"); + executeInContext( + context, + () -> { + assertTrue(equalsNode.execute(ensoText, foreignString.asDirect())); + assertTrue(equalsNode.execute(ensoText, foreignString)); + assertTrue(equalsNode.execute(foreignString, ensoText)); + return null; + }); + } } diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index c0935db4aab4..0aab8598fe1a 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -63,8 +63,7 @@ type Fool to_text : Text to_text self = "{FOOL " + self.fool.to_text + "}" -Fool.from (that : Integer) = Fool.Value that -Fool.from (that : Boolean) = Fool.Value that +Fool.from (that : Any) = Fool.Value that spec = Test.group "Conversion" <| @@ -250,6 +249,23 @@ spec = do_boolean True + Test.specify "Requesting Text & Fool" <| + do_text (x : Text & Fool) = + x.fool . should_equal "Hello" + x==x . should_be_true + (x:Text)=="Hello" . should_be_true + (x:Fool)=="Hello" . should_be_false + x=="Hello" . should_be_true + "Hello"==(x:Text) . should_be_true + "Hello"==(x:Fool) . should_be_false + "Hello"==x . should_be_true + x.to_text . should_equal "Hello" + (x:Fool).to_text . should_equal "{FOOL Hello}" + (x:Text).to_text . should_equal "Hello" + Panic.recover Any (x:Boolean).to_text . should_fail_with Type_Error + + do_text "Hello" + Hello.from (that:Foo) suffix=" " = Hello.Say <| (that.foo.to_case Case.Upper) + suffix Hello.from (that:Bar) suffix="!" = Hello.Say <| (that.bar.to_case Case.Lower) + suffix From 340d76dafce018576141557ea894c02a3b92cbfb Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 13:53:49 +0200 Subject: [PATCH 11/21] Supporting date and time interop for multi values --- .../runtime/data/EnsoMultiValue.java | 94 ++++++++++++++++++- test/Tests/src/Semantic/Conversion_Spec.enso | 64 +++++++++++++ 2 files changed, 155 insertions(+), 3 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java index 789172a52002..787b48f1c3cf 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoMultiValue.java @@ -9,6 +9,10 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import java.math.BigInteger; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; import java.util.Arrays; import java.util.stream.Collectors; import org.enso.interpreter.node.callable.resolver.MethodResolverNode; @@ -92,9 +96,9 @@ boolean isString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary @ExportMessage String asString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) throws UnsupportedMessageException { - for (var i = 0; i < values.length; i++) { - if (iop.isString(values[i])) { - return iop.asString(values[i]); + for (Object value : values) { + if (iop.isString(value)) { + return iop.asString(value); } } throw UnsupportedMessageException.create(); @@ -257,6 +261,90 @@ BigInteger asBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropL throw UnsupportedMessageException.create(); } + @ExportMessage + boolean isTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isTime(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + LocalTime asTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.isTime(values[i])) { + return iop.asTime(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + boolean isDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isDate(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + LocalDate asDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.isDate(values[i])) { + return iop.asDate(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + boolean isTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isTimeZone(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + ZoneId asTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.isTimeZone(values[i])) { + return iop.asTimeZone(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + + @ExportMessage + boolean isDuration(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) { + for (var i = 0; i < values.length; i++) { + if (iop.isDuration(values[i])) { + return true; + } + } + return false; + } + + @ExportMessage + Duration asDuration(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) + throws UnsupportedMessageException { + for (var i = 0; i < values.length; i++) { + if (iop.isDuration(values[i])) { + return iop.asDuration(values[i]); + } + } + throw UnsupportedMessageException.create(); + } + @TruffleBoundary @Override public String toString() { diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index 0aab8598fe1a..7a679dc18d7e 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -266,6 +266,70 @@ spec = do_text "Hello" + Test.specify "Requesting Time_Of_Day & Fool" <| + now = Time_Of_Day.now + + do_time (x : Time_Of_Day & Fool) = + x.fool . should_equal now + x==x . should_be_true + (x:Time_Of_Day)==now . should_be_true + (x:Fool)==now . should_be_false + x==now . should_be_true + now==(x:Time_Of_Day) . should_be_true + now==(x:Fool) . should_be_false + now==x . should_be_true + x.to_text . should_equal now.to_text + + do_time now + + Test.specify "Requesting Date & Fool" <| + now = Date.today + + do_date (x : Date & Fool) = + x.fool . should_equal now + x==x . should_be_true + (x:Date)==now . should_be_true + (x:Fool)==now . should_be_false + x==now . should_be_true + now==(x:Date) . should_be_true + now==(x:Fool) . should_be_false + now==x . should_be_true + x.to_text . should_equal "{FOOL "+now.to_text+"}" + + do_date now + + Test.specify "Requesting Date_Time & Fool" <| + now = Date_Time.now + + do_time (x : Date_Time & Fool) = + x.fool . should_equal now + x==x . should_be_true + (x:Date_Time)==now . should_be_true + (x:Fool)==now . should_be_false + x==now . should_be_true + now==(x:Date_Time) . should_be_true + now==(x:Fool) . should_be_false + now==x . should_be_true + x.to_text . should_equal now.to_text + + do_time now + + Test.specify "Requesting Duration & Fool" <| + now = Duration.new hours=5 + + do_duration (x : Duration & Fool) = + x.fool . should_equal now + x==x . should_be_true + (x:Duration)==now . should_be_true + (x:Fool)==now . should_be_false + x==now . should_be_true + now==(x:Duration) . should_be_true + now==(x:Fool) . should_be_false + now==x . should_be_true + x.to_text . should_equal "{FOOL "+now.to_text+"}" + + do_duration now + Hello.from (that:Foo) suffix=" " = Hello.Say <| (that.foo.to_case Case.Upper) + suffix Hello.from (that:Bar) suffix="!" = Hello.Say <| (that.bar.to_case Case.Lower) + suffix From dad0fb1348fae7659c86298ef9aee136d5d4711b Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 15:48:02 +0200 Subject: [PATCH 12/21] Making integer AddNode work with foreign numbers --- .../builtin/number/integer/AddNode.java | 26 +++++++++++++++++++ .../builtin/number/integer/IntegerUtils.java | 10 +++++++ .../org/enso/interpreter/test/EqualsTest.java | 22 +++++++++++++--- test/Tests/src/Semantic/Conversion_Spec.enso | 1 + 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java index cfc2216e48ee..1bb46c525570 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java @@ -1,8 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.integer; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; @@ -10,6 +16,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "+", description = "Addition of numbers.") +@ImportStatic(IntegerUtils.class) public abstract class AddNode extends Node { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); @@ -55,6 +62,25 @@ Object doBigIntegerLong(EnsoBigInteger self, long that) { return self.asDouble() + that; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached AddNode delegate) { + try { + if (iop.fitsInLong(that)) { + return delegate.execute(self, iop.asLong(that)); + } else if (iop.fitsInDouble(that)) { + return delegate.execute(self, iop.asDouble(that)); + } else if (iop.fitsInBigInteger(that)) { + return delegate.execute(self, new EnsoBigInteger(iop.asBigInteger(that))); + } + } catch (UnsupportedMessageException ex) { + } + return doOther(self, that); + } + @Fallback Object doOther(Object self, Object that) { throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java index 5f62263a2f24..bef79a080117 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java @@ -1,10 +1,13 @@ package org.enso.interpreter.node.expression.builtin.number.integer; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; +import org.enso.interpreter.runtime.number.EnsoBigInteger; public final class IntegerUtils { private IntegerUtils() {} @@ -27,4 +30,11 @@ static PanicException throwTypeErrorIfNotInt(Object self, Node node) { var intType = builtins.number().getInteger(); return new PanicException(builtins.error().makeTypeError(intType, self, "self"), node); } + + static boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) { + if (obj instanceof EnsoBigInteger) { + return false; + } + return iop.isNumber(obj); + } } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java index 00af526916ee..b7b8ebc82831 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java @@ -8,6 +8,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; + import java.math.BigInteger; import java.time.LocalDate; import java.time.LocalTime; @@ -16,9 +17,11 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; + import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; import org.enso.interpreter.node.expression.builtin.meta.EqualsNode; import org.enso.interpreter.node.expression.builtin.meta.EqualsNodeGen; +import org.enso.polyglot.MethodNames; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; import org.junit.AfterClass; @@ -117,9 +120,6 @@ public void equalsNodeCachedIsConsistentWithUncached(Object firstVal, Object sec () -> { Object uncachedRes = EqualsNodeGen.getUncached().execute(firstVal, secondVal); Object cachedRes = equalsNode.execute(firstVal, secondVal); - if (uncachedRes != cachedRes) { - Thread.dumpStack(); - } assertEquals( "Result from uncached EqualsNode should be the same as result from its cached variant", uncachedRes, @@ -393,4 +393,20 @@ public void testTruffleString() { return null; }); } + + @Test + public void testTruffleNumberPlus() { + var plus100 = context.eval("enso", """ + plus100 x = 100+x + """).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "plus100"); + assertTrue("plus100 can be executed", plus100.canExecute()); + var foreignNumber = context.asValue(new WrappedPrimitive(42)); + var hundred42 = unwrapValue(context, plus100.execute(foreignNumber)); + executeInContext(context, + () -> { + assertTrue(equalsNode.execute(142L, hundred42)); + assertTrue(equalsNode.execute(hundred42, 142L)); + return null; + }); + } } diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index 7a679dc18d7e..35f36848651e 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -226,6 +226,7 @@ spec = 100+(x:Integer) . should_equal 142 (x:Integer)+100 . should_equal 142 x+100 . should_equal 142 + 100+x . should_equal 142 x.to_text . should_equal "{FOOL 42}" (x:Fool).to_text . should_equal "{FOOL 42}" (x:Integer).to_text . should_equal "42" From cc4ff63ce51a0f47fe73f0ea414b3b2a2a3666f7 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 18:46:20 +0200 Subject: [PATCH 13/21] Make all integer nodes extend common superclass --- .../builtin/number/integer/AbsNode.java | 6 ++-- .../builtin/number/integer/AddNode.java | 17 +++++------ .../builtin/number/integer/BitAndNode.java | 6 ++-- .../builtin/number/integer/BitNotNode.java | 6 ++-- .../builtin/number/integer/BitOrNode.java | 6 ++-- .../builtin/number/integer/BitShiftNode.java | 6 ++-- .../number/integer/BitShiftRightNode.java | 6 ++-- .../builtin/number/integer/BitXorNode.java | 6 ++-- .../builtin/number/integer/CeilNode.java | 6 ++-- .../builtin/number/integer/DivNode.java | 6 ++-- .../builtin/number/integer/DivideNode.java | 6 ++-- .../builtin/number/integer/FloorNode.java | 6 ++-- .../builtin/number/integer/GreaterNode.java | 4 +-- .../number/integer/GreaterOrEqualNode.java | 4 +-- .../{IntegerUtils.java => IntegerNode.java} | 29 ++++++++++--------- .../builtin/number/integer/LessNode.java | 4 +-- .../number/integer/LessOrEqualNode.java | 4 +-- .../builtin/number/integer/ModNode.java | 6 ++-- .../builtin/number/integer/MultiplyNode.java | 6 ++-- .../builtin/number/integer/NegateNode.java | 6 ++-- .../number/integer/ParseIntegerNode.java | 10 ++++--- .../builtin/number/integer/PowNode.java | 9 ++++-- .../builtin/number/integer/RoundNode.java | 4 +-- .../builtin/number/integer/SubtractNode.java | 8 +++-- .../builtin/number/integer/ToDecimalNode.java | 6 ++-- 25 files changed, 95 insertions(+), 88 deletions(-) rename engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/{IntegerUtils.java => IntegerNode.java} (68%) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java index ec401fe535e4..c999cef472c0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java @@ -2,14 +2,14 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "abs", description = "Absolute value of a number") -public abstract class AbsNode extends Node { +public abstract class AbsNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); public static AbsNode build() { @@ -39,6 +39,6 @@ Object doBigInt(EnsoBigInteger self) { @Fallback Object doOther(Object self) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, this); + throw throwTypeErrorIfNotInt(self, this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java index 1bb46c525570..d7db82bdc4b5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java @@ -1,23 +1,22 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; +import org.enso.interpreter.runtime.number.EnsoBigInteger; + import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.nodes.Node; -import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; -import org.enso.interpreter.runtime.number.EnsoBigInteger; +import com.oracle.truffle.api.nodes.Node.Child; @BuiltinMethod(type = "Integer", name = "+", description = "Addition of numbers.") -@ImportStatic(IntegerUtils.class) -public abstract class AddNode extends Node { +public abstract class AddNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); public abstract Object execute(Object self, Object that); @@ -83,6 +82,6 @@ Object doInterop( @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java index 37ac2f3d3bda..01afe9fe7ed4 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java @@ -2,14 +2,14 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_and", description = "Bitwise and.") -public abstract class BitAndNode extends Node { +public abstract class BitAndNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); public abstract Object execute(Object self, Object that); @@ -40,6 +40,6 @@ Object doBigIntBigInt(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java index 258dc36bb216..b8ac1222cf87 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java @@ -3,12 +3,12 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_not", description = "Bitwise negation.") -public abstract class BitNotNode extends Node { +public abstract class BitNotNode extends IntegerNode { abstract Object execute(Object self); static BitNotNode build() { @@ -28,6 +28,6 @@ EnsoBigInteger doBigInteger(EnsoBigInteger self) { @Fallback Object doOther(Object self) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, this); + throw throwTypeErrorIfNotInt(self, this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java index 7c999b759983..fa738b2def9f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java @@ -2,14 +2,14 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_or", description = "Bitwise or.") -public abstract class BitOrNode extends Node { +public abstract class BitOrNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -40,6 +40,6 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java index 73cc0ef31b15..6d97f7bbec0d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java @@ -6,7 +6,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.profiles.CountingConditionProfile; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; @@ -17,7 +17,7 @@ @ImportStatic(BigIntegerOps.class) @BuiltinMethod(type = "Integer", name = "bit_shift", description = "Bitwise shift.") -public abstract class BitShiftNode extends Node { +public abstract class BitShiftNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); private final CountingConditionProfile canShiftLeftInLongProfile = CountingConditionProfile.create(); @@ -126,7 +126,7 @@ Object doBigIntThat(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } boolean hasFreeBitsLeftShift(long number, long shift) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java index 45f0af05babe..14b0f202bfe9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java @@ -4,13 +4,13 @@ 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.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_shift_r", description = "Bitwise right-shift.") -public abstract class BitShiftRightNode extends Node { +public abstract class BitShiftRightNode extends IntegerNode { abstract Object execute(Object self, Object that); static BitShiftRightNode build() { @@ -49,6 +49,6 @@ Object doBigInteger( @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java index ac250da2a760..151c572880cb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java @@ -2,14 +2,14 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_xor", description = "Bitwise exclusive or.") -public abstract class BitXorNode extends Node { +public abstract class BitXorNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -40,6 +40,6 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java index 9c08abf178e5..cfd0ab6af420 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java @@ -2,12 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "ceil", description = "Small integer ceiling.") -public abstract class CeilNode extends Node { +public abstract class CeilNode extends IntegerNode { abstract Object execute(Object self); public static CeilNode build() { @@ -26,6 +26,6 @@ EnsoBigInteger doBigInt(EnsoBigInteger self) { @Fallback Object doOther(Object self) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, this); + throw throwTypeErrorIfNotInt(self, this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java index 4bc02366fe2e..35360c9d6b89 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java @@ -2,7 +2,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; @@ -11,7 +11,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "div", description = "Division of numbers.") -public abstract class DivNode extends Node { +public abstract class DivNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); @@ -55,6 +55,6 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java index 764275477588..f449f532a067 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java @@ -2,13 +2,13 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "/", description = "Division of numbers.") -public abstract class DivideNode extends Node { +public abstract class DivideNode extends IntegerNode { abstract double execute(Object self, Object that); static DivideNode build() { @@ -47,6 +47,6 @@ static DivideNode build() { @Fallback double doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java index 7e7578b826b5..6c7ad5012bea 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java @@ -2,12 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "floor", description = "Small integer floor.") -public abstract class FloorNode extends Node { +public abstract class FloorNode extends IntegerNode { public abstract Object execute(Object self); @@ -27,6 +27,6 @@ EnsoBigInteger doBigInt(EnsoBigInteger self) { @Fallback Object doOther(Object self) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, this); + throw throwTypeErrorIfNotInt(self, this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java index d07eb62eb644..4fafb7060b0e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java @@ -2,7 +2,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -10,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = ">", description = "Comparison of numbers.") -public abstract class GreaterNode extends Node { +public abstract class GreaterNode extends IntegerNode { abstract Object execute(Object self, Object that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java index 89f086a9d131..2240179c16a9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java @@ -2,7 +2,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -10,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = ">=", description = "Comparison of numbers.") -public abstract class GreaterOrEqualNode extends Node { +public abstract class GreaterOrEqualNode extends IntegerNode { abstract Object execute(Object self, Object that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java similarity index 68% rename from engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java rename to engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java index bef79a080117..3f1ab586b7cf 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerUtils.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java @@ -1,37 +1,38 @@ package org.enso.interpreter.node.expression.builtin.number.integer; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; import org.enso.interpreter.runtime.number.EnsoBigInteger; -public final class IntegerUtils { - private IntegerUtils() {} +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; + +abstract class IntegerNode extends Node { + IntegerNode() {} @TruffleBoundary - static PanicException throwTypeErrorIfNotInt(Object self, Object that, Node node) { - var builtins = EnsoContext.get(node).getBuiltins(); + final PanicException throwTypeErrorIfNotInt(Object self, Object that) { + var builtins = EnsoContext.get(this).getBuiltins(); var intType = builtins.number().getInteger(); var selfType = TypesLibrary.getUncached().getType(self); if (selfType != intType) { - return new PanicException(builtins.error().makeTypeError(intType, self, "self"), node); + return new PanicException(builtins.error().makeTypeError(intType, self, "self"), this); } else { - return new PanicException(builtins.error().makeTypeError(intType, that, "that"), node); + return new PanicException(builtins.error().makeTypeError(intType, that, "that"), this); } } @TruffleBoundary - static PanicException throwTypeErrorIfNotInt(Object self, Node node) { - var builtins = EnsoContext.get(node).getBuiltins(); + final PanicException throwTypeErrorIfNotInt(Object self) { + var builtins = EnsoContext.get(this).getBuiltins(); var intType = builtins.number().getInteger(); - return new PanicException(builtins.error().makeTypeError(intType, self, "self"), node); + return new PanicException(builtins.error().makeTypeError(intType, self, "self"), this); } - static boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) { + final boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) { if (obj instanceof EnsoBigInteger) { return false; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java index 9947cb931c53..3bc1e78cc6e6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java @@ -2,7 +2,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -10,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "<", description = "Comparison of numbers.") -public abstract class LessNode extends Node { +public abstract class LessNode extends IntegerNode { abstract Object execute(Object self, Object that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java index f4c225c1c8f2..71c29648f70b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java @@ -2,7 +2,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -10,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "<=", description = "Comparison of numbers.") -public abstract class LessOrEqualNode extends Node { +public abstract class LessOrEqualNode extends IntegerNode { abstract Object execute(Object self, Object that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java index 7f4442520a9f..40f262656434 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java @@ -3,7 +3,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import java.math.BigInteger; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; @@ -13,7 +13,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "%", description = "Modulo division of numbers.") -public abstract class ModNode extends Node { +public abstract class ModNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -80,6 +80,6 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java index 3a9b1bb24784..38afd2f81158 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java @@ -2,14 +2,14 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "*", description = "Multiplication of numbers.") -public abstract class MultiplyNode extends Node { +public abstract class MultiplyNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -55,6 +55,6 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java index bad75b2e7a26..2c5de8f356c2 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java @@ -2,14 +2,14 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "negate", description = "Negation for numbers.") -public abstract class NegateNode extends Node { +public abstract class NegateNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); static NegateNode build() { @@ -35,6 +35,6 @@ Object doOverflow(long self) { @Fallback Object doOther(Object self) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, this); + throw throwTypeErrorIfNotInt(self, this); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java index b9c75e64730c..a4b70709f061 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java @@ -1,9 +1,11 @@ package org.enso.interpreter.node.expression.builtin.number.integer; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.profiles.BranchProfile; + import java.math.BigInteger; -import org.enso.interpreter.dsl.*; + +import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.data.text.Text; @@ -12,8 +14,8 @@ @BuiltinMethod(type = "Integer", name = "parse", description = """ Parse integer number""", autoRegister = false) -public final class ParseIntegerNode extends Node { - @Node.Child +public final class ParseIntegerNode extends IntegerNode { + @Child ToJavaStringNode toJavaString = ToJavaStringNode.build(); private final BranchProfile noEx1 = BranchProfile.create(); private final BranchProfile noEx2 = BranchProfile.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java index ece5406ba998..a632e59c1e0d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java @@ -3,15 +3,18 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; + import java.math.BigInteger; + import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; +import com.oracle.truffle.api.nodes.Node.Child; + @BuiltinMethod(type = "Integer", name = "^", description = "Exponentiation of numbers.") -public abstract class PowNode extends Node { +public abstract class PowNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); private @Child MultiplyNode multiplyNode = MultiplyNode.build(); @@ -88,6 +91,6 @@ private static EnsoBigInteger toBigInteger(long self) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java index 01e8d80fb358..b10408d89288 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java @@ -1,6 +1,6 @@ package org.enso.interpreter.node.expression.builtin.number.integer; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.CountingConditionProfile; import com.oracle.truffle.api.profiles.PrimitiveValueProfile; @@ -11,7 +11,7 @@ type = "Integer", name = "round", description = "Decimal ceiling, converting to a small or big integer depending on size.") -public class RoundNode extends Node { +public class RoundNode extends IntegerNode { private final CountingConditionProfile fitsProfile = CountingConditionProfile.create(); private final PrimitiveValueProfile constantPlacesDecimalPlaces = PrimitiveValueProfile.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java index 635abb2a6f9f..e04cb3df35bf 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java @@ -2,14 +2,16 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; + import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; +import com.oracle.truffle.api.nodes.Node.Child; + @BuiltinMethod(type = "Integer", name = "-", description = "Subtraction of numbers.") -public abstract class SubtractNode extends Node { +public abstract class SubtractNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -55,6 +57,6 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { @Fallback Object doOther(Object self, Object that) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this); + throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java index 5035aafe0858..da8a504b644b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java @@ -2,7 +2,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; @@ -11,7 +11,7 @@ type = "Integer", name = "to_decimal", description = "Conversion of integers to decimals.") -public abstract class ToDecimalNode extends Node { +public abstract class ToDecimalNode extends IntegerNode { public abstract Object execute(Object self); public static ToDecimalNode build() { @@ -30,6 +30,6 @@ public static ToDecimalNode build() { @Fallback Object doOther(Object self) { - throw IntegerUtils.throwTypeErrorIfNotInt(self, this); + throw throwTypeErrorIfNotInt(self); } } From 4614be218ee87580c596a0333d2fc634dbdb61fb Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 13 Sep 2023 19:38:58 +0200 Subject: [PATCH 14/21] Test to verify integer operation on foreign objects --- .../builtin/number/integer/AddNode.java | 9 +- .../builtin/number/integer/BitNotNode.java | 1 - .../number/integer/BitShiftRightNode.java | 1 - .../builtin/number/integer/CeilNode.java | 1 - .../builtin/number/integer/DivideNode.java | 1 - .../builtin/number/integer/FloorNode.java | 1 - .../builtin/number/integer/GreaterNode.java | 1 - .../number/integer/GreaterOrEqualNode.java | 1 - .../builtin/number/integer/IntegerNode.java | 9 +- .../builtin/number/integer/LessNode.java | 1 - .../number/integer/LessOrEqualNode.java | 1 - .../builtin/number/integer/PowNode.java | 5 +- .../builtin/number/integer/RoundNode.java | 1 - .../builtin/number/integer/SubtractNode.java | 4 +- .../builtin/number/integer/ToDecimalNode.java | 1 - .../org/enso/interpreter/test/EqualsTest.java | 124 ---------------- .../enso/interpreter/test/NumbersTest.java | 78 ++++++++++ .../interpreter/test/WrappedPrimitive.java | 133 ++++++++++++++++++ 18 files changed, 221 insertions(+), 152 deletions(-) create mode 100644 engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java create mode 100644 engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java index d7db82bdc4b5..26526d47b077 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java @@ -1,10 +1,5 @@ package org.enso.interpreter.node.expression.builtin.number.integer; -import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; -import org.enso.interpreter.runtime.number.EnsoBigInteger; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; @@ -14,6 +9,10 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node.Child; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; +import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "+", description = "Addition of numbers.") public abstract class AddNode extends IntegerNode { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java index b8ac1222cf87..7b03a8bf4ce7 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitNotNode.java @@ -3,7 +3,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.number.EnsoBigInteger; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java index 14b0f202bfe9..8a436f2a4df8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java @@ -4,7 +4,6 @@ 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.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java index cfd0ab6af420..d05b0654023d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/CeilNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.number.EnsoBigInteger; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java index f449f532a067..77f71d2f95f0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java index 6c7ad5012bea..8f197dae3522 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/FloorNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.number.EnsoBigInteger; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java index 4fafb7060b0e..33ee6f96ed7d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java index 2240179c16a9..fdf53dbea915 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java index 3f1ab586b7cf..f3444c6275c2 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java @@ -1,14 +1,13 @@ package org.enso.interpreter.node.expression.builtin.number.integer; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.error.PanicException; -import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; -import org.enso.interpreter.runtime.number.EnsoBigInteger; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.error.PanicException; +import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; +import org.enso.interpreter.runtime.number.EnsoBigInteger; abstract class IntegerNode extends Node { IntegerNode() {} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java index 3bc1e78cc6e6..0dd150218b3c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java index 71c29648f70b..779626c3d3b8 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java index a632e59c1e0d..357ce002538b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java @@ -3,16 +3,13 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; - +import com.oracle.truffle.api.nodes.Node.Child; import java.math.BigInteger; - import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; -import com.oracle.truffle.api.nodes.Node.Child; - @BuiltinMethod(type = "Integer", name = "^", description = "Exponentiation of numbers.") public abstract class PowNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java index b10408d89288..0b0fa0d5fd89 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/RoundNode.java @@ -1,6 +1,5 @@ package org.enso.interpreter.node.expression.builtin.number.integer; -import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.CountingConditionProfile; import com.oracle.truffle.api.profiles.PrimitiveValueProfile; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java index e04cb3df35bf..acc69b735b76 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java @@ -2,14 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; - +import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; -import com.oracle.truffle.api.nodes.Node.Child; - @BuiltinMethod(type = "Integer", name = "-", description = "Subtraction of numbers.") public abstract class SubtractNode extends IntegerNode { private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java index da8a504b644b..9660b3e69c79 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ToDecimalNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java index b7b8ebc82831..67477989c3f6 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/EqualsTest.java @@ -199,130 +199,6 @@ public void testVectorsEquality() { }); } - @ExportLibrary(InteropLibrary.class) - static final class WrappedPrimitive implements TruffleObject { - private final Object value; - - WrappedPrimitive(long value) { - this.value = value; - } - - WrappedPrimitive(boolean value) { - this.value = value; - } - - WrappedPrimitive(double value) { - this.value = value; - } - - WrappedPrimitive(BigInteger value) { - this.value = value; - } - - WrappedPrimitive(String value) { - this.value = value; - } - - @ExportMessage - boolean isString() { - return value instanceof String; - } - - @ExportMessage - String asString() { - return (String) value; - } - - @ExportMessage - boolean isNumber() { - return value instanceof Number; - } - - @ExportMessage - boolean isBoolean() { - return value instanceof Boolean; - } - - @ExportMessage - boolean asBoolean() { - return (Boolean) value; - } - - @ExportMessage - boolean fitsInByte() { - return false; - } - - @ExportMessage - boolean fitsInShort() { - return false; - } - - @ExportMessage - boolean fitsInInt() { - return false; - } - - @ExportMessage - boolean fitsInLong() { - return value instanceof Long; - } - - @ExportMessage - boolean fitsInFloat() { - return false; - } - - @ExportMessage - boolean fitsInDouble() { - return value instanceof Double; - } - - @ExportMessage - byte asByte() throws UnsupportedMessageException { - throw UnsupportedMessageException.create(); - } - - @ExportMessage - short asShort() throws UnsupportedMessageException { - throw UnsupportedMessageException.create(); - } - - @ExportMessage - int asInt() throws UnsupportedMessageException { - throw UnsupportedMessageException.create(); - } - - @ExportMessage - long asLong() throws UnsupportedMessageException { - return (Long) value; - } - - @ExportMessage - float asFloat() throws UnsupportedMessageException { - throw UnsupportedMessageException.create(); - } - - @ExportMessage - double asDouble() throws UnsupportedMessageException { - return (Double) value; - } - - @ExportMessage - boolean fitsInBigInteger() { - return value instanceof BigInteger; - } - - @ExportMessage - BigInteger asBigInteger() throws UnsupportedMessageException { - return (BigInteger) value; - } - - Object asDirect() { - return value; - } - } - @Test public void testTruffleNumberLong() { var ensoNumber = unwrapValue(context, createValue(context, "1", "")); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java new file mode 100644 index 000000000000..64ffd29c0b02 --- /dev/null +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java @@ -0,0 +1,78 @@ +package org.enso.interpreter.test; + +import java.util.Random; + +import org.enso.polyglot.MethodNames; +import org.graalvm.polyglot.Context; +import org.junit.AfterClass; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import org.junit.BeforeClass; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.FromDataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; + +@RunWith(Theories.class) +public class NumbersTest extends TestBase { + + @DataPoints("operation") + public static final String[] OPERATION = { + " +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /", + ".div", ".bit_xor", ".bit_shift", ".bit_shift_r", ".bit_or", ".bit_and" + }; + private static Context ctx; + + @BeforeClass + public static void initContext() { + ctx = createDefaultContext(); + } + + @AfterClass + public static void closeContext() { + ctx.close(); + } + + @Theory + public void verifyOperationOnForeignObject( + @FromDataPoints("operation") String operation + ) { + executeInContext(ctx, () -> { + var code = """ + fn a b = a{op} b + """.replace("{op}", operation); + var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn"); + + var r = new Random(); + var n1 = r.nextInt(); + var n2 = r.nextInt(); + System.out.println(n1 + operation + " " + n2); + + var r1 = fn.execute(n1, n2); + + var wrap2 = ctx.asValue(new WrappedPrimitive(n2)); + var r2 = fn.execute(n1, wrap2); + + assertEquals("r1: " + r1 + " r2: " + r2, r1.isBoolean(), r2.isBoolean()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInLong(), r2.fitsInLong()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInDouble(), r2.fitsInDouble()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInBigInteger(), r2.fitsInBigInteger()); + + if (r1.fitsInLong()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asLong(), r2.asLong()); + } else if (r1.fitsInDouble()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asDouble(), r2.asDouble(), 0.1); + } else if (r1.fitsInBigInteger()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asBigInteger(), r2.asBigInteger()); + } else if (r1.isBoolean()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asBoolean(), r2.asBoolean()); + } else { + fail("Doesn't fit: " + r1); + } + + return null; + }); + } +} diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java b/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java new file mode 100644 index 000000000000..0b102216fc90 --- /dev/null +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java @@ -0,0 +1,133 @@ +package org.enso.interpreter.test; + +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import java.math.BigInteger; + +@ExportLibrary(InteropLibrary.class) +final class WrappedPrimitive implements TruffleObject { + + private final Object value; + + WrappedPrimitive(long value) { + this.value = value; + } + + WrappedPrimitive(boolean value) { + this.value = value; + } + + WrappedPrimitive(double value) { + this.value = value; + } + + WrappedPrimitive(BigInteger value) { + this.value = value; + } + + WrappedPrimitive(String value) { + this.value = value; + } + + @ExportMessage + boolean isString() { + return value instanceof String; + } + + @ExportMessage + String asString() { + return (String) value; + } + + @ExportMessage + boolean isNumber() { + return value instanceof Number; + } + + @ExportMessage + boolean isBoolean() { + return value instanceof Boolean; + } + + @ExportMessage + boolean asBoolean() { + return (Boolean) value; + } + + @ExportMessage + boolean fitsInByte() { + return false; + } + + @ExportMessage + boolean fitsInShort() { + return false; + } + + @ExportMessage + boolean fitsInInt() { + return false; + } + + @ExportMessage + boolean fitsInLong() { + return value instanceof Long; + } + + @ExportMessage + boolean fitsInFloat() { + return false; + } + + @ExportMessage + boolean fitsInDouble() { + return value instanceof Double; + } + + @ExportMessage + byte asByte() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + short asShort() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + int asInt() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + long asLong() throws UnsupportedMessageException { + return (Long) value; + } + + @ExportMessage + float asFloat() throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + double asDouble() throws UnsupportedMessageException { + return (Double) value; + } + + @ExportMessage + boolean fitsInBigInteger() { + return value instanceof BigInteger; + } + + @ExportMessage + BigInteger asBigInteger() throws UnsupportedMessageException { + return (BigInteger) value; + } + + Object asDirect() { + return value; + } +} From 0ab53f9534ba1dea2485d74d2c904d56d6ed5845 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 06:19:34 +0200 Subject: [PATCH 15/21] Using Parameterized instead of Theories --- .../enso/interpreter/test/NumbersTest.java | 48 ++++++++++++------- .../interpreter/test/WrappedPrimitive.java | 12 +++++ 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java index 64ffd29c0b02..01edf76688e5 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java @@ -1,5 +1,6 @@ package org.enso.interpreter.test; +import java.util.Arrays; import java.util.Random; import org.enso.polyglot.MethodNames; @@ -9,22 +10,31 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.BeforeClass; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; +import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -@RunWith(Theories.class) +@RunWith(Parameterized.class) public class NumbersTest extends TestBase { - - @DataPoints("operation") - public static final String[] OPERATION = { + private static final String[] OPERATIONS = { " +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /", ".div", ".bit_xor", ".bit_shift", ".bit_shift_r", ".bit_or", ".bit_and" }; - private static Context ctx; + @Parameterized.Parameters(name="({1}){0} ({2})") + public static Object[][] parameters() { + var r = new Random(); + var ops = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextLong(), switch (op) { + case " ^" -> r.nextLong(10); + case " *" -> r.nextLong(Integer.MAX_VALUE); + default -> r.nextLong(); + }} + ).toArray(Object[][]::new); + return ops; + } + + private static Context ctx; @BeforeClass public static void initContext() { ctx = createDefaultContext(); @@ -35,19 +45,25 @@ public static void closeContext() { ctx.close(); } - @Theory - public void verifyOperationOnForeignObject( - @FromDataPoints("operation") String operation - ) { + + private final String operation; + private final long n1; + private final long n2; + + public NumbersTest(String operation, long n1, long n2) { + this.operation = operation; + this.n1 = n1; + this.n2 = n2; + } + + @Test + public void verifyOperationOnForeignObject() { executeInContext(ctx, () -> { var code = """ fn a b = a{op} b """.replace("{op}", operation); var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn"); - var r = new Random(); - var n1 = r.nextInt(); - var n2 = r.nextInt(); System.out.println(n1 + operation + " " + n2); var r1 = fn.execute(n1, n2); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java b/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java index 0b102216fc90..b141b7db2d63 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/WrappedPrimitive.java @@ -1,5 +1,6 @@ package org.enso.interpreter.test; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -127,7 +128,18 @@ BigInteger asBigInteger() throws UnsupportedMessageException { return (BigInteger) value; } + @ExportMessage + String toDisplayString(boolean ignore) { + return toString(); + } + Object asDirect() { return value; } + + @TruffleBoundary + @Override + public String toString() { + return "WrappedPrimitive[" + value + "]"; + } } From 7cf503a708959c7a710a6db467da6e718f3c0e8e Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 08:20:49 +0200 Subject: [PATCH 16/21] Let all integer operations accept foreign number as second argument --- .../builtin/number/integer/AbsNode.java | 3 - .../builtin/number/integer/AddNode.java | 16 +-- .../builtin/number/integer/BitAndNode.java | 16 ++- .../builtin/number/integer/BitOrNode.java | 16 ++- .../builtin/number/integer/BitShiftNode.java | 16 ++- .../number/integer/BitShiftRightNode.java | 12 ++ .../builtin/number/integer/BitXorNode.java | 16 ++- .../builtin/number/integer/DivNode.java | 17 ++- .../builtin/number/integer/DivideNode.java | 18 ++- .../builtin/number/integer/GreaterNode.java | 13 ++ .../number/integer/GreaterOrEqualNode.java | 13 ++ .../builtin/number/integer/IntegerNode.java | 27 ++++ .../builtin/number/integer/LessNode.java | 13 ++ .../number/integer/LessOrEqualNode.java | 14 +++ .../builtin/number/integer/ModNode.java | 16 ++- .../builtin/number/integer/MultiplyNode.java | 16 ++- .../builtin/number/integer/NegateNode.java | 3 - .../number/integer/ParseIntegerNode.java | 2 - .../builtin/number/integer/PowNode.java | 16 ++- .../builtin/number/integer/SubtractNode.java | 16 ++- .../interpreter/test/BinaryOpIntegerTest.java | 117 ++++++++++++++++++ .../enso/interpreter/test/NumbersTest.java | 94 -------------- 22 files changed, 344 insertions(+), 146 deletions(-) create mode 100644 engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpIntegerTest.java delete mode 100644 engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java index c999cef472c0..a8f09bcf8976 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AbsNode.java @@ -2,15 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "abs", description = "Absolute value of a number") public abstract class AbsNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); public static AbsNode build() { return AbsNodeGen.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java index 26526d47b077..739576d4ccd1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/AddNode.java @@ -6,17 +6,13 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "+", description = "Addition of numbers.") public abstract class AddNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); public abstract Object execute(Object self, Object that); @@ -66,17 +62,7 @@ Object doInterop( TruffleObject that, @CachedLibrary(limit = "3") InteropLibrary iop, @Cached AddNode delegate) { - try { - if (iop.fitsInLong(that)) { - return delegate.execute(self, iop.asLong(that)); - } else if (iop.fitsInDouble(that)) { - return delegate.execute(self, iop.asDouble(that)); - } else if (iop.fitsInBigInteger(that)) { - return delegate.execute(self, new EnsoBigInteger(iop.asBigInteger(that))); - } - } catch (UnsupportedMessageException ex) { - } - return doOther(self, that); + return super.doInterop(self, that, iop, delegate); } @Fallback diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java index 01afe9fe7ed4..9dabe13dd46f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitAndNode.java @@ -1,16 +1,17 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_and", description = "Bitwise and.") public abstract class BitAndNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); public abstract Object execute(Object self, Object that); @@ -38,6 +39,15 @@ Object doBigIntBigInt(EnsoBigInteger self, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.bitAnd(self.getValue(), that.getValue())); } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached BitAndNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java index fa738b2def9f..be0d0be9c678 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitOrNode.java @@ -1,16 +1,17 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_or", description = "Bitwise or.") public abstract class BitOrNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -38,6 +39,15 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.bitOr(self.getValue(), that.getValue())); } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached BitOrNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java index 6d97f7bbec0d..33880022cfce 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftNode.java @@ -6,11 +6,12 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.profiles.CountingConditionProfile; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @@ -18,7 +19,7 @@ @ImportStatic(BigIntegerOps.class) @BuiltinMethod(type = "Integer", name = "bit_shift", description = "Bitwise shift.") public abstract class BitShiftNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); + private final CountingConditionProfile canShiftLeftInLongProfile = CountingConditionProfile.create(); private final CountingConditionProfile positiveFitsInInt = CountingConditionProfile.create(); @@ -124,6 +125,15 @@ Object doBigIntThat(EnsoBigInteger self, EnsoBigInteger that) { } } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached BitShiftNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java index 8a436f2a4df8..175915dd708b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitShiftRightNode.java @@ -4,6 +4,9 @@ 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.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; @@ -46,6 +49,15 @@ Object doBigInteger( return bitShiftNode.execute(self, new EnsoBigInteger(BigIntegerOps.negate(that.getValue()))); } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached BitShiftRightNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java index 151c572880cb..f5a1d0c89509 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/BitXorNode.java @@ -1,16 +1,17 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "bit_xor", description = "Bitwise exclusive or.") public abstract class BitXorNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -38,6 +39,15 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.bitXor(self.getValue(), that.getValue())); } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached BitXorNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java index 35360c9d6b89..b288dda5758d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivNode.java @@ -1,11 +1,13 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @@ -13,8 +15,6 @@ @BuiltinMethod(type = "Integer", name = "div", description = "Division of numbers.") public abstract class DivNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); - abstract Object execute(Object self, Object that); static DivNode build() { @@ -53,6 +53,15 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return toEnsoNumberNode.execute(BigIntegerOps.divide(self.getValue(), that.getValue())); } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached DivNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java index 77f71d2f95f0..9b140f93e2e4 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/DivideNode.java @@ -1,14 +1,19 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "/", description = "Division of numbers.") public abstract class DivideNode extends IntegerNode { - abstract double execute(Object self, Object that); + @Override + abstract Object execute(Object self, Object that); static DivideNode build() { return DivideNodeGen.create(); @@ -44,8 +49,17 @@ static DivideNode build() { return BigIntegerOps.toDouble(self.getValue()) / that; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached DivideNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback - double doOther(Object self, Object that) { + Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java index 33ee6f96ed7d..be049378c3a1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterNode.java @@ -1,7 +1,11 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -47,6 +51,15 @@ boolean doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return BigIntegerOps.compare(self.getValue(), that.getValue()) > 0; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached GreaterNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { var builtins = EnsoContext.get(this).getBuiltins(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java index fdf53dbea915..db3a2f05c0b0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/GreaterOrEqualNode.java @@ -1,7 +1,11 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -47,6 +51,15 @@ boolean doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return BigIntegerOps.compare(self.getValue(), that.getValue()) >= 0; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached GreaterOrEqualNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { var builtins = EnsoContext.get(this).getBuiltins(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java index f3444c6275c2..30d0b717262e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/IntegerNode.java @@ -3,13 +3,17 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; import org.enso.interpreter.runtime.number.EnsoBigInteger; abstract class IntegerNode extends Node { + @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); + IntegerNode() {} @TruffleBoundary @@ -37,4 +41,27 @@ final boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) { } return iop.isNumber(obj); } + + final Object doInterop( + Object self, TruffleObject that, InteropLibrary iop, IntegerNode delegate) { + try { + if (iop.fitsInLong(that)) { + return delegate.execute(self, iop.asLong(that)); + } else if (iop.fitsInDouble(that)) { + return delegate.execute(self, iop.asDouble(that)); + } else if (iop.fitsInBigInteger(that)) { + return delegate.execute(self, toEnsoNumberNode.execute(iop.asBigInteger(that))); + } + } catch (UnsupportedMessageException ex) { + } + return doOther(self, that); + } + + Object execute(Object self, Object that) { + throw new AbstractMethodError(); + } + + Object doOther(Object self, Object that) { + throw new AbstractMethodError(); + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java index 0dd150218b3c..67661dc0a7e5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessNode.java @@ -1,7 +1,11 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -47,6 +51,15 @@ boolean doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return BigIntegerOps.compare(self.getValue(), that.getValue()) < 0; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached LessNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { var builtins = EnsoContext.get(this).getBuiltins(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java index 779626c3d3b8..eb1bfd270259 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/LessOrEqualNode.java @@ -1,7 +1,11 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -11,6 +15,7 @@ @BuiltinMethod(type = "Integer", name = "<=", description = "Comparison of numbers.") public abstract class LessOrEqualNode extends IntegerNode { + @Override abstract Object execute(Object self, Object that); static LessOrEqualNode build() { @@ -47,6 +52,15 @@ boolean doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return BigIntegerOps.compare(self.getValue(), that.getValue()) <= 0; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached LessOrEqualNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { var builtins = EnsoContext.get(this).getBuiltins(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java index 40f262656434..16cc052be042 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ModNode.java @@ -1,20 +1,21 @@ package org.enso.interpreter.node.expression.builtin.number.integer; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import java.math.BigInteger; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "%", description = "Modulo division of numbers.") public abstract class ModNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -78,6 +79,15 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { } } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached ModNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java index 38afd2f81158..a26b1bd8578e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/MultiplyNode.java @@ -1,16 +1,17 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "*", description = "Multiplication of numbers.") public abstract class MultiplyNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -53,6 +54,15 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return BigIntegerOps.toDouble(self.getValue()) * that; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached MultiplyNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java index 2c5de8f356c2..e68f1dbaca54 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/NegateNode.java @@ -2,15 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "negate", description = "Negation for numbers.") public abstract class NegateNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); static NegateNode build() { return NegateNodeGen.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java index a4b70709f061..14dcfe3ba6eb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/ParseIntegerNode.java @@ -2,9 +2,7 @@ import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.profiles.BranchProfile; - import java.math.BigInteger; - import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode; import org.enso.interpreter.runtime.EnsoContext; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java index 357ce002538b..2c27a7f59dea 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/PowNode.java @@ -1,18 +1,21 @@ package org.enso.interpreter.node.expression.builtin.number.integer; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node.Child; import java.math.BigInteger; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "^", description = "Exponentiation of numbers.") public abstract class PowNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); + private @Child MultiplyNode multiplyNode = MultiplyNode.build(); abstract Object execute(Object self, Object that); @@ -86,6 +89,15 @@ private static EnsoBigInteger toBigInteger(long self) { return new EnsoBigInteger(BigInteger.valueOf(self)); } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached PowNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java index acc69b735b76..25e35614ca3f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/integer/SubtractNode.java @@ -1,16 +1,17 @@ package org.enso.interpreter.node.expression.builtin.number.integer; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Integer", name = "-", description = "Subtraction of numbers.") public abstract class SubtractNode extends IntegerNode { - private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create(); abstract Object execute(Object self, Object that); @@ -53,6 +54,15 @@ Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) { return BigIntegerOps.toDouble(self.getValue()) - that; } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + Object self, + TruffleObject that, + @CachedLibrary(limit = "3") InteropLibrary iop, + @Cached SubtractNode delegate) { + return super.doInterop(self, that, iop, delegate); + } + @Fallback Object doOther(Object self, Object that) { throw throwTypeErrorIfNotInt(self, that); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpIntegerTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpIntegerTest.java new file mode 100644 index 000000000000..39ccc709f92b --- /dev/null +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpIntegerTest.java @@ -0,0 +1,117 @@ +package org.enso.interpreter.test; + +import java.util.Arrays; +import java.util.Random; +import java.util.stream.Stream; + +import org.enso.polyglot.MethodNames; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; +import org.junit.AfterClass; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import com.google.common.collect.Streams; + +@RunWith(Parameterized.class) +public class BinaryOpIntegerTest extends TestBase { + private static final String[] OPERATIONS = { + " +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /", + ".div", ".bit_xor", ".bit_shift", ".bit_shift_r", ".bit_or", ".bit_and" + }; + + @Parameterized.Parameters(name="({1}){0} ({2})") + public static Object[][] parameters() { + var r = new Random(); + var randomOps = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextLong(), switch (op) { + case " ^" -> r.nextLong(10); + case " *" -> r.nextLong(Integer.MAX_VALUE); + default -> r.nextLong(); + }} + ); + var zeroOps = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextLong(), 0 } + ); + var oneOps = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextLong(), 1 } + ); + var extraOps = Stream.of( + new Object[] { " %", 19, 73 }, + new Object[] { ".bit_shift", 12, 10 } + ); + return Streams.concat( + randomOps, + zeroOps, + oneOps, + extraOps + ).toArray(Object[][]::new); + } + + private static Context ctx; + @BeforeClass + public static void initContext() { + ctx = createDefaultContext(); + } + + @AfterClass + public static void closeContext() { + ctx.close(); + } + + + private final String operation; + private final long n1; + private final long n2; + + public BinaryOpIntegerTest(String operation, long n1, long n2) { + this.operation = operation; + this.n1 = n1; + this.n2 = n2; + } + + @Test + public void verifyOperationOnForeignObject() { + executeInContext(ctx, () -> { + var code = """ + fn a b = a{op} b + """.replace("{op}", operation); + var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn"); + + var r1 = fn.execute(n1, n2); + + var wrap2 = ctx.asValue(new WrappedPrimitive(n2)); + var r2 = fn.execute(n1, wrap2); + + assertSameResult(r1, r2); + return null; + }); + } + + private void assertSameResult(Value r1, Value r2) { + assertEquals("r1: " + r1 + " r2: " + r2, r1.isException(), r2.isException()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.isBoolean(), r2.isBoolean()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInLong(), r2.fitsInLong()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInDouble(), r2.fitsInDouble()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInBigInteger(), r2.fitsInBigInteger()); + + if (r1.fitsInLong()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asLong(), r2.asLong()); + } else if (r1.fitsInDouble()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asDouble(), r2.asDouble(), 0.1); + } else if (r1.fitsInBigInteger()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asBigInteger(), r2.asBigInteger()); + } else if (r1.isBoolean()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asBoolean(), r2.asBoolean()); + } else if (r1.isException()) { + assertTrue("Both are exceptions for " + n1 + operation + " " + n2, r2.isException()); + } else { + fail("Doesn't fit: " + r1); + } + } +} diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java deleted file mode 100644 index 01edf76688e5..000000000000 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/NumbersTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.enso.interpreter.test; - -import java.util.Arrays; -import java.util.Random; - -import org.enso.polyglot.MethodNames; -import org.graalvm.polyglot.Context; -import org.junit.AfterClass; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -@RunWith(Parameterized.class) -public class NumbersTest extends TestBase { - private static final String[] OPERATIONS = { - " +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /", - ".div", ".bit_xor", ".bit_shift", ".bit_shift_r", ".bit_or", ".bit_and" - }; - - @Parameterized.Parameters(name="({1}){0} ({2})") - public static Object[][] parameters() { - var r = new Random(); - var ops = Arrays.asList(OPERATIONS).stream().map( - (op) -> new Object[] { op, r.nextLong(), switch (op) { - case " ^" -> r.nextLong(10); - case " *" -> r.nextLong(Integer.MAX_VALUE); - default -> r.nextLong(); - }} - ).toArray(Object[][]::new); - return ops; - } - - private static Context ctx; - @BeforeClass - public static void initContext() { - ctx = createDefaultContext(); - } - - @AfterClass - public static void closeContext() { - ctx.close(); - } - - - private final String operation; - private final long n1; - private final long n2; - - public NumbersTest(String operation, long n1, long n2) { - this.operation = operation; - this.n1 = n1; - this.n2 = n2; - } - - @Test - public void verifyOperationOnForeignObject() { - executeInContext(ctx, () -> { - var code = """ - fn a b = a{op} b - """.replace("{op}", operation); - var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn"); - - System.out.println(n1 + operation + " " + n2); - - var r1 = fn.execute(n1, n2); - - var wrap2 = ctx.asValue(new WrappedPrimitive(n2)); - var r2 = fn.execute(n1, wrap2); - - assertEquals("r1: " + r1 + " r2: " + r2, r1.isBoolean(), r2.isBoolean()); - assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInLong(), r2.fitsInLong()); - assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInDouble(), r2.fitsInDouble()); - assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInBigInteger(), r2.fitsInBigInteger()); - - if (r1.fitsInLong()) { - assertEquals("Results for " + n1 + operation + " " + n2, r1.asLong(), r2.asLong()); - } else if (r1.fitsInDouble()) { - assertEquals("Results for " + n1 + operation + " " + n2, r1.asDouble(), r2.asDouble(), 0.1); - } else if (r1.fitsInBigInteger()) { - assertEquals("Results for " + n1 + operation + " " + n2, r1.asBigInteger(), r2.asBigInteger()); - } else if (r1.isBoolean()) { - assertEquals("Results for " + n1 + operation + " " + n2, r1.asBoolean(), r2.asBoolean()); - } else { - fail("Doesn't fit: " + r1); - } - - return null; - }); - } -} From 6678dd7884a770e27a024355ba4bce12f16ccf38 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 08:23:06 +0200 Subject: [PATCH 17/21] foreach rather than if Co-authored-by: Hubert Plociniczak --- .../main/scala/org/enso/compiler/codegen/IrToTruffle.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index 3cb5cf10bb08..66729fe9566f 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -1018,8 +1018,8 @@ class IrToTruffle( case _: Expression.Binding => case _ => val types = ir.getMetadata(TypeSignatures) - if (types.isDefined) { - val checkNode = extractAscribedType(null, types.get.signature); + types.foreach { tpe => + val checkNode = extractAscribedType(null, tpe.signature); if (checkNode != null) { runtimeExpression = ReadArgumentCheckNode.wrap(runtimeExpression, checkNode) From 3d5b0141883656a272a25975caba12e172310ad1 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 08:49:59 +0200 Subject: [PATCH 18/21] Make all nodes extend a shared node --- .../builtin/number/decimal/AbsNode.java | 3 +- .../builtin/number/decimal/AddNode.java | 3 +- .../builtin/number/decimal/CeilNode.java | 3 +- .../builtin/number/decimal/DivideNode.java | 10 +- .../builtin/number/decimal/FloatNode.java | 20 +++ .../builtin/number/decimal/FloorNode.java | 3 +- .../builtin/number/decimal/GreaterNode.java | 11 +- .../number/decimal/GreaterOrEqualNode.java | 11 +- .../builtin/number/decimal/LessNode.java | 11 +- .../number/decimal/LessOrEqualNode.java | 11 +- .../builtin/number/decimal/ModNode.java | 10 +- .../builtin/number/decimal/MultiplyNode.java | 3 +- .../builtin/number/decimal/NegateNode.java | 3 +- .../builtin/number/decimal/PowNode.java | 10 +- .../builtin/number/decimal/RoundNode.java | 3 +- .../builtin/number/decimal/SubtractNode.java | 10 +- .../builtin/number/decimal/ToDecimalNode.java | 3 +- .../builtin/number/decimal/TruncateNode.java | 3 +- .../interpreter/test/BinaryOpFloatTest.java | 125 ++++++++++++++++++ 19 files changed, 166 insertions(+), 90 deletions(-) create mode 100644 engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java create mode 100644 engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java index a47452188cf1..b64a31a9fb0e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AbsNode.java @@ -1,10 +1,9 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; @BuiltinMethod(type = "Decimal", name = "abs", description = "Absolute value of a number.") -public class AbsNode extends Node { +public class AbsNode extends FloatNode { double execute(double self) { return Math.abs(self); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java index 00e19eb5fdd3..056cb561defb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -11,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "+", description = "Addition of numbers.") -public abstract class AddNode extends Node { +public abstract class AddNode extends FloatNode { abstract double execute(double self, Object that); static AddNode build() { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/CeilNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/CeilNode.java index fd0a82d5d6f1..7400a1f3edd0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/CeilNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/CeilNode.java @@ -1,7 +1,6 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.CountingConditionProfile; import java.math.BigDecimal; import java.math.BigInteger; @@ -13,7 +12,7 @@ type = "Decimal", name = "ceil", description = "Decimal ceiling, converting to a small or big integer depending on size.") -public class CeilNode extends Node { +public class CeilNode extends FloatNode { private final CountingConditionProfile fitsProfile = CountingConditionProfile.create(); Object execute(double self) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java index e4699567a2be..83fea148e361 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java @@ -2,16 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "/", description = "Division of numbers.") -public abstract class DivideNode extends Node { +public abstract class DivideNode extends FloatNode { abstract double execute(double self, Object that); static DivideNode build() { @@ -35,8 +31,6 @@ static DivideNode build() { @Fallback double doOther(double self, Object that) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - var number = builtins.number().getNumber(); - throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + return handleOther(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java new file mode 100644 index 000000000000..2f9d481ac97c --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java @@ -0,0 +1,20 @@ +package org.enso.interpreter.node.expression.builtin.number.decimal; + +import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.error.DataflowError; +import org.enso.interpreter.runtime.error.PanicException; + +abstract class FloatNode extends Node { + final double handleOther(double self, Object that) { + var builtins = EnsoContext.get(this).getBuiltins(); + var number = builtins.number().getNumber(); + throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + } + + final DataflowError incomparableError(Object self, Object that) { + var builtins = EnsoContext.get(this).getBuiltins(); + var incomparableErr = builtins.error().makeIncomparableValues(self, that); + return DataflowError.withoutTrace(incomparableErr, this); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloorNode.java index a4abfb07ed34..f37e5b59f65d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloorNode.java @@ -1,7 +1,6 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.CountingConditionProfile; import java.math.BigDecimal; import java.math.BigInteger; @@ -13,7 +12,7 @@ type = "Decimal", name = "floor", description = "Decimal floor, converting to a small or big integer depending on size.") -public class FloorNode extends Node { +public class FloorNode extends FloatNode { private final CountingConditionProfile fitsProfile = CountingConditionProfile.create(); Object execute(double self) { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java index 7a301eb8221a..61efbbc234d9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java @@ -2,15 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = ">", description = "Comparison of numbers.") -public abstract class GreaterNode extends Node { +public abstract class GreaterNode extends FloatNode { abstract Object execute(double self, Object that); @@ -49,10 +46,4 @@ Object doBigInteger(double self, EnsoBigInteger that) { Object doOther(double self, Object that) { return incomparableError(self, that); } - - private DataflowError incomparableError(Object self, Object that) { - var builtins = EnsoContext.get(this).getBuiltins(); - var incomparableErr = builtins.error().makeIncomparableValues(self, that); - return DataflowError.withoutTrace(incomparableErr, this); - } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java index 068ecbce3343..0c0edd3b658e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java @@ -2,15 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = ">=", description = "Comparison of numbers.") -public abstract class GreaterOrEqualNode extends Node { +public abstract class GreaterOrEqualNode extends FloatNode { abstract Object execute(double self, Object that); @@ -49,10 +46,4 @@ Object doBigInteger(double self, EnsoBigInteger that) { Object doOther(double self, Object that) { return incomparableError(self, that); } - - private DataflowError incomparableError(Object self, Object that) { - var builtins = EnsoContext.get(this).getBuiltins(); - var incomparableErr = builtins.error().makeIncomparableValues(self, that); - return DataflowError.withoutTrace(incomparableErr, this); - } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java index b068cab10c5c..2f7cd40f5552 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java @@ -2,15 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "<", description = "Comparison of numbers.") -public abstract class LessNode extends Node { +public abstract class LessNode extends FloatNode { abstract Object execute(double self, Object that); @@ -49,10 +46,4 @@ Object doBigInteger(double self, EnsoBigInteger that) { Object doOther(double self, Object that) { return incomparableError(self, that); } - - private DataflowError incomparableError(Object self, Object that) { - var builtins = EnsoContext.get(this).getBuiltins(); - var incomparableErr = builtins.error().makeIncomparableValues(self, that); - return DataflowError.withoutTrace(incomparableErr, this); - } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java index 45ad6707ab8f..0f892dc16f3f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java @@ -2,15 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "<=", description = "Comparison of numbers.") -public abstract class LessOrEqualNode extends Node { +public abstract class LessOrEqualNode extends FloatNode { abstract Object execute(double self, Object that); @@ -49,10 +46,4 @@ Object doBigInteger(double self, EnsoBigInteger that) { Object doOther(double self, Object that) { return incomparableError(self, that); } - - private DataflowError incomparableError(Object self, Object that) { - var builtins = EnsoContext.get(this).getBuiltins(); - var incomparableErr = builtins.error().makeIncomparableValues(self, that); - return DataflowError.withoutTrace(incomparableErr, this); - } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java index 1b33ae9af8b3..b8848d5dcc7e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java @@ -2,16 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "%", description = "Modulo division of numbers.") -public abstract class ModNode extends Node { +public abstract class ModNode extends FloatNode { abstract double execute(double self, Object that); static ModNode build() { @@ -35,8 +31,6 @@ static ModNode build() { @Fallback double doOther(double self, Object that) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - var number = builtins.number().getNumber(); - throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + return handleOther(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java index 433268d22f33..31d9115577e9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java @@ -2,7 +2,6 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; import org.enso.interpreter.runtime.EnsoContext; @@ -11,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "*", description = "Multiplication of numbers.") -public abstract class MultiplyNode extends Node { +public abstract class MultiplyNode extends FloatNode { abstract double execute(double self, Object that); static MultiplyNode build() { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java index 467a4062d40d..be83ecf479c6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/NegateNode.java @@ -1,10 +1,9 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; @BuiltinMethod(type = "Decimal", name = "negate", description = "Negation for numbers.") -public class NegateNode extends Node { +public class NegateNode extends FloatNode { double execute(double self) { return -self; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java index 27b3c0b99d51..7886f796b38c 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java @@ -2,16 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "^", description = "Exponentiation of numbers.") -public abstract class PowNode extends Node { +public abstract class PowNode extends FloatNode { abstract double execute(double self, Object that); static PowNode build() { @@ -35,8 +31,6 @@ static PowNode build() { @Fallback double doOther(double self, Object that) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - var number = builtins.number().getNumber(); - throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + return handleOther(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/RoundNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/RoundNode.java index bdaef39105dc..323659930926 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/RoundNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/RoundNode.java @@ -1,7 +1,6 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.CountingConditionProfile; import com.oracle.truffle.api.profiles.PrimitiveValueProfile; @@ -16,7 +15,7 @@ type = "Decimal", name = "round", description = "Decimal ceiling, converting to a small or big integer depending on size.") -public class RoundNode extends Node { +public class RoundNode extends FloatNode { private final CountingConditionProfile fitsProfile = CountingConditionProfile.create(); private final PrimitiveValueProfile constantPlacesDecimalPlaces = PrimitiveValueProfile.create(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java index 40516200c2da..c312664036eb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java @@ -2,16 +2,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "-", description = "Subtraction of numbers.") -public abstract class SubtractNode extends Node { +public abstract class SubtractNode extends FloatNode { abstract double execute(double self, Object that); static SubtractNode build() { @@ -35,8 +31,6 @@ static SubtractNode build() { @Fallback double doOther(double self, Object that) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - var number = builtins.number().getNumber(); - throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + return handleOther(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java index ba974b8a7bfc..c53095118507 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ToDecimalNode.java @@ -1,10 +1,9 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; -import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; @BuiltinMethod(type = "Decimal", name = "to_decimal", description = "Identity on decimals") -public class ToDecimalNode extends Node { +public class ToDecimalNode extends FloatNode { double execute(double self) { return self; } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/TruncateNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/TruncateNode.java index 57abfe285a8c..2a329c1681e1 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/TruncateNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/TruncateNode.java @@ -1,7 +1,6 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.CountingConditionProfile; import java.math.BigDecimal; import java.math.BigInteger; @@ -13,7 +12,7 @@ type = "Decimal", name = "truncate_builtin", description = "Truncate a floating-point number to an integer by dropping the fractional part.") -public class TruncateNode extends Node { +public class TruncateNode extends FloatNode { private final CountingConditionProfile fitsProfile = CountingConditionProfile.create(); Object execute(double self) { diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java new file mode 100644 index 000000000000..5782867db2e7 --- /dev/null +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java @@ -0,0 +1,125 @@ +package org.enso.interpreter.test; + +import java.util.Arrays; +import java.util.Random; +import java.util.stream.Stream; + +import org.enso.polyglot.MethodNames; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.PolyglotException; +import org.graalvm.polyglot.Value; +import org.junit.AfterClass; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import com.google.common.collect.Streams; + +@RunWith(Parameterized.class) +public class BinaryOpFloatTest extends TestBase { + private static final String[] OPERATIONS = { + " +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /" + }; + + @Parameterized.Parameters(name="({1}){0} ({2})") + public static Object[][] parameters() { + var r = new Random(); + var randomOps = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextDouble(), switch (op) { + case " ^" -> r.nextDouble(10); + case " *" -> r.nextDouble(Integer.MAX_VALUE); + default -> r.nextDouble(); + }} + ); + var zeroOps = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextDouble(), 0.0 } + ); + var oneOps = Arrays.asList(OPERATIONS).stream().map( + (op) -> new Object[] { op, r.nextDouble(), 1.0 } + ); + var extraOps = Stream.of( + new Object[] { " %", 19.73, 12.10 }, + new Object[] { " ^", 10.12, 73.19 } + ); + return Streams.concat( + randomOps, + zeroOps, + oneOps, + extraOps + ).toArray(Object[][]::new); + } + + private static Context ctx; + @BeforeClass + public static void initContext() { + ctx = createDefaultContext(); + } + + @AfterClass + public static void closeContext() { + ctx.close(); + } + + + private final String operation; + private final double n1; + private final double n2; + + public BinaryOpFloatTest(String operation, double n1, double n2) { + this.operation = operation; + this.n1 = n1; + this.n2 = n2; + } + + @Test + public void verifyOperationOnForeignObject() { + executeInContext(ctx, () -> { + var code = """ + fn a b = a{op} b + """.replace("{op}", operation); + var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn"); + + var r1 = execute(fn, n1, n2); + + var wrap2 = n2; //ctx.asValue(new WrappedPrimitive(n2)); + var r2 = execute(fn, n1, wrap2); + + assertSameResult(r1, r2); + return null; + }); + } + + private Value execute(Value fn, Object... args) { + try { + return fn.execute(args); + } catch (PolyglotException ex) { + return ex.getGuestObject(); + } + } + + private void assertSameResult(Value r1, Value r2) { + assertEquals("r1: " + r1 + " r2: " + r2, r1.isException(), r2.isException()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.isBoolean(), r2.isBoolean()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInLong(), r2.fitsInLong()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInDouble(), r2.fitsInDouble()); + assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInBigInteger(), r2.fitsInBigInteger()); + + if (r1.fitsInLong()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asLong(), r2.asLong()); + } else if (r1.fitsInDouble()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asDouble(), r2.asDouble(), 0.1); + } else if (r1.fitsInBigInteger()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asBigInteger(), r2.asBigInteger()); + } else if (r1.isBoolean()) { + assertEquals("Results for " + n1 + operation + " " + n2, r1.asBoolean(), r2.asBoolean()); + } else if (r1.isException()) { + assertTrue("Both are exceptions for " + n1 + operation + " " + n2, r2.isException()); + } else { + fail("Doesn't fit: " + r1); + } + } +} From 634b25ca3740dbb3778b32c57b5c7ed6c79788c2 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 09:34:54 +0200 Subject: [PATCH 19/21] Support foreign number argument in double arithmetic nodes --- .../builtin/number/decimal/AddNode.java | 22 ++++++++---- .../builtin/number/decimal/DivideNode.java | 17 ++++++++- .../builtin/number/decimal/FloatNode.java | 35 ++++++++++++++++++- .../builtin/number/decimal/GreaterNode.java | 15 ++++++++ .../number/decimal/GreaterOrEqualNode.java | 15 ++++++++ .../builtin/number/decimal/LessNode.java | 15 ++++++++ .../number/decimal/LessOrEqualNode.java | 15 ++++++++ .../builtin/number/decimal/ModNode.java | 17 ++++++++- .../builtin/number/decimal/MultiplyNode.java | 22 ++++++++---- .../builtin/number/decimal/PowNode.java | 17 ++++++++- .../builtin/number/decimal/SubtractNode.java | 17 ++++++++- .../interpreter/test/BinaryOpFloatTest.java | 2 +- test/Tests/src/Semantic/Conversion_Spec.enso | 21 +++++++++++ 13 files changed, 212 insertions(+), 18 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java index 056cb561defb..aa25f343a441 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/AddNode.java @@ -1,12 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "+", description = "Addition of numbers.") @@ -32,10 +34,18 @@ static AddNode build() { return self + BigIntegerOps.toDouble(that.getValue()); } + @Specialization(guards = "isForeignNumber(iop, that)") + double doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached AddNode delegate) { + return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode)); + } + @Fallback double doOther(double self, Object that) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - var number = builtins.number().getNumber(); - throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + throw panicOtherwise(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java index 83fea148e361..524e8bae95d0 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/DivideNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "/", description = "Division of numbers.") @@ -29,8 +34,18 @@ static DivideNode build() { return self / BigIntegerOps.toDouble(that.getValue()); } + @Specialization(guards = "isForeignNumber(iop, that)") + double doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached DivideNode delegate) { + return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode)); + } + @Fallback double doOther(double self, Object that) { - return handleOther(self, that); + throw panicOtherwise(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java index 2f9d481ac97c..a6e9a10feb9a 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/FloatNode.java @@ -1,12 +1,45 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.error.PanicException; +import org.enso.interpreter.runtime.number.EnsoBigInteger; abstract class FloatNode extends Node { - final double handleOther(double self, Object that) { + static final String INTEROP_LIMIT = "3"; + + final boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) { + if (obj instanceof EnsoBigInteger) { + return false; + } + return iop.isNumber(obj); + } + + final Object handleInterop( + boolean incomparableError, + double self, + TruffleObject that, + InteropLibrary iop, + ToEnsoNumberNode toEnsoNumberNode) { + try { + if (iop.fitsInLong(that)) { + return iop.asLong(that); + } else if (iop.fitsInDouble(that)) { + return iop.asDouble(that); + } else if (iop.fitsInBigInteger(that)) { + return toEnsoNumberNode.execute(iop.asBigInteger(that)); + } + } catch (UnsupportedMessageException ex) { + } + return incomparableError ? incomparableError(self, that) : panicOtherwise(self, that); + } + + final PanicException panicOtherwise(double self, Object that) { var builtins = EnsoContext.get(this).getBuiltins(); var number = builtins.number().getNumber(); throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java index 61efbbc234d9..d18489ec5a21 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = ">", description = "Comparison of numbers.") @@ -42,6 +47,16 @@ Object doBigInteger(double self, EnsoBigInteger that) { } } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached GreaterNode delegate) { + return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode)); + } + @Fallback Object doOther(double self, Object that) { return incomparableError(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java index 0c0edd3b658e..b733ef468581 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/GreaterOrEqualNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = ">=", description = "Comparison of numbers.") @@ -42,6 +47,16 @@ Object doBigInteger(double self, EnsoBigInteger that) { } } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached GreaterOrEqualNode delegate) { + return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode)); + } + @Fallback Object doOther(double self, Object that) { return incomparableError(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java index 2f7cd40f5552..18f780d5f023 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "<", description = "Comparison of numbers.") @@ -42,6 +47,16 @@ Object doBigInteger(double self, EnsoBigInteger that) { } } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached LessNode delegate) { + return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode)); + } + @Fallback Object doOther(double self, Object that) { return incomparableError(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java index 0f892dc16f3f..0675c71da188 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/LessOrEqualNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "<=", description = "Comparison of numbers.") @@ -42,6 +47,16 @@ Object doBigInteger(double self, EnsoBigInteger that) { } } + @Specialization(guards = "isForeignNumber(iop, that)") + Object doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached LessOrEqualNode delegate) { + return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode)); + } + @Fallback Object doOther(double self, Object that) { return incomparableError(self, that); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java index b8848d5dcc7e..2e1a16fa0ac5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/ModNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "%", description = "Modulo division of numbers.") @@ -29,8 +34,18 @@ static ModNode build() { return self % BigIntegerOps.toDouble(that.getValue()); } + @Specialization(guards = "isForeignNumber(iop, that)") + double doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached ModNode delegate) { + return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode)); + } + @Fallback double doOther(double self, Object that) { - return handleOther(self, that); + throw panicOtherwise(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java index 31d9115577e9..3344d9088777 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/MultiplyNode.java @@ -1,12 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "*", description = "Multiplication of numbers.") @@ -32,10 +34,18 @@ static MultiplyNode build() { return self * BigIntegerOps.toDouble(that.getValue()); } + @Specialization(guards = "isForeignNumber(iop, that)") + double doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached MultiplyNode delegate) { + return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode)); + } + @Fallback double doOther(double self, Object that) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - var number = builtins.number().getNumber(); - throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this); + throw panicOtherwise(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java index 7886f796b38c..4d60748e7120 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/PowNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "^", description = "Exponentiation of numbers.") @@ -29,8 +34,18 @@ static PowNode build() { return Math.pow(self, BigIntegerOps.toDouble(that.getValue())); } + @Specialization(guards = "isForeignNumber(iop, that)") + double doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached PowNode delegate) { + return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode)); + } + @Fallback double doOther(double self, Object that) { - return handleOther(self, that); + throw panicOtherwise(self, that); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java index c312664036eb..63eb517b7f54 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/number/decimal/SubtractNode.java @@ -1,9 +1,14 @@ package org.enso.interpreter.node.expression.builtin.number.decimal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.CachedLibrary; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps; +import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.runtime.number.EnsoBigInteger; @BuiltinMethod(type = "Decimal", name = "-", description = "Subtraction of numbers.") @@ -29,8 +34,18 @@ static SubtractNode build() { return self - BigIntegerOps.toDouble(that.getValue()); } + @Specialization(guards = "isForeignNumber(iop, that)") + double doInterop( + double self, + TruffleObject that, + @CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop, + @Cached ToEnsoNumberNode toEnsoNumberNode, + @Cached SubtractNode delegate) { + return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode)); + } + @Fallback double doOther(double self, Object that) { - return handleOther(self, that); + throw panicOtherwise(self, that); } } diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java b/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java index 5782867db2e7..d0e19fa40ff3 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/BinaryOpFloatTest.java @@ -85,7 +85,7 @@ public void verifyOperationOnForeignObject() { var r1 = execute(fn, n1, n2); - var wrap2 = n2; //ctx.asValue(new WrappedPrimitive(n2)); + var wrap2 = ctx.asValue(new WrappedPrimitive(n2)); var r2 = execute(fn, n1, wrap2); assertSameResult(r1, r2); diff --git a/test/Tests/src/Semantic/Conversion_Spec.enso b/test/Tests/src/Semantic/Conversion_Spec.enso index 35f36848651e..40a52c6b40e7 100644 --- a/test/Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Tests/src/Semantic/Conversion_Spec.enso @@ -233,6 +233,27 @@ spec = do_number 42 + Test.specify "Requesting Decimal & Fool" <| + do_number (x : Decimal & Fool) = + x.foo . should_equal "foo called" + x.fool . should_equal 42.3 + x==x . should_be_true + (x:Decimal)==42.3 . should_be_true + (x:Fool)==42.3 . should_be_false + x==42.3 . should_be_true + 42.3==(x.to Decimal) . should_be_true + 42.3==(x.to Fool) . should_be_false + 42.3==x . should_be_true + 100+(x:Decimal) . should_equal 142.3 + (x:Decimal)+100 . should_equal 142.3 + x+100 . should_equal 142.3 + 100+x . should_equal 142.3 + x.to_text . should_equal "{FOOL 42.3}" + (x:Fool).to_text . should_equal "{FOOL 42.3}" + (x:Decimal).to_text . should_equal "42.3" + + do_number 42.3 + Test.specify "Requesting Boolean & Fool" <| do_boolean (x : Boolean & Fool) = x.fool . should_equal True From 04a1d14fc5b37af2fc7f5892387124fb72fa06d1 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 09:47:41 +0200 Subject: [PATCH 20/21] Removing notes on \ --- docs/syntax/types.md | 4 ---- docs/types/hierarchy.md | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/syntax/types.md b/docs/syntax/types.md index b680e066f2a8..d0379c1e0c40 100644 --- a/docs/syntax/types.md +++ b/docs/syntax/types.md @@ -87,7 +87,6 @@ working with types. These are listed below. | `;` | `< :`, `> =` | -2 | Left | Concatenates the left and right operand typesets to create a new typeset. | | `\|` | `> <:`, `> !`, `> in`, `> :` | 5 | Left | Computes the union of the left and right operand typesets. | | `&` | `> \|` | 6 | Left | Computes the intersection of the left and right operand typesets. | -| `\` | `> &` | 7 | Left | Computes the subtraction of the right typeset from the left typeset. | | `:=` | `< :`, `> =`, `> ;` | -1 | Left | Creates a typeset member by assigning a value to a label. | @@ -108,7 +107,6 @@ bind (`=`) has a relative level of -3 in this ordering. (declare-fun tsConcat () Int) ; `;` (declare-fun tsUnion () Int) ; `|` (declare-fun tsInter () Int) ; `&` -(declare-fun minus () Int) ; `\` (declare-fun tsMember () Int) ; `:=` (assert (> ascrip bind)) @@ -265,8 +263,6 @@ of typesets. Their syntax is as follows: arguments. - **Intersection - `&`:** The resultant typeset may contain values that are members of _both_ its arguments. -- **Subtraction - `\`:** The resultant typeset may contain values that are in - the first argument's set but not in the second. > The actionables for this section are: > diff --git a/docs/types/hierarchy.md b/docs/types/hierarchy.md index 8dd5d7cbd461..9b119bec5921 100644 --- a/docs/types/hierarchy.md +++ b/docs/types/hierarchy.md @@ -194,10 +194,8 @@ They are as follows: product types. - **Union - `|`:** This operator creates a typeset that contains the members in the union of its operands. -- **Intersection - `|`:** This operator creates a typeset that contains the +- **Intersection - `&`:** This operator creates a typeset that contains the members in the intersection of its operands. -- **Subtraction - `\`:** This operator creates a typeset that contains all of - the members in the left operand that do not occur in the right operand. For information on the syntactic usage of these operators, please see the section on [type operators](#../syntax/types.md#type-operators) in the syntax From 8954f5c9214c8dec51bd2937b384d7540f3c0ec3 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Thu, 14 Sep 2023 10:03:45 +0200 Subject: [PATCH 21/21] Reusing Type from Pair returned by the resolveFor method --- .../node/callable/InvokeMethodNode.java | 7 ++++--- .../runtime/callable/UnresolvedSymbol.java | 21 ++----------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java index b274e947420e..4f96ae979aaa 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/callable/InvokeMethodNode.java @@ -353,9 +353,10 @@ Function resolveWarningFunction( e); } - Type typeOfSymbol = symbol.resolveDeclaringType(this, types.getType(selfWithoutWarnings)); - Builtins builtins = EnsoContext.get(this).getBuiltins(); - if (typeOfSymbol == builtins.any()) { + var selfType = types.getType(selfWithoutWarnings); + var fnAndType = symbol.resolveFor(this, selfType); + var builtins = EnsoContext.get(this).getBuiltins(); + if (fnAndType != null && fnAndType.getRight() == builtins.any()) { return symbol .getScope() .lookupMethodDefinition(builtins.warning().getEigentype(), symbol.getName()); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java index 10a7d35a28a8..ea9034b9ee40 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/callable/UnresolvedSymbol.java @@ -62,28 +62,11 @@ public ModuleScope getScope() { * @return the resolved function definition and type it was resolved in, or null if not found */ public Pair resolveFor(Node node, Type type) { - for (var current : type.allTypes(EnsoContext.get(node))) { - Function candidate = scope.lookupMethodDefinition(current, name); - if (candidate != null) { - return Pair.create(candidate, current); - } - } - return null; - } - - /** - * Resolves the type where the symbol is declared. - * - * @param type the type for which this symbol should be resolved - * @return the resolved function definition, or null if not found - */ - public Type resolveDeclaringType(Node node, Type type) { - var ctx = EnsoContext.get(node); if (type != null) { - for (var current : type.allTypes(ctx)) { + for (var current : type.allTypes(EnsoContext.get(node))) { Function candidate = scope.lookupMethodDefinition(current, name); if (candidate != null) { - return current; + return Pair.create(candidate, current); } } }