diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso index 3a0e732095f29..ada8f9b43efc4 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso @@ -270,6 +270,17 @@ Any.is_a self typ = is_a self typ Any.is_an : Any -> Boolean Any.is_an self typ = is_a self typ +## UNSTABLE + ADVANCED + PRIVATE + + Checks if `self` type matches `typ` type. + + Arguments: + - typ: The type to check `self` against. +Any.is_of_type : Any -> Boolean +Any.is_of_type self typ = is_of_type self typ + ## UNSTABLE ADVANCED @@ -303,12 +314,17 @@ is_a value typ = if is_same_object value typ then True else if typ == Any then True else if is_error value then typ == Base.Error else case value of - Array -> typ == Array + Vector.Vector -> typ.is_of_type Vector.Vector + Array -> typ.is_of_type Array Boolean -> if typ == Boolean then True else value == typ Text -> typ == Text Number -> if typ == Number then True else case value of Integer -> typ == Integer Decimal -> typ == Decimal + Date_Time.Date_Time -> typ.is_of_type Date_Time.Date_Time + Date.Date -> typ.is_of_type Date.Date + Time_Of_Day.Time_Of_Day -> typ.is_of_type Time_Of_Day.Time_Of_Day + Time_Zone.Time_Zone -> typ.is_of_type Time_Zone.Time_Zone Base.Polyglot -> typ==Base.Polyglot || java_instance_check value typ _ -> @@ -354,24 +370,27 @@ type_of : Any -> Any type_of value = if is_error value then Base.Error else case value of - Base.Polyglot -> Meta.type_of_polyglot_builtin value Integer -> Integer Decimal -> Decimal Number -> Number _ -> Meta.type_of_builtin value -## PRIVATE +## UNSTABLE + ADVANCED + PRIVATE - Returns the type of the polyglot value. + Checks if the given type agrees with the expected one Arguments: - - value: the value to get the type of. -type_of_polyglot_builtin value = @Builtin_Method "Meta.type_of_polyglot_builtin" + - tpe: the type to check + - expected: the expected type +is_of_type : Any -> Any -> Boolean +is_of_type tpe expected = @Builtin_Method "Meta.is_of_type_builtin" ## PRIVATE - A builtin method returning the type of a non-polyglot value. + A builtin method returning the type of a (polyglot or non-polyglot) value. Arguments: - value: the value to get the type of. diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsOfTypeMetaNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsOfTypeMetaNode.java new file mode 100644 index 0000000000000..a607a592d88b3 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsOfTypeMetaNode.java @@ -0,0 +1,38 @@ +package org.enso.interpreter.node.expression.builtin.meta; + +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.BranchProfile; +import org.enso.interpreter.Constants; +import org.enso.interpreter.dsl.BuiltinMethod; +import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.builtin.Builtins; +import org.enso.interpreter.runtime.error.PanicException; +import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; + +@BuiltinMethod( + type = "Meta", + name = "is_of_type_builtin", + description = "Checks if the given type matches the expected type.") +public class IsOfTypeMetaNode extends Node { + private @Child TypesLibrary types = + TypesLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); + private @Child + InteropLibrary library = + InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); + private final BranchProfile err = BranchProfile.create(); + + Object execute(Object tpe, Object expected) { + if (library.isMetaObject(tpe) && library.isMetaObject(expected)) { + return library.isIdentical(tpe, expected, InteropLibrary.getUncached()); + } else { + if (types.hasType(tpe) && types.hasType(expected)) { + return types.getType(tpe) == types.getType(expected); + } else { + Context ctx = Context.get(this); + return false; + } + } + } +} 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 436a9122e1853..39c5bdda0baf1 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,10 +1,14 @@ package org.enso.interpreter.node.expression.builtin.meta; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.Context; +import org.enso.interpreter.runtime.builtin.Builtins; +import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.library.dispatch.TypesLibrary; @BuiltinMethod( @@ -12,16 +16,30 @@ name = "type_of_builtin", description = "Returns the type of a value.") public class TypeOfNode extends Node { + private @Child + InteropLibrary library = + InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private @Child TypesLibrary types = TypesLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); private final BranchProfile err = BranchProfile.create(); Object execute(Object value) { - if (types.hasType(value)) { - return types.getType(value); + if (library.hasMetaObject(value)) { + try { + return library.getMetaObject(value); + } catch (UnsupportedMessageException e) { + err.enter(); + Builtins builtins = Context.get(this).getBuiltins(); + throw new PanicException( + builtins.error().makeTypeError(builtins.any(), value, "object"), this); + } } else { - Context ctx = Context.get(this); - return ctx.getBuiltins().any(); + if (types.hasType(value)) { + return types.getType(value); + } else { + Context ctx = Context.get(this); + return ctx.getBuiltins().any(); + } } } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfPolyglotNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfPolyglotNode.java deleted file mode 100644 index 3983e5472e9e9..0000000000000 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/TypeOfPolyglotNode.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.enso.interpreter.node.expression.builtin.meta; - -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.BranchProfile; -import org.enso.interpreter.Constants; -import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.runtime.Context; -import org.enso.interpreter.runtime.builtin.Builtins; -import org.enso.interpreter.runtime.error.PanicException; - -@BuiltinMethod( - type = "Meta", - name = "type_of_polyglot_builtin", - description = "Returns the type of a polyglot value.") -public class TypeOfPolyglotNode extends Node { - private @Child InteropLibrary library = - InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); - private final BranchProfile err = BranchProfile.create(); - - Object execute(Object value) { - if (library.hasMetaObject(value)) { - try { - return library.getMetaObject(value); - } catch (UnsupportedMessageException e) { - err.enter(); - Builtins builtins = Context.get(this).getBuiltins(); - throw new PanicException( - builtins.error().makeTypeError(builtins.any(), value, "object"), this); - } - } else { - Context ctx = Context.get(this); - return ctx.getBuiltins().any(); - } - } -} 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 c8c6befc2b26a..85a61b165880a 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 @@ -10,67 +10,29 @@ import org.enso.compiler.data.{BindingsMap, CompilerConfig} import org.enso.compiler.exception.{BadPatternMatch, CompilerError} import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{Scope => AliasScope} import org.enso.compiler.pass.analyse.AliasAnalysis.{Graph => AliasGraph} -import org.enso.compiler.pass.analyse.{ - AliasAnalysis, - BindingAnalysis, - DataflowAnalysis, - TailCall -} +import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis, DataflowAnalysis, TailCall} import org.enso.compiler.pass.optimise.ApplicationSaturation -import org.enso.compiler.pass.resolve.{ - ExpressionAnnotations, - GlobalNames, - MethodDefinitions, - Patterns -} +import org.enso.compiler.pass.resolve.{ExpressionAnnotations, GlobalNames, MethodDefinitions, Patterns} import org.enso.interpreter.epb.EpbParser import org.enso.interpreter.node.callable.argument.ReadArgumentNode -import org.enso.interpreter.node.callable.function.{ - BlockNode, - CreateFunctionNode -} +import org.enso.interpreter.node.callable.function.{BlockNode, CreateFunctionNode} import org.enso.interpreter.node.callable.thunk.{CreateThunkNode, ForceNode} -import org.enso.interpreter.node.callable.{ - ApplicationNode, - InvokeCallableNode, - SequenceLiteralNode -} +import org.enso.interpreter.node.callable.{ApplicationNode, InvokeCallableNode, SequenceLiteralNode} import org.enso.interpreter.node.controlflow.caseexpr._ -import org.enso.interpreter.node.expression.atom.{ - ConstantNode, - QualifiedAccessorNode -} +import org.enso.interpreter.node.expression.atom.{ConstantNode, QualifiedAccessorNode} import org.enso.interpreter.node.expression.constant._ import org.enso.interpreter.node.expression.foreign.ForeignMethodCallNode import org.enso.interpreter.node.expression.literal.LiteralNode import org.enso.interpreter.node.scope.{AssignmentNode, ReadLocalVariableNode} -import org.enso.interpreter.node.{ - BaseNode, - ClosureRootNode, - MethodRootNode, - ExpressionNode => RuntimeExpression -} +import org.enso.interpreter.node.{BaseNode, ClosureRootNode, MethodRootNode, ExpressionNode => RuntimeExpression} import org.enso.interpreter.runtime.Context -import org.enso.interpreter.runtime.callable.{ - UnresolvedConversion, - UnresolvedSymbol -} -import org.enso.interpreter.runtime.callable.argument.{ - ArgumentDefinition, - CallArgument -} +import org.enso.interpreter.runtime.callable.{UnresolvedConversion, UnresolvedSymbol} +import org.enso.interpreter.runtime.callable.argument.{ArgumentDefinition, CallArgument} import org.enso.interpreter.runtime.callable.atom.Atom import org.enso.interpreter.runtime.callable.atom.AtomConstructor -import org.enso.interpreter.runtime.callable.function.{ - FunctionSchema, - Function => RuntimeFunction -} +import org.enso.interpreter.runtime.callable.function.{FunctionSchema, Function => RuntimeFunction} import org.enso.interpreter.runtime.data.text.Text -import org.enso.interpreter.runtime.scope.{ - FramePointer, - LocalScope, - ModuleScope -} +import org.enso.interpreter.runtime.scope.{FramePointer, LocalScope, ModuleScope} import org.enso.interpreter.{Constants, Language} import java.math.BigInteger diff --git a/test/Tests/src/Semantic/Meta_Spec.enso b/test/Tests/src/Semantic/Meta_Spec.enso index 2f116b144e42a..e53fb4469f939 100644 --- a/test/Tests/src/Semantic/Meta_Spec.enso +++ b/test/Tests/src/Semantic/Meta_Spec.enso @@ -50,6 +50,8 @@ spec = Test.group "Meta-Value Manipulation" <| Array.is_an Array . should_be_true [].to_array.is_an Array . should_be_true [].to_array.is_a Decimal . should_be_false + [1,2,3].is_a Vector.Vector . should_be_true + [1,2,3].is_a Array . should_be_false Boolean.is_a Boolean . should_be_true True.is_a Boolean . should_be_true @@ -69,6 +71,8 @@ spec = Test.group "Meta-Value Manipulation" <| 1.0.is_an Integer . should_be_false 1.0.is_a Text . should_be_false + + random_gen = Random.new Meta.is_a random_gen Polyglot . should_be_true Meta.is_an random_gen Integer . should_be_false @@ -84,6 +88,15 @@ spec = Test.group "Meta-Value Manipulation" <| Meta.is_an err Error . should_be_true Meta.is_a err Text . should_be_false + Meta.is_a Date.now Date.Date . should_be_true + Meta.is_a Date_Time.now Date_Time.Date_Time . should_be_true + Meta.is_a Date_Time.now Date.Date . should_be_false + Meta.is_a Time_Of_Day.now Time_Of_Day.Time_Of_Day . should_be_true + Meta.is_a Time_Of_Day.now Date.Date . should_be_false + Meta.is_a Date_Time.now.zone Time_Zone.Time_Zone . should_be_true + Meta.is_a Date_Time.now.zone Date.Date . should_be_false + + Test.specify "should allow for returning the type of a value" <| Meta.type_of 42 . should_equal Integer Meta.type_of 2.81 . should_equal Decimal @@ -91,8 +104,11 @@ spec = Test.group "Meta-Value Manipulation" <| # Can't compare like # Meta.type_of [1,2,3] . should_equal Vector.Vector - # because it tries to compare lengths, where RHS is a type - Meta.is_a (Meta.type_of [1,2,3]) Vector.Vector . should_be_true + # because equality check tries to compare lengths, where RHS is a type + v_tpe = Meta.type_of [1,2,3] + v_tpe.is_of_type Vector.Vector . should_be_true + v_tpe.is_of_type Array . should_be_false + [1,2,3].to_array.is_of_type Array . should_be_true Meta.type_of "foo" . should_equal Text Meta.type_of "0" . should_not_equal Integer @@ -100,30 +116,35 @@ spec = Test.group "Meta-Value Manipulation" <| Meta.type_of True . should_equal Boolean Meta.type_of False . should_not_equal Any - Meta.is_a (Meta.type_of Date.now) Date.Date . should_be_true - Meta.is_a (Meta.type_of Date_Time.now) Date_Time.Date_Time . should_be_true - Meta.is_a (Meta.type_of Date_Time.now) Date.Date . should_be_false - Meta.is_a (Meta.type_of Time_Of_Day.now) Time_Of_Day.Time_Of_Day . should_be_true - Meta.is_a (Meta.type_of Time_Of_Day.now) Date.Date . should_be_false - Meta.is_a (Meta.type_of Date_Time.now.zone) Time_Zone.Time_Zone . should_be_true - Meta.is_a (Meta.type_of Date_Time.now.zone) Date.Date . should_be_false + (Meta.type_of Date.now).is_of_type Date.Date . should_be_true + (Meta.type_of Date.now).is_of_type Date_Time.Date_Time . should_be_false + (Meta.type_of Date_Time.now).is_of_type Date_Time.Date_Time . should_be_true + (Meta.type_of Date_Time.now).is_of_type Date.Date . should_be_false + (Meta.type_of Time_Of_Day.now).is_of_type Time_Of_Day.Time_Of_Day . should_be_true + (Meta.type_of Time_Of_Day.now).is_of_type Date.Date . should_be_false + (Meta.type_of Date_Time.now.zone).is_of_type Time_Zone.Time_Zone . should_be_true + (Meta.type_of Date_Time.now.zone).is_of_type Date.Date . should_be_false list = ArrayList.new list.add 123 - Meta.type_of list . should_not_equal JObject - Meta.type_of list . should_equal ArrayList + list_tpe = Meta.type_of list + list_tpe . should_not_equal JObject + list_tpe . should_equal ArrayList + list_tpe.is_of_type ArrayList . should_be_true e = IOException.new "meh" - Meta.type_of list . should_not_equal JObject - Meta.type_of e . should_equal IOException - Meta.type_of e . should_not_equal JException + e_tpe = Meta.type_of e + e_tpe . should_equal IOException + e_tpe . should_not_equal JException + e_tpe.is_of_type IOException . should_be_true + e_tpe.is_of_type JException . should_be_false location_pending = case Platform.os of Platform.Windows -> "This test is disabled on Windows until issue 1561 is fixed." _ -> Nothing Test.specify "should allow to get the source location of a frame" pending=location_pending <| src = Meta.get_source_location 0 - loc = "Meta_Spec.enso:125:15-40" + loc = "Meta_Spec.enso:146:15-40" src.take (Last loc.length) . should_equal loc Test.specify "should allow to get qualified type names of values" <|