diff --git a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/AutoscopedConstructorTest.java b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/AutoscopedConstructorTest.java index a50de81e72..41515e2c0e 100644 --- a/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/AutoscopedConstructorTest.java +++ b/engine/runtime-integration-tests/src/test/java/org/enso/interpreter/test/AutoscopedConstructorTest.java @@ -1,5 +1,7 @@ package org.enso.interpreter.test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -267,4 +269,68 @@ public class AutoscopedConstructorTest { e.getMessage().contains("Type_Error")); } } + + @Test + public void simpleAnyCheck() { + var code = + """ + import Standard.Base.Any.Any + + type A + Typed x:Any + + t = ..Typed ..My_Other + materialize v:A = v + + create = materialize t + """; + + var create = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create"); + + assertEquals("A", create.getMetaObject().getMetaSimpleName()); + } + + @Test + public void simpleAnyOrACheck() { + var code = + """ + import Standard.Base.Any.Any + + type A + Typed (x:Any|A) + + t = ..Typed ..My_Other + materialize v:A = v + + create = materialize t + """; + + var create = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create"); + + assertEquals("A", create.getMetaObject().getMetaSimpleName()); + } + + @Test + public void intersectionAnyOrACheck() { + var code = + """ + import Standard.Base.Any.Any + + type A + Typed (x:Any&A) + + t = ..Typed ..My_Other + materialize v:A = v + + create = materialize t + """; + + try { + var create = + ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create"); + fail("Got value, but expecting an exception: " + create); + } catch (PolyglotException ex) { + assertThat(ex.getMessage(), containsString("Cannot find constructor ..My_Other among A.")); + } + } } 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 5813b1436d..0d7bec80bd 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 @@ -157,7 +157,8 @@ public abstract class ReadArgumentCheckNode extends Node { }; } - public static ReadArgumentCheckNode build(String comment, Type expectedType) { + public static ReadArgumentCheckNode build(EnsoContext ctx, String comment, Type expectedType) { + assert ctx.getBuiltins().any() != expectedType : "Don't check for Any: " + expectedType; return ReadArgumentCheckNodeFactory.TypeCheckNodeGen.create(comment, expectedType); } @@ -423,6 +424,9 @@ public abstract class ReadArgumentCheckNode extends Node { if (v instanceof EnsoMultiValue multi) { return multi.allTypes(); } + if (v instanceof UnresolvedConstructor) { + return null; + } if (typeOfNode.execute(v) instanceof Type from) { if (previous != null && previous.length == 1 && previous[0] == from) { return previous; diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala index 3e1c71f588..9cf7ea48c7 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala @@ -752,10 +752,15 @@ class IrToTruffle( t: Expression ): ReadArgumentCheckNode = t match { case u: `type`.Set.Union => - ReadArgumentCheckNode.oneOf( - comment, - u.operands.map(extractAscribedType(comment, _)).asJava - ) + val oneOf = u.operands.map(extractAscribedType(comment, _)) + if (oneOf.contains(null)) { + null + } else { + ReadArgumentCheckNode.oneOf( + comment, + oneOf.asJava + ) + } case i: `type`.Set.Intersection => ReadArgumentCheckNode.allOf( comment, @@ -765,6 +770,7 @@ class IrToTruffle( case p: Application.Prefix => extractAscribedType(comment, p.function) case _: Tpe.Function => ReadArgumentCheckNode.build( + context, comment, context.getTopScope().getBuiltins().function() ) @@ -780,10 +786,12 @@ class IrToTruffle( BindingsMap .Resolution(binding @ BindingsMap.ResolvedType(_, _)) ) => - ReadArgumentCheckNode.build( - comment, - asType(binding) - ) + val typeOrAny = asType(binding) + if (context.getBuiltins().any() == typeOrAny) { + null + } else { + ReadArgumentCheckNode.build(context, comment, typeOrAny) + } case Some( BindingsMap .Resolution(BindingsMap.ResolvedPolyglotSymbol(mod, symbol)) diff --git a/test/Base_Tests/src/Semantic/Conversion_Spec.enso b/test/Base_Tests/src/Semantic/Conversion_Spec.enso index b42d5bd142..be4b82cb28 100644 --- a/test/Base_Tests/src/Semantic/Conversion_Spec.enso +++ b/test/Base_Tests/src/Semantic/Conversion_Spec.enso @@ -72,6 +72,16 @@ type Forth Back.from (that:Forth) = Back.Times that.n+1 Forth.from (that:Back) = Forth.Times that.n+1 +type Autoscope_Type + Raw v + Typed v:Any + Complex1 v:Autoscope_Type|Any + Complex2 v:Any|Autoscope_Type + + f_typed v:Any = Autoscope_Type.Raw v + f_complex1 v:Autoscope_Type|Any = Autoscope_Type.Raw v + f_complex2 v:Any|Autoscope_Type = Autoscope_Type.Raw v + foreign js make_str x = """ return "js string" @@ -543,6 +553,70 @@ add_specs suite_builder = accept ..Nothing . is_nothing . should_be_true + group_builder.specify "Autoscope_Type Raw" <| + r = ..Raw ..My_Other + x = r:Autoscope_Type + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Raw ..My_Other)" + + group_builder.specify "Autoscope_Type Typed" <| + r = ..Typed ..My_Other + x = r:Autoscope_Type + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Typed ..My_Other)" + + group_builder.specify "Autoscope_Type Complex1" <| + r = ..Complex1 ..My_Other + x = r:Autoscope_Type + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Complex1 ..My_Other)" + + group_builder.specify "Autoscope_Type Complex2" <| + r = ..Complex2 ..My_Other + x = r:Autoscope_Type + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Complex2 ..My_Other)" + + group_builder.specify "Autoscope_Type factory typed" <| + x = Autoscope_Type.f_typed ..My_Other + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Raw ..My_Other)" + + group_builder.specify "Autoscope_Type factory complex1" <| + x = Autoscope_Type.f_complex1 ..My_Other + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Raw ..My_Other)" + + group_builder.specify "Autoscope_Type factory complex2" <| + x = Autoscope_Type.f_complex2 ..My_Other + Meta.type_of x . should_equal Autoscope_Type + x.to_text . should_equal "(Raw ..My_Other)" + + + confused1 filter = + materialize f:Foo = f + + case filter of + _:Function -> Panic.catch Any (materialize filter) err-> + [err, filter] + _ -> filter + + group_builder.specify "Order of specializations 1 & 2" <| + fn x = x+2 + + r1 = confused1 fn + r2 = confused1 (..Value 4) + r = [r1, r2] + r.to_text . should_contain "Foo.Value 4" + + group_builder.specify "Order of specializations 2 & 1" <| + fn x = x+2 + + r2 = confused1 (..Value 4) + r1 = confused1 fn + r = [r1, r2] + r.to_text . should_contain "Foo.Value 4" + suite_builder.group "Polyglot Argument" group_builder-> f1 (x : DateTimeFormatter) = x.to_text f2 (x : Text | DateTimeFormatter) = case x of