Skip to content

Commit

Permalink
[NTI] Introduce a new acceptsArguments method to FunctionTypeI.
Browse files Browse the repository at this point in the history
Also use it in ConformanceRules and prune any dead code that results.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=129480955
  • Loading branch information
aravind-pg authored and blickly committed Aug 5, 2016
1 parent ed3e7ef commit 733261f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 80 deletions.
72 changes: 10 additions & 62 deletions src/com/google/javascript/jscomp/ConformanceRules.java
Expand Up @@ -586,13 +586,12 @@ static TypeI evaluateTypeString(
* @see TypeCheck#visitParameterList * @see TypeCheck#visitParameterList
*/ */
static boolean validateCall( static boolean validateCall(
AbstractCompiler compiler,
Node callOrNew, Node callOrNew,
FunctionTypeI functionType, FunctionTypeI functionType,
boolean isCallInvocation) { boolean isCallInvocation) {
Preconditions.checkState(callOrNew.isCall() || callOrNew.isNew()); Preconditions.checkState(callOrNew.isCall() || callOrNew.isNew());


return validateParameterList(compiler, callOrNew, functionType, isCallInvocation) return validateParameterList(callOrNew, functionType, isCallInvocation)
&& validateThis(callOrNew, functionType, isCallInvocation); && validateThis(callOrNew, functionType, isCallInvocation);
} }


Expand All @@ -619,7 +618,6 @@ private static boolean validateThis(
} }


private static boolean validateParameterList( private static boolean validateParameterList(
AbstractCompiler compiler,
Node callOrNew, Node callOrNew,
FunctionTypeI functionType, FunctionTypeI functionType,
boolean isCallInvocation) { boolean isCallInvocation) {
Expand All @@ -629,61 +627,13 @@ private static boolean validateParameterList(
arguments.next(); arguments.next();
} }


Iterator<Node> parameters = functionType.getParameters().iterator(); // Get all the annotated types of the argument nodes
Node parameter = null; ImmutableList.Builder<TypeI> argumentTypes = ImmutableList.builder();
Node argument = null; while (arguments.hasNext()) {
while (arguments.hasNext() argumentTypes.add(arguments.next().getTypeI());
&& (parameters.hasNext() || parameter != null && parameter.isVarArgs())) {
// If there are no parameters left in the list, then the while loop
// above implies that this must be a var_args function.
if (parameters.hasNext()) {
parameter = parameters.next();
}
argument = arguments.next();

if (!validateParameter(
getTypeI(compiler, argument), getTypeI(compiler, parameter))) {
return false;
}
}

int numArgs = callOrNew.getChildCount() - 1;
if (isCallInvocation && numArgs > 0) {
numArgs -= 1;
}
int minArgs = functionType.getMinArguments();
int maxArgs = functionType.getMaxArguments();
return minArgs <= numArgs && numArgs <= maxArgs;
}

/**
* Expect that the type of an argument matches the type of the parameter
* that it's fulfilling.
*
* @param argType The type of the argument.
* @param paramType The type of the parameter.
*/
static boolean validateParameter(TypeI argType, TypeI paramType) {
return argType.isSubtypeOf(paramType);
}

/**
* This method gets the TypeI from the Node argument and verifies that it is
* present.
*/
static TypeI getTypeI(AbstractCompiler compiler, Node n) {
TypeI type = n.getTypeI();
if (type == null) {
return getNativeType(compiler, JSTypeNative.UNKNOWN_TYPE);
} else {
return type;
} }
return functionType.acceptsArguments(argumentTypes.build());
} }

static TypeI getNativeType(AbstractCompiler compiler, JSTypeNative typeId) {
return compiler.getTypeIRegistry().getNativeType(typeId);
}

} }


