Search in sources :

Example 1 with Bind

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;
}
Also used : Bind(com.google.javascript.jscomp.CodingConvention.Bind) Node(com.google.javascript.rhino.Node)

Example 2 with Bind

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()));
}
Also used : Bind(com.google.javascript.jscomp.CodingConvention.Bind) JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) ArrayList(java.util.ArrayList) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv) FunctionTypeBuilder(com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)

Aggregations

Bind (com.google.javascript.jscomp.CodingConvention.Bind)2 Node (com.google.javascript.rhino.Node)2 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)1 DeclaredFunctionType (com.google.javascript.jscomp.newtypes.DeclaredFunctionType)1 FunctionType (com.google.javascript.jscomp.newtypes.FunctionType)1 FunctionTypeBuilder (com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)1 JSType (com.google.javascript.jscomp.newtypes.JSType)1 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)1 ArrayList (java.util.ArrayList)1