Skip to content

Commit

Permalink
[GR-7900] Support executables requiring exact parameter count.
Browse files Browse the repository at this point in the history
  • Loading branch information
tzezula committed Jan 23, 2018
1 parent fcb550d commit bbfa1be
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public final class TypeDescriptor {
* @see Value#canExecute().
* @since 0.30
*/
public static final TypeDescriptor EXECUTABLE = new TypeDescriptor(new ExecutableImpl(ExecutableImpl.Kind.BOTTOM, ANY.impl, Collections.emptyList()));
public static final TypeDescriptor EXECUTABLE = new TypeDescriptor(new ExecutableImpl(ExecutableImpl.Kind.BOTTOM, ANY.impl, true, Collections.emptyList()));

/**
* Represents a raw executable type. Any executable can be assigned into the raw executable
Expand All @@ -143,7 +143,7 @@ public final class TypeDescriptor {
* @see TypeDescriptor#EXECUTABLE
* @since 1.0
*/
public static final TypeDescriptor EXECUTABLE_ANY = new TypeDescriptor(new ExecutableImpl(ExecutableImpl.Kind.TOP, ANY.impl, Collections.emptyList()));
public static final TypeDescriptor EXECUTABLE_ANY = new TypeDescriptor(new ExecutableImpl(ExecutableImpl.Kind.TOP, ANY.impl, true, Collections.emptyList()));

private static final TypeDescriptor[] PREDEFINED_TYPES = new TypeDescriptor[]{
NULL, BOOLEAN, NUMBER, STRING, HOST_OBJECT, NATIVE_POINTER, OBJECT, ARRAY, EXECUTABLE, EXECUTABLE_ANY, ANY
Expand Down Expand Up @@ -442,6 +442,23 @@ public static TypeDescriptor array(TypeDescriptor componentType) {
* @since 0.30
*/
public static TypeDescriptor executable(TypeDescriptor returnType, TypeDescriptor... parameterTypes) {
return executable(returnType, true, parameterTypes);
}

/**
* Creates a new executable type with a given return type and parameter types.
*
* @param returnType the required return type, use ANY as any type
* @param vararg the executable has variable length arguments or ignores additional parameters.
* For executables created by the
* {@link LanguageProvider#createValueConstructors(org.graalvm.polyglot.Context)} set
* to {@code false} if the language neither ignores extra parameters nor the
* executable has variable arguments length.
* @param parameterTypes the required parameter types
* @return an executable type
* @since 0.31
*/
public static TypeDescriptor executable(TypeDescriptor returnType, boolean vararg, TypeDescriptor... parameterTypes) {
Objects.requireNonNull(returnType, "Return type cannot be null");
Objects.requireNonNull(parameterTypes, "Parameter types cannot be null");
if (returnType.isAssignable(ANY) && parameterTypes.length == 0) {
Expand All @@ -452,7 +469,7 @@ public static TypeDescriptor executable(TypeDescriptor returnType, TypeDescripto
Objects.requireNonNull(td, "Parameter types cannot contain null");
paramTypeImpls.add(td.impl);
}
return new TypeDescriptor(new ExecutableImpl(ExecutableImpl.Kind.UNIT, returnType.impl, paramTypeImpls));
return new TypeDescriptor(new ExecutableImpl(ExecutableImpl.Kind.UNIT, returnType.impl, vararg, paramTypeImpls));
}

/**
Expand Down Expand Up @@ -609,18 +626,21 @@ enum Kind {

private final Kind kind;
private final TypeDescriptorImpl retType;
private final boolean vararg;
private final List<? extends TypeDescriptorImpl> paramTypes;

ExecutableImpl(
final Kind kind,
final TypeDescriptorImpl retType,
final boolean vararg,
final List<? extends TypeDescriptorImpl> paramTypes) {
assert kind != null;
assert retType != null;
assert paramTypes != null;
assert kind == Kind.UNIT || (retType.equals(ANY.impl) && paramTypes.isEmpty());
this.kind = kind;
this.retType = retType;
this.vararg = vararg;
this.paramTypes = paramTypes;
}

Expand All @@ -647,6 +667,9 @@ boolean isAssignable(final TypeDescriptorImpl origType, final TypeDescriptorImpl
if (origExec.paramTypes.size() < byExec.paramTypes.size()) {
return false;
}
if (!byExec.vararg && origExec.paramTypes.size() != byExec.paramTypes.size()) {
return false;
}
for (int i = 0; i < byExec.paramTypes.size(); i++) {
final TypeDescriptorImpl pt = origExec.paramTypes.get(i);
final TypeDescriptorImpl opt = byExec.paramTypes.get(i);
Expand All @@ -664,6 +687,7 @@ boolean isAssignable(final TypeDescriptorImpl origType, final TypeDescriptorImpl
@Override
public int hashCode() {
int res = 17;
res = res * 31 + (vararg ? 1 : 0);
res = res * 31 + kind.hashCode();
res = res * 31 + retType.hashCode();
for (TypeDescriptorImpl paramType : paramTypes) {
Expand All @@ -681,7 +705,7 @@ public boolean equals(final Object obj) {
return false;
}
final ExecutableImpl other = (ExecutableImpl) obj;
return kind == other.kind && retType.equals(other.retType) && paramTypes.equals(other.paramTypes);
return vararg == other.vararg && kind == other.kind && retType.equals(other.retType) && paramTypes.equals(other.paramTypes);
}

@Override
Expand All @@ -708,6 +732,9 @@ public String toString() {
default:
throw new IllegalStateException("Unknown kind: " + kind);
}
if (vararg) {
sb.append(", *");
}
sb.append("):");
sb.append(retType.isAssignable(retType, ANY.impl) ? "<any>" : retType);
return sb.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ public void testExecutable() {
Assert.assertTrue(ue4.isAssignable(ue2));
Assert.assertTrue(ue4.isAssignable(ue3));
Assert.assertFalse(ue4.isAssignable(up));
// strictParameterCount
final TypeDescriptor exeStrictAnyAny = TypeDescriptor.executable(TypeDescriptor.ANY, false, TypeDescriptor.ANY);
final TypeDescriptor exeAnyNum = TypeDescriptor.executable(TypeDescriptor.ANY, TypeDescriptor.NUMBER);
final TypeDescriptor exeAnyNumNum = TypeDescriptor.executable(TypeDescriptor.ANY, TypeDescriptor.NUMBER, TypeDescriptor.NUMBER);
Assert.assertTrue(exeAnyNum.isAssignable(exeStrictAnyAny));
Assert.assertFalse(exeAnyNumNum.isAssignable(exeStrictAnyAny));
}

@Test
Expand Down

0 comments on commit bbfa1be

Please sign in to comment.