Search in sources :

Example 11 with TemplateType

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

the class TypeInference method evaluateTypeTransformations.

/**
 * This function will evaluate the type transformations associated to the
 * template types
 */
private Map<TemplateType, JSType> evaluateTypeTransformations(ImmutableList<TemplateType> templateTypes, Map<TemplateType, JSType> inferredTypes) {
    Map<String, JSType> typeVars = null;
    Map<TemplateType, JSType> result = null;
    TypeTransformation ttlObj = null;
    for (TemplateType type : templateTypes) {
        if (type.isTypeTransformation()) {
            // Lazy initialization when the first type transformation is found
            if (ttlObj == null) {
                ttlObj = new TypeTransformation(compiler, currentScope);
                typeVars = buildTypeVariables(inferredTypes);
                result = new LinkedHashMap<>();
            }
            // Evaluate the type transformation expression using the current
            // known types for the template type variables
            @SuppressWarnings({ "unchecked", "rawtypes" }) JSType transformedType = (JSType) ttlObj.eval(type.getTypeTransformation(), (ImmutableMap) ImmutableMap.copyOf(typeVars));
            result.put(type, transformedType);
            // Add the transformed type to the type variables
            typeVars.put(type.getReferenceName(), transformedType);
        }
    }
    return result;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) TemplateType(com.google.javascript.rhino.jstype.TemplateType) ImmutableMap(com.google.common.collect.ImmutableMap)

Example 12 with TemplateType

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

the class InvocationTemplateTypeMatcher method matchTemplateTypesRecursive.

private void matchTemplateTypesRecursive(JSType paramType, JSType argType) {
    if (paramType.isTemplateType()) {
        // Recursive base case.
        // example: @param {T}
        this.recordTemplateMatch(paramType.toMaybeTemplateType(), argType);
        return;
    }
    // Unpack unions.
    if (paramType.isUnionType()) {
        // example: @param {Array.<T>|NodeList|Arguments|{length:number}}
        UnionType unionType = paramType.toMaybeUnionType();
        for (JSType alternate : unionType.getAlternates()) {
            this.matchTemplateTypesRecursive(alternate, argType);
        }
        return;
    } else if (argType.isUnionType()) {
        UnionType unionType = argType.toMaybeUnionType();
        for (JSType alternate : unionType.getAlternates()) {
            this.matchTemplateTypesRecursive(paramType, alternate);
        }
        return;
    }
    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
            this.matchTemplateTypesRecursive(paramFunctionType.getTypeOfThis(), argFunctionType.getTypeOfThis());
            // infer from return type of the function type
            this.matchTemplateTypesRecursive(paramFunctionType.getReturnType(), argFunctionType.getReturnType());
            // infer from parameter types of the function type
            this.matchTemplateTypesFromParameters(paramFunctionType.getParameters().iterator(), argFunctionType.getParameters().iterator());
        }
    } else if (paramType.isRecordType() && !paramType.isNominalType()) {
        // example: @param {{foo:T}}
        if (this.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)) {
                        this.matchTemplateTypesRecursive(paramRecordType.getPropertyType(name), argObjectType.getPropertyType(name));
                    }
                }
            }
            this.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) {
            return;
        }
        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);
                this.matchTemplateTypesRecursive(paramTypeMap.getResolvedTemplateType(key), argTypeMap.getResolvedTemplateType(key));
            }
        }
    }
}
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) FunctionType(com.google.javascript.rhino.jstype.FunctionType) TemplateType(com.google.javascript.rhino.jstype.TemplateType) TemplatizedType(com.google.javascript.rhino.jstype.TemplatizedType)

Example 13 with TemplateType

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

the class JsIterables method maybeBoxIterableOrAsyncIterable.

/**
 * Given a type, if it is an iterable or async iterable, will return its template. If not a
 * subtype of Iterable|AsyncIterable, returns an object that has no match, and will indicate the
 * mismatch. e.g. both {@code number} and {@code number|Iterable} are not subtypes of
 * Iterable|AsyncIterable.
 */
static final MaybeBoxedIterableOrAsyncIterable maybeBoxIterableOrAsyncIterable(JSType type, JSTypeRegistry typeRegistry) {
    List<JSType> templatedTypes = new ArrayList<>();
    // We want to keep null and undefined around because they should cause a mismatch.
    if (type.isUnionType()) {
        for (JSType alt : type.toMaybeUnionType().getAlternates()) {
            alt = alt.isBoxableScalar() ? alt.autoboxesTo() : alt;
            boolean isIterable = alt.isSubtypeOf(typeRegistry.getNativeType(ITERABLE_TYPE));
            boolean isAsyncIterable = alt.isSubtypeOf(typeRegistry.getNativeType(ASYNC_ITERABLE_TYPE));
            if (!isIterable && !isAsyncIterable) {
                return new MaybeBoxedIterableOrAsyncIterable(null, alt);
            }
            TemplateType valueTemplate = isAsyncIterable ? typeRegistry.getAsyncIterableTemplate() : typeRegistry.getIterableTemplate();
            templatedTypes.add(alt.getTemplateTypeMap().getResolvedTemplateType(valueTemplate));
        }
    } else {
        JSType autoboxedType = type.isBoxableScalar() ? type.autoboxesTo() : type;
        boolean isIterable = autoboxedType.isSubtypeOf(typeRegistry.getNativeType(ITERABLE_TYPE));
        boolean isAsyncIterable = autoboxedType.isSubtypeOf(typeRegistry.getNativeType(ASYNC_ITERABLE_TYPE));
        if (!isIterable && !isAsyncIterable) {
            return new MaybeBoxedIterableOrAsyncIterable(null, autoboxedType);
        }
        TemplateType templateType = isAsyncIterable ? typeRegistry.getAsyncIterableTemplate() : typeRegistry.getIterableTemplate();
        templatedTypes.add(autoboxedType.getTemplateTypeMap().getResolvedTemplateType(templateType));
    }
    return new MaybeBoxedIterableOrAsyncIterable(typeRegistry.createUnionType(templatedTypes), null);
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) ArrayList(java.util.ArrayList) TemplateType(com.google.javascript.rhino.jstype.TemplateType)

