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

Runtime check of ascribed types #6790

Merged
merged 36 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
18abc60
Use ascribed types in ReadArgumentNode
JaroslavTulach May 15, 2023
b90cd6e
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Ascrib…
JaroslavTulach May 22, 2023
81295da
Bound type is available directly in the Interval module
JaroslavTulach May 22, 2023
4ebea38
Context is directly imported
JaroslavTulach May 22, 2023
3358d6b
Accept type parameters in ascribed signatures
JaroslavTulach May 22, 2023
947a58f
It's Utf_16_Span
JaroslavTulach May 22, 2023
d472f18
Type_Error.Error when wrong type is send to ascribed constructor
JaroslavTulach May 22, 2023
b5125a3
Everything that hasHashEntries is of type Map
JaroslavTulach May 23, 2023
927b42f
Unignore method that was crashing the old parser
JaroslavTulach May 23, 2023
26168fd
Formatting
JaroslavTulach May 23, 2023
2134148
Caching ValuesGenerator speeds the test from 80s to 20s
JaroslavTulach May 23, 2023
f144268
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Ascrib…
JaroslavTulach May 23, 2023
e2c7ed5
Running the MetaIsATest also with JavaScript enabled
JaroslavTulach May 23, 2023
17fe010
Special isDate and isTime checks
JaroslavTulach May 23, 2023
2796679
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Ascrib…
JaroslavTulach May 24, 2023
8d345b9
Everything that hasHashEntries is a Map
JaroslavTulach May 24, 2023
e72620f
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Ascrib…
JaroslavTulach May 25, 2023
e17f619
Renaming and typo fixing
JaroslavTulach May 25, 2023
b5c19f6
Applying scala formatting/coding suggestions
JaroslavTulach May 25, 2023
34e0a2c
Less of currly braces
JaroslavTulach May 25, 2023
fe89655
Support for ascribed union types
JaroslavTulach May 25, 2023
52c0357
Better error messages
JaroslavTulach May 25, 2023
ccf7ef0
Support for nested union and parameterized types
JaroslavTulach May 26, 2023
9528617
Errors get in without any type checks
JaroslavTulach May 26, 2023
9ad5d54
Produces Type_Error instead of Unsupported_Argument_Types now
JaroslavTulach May 26, 2023
eb60cad
Allowing Column to make test/Benchmarks pass the runtime argument typ…
JaroslavTulach May 26, 2023
31dff3c
line_endings can be Infer-ed
JaroslavTulach May 28, 2023
fe0edb0
Store location of atom constructors
JaroslavTulach May 29, 2023
19f753f
Opt-out of type checks to make test/Visualization_Tests pass
JaroslavTulach May 30, 2023
35f86a4
Skip type check of lazy arguments
JaroslavTulach May 30, 2023
5ca27c6
test/Table_Tests are passing now
JaroslavTulach May 30, 2023
f5c365b
Report union types using Enso syntax
JaroslavTulach May 30, 2023
89a5150
Make sure error messages contain name of variables
JaroslavTulach May 30, 2023
d4f55bc
Revering back 9ad5d54 until opt-out | Any is removed from Filter_Cond…
JaroslavTulach May 30, 2023
d568ab3
Not in change log
JaroslavTulach May 30, 2023
2dbcd7a
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Ascrib…
JaroslavTulach May 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package org.enso.interpreter.node.callable.argument;

import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.node.expression.builtin.meta.IsValueOfTypeNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.error.PanicException;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.callable.function.Function;

