Search in sources :

Example 6 with TemplateType

use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.

the class TypeInference method inferTemplatedTypesForCall.

/**
 * For functions that use template types, specialize the function type for the call target based
 * on the call-site specific arguments. Specifically, this enables inference to set the type of
 * any function literal parameters based on these inferred types.
 */
private boolean inferTemplatedTypesForCall(Node n, FunctionType fnType, FlowScope scope) {
    ImmutableList<TemplateType> keys = fnType.getTemplateTypeMap().getTemplateKeys();
    if (keys.isEmpty()) {
        return false;
    }
    // Try to infer the template types
    Map<TemplateType, JSType> bindings = new InvocationTemplateTypeMatcher(this.registry, fnType, scope.getTypeOfThis(), n).match();
    Map<TemplateType, JSType> inferred = new LinkedHashMap<>();
    for (TemplateType key : keys) {
        inferred.put(key, bindings.getOrDefault(key, unknownType));
    }
    // If the inferred type doesn't satisfy the template bound, swap to using the bound. This
    // ensures errors will be reported in type-checking.
    inferred.replaceAll((k, v) -> v.isSubtypeOf(k.getBound()) ? v : k.getBound());
    // Try to infer the template types using the type transformations
    Map<TemplateType, JSType> typeTransformations = evaluateTypeTransformations(keys, inferred, scope);
    if (typeTransformations != null) {
        inferred.putAll(typeTransformations);
    }
    // Replace all template types. If we couldn't find a replacement, we
    // replace it with UNKNOWN.
    TemplateTypeReplacer replacer = TemplateTypeReplacer.forInference(registry, inferred);
    Node callTarget = n.getFirstChild();
    FunctionType replacementFnType = fnType.visit(replacer).toMaybeFunctionType();
    checkNotNull(replacementFnType);
    callTarget.setJSType(replacementFnType);
    n.setJSType(replacementFnType.getReturnType());
    return replacer.hasMadeReplacement();
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) TemplateTypeReplacer(com.google.javascript.rhino.jstype.TemplateTypeReplacer) Node(com.google.javascript.rhino.Node) FunctionType(com.google.javascript.rhino.jstype.FunctionType) TemplateType(com.google.javascript.rhino.jstype.TemplateType) LinkedHashMap(java.util.LinkedHashMap)

Example 7 with TemplateType

use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.

the class TypeInference method maybeResolveTemplatedType.

private void maybeResolveTemplatedType(JSType paramType, JSType argType, Map<TemplateType, JSType> resolvedTypes, Set<JSType> seenTypes) {
    if (paramType.isTemplateType()) {
        // example: @param {T}
        resolvedTemplateType(resolvedTypes, paramType.toMaybeTemplateType(), argType);
    } else if (paramType.isUnionType()) {
        // example: @param {Array.<T>|NodeList|Arguments|{length:number}}
        UnionType unionType = paramType.toMaybeUnionType();
        for (JSType alernative : unionType.getAlternates()) {
            maybeResolveTemplatedType(alernative, argType, resolvedTypes, seenTypes);
        }
    } else if (paramType.isFunctionType()) {
        FunctionType paramFunctionType = paramType.toMaybeFunctionType();
        FunctionType argFunctionType = argType.restrictByNotNullOrUndefined().collapseUnion().toMaybeFunctionType();
        if (argFunctionType != null && argFunctionType.isSubtype(paramType)) {
            // infer from return type of the function type
            maybeResolveTemplatedType(paramFunctionType.getTypeOfThis(), argFunctionType.getTypeOfThis(), resolvedTypes, seenTypes);
            // infer from return type of the function type
            maybeResolveTemplatedType(paramFunctionType.getReturnType(), argFunctionType.getReturnType(), resolvedTypes, seenTypes);
            // infer from parameter types of the function type
            maybeResolveTemplateTypeFromNodes(paramFunctionType.getParameters(), argFunctionType.getParameters(), resolvedTypes, seenTypes);
        }
    } else if (paramType.isRecordType() && !paramType.isNominalType()) {
        // example: @param {{foo:T}}
        if (seenTypes.add(paramType)) {
            ObjectType paramRecordType = paramType.toObjectType();
            ObjectType argObjectType = argType.restrictByNotNullOrUndefined().toObjectType();
            if (argObjectType != null && !argObjectType.isUnknownType() && !argObjectType.isEmptyType()) {
                Set<String> names = paramRecordType.getPropertyNames();
                for (String name : names) {
                    if (paramRecordType.hasOwnProperty(name) && argObjectType.hasProperty(name)) {
                        maybeResolveTemplatedType(paramRecordType.getPropertyType(name), argObjectType.getPropertyType(name), resolvedTypes, seenTypes);
                    }
                }
            }
            seenTypes.remove(paramType);
        }
    } else if (paramType.isTemplatizedType()) {
        // example: @param {Array<T>}
        TemplatizedType templatizedParamType = paramType.toMaybeTemplatizedType();
        int keyCount = templatizedParamType.getTemplateTypes().size();
        // types with no type arguments.
        if (keyCount > 0) {
            ObjectType referencedParamType = templatizedParamType.getReferencedType();
            JSType argObjectType = argType.restrictByNotNullOrUndefined().collapseUnion();
            if (argObjectType.isSubtypeOf(referencedParamType)) {
                // If the argument type is a subtype of the parameter type, resolve any
                // template types amongst their templatized types.
                TemplateTypeMap paramTypeMap = paramType.getTemplateTypeMap();
                ImmutableList<TemplateType> keys = paramTypeMap.getTemplateKeys();
                TemplateTypeMap argTypeMap = argObjectType.getTemplateTypeMap();
                for (int index = keys.size() - keyCount; index < keys.size(); index++) {
                    TemplateType key = keys.get(index);
                    maybeResolveTemplatedType(paramTypeMap.getResolvedTemplateType(key), argTypeMap.getResolvedTemplateType(key), resolvedTypes, seenTypes);
                }
            }
        }
    }
}
Also used : UnionType(com.google.javascript.rhino.jstype.UnionType) ObjectType(com.google.javascript.rhino.jstype.ObjectType) TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) JSType(com.google.javascript.rhino.jstype.JSType) Set(java.util.Set) BooleanLiteralSet(com.google.javascript.rhino.jstype.BooleanLiteralSet) FunctionType(com.google.javascript.rhino.jstype.FunctionType) TemplateType(com.google.javascript.rhino.jstype.TemplateType) TemplatizedType(com.google.javascript.rhino.jstype.TemplatizedType)

