use of com.google.javascript.jscomp.CodingConvention.Bind in project closure-compiler by google.
the class PeepholeSubstituteAlternateSyntax method tryFoldImmediateCallToBoundFunction.
private Node tryFoldImmediateCallToBoundFunction(Node n) {
// Rewriting "(fn.bind(a,b))()" to "fn.call(a,b)" makes it inlinable
checkState(n.isCall());
Node callTarget = n.getFirstChild();
Bind bind = getCodingConvention().describeFunctionBind(callTarget, false, false);
if (bind != null) {
// replace the call target
bind.target.detach();
callTarget.replaceWith(bind.target);
callTarget = bind.target;
// push the parameters
addParameterAfter(bind.parameters, callTarget);
// add the this value before the parameters if necessary
if (bind.thisValue != null && !NodeUtil.isUndefined(bind.thisValue)) {
// rewrite from "fn(a, b)" to "fn.call(thisValue, a, b)"
Node newCallTarget = IR.getprop(callTarget.cloneTree(), "call");
markNewScopesChanged(newCallTarget);
callTarget.replaceWith(newCallTarget);
markFunctionsDeleted(callTarget);
bind.thisValue.cloneTree().insertAfter(newCallTarget);
n.putBooleanProp(Node.FREE_CALL, false);
} else {
n.putBooleanProp(Node.FREE_CALL, true);
}
reportChangeToEnclosingScope(n);
}
return n;
}
use of com.google.javascript.jscomp.CodingConvention.Bind in project closure-compiler by google.
the class NewTypeInference method analyzeFunctionBindFwd.
private EnvTypePair analyzeFunctionBindFwd(Node call, TypeEnv inEnv) {
checkArgument(call.isCall());
Bind bindComponents = this.convention.describeFunctionBind(call, true, false);
Node boundFunNode = bindComponents.target;
EnvTypePair pair = analyzeExprFwd(boundFunNode, inEnv);
TypeEnv env = pair.env;
FunctionType boundFunType = pair.type.getFunTypeIfSingletonObj();
if (!pair.type.isSubtypeOf(commonTypes.topFunction())) {
warnings.add(JSError.make(boundFunNode, GOOG_BIND_EXPECTS_FUNCTION, pair.type.toString()));
}
// For some function types, we don't know enough to handle .bind specially.
if (boundFunType == null || boundFunType.isTopFunction() || boundFunType.isQmarkFunction() || boundFunType.isLoose()) {
return analyzeInvocationArgsFwdWhenError(call, env);
}
if (boundFunType.isSomeConstructorOrInterface()) {
warnings.add(JSError.make(call, CANNOT_BIND_CTOR));
return new EnvTypePair(env, UNKNOWN);
}
// Check if the receiver argument is there
int callChildCount = call.getChildCount();
if ((NodeUtil.isGoogBind(call.getFirstChild()) && callChildCount <= 2) || (!NodeUtil.isGoogPartial(call.getFirstChild()) && callChildCount == 1)) {
warnings.add(JSError.make(call, WRONG_ARGUMENT_COUNT, getReadableCalleeName(call.getFirstChild()), "0", "1", ""));
}
// Check that there are not too many of the other arguments
int maxArity = boundFunType.hasRestFormals() ? Integer.MAX_VALUE : boundFunType.getMaxArity();
int numArgs = bindComponents.getBoundParameterCount();
if (numArgs > maxArity) {
warnings.add(JSError.make(call, WRONG_ARGUMENT_COUNT, getReadableCalleeName(call.getFirstChild()), Integer.toString(numArgs), "0", " and at most " + maxArity));
return analyzeInvocationArgsFwdWhenError(call, inEnv);
}
// If the bound function is polymorphic, we only support the case where we
// can completely calculate the type instantiation at the .bind call site.
// We don't support splitting the instantiation between call sites.
//
Node receiver = bindComponents.thisValue;
if (boundFunType.isGeneric()) {
Map<String, JSType> typeMap = calcTypeInstantiationFwd(call, receiver, bindComponents.parameters, boundFunType, env);
boundFunType = boundFunType.instantiateGenerics(typeMap);
}
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
if (receiver != null) {
// receiver is null for goog.partial
JSType reqThisType = boundFunType.getThisType();
if (reqThisType == null || boundFunType.isSomeConstructorOrInterface()) {
reqThisType = JSType.join(NULL, TOP_OBJECT);
}
pair = analyzeExprFwd(receiver, env, reqThisType);
env = pair.env;
if (!pair.type.isSubtypeOf(reqThisType)) {
warnings.add(JSError.make(call, INVALID_THIS_TYPE_IN_BIND, errorMsgWithTypeDiff(reqThisType, pair.type)));
} else {
instantiateGoogBind(call.getFirstChild(), pair.type);
}
}
Iterable<Node> parametersIterable = bindComponents.parameters == null ? ImmutableList.<Node>of() : bindComponents.parameters.siblings();
// We are passing an arraylist but don't do deferred checks for bind.
env = analyzeInvocationArgumentsFwd(call, parametersIterable, boundFunType, new ArrayList<JSType>(), env);
// For any formal not bound here, add it to the resulting function type.
for (int j = numArgs; j < boundFunType.getMaxArityWithoutRestFormals(); j++) {
JSType formalType = boundFunType.getFormalType(j);
if (boundFunType.isRequiredArg(j)) {
builder.addReqFormal(formalType);
} else {
builder.addOptFormal(formalType);
}
}
if (boundFunType.hasRestFormals()) {
builder.addRestFormals(boundFunType.getRestFormalsType());
}
return new EnvTypePair(env, commonTypes.fromFunctionType(builder.addRetType(boundFunType.getReturnType()).buildFunction()));
}
Aggregations