/**
* Reads and evaluates the expression provided as a function argument. It handles the case where
Expand All @@ -14,22 +20,31 @@
public class ReadArgumentNode extends ExpressionNode {
private final int index;
@Child ExpressionNode defaultValue;
@Child IsValueOfTypeNode checkType;
private final ConditionProfile defaultingProfile = ConditionProfile.createCountingProfile();
// XXX: Type in a Node is wrong!!!!!
private final Type expectedType;
Copy link
Member Author

@JaroslavTulach JaroslavTulach May 23, 2023

Choose a reason for hiding this comment

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


private ReadArgumentNode(int position, ExpressionNode defaultValue) {
private ReadArgumentNode(int position, ExpressionNode defaultValue, Type expectedType) {
this.index = position;
this.defaultValue = defaultValue;
this.expectedType = expectedType;
if (expectedType != null) {
checkType = IsValueOfTypeNode.build();
}
}

/**
* Creates an instance of this node.
*
* @param position the argument's position at the definition site
* @param defaultValue the default value provided for that argument
* @param expectedType {@code null} or expected type to check input for
* @return a node representing the argument at position {@code idx}
*/
public static ReadArgumentNode build(int position, ExpressionNode defaultValue) {
return new ReadArgumentNode(position, defaultValue);
public static ReadArgumentNode build(
int position, ExpressionNode defaultValue, Type expectedType) {
return new ReadArgumentNode(position, defaultValue, expectedType);
}

/**
Expand All @@ -47,15 +62,24 @@ public static ReadArgumentNode build(int position, ExpressionNode defaultValue)
public Object executeGeneric(VirtualFrame frame) {
Object arguments[] = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());

Object v;
if (defaultValue == null) {
return arguments[index];
v = arguments[index];
} else {
// Note [Handling Argument Defaults]
if (defaultingProfile.profile(arguments.length <= index || arguments[index] == null)) {
v = defaultValue.executeGeneric(frame);
} else {
v = arguments[index];
}
}

// Note [Handling Argument Defaults]
if (defaultingProfile.profile(arguments.length <= index || arguments[index] == null)) {
return defaultValue.executeGeneric(frame);
if (checkType != null && !checkType.execute(expectedType, v)) {
CompilerDirectives.transferToInterpreter();
var ctx = EnsoContext.get(this);
var err = ctx.getBuiltins().error().makeTypeError(expectedType, v, "" + v);
throw new PanicException(err, this);
} else {
return arguments[index];
return v;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package org.enso.interpreter.node.expression.builtin.meta;

import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.enso.interpreter.runtime.type.TypesGen;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
Expand All @@ -9,85 +17,40 @@
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.epb.runtime.PolyglotExceptionProxy;
import org.enso.interpreter.epb.runtime.PolyglotProxy;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.enso.interpreter.runtime.type.TypesGen;

/** An implementation of the payload check against the expected panic type. */
@NodeInfo(shortName = "IsValueOfTypeNode")
public abstract class IsValueOfTypeNode extends Node {
private @Child IsSameObjectNode isSameObject = IsSameObjectNode.build();
private @Child TypeOfNode typeOfNode = TypeOfNode.build();
private final ConditionProfile profile = ConditionProfile.createCountingProfile();

public static IsValueOfTypeNode build() {
return IsValueOfTypeNodeGen.create();
}

public abstract boolean execute(Object expectedType, Object payload);

@Specialization
boolean doPolyglotProxy(Object expectedType, PolyglotProxy proxy) {
Object tpeOfPayload = typeOfNode.execute(proxy);
return isSameObject.execute(expectedType, tpeOfPayload);
}

@Specialization(guards = "!isAnyType(expectedType)")
boolean doPolyglotExceptionProxy(Object expectedType, PolyglotExceptionProxy proxy) {
Object tpeOfPayload = typeOfNode.execute(proxy.getDelegate());
return isSameObject.execute(expectedType, tpeOfPayload);
}

@Specialization(guards = "isAnyType(expectedType)")
boolean doAnyType(Object expectedType, Object payload) {
return true;
}

@Specialization
boolean doLongCheck(Type expectedType, long payload) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getSmallInteger(), expectedType);
}

@Specialization
boolean doDoubleCheck(Type expectedType, double payload) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getDecimal(), expectedType);
}

@Specialization
boolean doBigIntegerCheck(Type expectedType, EnsoBigInteger value) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getBigInteger(), expectedType);
}