Example 14 with TemplateType

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

the class TypeCheck method visitYield.

/**
 * Visits a YIELD node.
 */
private void visitYield(NodeTraversal t, Node n) {
    JSType jsType = getJSType(t.getEnclosingFunction());
    JSType declaredYieldType = getNativeType(UNKNOWN_TYPE);
    if (jsType.isFunctionType()) {
        FunctionType functionType = jsType.toMaybeFunctionType();
        JSType returnType = functionType.getReturnType();
        declaredYieldType = JsIterables.getElementType(returnType, typeRegistry);
        if (t.getEnclosingFunction().isAsyncGeneratorFunction()) {
            // Can yield x|IThenable<x> in an AsyncGenerator<x>, no await needed. Note that we must
            // first wrap the type in IThenable as createAsyncReturnableType will map a non-IThenable to
            // `?`.
            declaredYieldType = Promises.createAsyncReturnableType(typeRegistry, Promises.wrapInIThenable(typeRegistry, declaredYieldType));
        }
    }
    // fetching the yielded value's type
    Node valueNode = n.getFirstChild();
    JSType actualYieldType;
    if (valueNode == null) {
        actualYieldType = getNativeType(VOID_TYPE);
        valueNode = n;
    } else {
        actualYieldType = getJSType(valueNode);
    }
    if (n.isYieldAll()) {
        if (t.getEnclosingFunction().isAsyncGeneratorFunction()) {
            Optional<JSType> maybeActualYieldType = validator.expectAutoboxesToIterableOrAsyncIterable(n, actualYieldType, "Expression yield* expects an iterable or async iterable");
            if (!maybeActualYieldType.isPresent()) {
                // don't do any further typechecking of the yield* type.
                return;
            }
            actualYieldType = maybeActualYieldType.get();
        } else {
            if (!validator.expectAutoboxesToIterable(n, actualYieldType, "Expression yield* expects an iterable")) {
                // don't do any further typechecking of the yield* type.
                return;
            }
            TemplateType templateType = typeRegistry.getIterableTemplate();
            actualYieldType = actualYieldType.autobox().getTemplateTypeMap().getResolvedTemplateType(templateType);
        }
    }
    // verifying
    validator.expectCanAssignTo(valueNode, actualYieldType, declaredYieldType, "Yielded type does not match declared return type.");
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) FunctionType(com.google.javascript.rhino.jstype.FunctionType) Node(com.google.javascript.rhino.Node) TemplateType(com.google.javascript.rhino.jstype.TemplateType)

Example 15 with TemplateType

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

the class TypeInference method initializeEnhancedForScope.

private FlowScope initializeEnhancedForScope(Node source, FlowScope output) {
    Node item = source.getFirstChild();
    Node obj = item.getNext();
    FlowScope informed = traverse(obj, output);
    final AssignmentType assignmentType;
    if (NodeUtil.isNameDeclaration(item)) {
        item = item.getFirstChild();
        assignmentType = AssignmentType.DECLARATION;
    } else {
        assignmentType = AssignmentType.ASSIGN;
    }
    if (item.isDestructuringLhs()) {
        item = item.getFirstChild();
    }
    final JSType newType;
    switch(source.getToken()) {
        case FOR_IN:
            {
                // item is assigned a property name, so its type should be string
                JSType iterKeyType = getNativeType(STRING_TYPE);
                JSType objType = getJSType(obj).autobox();
                JSType objIndexType = objType.getTemplateTypeMap().getResolvedTemplateType(registry.getObjectIndexKey());
                if (objIndexType != null && !objIndexType.isUnknownType()) {
                    JSType narrowedKeyType = iterKeyType.getGreatestSubtype(objIndexType);
                    if (!narrowedKeyType.isEmptyType()) {
                        iterKeyType = narrowedKeyType;
                    }
                }
                newType = iterKeyType;
                break;
            }
        case FOR_OF:
            {
                // for/of. The type of `item` is the type parameter of the Iterable type.
                JSType objType = getJSType(obj).autobox();
                TemplateType templateType = registry.getIterableTemplate();
                // NOTE: this returns the UNKNOWN_TYPE if objType does not implement Iterable
                newType = objType.getTemplateTypeMap().getResolvedTemplateType(templateType);
                break;
            }
        case FOR_AWAIT_OF:
            {
                // for/await/of. the iterated object is either of the Iterable or AsyncIterable type.
                // the type of `item` is the Promise.resolve() type of the object's type parameter.
                JSType iterableType = JsIterables.maybeBoxIterableOrAsyncIterable(getJSType(obj), registry).orElse(unknownType);
                newType = Promises.getResolvedType(registry, iterableType);
                break;
            }
        default:
            throw new IllegalArgumentException("Unexpected source node " + source);
    }
    // Note that `item` can be an arbitrary LHS expression we need to check.
    if (item.isDestructuringPattern()) {
        // for (const {x, y} of data) {
        informed = traverseDestructuringPattern(item, informed, newType, assignmentType);
    } else {
        informed = traverse(item, informed);
        informed = updateScopeForAssignment(informed, item, newType, assignmentType);
    }
    return informed;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) TemplateType(com.google.javascript.rhino.jstype.TemplateType) FlowScope(com.google.javascript.jscomp.type.FlowScope)

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