/** /**
Expand Down Expand Up @@ -736,13 +686,13 @@ protected ConformanceResult checkConformance(NodeTraversal t, Node n) {


if (n.matchesQualifiedName(r.name)) { if (n.matchesQualifiedName(r.name)) {
if (!ConformanceUtil.validateCall( if (!ConformanceUtil.validateCall(
compiler, n.getParent(), r.restrictedCallType, false)) { n.getParent(), r.restrictedCallType, false)) {
return ConformanceResult.VIOLATION; return ConformanceResult.VIOLATION;
} }
} else if (n.isGetProp() && n.getLastChild().getString().equals("call") } else if (n.isGetProp() && n.getLastChild().getString().equals("call")
&& n.getFirstChild().matchesQualifiedName(r.name)) { && n.getFirstChild().matchesQualifiedName(r.name)) {
if (!ConformanceUtil.validateCall( if (!ConformanceUtil.validateCall(
compiler, n.getParent(), r.restrictedCallType, true)) { n.getParent(), r.restrictedCallType, true)) {
return ConformanceResult.VIOLATION; return ConformanceResult.VIOLATION;
} }
} }
Expand Down Expand Up @@ -858,14 +808,12 @@ private ConformanceResult checkConformance(
|| targetType.isEquivalentTo( || targetType.isEquivalentTo(
registry.getNativeType(JSTypeNative.OBJECT_TYPE))) { registry.getNativeType(JSTypeNative.OBJECT_TYPE))) {
if (!ConformanceUtil.validateCall( if (!ConformanceUtil.validateCall(
compiler, n.getParent(), r.restrictedCallType, n.getParent(), r.restrictedCallType, isCallInvocation)) {
isCallInvocation)) {
return ConformanceResult.POSSIBLE_VIOLATION_DUE_TO_LOOSE_TYPES; return ConformanceResult.POSSIBLE_VIOLATION_DUE_TO_LOOSE_TYPES;
} }
} else if (targetType.isSubtypeOf(methodClassType)) { } else if (targetType.isSubtypeOf(methodClassType)) {
if (!ConformanceUtil.validateCall( if (!ConformanceUtil.validateCall(
compiler, n.getParent(), r.restrictedCallType, n.getParent(), r.restrictedCallType, isCallInvocation)) {
isCallInvocation)) {
return ConformanceResult.VIOLATION; return ConformanceResult.VIOLATION;
} }
} }
Expand Down
27 changes: 17 additions & 10 deletions src/com/google/javascript/jscomp/newtypes/JSType.java
Expand Up @@ -1674,18 +1674,25 @@ public TypeI getTypeOfThis() {
} }


@Override @Override
public int getMinArguments() { public boolean acceptsArguments(List<? extends TypeI> argumentTypes) {
throw new UnsupportedOperationException("getMinArguments not implemented yet"); Preconditions.checkState(this.isFunctionType());
}


@Override int numArgs = argumentTypes.size();
public int getMaxArguments() { FunctionType fnType = this.getFunTypeIfSingletonObj();
throw new UnsupportedOperationException("getMaxArguments not implemented yet");
}


@Override if (numArgs < fnType.getMinArity() || numArgs > fnType.getMaxArity()) {
public Iterable<Node> getParameters() { return false;
throw new UnsupportedOperationException("getParameters not implemented yet"); }

for (int i = 0; i < numArgs; i++) {
TypeI ithArgType = argumentTypes.get(i);
JSType ithParamType = fnType.getFormalType(i);
if (!ithArgType.isSubtypeOf(ithParamType)) {
return false;
}
}

return true;
} }


@Override @Override
Expand Down
7 changes: 2 additions & 5 deletions src/com/google/javascript/rhino/FunctionTypeI.java
Expand Up @@ -77,9 +77,6 @@ public interface FunctionTypeI extends TypeI {


void setSource(Node n); void setSource(Node n);


int getMinArguments(); /** Checks if a call to this function with the given list of arguments is valid. */

boolean acceptsArguments(List<? extends TypeI> argumentTypes);
int getMaxArguments();

Iterable<Node> getParameters();
} }
30 changes: 27 additions & 3 deletions src/com/google/javascript/rhino/jstype/FunctionType.java
Expand Up @@ -53,6 +53,7 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
Expand Down Expand Up @@ -300,7 +301,6 @@ public boolean hasImplementedInterfaces() {
return false; return false;
} }


@Override
public Iterable<Node> getParameters() { public Iterable<Node> getParameters() {
Node n = getParametersNode(); Node n = getParametersNode();
if (n != null) { if (n != null) {
Expand All @@ -316,7 +316,6 @@ public Node getParametersNode() {
} }


/** Gets the minimum number of arguments that this function requires. */ /** Gets the minimum number of arguments that this function requires. */
@Override
public int getMinArguments() { public int getMinArguments() {
// NOTE(nicksantos): There are some native functions that have optional // NOTE(nicksantos): There are some native functions that have optional
// parameters before required parameters. This algorithm finds the position // parameters before required parameters. This algorithm finds the position
Expand All @@ -336,7 +335,6 @@ public int getMinArguments() {
* Gets the maximum number of arguments that this function requires, * Gets the maximum number of arguments that this function requires,
* or Integer.MAX_VALUE if this is a variable argument function. * or Integer.MAX_VALUE if this is a variable argument function.
*/ */
@Override
public int getMaxArguments() { public int getMaxArguments() {
Node params = getParametersNode(); Node params = getParametersNode();
if (params != null) { if (params != null) {
Expand Down Expand Up @@ -1510,4 +1508,30 @@ public List<FunctionType> checkExtendsLoop(HashSet<FunctionType> cache,
} }
return null; return null;
} }

@Override
public boolean acceptsArguments(List<? extends TypeI> argumentTypes) {
// NOTE(aravindpg): This code is essentially lifted from TypeCheck::visitParameterList,
// but what small differences there are make it very painful to refactor out the shared code.
Iterator<? extends TypeI> arguments = argumentTypes.iterator();
Iterator<Node> parameters = this.getParameters().iterator();
Node parameter = null;
TypeI argument = null;
while (arguments.hasNext()
&& (parameters.hasNext() || parameter != null && parameter.isVarArgs())) {
// If there are no parameters left in the list, then the while loop
// above implies that this must be a var_args function.
if (parameters.hasNext()) {
parameter = parameters.next();
}
argument = arguments.next();

if (!argument.isSubtypeOf(parameter.getTypeI())) {
return false;
}
}

int numArgs = argumentTypes.size();
return this.getMinArguments() <= numArgs && numArgs <= this.getMaxArguments();
}
} }

0 comments on commit 733261f

Please sign in to comment.