@Specialization
boolean doUresolvedSymbol(Type expectedType, UnresolvedSymbol value) {
var funTpe = EnsoContext.get(this).getBuiltins().function();
return expectedType == funTpe;
@Specialization(guards = {"types.hasType(payload)"})
boolean doTyped(
Object expectedType,
Object payload,
@CachedLibrary(limit = "3") TypesLibrary types,
@Cached Typed typed) {
return typed.execute(expectedType, payload);
}

@ExplodeLoop
private boolean checkParentTypes(Type actual, Type expected) {
for (; ; ) {
if (actual == null) {
return false;
}
if (actual == expected) {
return true;
}
actual = actual.getSupertype();
}
@Specialization(guards = {"!types.hasType(payload)"})
boolean doPolyglot(
Object expectedType,
Object payload,
@CachedLibrary(limit = "3") TypesLibrary types,
@Cached Untyped typed) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
return typed.execute(expectedType, payload);
}

@Specialization(guards = {"!isArrayType(expectedType)", "!isAnyType(expectedType)"})
boolean doType(Type expectedType, Object payload) {
private static boolean typeAndCheck(
Object payload,
Object expectedType,
TypeOfNode typeOfNode,
IsSameObjectNode isSameObject,
ConditionProfile profile) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
Object tpeOfPayload = typeOfNode.execute(payload);
if (profile.profile(isSameObject.execute(expectedType, tpeOfPayload))) {
return true;
Expand All @@ -107,57 +70,116 @@ boolean doType(Type expectedType, Object payload) {
return false;
}

@Specialization(
guards = {
"isArrayType(expectedType)",
"interop.hasArrayElements(payload)",
"!types.hasType(payload)"
})
boolean doArray(
Object expectedType,
Object payload,
@CachedLibrary(limit = "3") InteropLibrary interop,
@CachedLibrary(limit = "3") TypesLibrary types) {
return true;
}
abstract static class Typed extends Node {
private @Child IsSameObjectNode isSameObject = IsSameObjectNode.build();
private @Child TypeOfNode typeOfNode = TypeOfNode.build();
private final ConditionProfile profile = ConditionProfile.createCountingProfile();

@Specialization(
guards = {
"isArrayType(expectedType)",
"interop.hasArrayElements(payload)",
"types.hasType(payload)"
})
public boolean doArrayViaType(
Object expectedType,
Object payload,
@CachedLibrary(limit = "3") InteropLibrary interop,
@CachedLibrary(limit = "3") TypesLibrary types) {
return EnsoContext.get(this).getBuiltins().array() == types.getType(payload);
}
abstract boolean execute(Object expectedType, Object payload);

@Specialization(guards = {"interop.isMetaObject(expectedType)", "!types.hasType(expectedType)"})
boolean doPolyglotType(
Object expectedType,
Object payload,
@CachedLibrary(limit = "3") InteropLibrary interop,
@CachedLibrary(limit = "3") TypesLibrary types) {
try {
return interop.isMetaInstance(expectedType, payload);
} catch (UnsupportedMessageException e) {
throw new IllegalStateException(e);
@Specialization(guards = "isAnyType(expectedType)")
boolean doAnyType(Object expectedType, Object payload) {
return true;
}
}

boolean isAnyType(Object expectedType) {
return EnsoContext.get(this).getBuiltins().any() == expectedType;
}
@Specialization
boolean doLongCheck(Type expectedType, long payload) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getSmallInteger(), expectedType);
}

@Specialization
boolean doDoubleCheck(Type expectedType, double payload) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getDecimal(), expectedType);
}

@Specialization
boolean doBigIntegerCheck(Type expectedType, EnsoBigInteger value) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getBigInteger(), expectedType);
}

@Specialization
boolean doUresolvedSymbol(Type expectedType, UnresolvedSymbol value) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
var funTpe = EnsoContext.get(this).getBuiltins().function();
return expectedType == funTpe;
}

@ExplodeLoop
private boolean checkParentTypes(Type actual, Type expected) {
for (; ; ) {
if (actual == null) {
return false;
}
if (actual == expected) {
return true;
}
actual = actual.getSupertype();
}
}

boolean isArrayType(Object expectedType) {
return EnsoContext.get(this).getBuiltins().array() == expectedType;
@Specialization(guards = {"!isArrayType(expectedType)", "!isAnyType(expectedType)"})
boolean doType(
Type expectedType, Object payload, @CachedLibrary(limit = "3") TypesLibrary types) {
return typeAndCheck(payload, expectedType, typeOfNode, isSameObject, profile);
}

@Specialization(
guards = {
"isArrayType(expectedType)",
"interop.hasArrayElements(payload)",
})
public boolean doArrayViaType(
Object expectedType,
Object payload,
@CachedLibrary(limit = "3") InteropLibrary interop,
@CachedLibrary(limit = "3") TypesLibrary types) {
return EnsoContext.get(this).getBuiltins().array() == types.getType(payload);
}

@Fallback
boolean doOther(Object expectedType, Object payload) {
return false;
}

boolean isAnyType(Object expectedType) {
return EnsoContext.get(this).getBuiltins().any() == expectedType;
}

boolean isArrayType(Object expectedType) {
return EnsoContext.get(this).getBuiltins().array() == expectedType;
}
}

@Fallback
public boolean doOther(Object expectedType, Object payload) {
return false;
abstract static class Untyped extends Node {
private @Child IsSameObjectNode isSameObject = IsSameObjectNode.build();
private @Child TypeOfNode typeOfNode = TypeOfNode.build();
private final ConditionProfile profile = ConditionProfile.createCountingProfile();

abstract boolean execute(Object expectedType, Object payload);

@Specialization(
guards = {
"interop.isMetaObject(expectedType)",
"isMetaInstance(interop, expectedType, payload)"
})
boolean doPolyglotType(
Object expectedType, Object payload, @CachedLibrary(limit = "3") InteropLibrary interop) {
return true;
}

static boolean isMetaInstance(InteropLibrary interop, Object expectedType, Object payload) {
try {
return interop.isMetaInstance(expectedType, payload);
} catch (UnsupportedMessageException ex) {
return false;
}
}

@Fallback
public boolean doOther(Object expectedType, Object payload) {
return typeAndCheck(payload, expectedType, typeOfNode, isSameObject, profile);
}
}
}
Loading