Presence of Any disables type checks (#10248)

Fixes #10237 by avoiding creation of `ReadArgumentCheckNode` when the requested type allows `Any`.
This commit is contained in:
Jaroslav Tulach 2024-06-12 13:10:23 +02:00 committed by GitHub
parent 46f6b4f698
commit 87864bf564
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 161 additions and 9 deletions

View File

@ -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."));
}
}
}

View File

@ -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;

View File

@ -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))

View File

@ -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