Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

case of and intersection types #11850

Merged
merged 9 commits into from
Dec 13, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ Error.should_equal self that frames_to_skip=0 =
Number.should_equal : Float -> Float -> Integer -> Spec_Result
Number.should_equal self that epsilon=0 frames_to_skip=0 =
matches = case that of
_ : Number -> self.equals that epsilon
n : Number -> self.equals n epsilon
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shows a small nuance. Previously there was no difference between that and n. Now there is as 571cce6 documents.

_ -> self==that
case matches of
True -> Spec_Result.Success
Expand Down
20 changes: 8 additions & 12 deletions docs/types/intersection-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,14 @@ method calls will also only accept the value if it satisfies the type it
_has been cast to_. Any additional remaining _hidden_ types
can only be brought back through an _explicit_ cast.
To perform an explicit cast that can uncover the 'hidden' part of a type write
`f = c:Float`.

<!--
When #11828 is fixed.

- or inspect the types in a `case` expression, e.g.
```
case c of
f : Float -> f.sqrt
_ -> "Not a float"
```
-->
`f = c:Float` or inspect the types in a `case` expression, e.g.
```ruby
case c of
f : Float -> f.sqrt
_ -> "Not a float"
```
Remember to use `f.sqrt` and not `c.sqrt`. `f` in the case branch _has been cast to_ `Float` while
`c` in the case branch only _can be cast to_.

> [!WARNING]
> Keep in mind that while both argument type check in method definitions and a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private String[] typeOf(Object value) {
}