Example 8 with TemplateType

use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.

the class FunctionTypeBuilder method inferInheritance.

/**
 * Infer the role of the function (whether it's a constructor or interface)
 * and what it inherits from in JSDocInfo.
 */
FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
    if (info != null) {
        isConstructor = info.isConstructor();
        isInterface = info.isInterface();
        isAbstract = info.isAbstract();
        makesStructs = info.makesStructs();
        makesDicts = info.makesDicts();
        if (makesStructs && !(isConstructor || isInterface)) {
            reportWarning(CONSTRUCTOR_REQUIRED, "@struct", formatFnName());
        } else if (makesDicts && !isConstructor) {
            reportWarning(CONSTRUCTOR_REQUIRED, "@dict", formatFnName());
        }
        // TODO(b/74253232): maybeGetNativeTypesOfBuiltin should also handle cases where a local type
        // declaration shadows a templatized native type.
        ImmutableList<TemplateType> nativeClassTemplateTypeNames = typeRegistry.maybeGetTemplateTypesOfBuiltin(fnName);
        ImmutableList<String> infoTemplateTypeNames = info.getTemplateTypeNames();
        // Preconditions check. It currently fails for "var symbol" in the externs.
        if (nativeClassTemplateTypeNames != null && infoTemplateTypeNames.size() == nativeClassTemplateTypeNames.size()) {
            classTemplateTypeNames = nativeClassTemplateTypeNames;
            typeRegistry.setTemplateTypeNames(classTemplateTypeNames);
        } else {
            // Otherwise, create new template type for
            // the template values of the constructor/interface
            // Class template types, which can be used in the scope of a constructor
            // definition.
            ImmutableList<String> typeParameters = info.getTemplateTypeNames();
            if (!typeParameters.isEmpty() && (isConstructor || isInterface)) {
                ImmutableList.Builder<TemplateType> builder = ImmutableList.builder();
                for (String typeParameter : typeParameters) {
                    builder.add(typeRegistry.createTemplateType(typeParameter));
                }
                classTemplateTypeNames = builder.build();
                typeRegistry.setTemplateTypeNames(classTemplateTypeNames);
            }
        }
        // base type
        if (info.hasBaseType()) {
            if (isConstructor) {
                JSType maybeBaseType = info.getBaseType().evaluate(scope, typeRegistry);
                if (maybeBaseType != null && maybeBaseType.setValidator(new ExtendedTypeValidator())) {
                    baseType = (ObjectType) maybeBaseType;
                }
            } else {
                reportWarning(EXTENDS_WITHOUT_TYPEDEF, formatFnName());
            }
        }
        // Implemented interfaces (for constructors only).
        if (info.getImplementedInterfaceCount() > 0) {
            if (isConstructor) {
                implementedInterfaces = new ArrayList<>();
                Set<JSType> baseInterfaces = new HashSet<>();
                for (JSTypeExpression t : info.getImplementedInterfaces()) {
                    JSType maybeInterType = t.evaluate(scope, typeRegistry);
                    if (maybeInterType != null && maybeInterType.setValidator(new ImplementedTypeValidator())) {
                        // Disallow implementing the same base (not templatized) interface
                        // type more than once.
                        JSType baseInterface = maybeInterType;
                        if (baseInterface.toMaybeTemplatizedType() != null) {
                            baseInterface = baseInterface.toMaybeTemplatizedType().getReferencedType();
                        }
                        if (!baseInterfaces.add(baseInterface)) {
                            reportWarning(SAME_INTERFACE_MULTIPLE_IMPLEMENTS, baseInterface.toString());
                        }
                        implementedInterfaces.add((ObjectType) maybeInterType);
                    }
                }
            } else if (isInterface) {
                reportWarning(TypeCheck.CONFLICTING_IMPLEMENTED_TYPE, formatFnName());
            } else {
                reportWarning(CONSTRUCTOR_REQUIRED, "@implements", formatFnName());
            }
        }
        // We've already emitted a warning if this is not an interface.
        if (isInterface) {
            extendedInterfaces = new ArrayList<>();
            for (JSTypeExpression t : info.getExtendedInterfaces()) {
                JSType maybeInterfaceType = t.evaluate(scope, typeRegistry);
                if (maybeInterfaceType != null && maybeInterfaceType.setValidator(new ExtendedTypeValidator())) {
                    extendedInterfaces.add((ObjectType) maybeInterfaceType);
                }
            }
        }
    }
    return this;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) ImmutableList(com.google.common.collect.ImmutableList) TemplateType(com.google.javascript.rhino.jstype.TemplateType) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) HashSet(java.util.HashSet)

