From 792cbc448c04e7d3c086c23a329b2ab2ecc584c2 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 24 May 2023 20:42:24 +0200 Subject: [PATCH] Clearly select single specialization with enum dispatch pattern (#6819) --- .../expression/builtin/meta/TypeOfNode.java | 287 +++++++++++------- test/Tests/src/Semantic/Case_Spec.enso | 19 +- test/Tests/src/Semantic/Meta_Spec.enso | 3 +- 3 files changed, 193 insertions(+), 116 deletions(-) diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfNode.java index 44a53e70b342..6ff15727c328 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfNode.java @@ -1,28 +1,28 @@ package org.enso.interpreter.node.expression.builtin.meta; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Fallback; -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 org.enso.interpreter.dsl.AcceptsError; import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.epb.runtime.PolyglotProxy; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.builtin.Builtins; import org.enso.interpreter.runtime.callable.UnresolvedSymbol; -import org.enso.interpreter.runtime.data.text.Text; +import org.enso.interpreter.runtime.data.Type; import org.enso.interpreter.runtime.error.DataflowError; import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.error.PanicSentinel; -import org.enso.interpreter.runtime.error.Warning; import org.enso.interpreter.runtime.error.WithWarnings; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; import org.enso.interpreter.runtime.number.EnsoBigInteger; +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.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; + @BuiltinMethod( type = "Meta", name = "type_of", @@ -77,102 +77,14 @@ Object doWarning(WithWarnings value) { return execute(value.getValue()); } - @Specialization( - guards = { - "interop.hasArrayElements(proxy)", - "!interop.isString(proxy)", // R string value is an array and a string - "!types.hasType(proxy)", - "!interop.hasMetaObject(proxy)" - }) - Object doPolyglotArray( - PolyglotProxy proxy, - @CachedLibrary(limit = "3") InteropLibrary interop, - @CachedLibrary(limit = "3") TypesLibrary types) { - return EnsoContext.get(this).getBuiltins().array(); - } - - @Specialization( - guards = { - "interop.isString(proxy)", - "!types.hasType(proxy)", - "!interop.hasMetaObject(proxy)" - }) - Object doPolyglotString( - PolyglotProxy proxy, - @CachedLibrary(limit = "3") InteropLibrary interop, - @CachedLibrary(limit = "3") TypesLibrary types) { - return EnsoContext.get(this).getBuiltins().text(); - } - - @Specialization( - guards = { - "interop.isNumber(proxy)", - "!types.hasType(proxy)", - "!interop.hasMetaObject(proxy)" - }) - Object doPolyglotNumber( - PolyglotProxy proxy, - @CachedLibrary(limit = "3") InteropLibrary interop, - @CachedLibrary(limit = "3") TypesLibrary types) { - Builtins builtins = EnsoContext.get(this).getBuiltins(); - if (interop.fitsInInt(proxy)) { - return builtins.number().getInteger(); - } else if (interop.fitsInDouble(proxy)) { - return builtins.number().getDecimal(); - } else { - return EnsoContext.get(this).getBuiltins().number(); - } - } - - @Specialization(guards = {"interop.isTime(value)", "interop.isDate(value)"}) - Object doDateTime(Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { - return EnsoContext.get(this).getBuiltins().dateTime(); - } - - @Specialization( - guards = {"interop.isTimeZone(value)", "!interop.isDate(value)", "!interop.isTime(value)"}) - Object doTimeZone(Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { - EnsoContext ctx = EnsoContext.get(this); - return ctx.getBuiltins().timeZone(); - } - - @Specialization(guards = {"interop.isDate(value)", "!interop.isTime(value)"}) - Object doDate(Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { - EnsoContext ctx = EnsoContext.get(this); - return ctx.getBuiltins().date(); - } - - @Specialization(guards = {"interop.isTime(value)", "!interop.isDate(value)"}) - Object doTime(Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { - EnsoContext ctx = EnsoContext.get(this); - return ctx.getBuiltins().timeOfDay(); - } - - @Specialization(guards = "interop.isDuration(value)") - Object doDuration(Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { - EnsoContext ctx = EnsoContext.get(this); - return ctx.getBuiltins().duration(); - } - - @Specialization( - guards = { - "interop.hasMetaObject(value)", - "!types.hasType(value)", - "!interop.isDate(value)", - "!interop.isTime(value)", - "!interop.isTimeZone(value)" - }) - Object doMetaObject( + @Specialization(guards = {"!types.hasType(value)"}) + Object withoutType( Object value, @CachedLibrary(limit = "3") InteropLibrary interop, - @CachedLibrary(limit = "3") TypesLibrary types) { - try { - return interop.getMetaObject(value); - } catch (UnsupportedMessageException e) { - CompilerDirectives.transferToInterpreter(); - Builtins builtins = EnsoContext.get(this).getBuiltins(); - throw new PanicException(builtins.error().makeCompileError("invalid meta object"), this); - } + @CachedLibrary(limit = "3") TypesLibrary types, + @Cached WithoutType delegate) { + var type = WithoutType.Interop.resolve(value, interop); + return delegate.execute(type, value); } @Specialization(guards = {"types.hasType(value)", "!interop.isNumber(value)"}) @@ -193,4 +105,169 @@ Object doAny(Object value) { .makeCompileError("unknown type_of for " + value), this); } + + @GenerateUncached + abstract static class WithoutType extends Node { + abstract Object execute(Interop op, Object value); + + @Specialization(guards = {"type.isArray()"}) + Type doPolyglotArray(Interop type, Object value) { + return EnsoContext.get(this).getBuiltins().array(); + } + + @Specialization(guards = {"type.isString()"}) + Type doPolyglotString(Interop type, Object value) { + return EnsoContext.get(this).getBuiltins().text(); + } + + @Specialization(guards = {"type.isNumber()"}) + Type doPolyglotNumber( + Interop type, Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { + Builtins builtins = EnsoContext.get(this).getBuiltins(); + if (interop.fitsInInt(value)) { + return builtins.number().getInteger(); + } else if (interop.fitsInDouble(value)) { + return builtins.number().getDecimal(); + } else { + return EnsoContext.get(this).getBuiltins().number().getNumber(); + } + } + + @Specialization(guards = {"type.isDateTime()"}) + Type doDateTime(Interop type, Object value) { + return EnsoContext.get(this).getBuiltins().dateTime(); + } + + @Specialization(guards = {"type.isTimeZone()"}) + Type doTimeZone(Interop type, Object value) { + EnsoContext ctx = EnsoContext.get(this); + return ctx.getBuiltins().timeZone(); + } + + @Specialization(guards = {"type.isDate()"}) + Type doDate(Interop type, Object value) { + + EnsoContext ctx = EnsoContext.get(this); + return ctx.getBuiltins().date(); + } + + @Specialization(guards = {"type.isTime()"}) + Type doTime(Interop type, Object value) { + + EnsoContext ctx = EnsoContext.get(this); + return ctx.getBuiltins().timeOfDay(); + } + + @Specialization(guards = "type.isDuration()") + Type doDuration(Interop type, Object value) { + EnsoContext ctx = EnsoContext.get(this); + return ctx.getBuiltins().duration(); + } + + @Specialization(guards = {"type.isMetaObject()"}) + Object doMetaObject( + Interop type, Object value, @CachedLibrary(limit = "3") InteropLibrary interop) { + try { + return interop.getMetaObject(value); + } catch (UnsupportedMessageException e) { + CompilerDirectives.transferToInterpreter(); + Builtins builtins = EnsoContext.get(this).getBuiltins(); + throw new PanicException(builtins.error().makeCompileError("invalid meta object"), this); + } + } + + @Fallback + @CompilerDirectives.TruffleBoundary + Object doAny(Interop any, Object value) { + return DataflowError.withoutTrace( + EnsoContext.get(this) + .getBuiltins() + .error() + .makeCompileError("unknown type_of for " + value), + this); + } + + enum Interop { + NONE, + STRING, + NUMBER, + ARRAY, + DATE_TIME, + TIME_ZONE, + DATE, + TIME, + DURATION, + META_OBJECT; + + static Interop resolve(Object value, InteropLibrary interop) { + if (interop.isString(value)) { + return STRING; + } + if (interop.isNumber(value)) { + return NUMBER; + } + if (interop.hasArrayElements(value)) { + return ARRAY; + } + boolean time = interop.isTime(value); + boolean date = interop.isDate(value); + if (time) { + return date ? DATE_TIME : TIME; + } + if (date) { + return DATE; + } + if (interop.isTimeZone(value)) { + return TIME_ZONE; + } + if (interop.isDuration(value)) { + return DURATION; + } + if (interop.hasMetaObject(value)) { + return META_OBJECT; + } + return NONE; + } + + boolean isString() { + return this == STRING; + } + + boolean isNumber() { + return this == NUMBER; + } + + boolean isArray() { + return this == ARRAY; + } + + boolean isDateTime() { + return this == DATE_TIME; + } + + boolean isTimeZone() { + return this == TIME_ZONE; + } + + boolean isTime() { + return this == TIME; + } + + boolean isDate() { + return this == DATE; + } + + boolean isDuration() { + return this == DURATION; + } + + boolean isMetaObject() { + return this == META_OBJECT; + } + + boolean isNone() { + return this == NONE; + } + } + } } diff --git a/test/Tests/src/Semantic/Case_Spec.enso b/test/Tests/src/Semantic/Case_Spec.enso index 4d2bed696403..73a14553bbd3 100644 --- a/test/Tests/src/Semantic/Case_Spec.enso +++ b/test/Tests/src/Semantic/Case_Spec.enso @@ -257,18 +257,17 @@ spec = Test.group "Pattern Matches" <| _ -> Test.fail "Expected to match on ArrayList type." case Meta.type_of list of - _ : Vector -> Test.fail "Expected to match in java.lang.Class case." - _ : Array -> Test.fail "Expected to match in java.lang.Class case." - _ : ArrayList -> Test.fail "Expected to match in java.lang.Class case." - _ : Class -> Nothing - _ : ArrayList -> Test.fail "Expected to match in java.lang.Class case." + _ : Vector -> Test.fail "Expected to match Array case." + _ : ArrayList -> Test.fail "Expected to match Array case." + _ : Class -> Test.fail "Expected to match Array case." + Array -> Nothing + _ -> Test.fail "Expected to match Array case." case Meta.type_of list of - Vector -> Test.fail "Expected to match on a polyglot symbol." - Array -> Test.fail "Expected to match on a polyglot symbol." - ArrayList -> Nothing - Class -> Test.fail "Expected to match on a polyglot symbol." - _ -> Test.fail "Expected to match on a polyglot symbol." + Vector -> Test.fail "Expected to match Array case." + Class -> Test.fail "Expected to match Array case." + Array -> Nothing + _ -> Test.fail "Expected to match Array case." # Tests a bug where array matching a polyglot Object[] array would fail if the same branch mis-matched earlier. foo x = case x of diff --git a/test/Tests/src/Semantic/Meta_Spec.enso b/test/Tests/src/Semantic/Meta_Spec.enso index 7561097b6e44..c4f6eb612118 100644 --- a/test/Tests/src/Semantic/Meta_Spec.enso +++ b/test/Tests/src/Semantic/Meta_Spec.enso @@ -194,7 +194,8 @@ spec = list.add 123 list_tpe = Meta.type_of list list_tpe . should_not_equal_type JObject - list_tpe . should_equal_type ArrayList + list_tpe . should_not_equal_type ArrayList + list_tpe . should_equal_type Array e = IOException.new "meh" e_tpe = Meta.type_of e