var typeOfNode = TypeOfNode.getUncached();
Type[] allTypes = value == null ? null : typeOfNode.findAllTypesOrNull(value);
Type[] allTypes = value == null ? null : typeOfNode.findAllTypesOrNull(value, true);
if (allTypes != null) {
String[] result = new String[allTypes.length];
for (var i = 0; i < allTypes.length; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ private static Context ctx() {
new TestRootNode(
(frame) -> {
var arg = frame.getArguments()[0];
var allTypes = (boolean) frame.getArguments()[1];
var t = node.findTypeOrError(arg);
var all = node.findAllTypesOrNull(arg);
var all = node.findAllTypesOrNull(arg, allTypes);
return new Object[] {t, all};
});
root.insertChildren(node);
Expand Down Expand Up @@ -116,16 +117,22 @@ public static void disposeCtx() throws Exception {
}

@Test
public void typeOfCheck() {
assertType(value, type, typeIndex);
public void typeOfCheckAllTypes() {
assertType(value, type, typeIndex, true);
}

private static void assertType(Object value, String expectedTypeName, int typeIndex) {
@Test
public void typeOfCheckHasBeenCastToTypes() {
assertType(value, type, typeIndex, false);
}

private static void assertType(
Object value, String expectedTypeName, int typeIndex, boolean allTypes) {
assertNotNull("Value " + value + " should have a type", expectedTypeName);
ContextUtils.executeInContext(
ctx(),
() -> {
var pairResult = (Object[]) testTypesCall.call(value);
var pairResult = (Object[]) testTypesCall.call(value, allTypes);
var t = pairResult[0];
var all = (Object[]) pairResult[1];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import static org.junit.Assert.assertEquals;

import com.oracle.truffle.api.RootCallTarget;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.UnresolvedConstructor;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.data.EnsoMultiValue;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
import org.enso.test.utils.ContextUtils;
Expand All @@ -28,8 +30,9 @@ private static Context ctx() {
new TestRootNode(
(frame) -> {
var arg = frame.getArguments()[0];
var allTypes = (boolean) frame.getArguments()[1];
var t = node.findTypeOrError(arg);
var all = node.findAllTypesOrNull(arg);
var all = node.findAllTypesOrNull(arg, allTypes);
return new Object[] {t, all};
});
root.insertChildren(node);
Expand All @@ -54,7 +57,7 @@ public void typeOfUnresolvedConstructor() {
ctx(),
() -> {
var cnstr = UnresolvedConstructor.build(null, "Unknown_Name");
var arr = (Object[]) testTypesCall.call(cnstr);
var arr = (Object[]) testTypesCall.call(cnstr, true);
var type = (Type) arr[0];
var allTypes = (Type[]) arr[1];
assertEquals("Function", type.getName());
Expand All @@ -70,7 +73,7 @@ public void typeOfUnresolvedSymbol() {
ctx(),
() -> {
var cnstr = UnresolvedSymbol.build("Unknown_Name", null);
var arr = (Object[]) testTypesCall.call(cnstr);
var arr = (Object[]) testTypesCall.call(cnstr, true);
var type = (Type) arr[0];
var allTypes = (Type[]) arr[1];
assertEquals("Function", type.getName());
Expand All @@ -79,4 +82,29 @@ public void typeOfUnresolvedSymbol() {
return null;
});
}

@Test
public void multiValueWithHiddenType() {
ContextUtils.executeInContext(
ctx(),
() -> {
var ensoCtx = EnsoContext.get(testTypesCall.getRootNode());
var types =
new Type[] {
ensoCtx.getBuiltins().number().getInteger(), ensoCtx.getBuiltins().text()
};
var multi = EnsoMultiValue.create(types, 1, new Object[] {42L, "Meaning"});
var arr = (Object[]) testTypesCall.call(multi, true);
var allTypes = (Type[]) arr[1];
assertEquals("Two types", 2, allTypes.length);
assertEquals("Integer", types[0], allTypes[0]);
assertEquals("Text", types[1], allTypes[1]);

var arr1 = (Object[]) testTypesCall.call(multi, false);
var allTypes1 = (Type[]) arr1[1];
assertEquals("Just one type", 1, allTypes1.length);
assertEquals("Integer", types[0], allTypes1[0]);
return null;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,13 @@ final Object doThatConversionUncached(
InvokeFunctionNode invokeNode) {
var selfType = findType(typeOfNode, self);
if (that instanceof EnsoMultiValue multi) {
var all = typeOfNode.findAllTypesOrNull(multi);
var all = typeOfNode.findAllTypesOrNull(multi, false);
assert all != null;
for (var thatType : all) {
var fn = findSymbol(symbol, thatType);
if (fn != null) {
var thatCasted =
EnsoMultiValue.CastToNode.getUncached()
.findTypeOrNull(thatType, multi, false, false);
if (thatCasted == null) {
continue;
}
var result =
doDispatch(
frame, self, thatCasted, selfType, thatType, fn, convertNode, invokeNode);
doDispatch(frame, self, multi, selfType, thatType, fn, convertNode, invokeNode);
if (result != null) {
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import org.enso.interpreter.node.expression.builtin.meta.IsValueOfTypeNode;
import org.enso.interpreter.runtime.data.EnsoMultiValue;
import org.enso.interpreter.runtime.data.Type;

/** An implementation of the case expression specialised to working on types. */
Expand Down Expand Up @@ -33,7 +34,13 @@ public static CatchTypeBranchNode build(
}

public void execute(VirtualFrame frame, Object state, Object value) {
if (profile.profile(isValueOfTypeNode.execute(expectedType, value))) {
if (profile.profile(isValueOfTypeNode.execute(expectedType, value, true))) {
if (value instanceof EnsoMultiValue multi) {
var replacement =
EnsoMultiValue.CastToNode.getUncached().findTypeOrNull(expectedType, multi, true, true);
assert replacement != null : "Must find the type, when isValueOfTypeNode is true";
value = replacement;
}
accept(frame, state, new Object[] {value});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private Object executeCallbackOrRethrow(
AbstractTruffleException originalException,
InteropLibrary interopLibrary) {

if (profile.profile(isValueOfTypeNode.execute(panicType, payload))) {
if (profile.profile(isValueOfTypeNode.execute(panicType, payload, true))) {
var builtins = EnsoContext.get(this).getBuiltins();
var cons = builtins.caughtPanic().getUniqueConstructor();
var caughtPanic =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.oracle.truffle.api.TruffleStackTrace;
import com.oracle.truffle.api.TruffleStackTraceElement;
import com.oracle.truffle.api.nodes.Node;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import org.enso.interpreter.dsl.BuiltinMethod;
Expand Down Expand Up @@ -76,6 +77,11 @@ String printStackTrace(Throwable throwable) {
var sourceLoc = errorFrame.getLocation().getEncapsulatingSourceSection();
if (sourceLoc != null) {
var path = sourceLoc.getSource().getPath();
try {
path = new File(sourceLoc.getSource().getURI()).getPath();
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
} catch (IllegalArgumentException | NullPointerException ignore) {
// keep original value of path
}
var ident = (path != null) ? path : sourceLoc.getSource().getName();
var loc =
(sourceLoc.getStartLine() == sourceLoc.getEndLine())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ EqualsAndInfo equalsMultiValue(
@Shared("multiCast") @Cached EnsoMultiValue.CastToNode castNode,
@Shared("multiType") @Cached TypeOfNode typesNode,
@Shared("multiEquals") @Cached EqualsSimpleNode delegate) {
var types = typesNode.findAllTypesOrNull(self);
var types = typesNode.findAllTypesOrNull(self, false);
assert types != null;
for (var t : types) {
var value = castNode.findTypeOrNull(t, self, false, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public class IsANode extends Node {
private @Child IsValueOfTypeNode check = IsValueOfTypeNode.build();

public boolean execute(@AcceptsError Object value, Object type) {
return check.execute(type, value);
return check.execute(type, value, true);
}
}
Loading
Loading