From b7e55e7997b745990a3ceb9f71de3d9153fc44dd Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 10 Feb 2025 05:23:21 +0100 Subject: [PATCH] case boolean of can be performed on non-primitive booleans --- .../org/enso/interpreter/test/CaseOfTest.java | 72 +++++++++++++++++++ .../caseexpr/BooleanBranchNode.java | 25 ++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/CaseOfTest.java diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/CaseOfTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/CaseOfTest.java new file mode 100644 index 000000000000..5ee7e9f610fe --- /dev/null +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/CaseOfTest.java @@ -0,0 +1,72 @@ +package org.enso.interpreter.test; + +import static org.junit.Assert.assertEquals; + +import org.enso.interpreter.runtime.EnsoContext; +import org.enso.interpreter.runtime.data.EnsoMultiValue; +import org.enso.interpreter.runtime.data.Type; +import org.enso.test.utils.ContextUtils; +import org.graalvm.polyglot.Context; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CaseOfTest { + private static Context ctx; + private static EnsoContext leak; + + @BeforeClass + public static void initCtx() throws Exception { + ctx = ContextUtils.createDefaultContext(); + leak = ContextUtils.leakContext(ctx); + } + + @AfterClass + public static void closeCtx() { + ctx.close(); + ctx = null; + leak = null; + } + + @Test + public void caseOfBoolean() { + doCaseOfBoolean(true, false); + } + + @Test + public void caseOfInteropBoolean() { + var t = new WrappedPrimitive(true); + var f = new WrappedPrimitive(false); + doCaseOfBoolean(t, f); + } + + @Test + public void caseOfMultiValueBoolean() { + var n = EnsoMultiValue.NewNode.getUncached(); + + var bAndT = + new Type[] {leak.getBuiltins().bool().getType(), leak.getBuiltins().number().getInteger()}; + var t = n.newValue(bAndT, 2, 0, new Object[] {true, 300}); + var f = n.newValue(bAndT, 2, 0, new Object[] {false, 200}); + doCaseOfBoolean(t, f); + } + + private void doCaseOfBoolean(Object t, Object f) { + var code = + """ + from Standard.Base import True, False + + choose v = case v of + True -> 1 + False -> 2 + _ -> 3 + """; + + var choose = ContextUtils.evalModule(ctx, code, "choose.enso", "choose"); + + var one = choose.execute(t); + assertEquals("With " + t + " we should get 1", 1, one.asInt()); + var two = choose.execute(f); + assertEquals("With " + f + " we should get 2", 2, two.asInt()); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/BooleanBranchNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/BooleanBranchNode.java index ad82c644d3d3..2cb67c34476e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/BooleanBranchNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/BooleanBranchNode.java @@ -4,8 +4,12 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.CountingConditionProfile; +import org.enso.interpreter.runtime.EnsoContext; /** An implementation of the case expression specialised to working on booleans. */ @NodeInfo(shortName = "BooleanMatch") @@ -31,12 +35,31 @@ public static BooleanBranchNode build( } @Specialization - void doAtom(VirtualFrame frame, Object state, boolean target) { + void doBoolean(VirtualFrame frame, Object state, boolean target) { if (profile.profile(matched == target)) { accept(frame, state, new Object[0]); } } + @Specialization( + guards = {"iop.isBoolean(target)"}, + limit = "3") + void doInterop( + VirtualFrame frame, + Object state, + Object target, + @CachedLibrary("target") InteropLibrary iop) { + try { + var value = iop.asBoolean(target); + if (profile.profile(matched == value)) { + accept(frame, state, new Object[0]); + } + } catch (UnsupportedMessageException ex) { + var ctx = EnsoContext.get(this); + throw ctx.raiseAssertionPanic(this, null, ex); + } + } + @Fallback void doFallback(VirtualFrame frame, Object state, Object target) {} }