Example 9 with TemplateType

use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.

the class TypeInference method inferTemplatedTypesForCall.

/**
 * For functions that use template types, specialize the function type for
 * the call target based on the call-site specific arguments.
 * Specifically, this enables inference to set the type of any function
 * literal parameters based on these inferred types.
 */
private boolean inferTemplatedTypesForCall(Node n, FunctionType fnType) {
    ImmutableList<TemplateType> keys = fnType.getTemplateTypeMap().getTemplateKeys();
    if (keys.isEmpty()) {
        return false;
    }
    // Try to infer the template types
    Map<TemplateType, JSType> rawInferrence = inferTemplateTypesFromParameters(fnType, n);
    Map<TemplateType, JSType> inferred = Maps.newIdentityHashMap();
    for (TemplateType key : keys) {
        JSType type = rawInferrence.get(key);
        if (type == null) {
            type = unknownType;
        }
        inferred.put(key, type);
    }
    // Try to infer the template types using the type transformations
    Map<TemplateType, JSType> typeTransformations = evaluateTypeTransformations(keys, inferred);
    if (typeTransformations != null) {
        inferred.putAll(typeTransformations);
    }
    // Replace all template types. If we couldn't find a replacement, we
    // replace it with UNKNOWN.
    TemplateTypeReplacer replacer = new TemplateTypeReplacer(registry, inferred);
    Node callTarget = n.getFirstChild();
    FunctionType replacementFnType = fnType.visit(replacer).toMaybeFunctionType();
    checkNotNull(replacementFnType);
    callTarget.setJSType(replacementFnType);
    n.setJSType(replacementFnType.getReturnType());
    return replacer.madeChanges;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) FunctionType(com.google.javascript.rhino.jstype.FunctionType) TemplateType(com.google.javascript.rhino.jstype.TemplateType)

Example 10 with TemplateType

use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.

the class TypeInference method inferTemplateTypesFromParameters.

private Map<TemplateType, JSType> inferTemplateTypesFromParameters(FunctionType fnType, Node call) {
    if (fnType.getTemplateTypeMap().getTemplateKeys().isEmpty()) {
        return Collections.emptyMap();
    }
    Map<TemplateType, JSType> resolvedTypes = Maps.newIdentityHashMap();
    Set<JSType> seenTypes = Sets.newIdentityHashSet();
    Node callTarget = call.getFirstChild();
    if (NodeUtil.isGet(callTarget)) {
        Node obj = callTarget.getFirstChild();
        maybeResolveTemplatedType(fnType.getTypeOfThis(), getJSType(obj).restrictByNotNullOrUndefined(), resolvedTypes, seenTypes);
    }
    if (call.hasMoreThanOneChild()) {
        maybeResolveTemplateTypeFromNodes(fnType.getParameters(), call.getSecondChild().siblings(), resolvedTypes, seenTypes);
    }
    return resolvedTypes;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) TemplateType(com.google.javascript.rhino.jstype.TemplateType)

Aggregations

TemplateType (com.google.javascript.rhino.jstype.TemplateType)17 JSType (com.google.javascript.rhino.jstype.JSType)13 FunctionType (com.google.javascript.rhino.jstype.FunctionType)8 Node (com.google.javascript.rhino.Node)7 ObjectType (com.google.javascript.rhino.jstype.ObjectType)3 TemplateTypeMap (com.google.javascript.rhino.jstype.TemplateTypeMap)3 ImmutableList (com.google.common.collect.ImmutableList)2 ImmutableMap (com.google.common.collect.ImmutableMap)2 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)2 TemplatizedType (com.google.javascript.rhino.jstype.TemplatizedType)2 UnionType (com.google.javascript.rhino.jstype.UnionType)2 ArrayList (java.util.ArrayList)2 LinkedHashMap (java.util.LinkedHashMap)2 Set (java.util.Set)2 FlowScope (com.google.javascript.jscomp.type.FlowScope)1 BooleanLiteralSet (com.google.javascript.rhino.jstype.BooleanLiteralSet)1 JSTypeRegistry (com.google.javascript.rhino.jstype.JSTypeRegistry)1 TemplateTypeReplacer (com.google.javascript.rhino.jstype.TemplateTypeReplacer)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1