Search in sources :

Example 1 with TemplateTypeMap

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

the class TypeInference method getPropertyType.

private JSType getPropertyType(JSType objType, String propName, Node n, FlowScope scope) {
    // We often have a couple of different types to choose from for the
    // property. Ordered by accuracy, we have
    // 1) A locally inferred qualified name (which is in the FlowScope)
    // 2) A globally declared qualified name (which is in the FlowScope)
    // 3) A property on the owner type (which is on objType)
    // 4) A name in the type registry (as a last resort)
    JSType propertyType = null;
    boolean isLocallyInferred = false;
    // Scopes sometimes contain inferred type info about qualified names.
    String qualifiedName = n.getQualifiedName();
    StaticTypedSlot<JSType> var = qualifiedName != null ? scope.getSlot(qualifiedName) : null;
    if (var != null) {
        JSType varType = var.getType();
        if (varType != null) {
            boolean isDeclared = !var.isTypeInferred();
            isLocallyInferred = (var != currentScope.getSlot(qualifiedName));
            if (isDeclared || isLocallyInferred) {
                propertyType = varType;
            }
        }
    }
    if (propertyType == null && objType != null) {
        JSType foundType = objType.findPropertyType(propName);
        if (foundType != null) {
            propertyType = foundType;
        }
    }
    if (propertyType != null && objType != null) {
        JSType restrictedObjType = objType.restrictByNotNullOrUndefined();
        if (!restrictedObjType.getTemplateTypeMap().isEmpty() && propertyType.hasAnyTemplateTypes()) {
            TemplateTypeMap typeMap = restrictedObjType.getTemplateTypeMap();
            TemplateTypeMapReplacer replacer = new TemplateTypeMapReplacer(registry, typeMap);
            propertyType = propertyType.visit(replacer);
        }
    }
    if ((propertyType == null || propertyType.isUnknownType()) && qualifiedName != null) {
        // If we find this node in the registry, then we can infer its type.
        ObjectType regType = ObjectType.cast(registry.getType(qualifiedName));
        if (regType != null) {
            propertyType = regType.getConstructor();
        }
    }
    if (propertyType == null) {
        return unknownType;
    } else if (propertyType.isEquivalentTo(unknownType) && isLocallyInferred) {
        // then use CHECKED_UNKNOWN_TYPE instead to indicate that.
        return getNativeType(CHECKED_UNKNOWN_TYPE);
    } else {
        return propertyType;
    }
}
Also used : TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) ObjectType(com.google.javascript.rhino.jstype.ObjectType) JSType(com.google.javascript.rhino.jstype.JSType) TemplateTypeMapReplacer(com.google.javascript.rhino.jstype.TemplateTypeMapReplacer)

Example 2 with TemplateTypeMap

use of com.google.javascript.rhino.jstype.TemplateTypeMap 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 3 with TemplateTypeMap

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

the class TypeCheck method checkDeclaredPropertyInheritance.

/**
 * Given a constructor type and a property name, check that the property has
 * the JSDoc annotation @override iff the property is declared on a
 * superclass. Several checks regarding inheritance correctness are also
 * performed.
 */
private void checkDeclaredPropertyInheritance(NodeTraversal t, Node n, FunctionType ctorType, String propertyName, JSDocInfo info, JSType propertyType) {
    // already.
    if (hasUnknownOrEmptySupertype(ctorType)) {
        return;
    }
    FunctionType superClass = ctorType.getSuperClassConstructor();
    boolean superClassHasProperty = superClass != null && superClass.getInstanceType().hasProperty(propertyName);
    boolean superClassHasDeclaredProperty = superClass != null && superClass.getInstanceType().isPropertyTypeDeclared(propertyName);
    // For interface
    boolean superInterfaceHasProperty = false;
    boolean superInterfaceHasDeclaredProperty = false;
    if (ctorType.isInterface()) {
        for (ObjectType interfaceType : ctorType.getExtendedInterfaces()) {
            superInterfaceHasProperty = superInterfaceHasProperty || interfaceType.hasProperty(propertyName);
            superInterfaceHasDeclaredProperty = superInterfaceHasDeclaredProperty || interfaceType.isPropertyTypeDeclared(propertyName);
        }
    }
    boolean declaredOverride = info != null && info.isOverride();
    boolean foundInterfaceProperty = false;
    if (ctorType.isConstructor()) {
        for (JSType implementedInterface : ctorType.getAllImplementedInterfaces()) {
            if (implementedInterface.isUnknownType() || implementedInterface.isEmptyType()) {
                continue;
            }
            FunctionType interfaceType = implementedInterface.toObjectType().getConstructor();
            checkNotNull(interfaceType);
            boolean interfaceHasProperty = interfaceType.getPrototype().hasProperty(propertyName);
            foundInterfaceProperty = foundInterfaceProperty || interfaceHasProperty;
            if (!declaredOverride && interfaceHasProperty && !"__proto__".equals(propertyName)) {
                // @override not present, but the property does override an interface property
                compiler.report(t.makeError(n, HIDDEN_INTERFACE_PROPERTY, propertyName, interfaceType.getTopMostDefiningType(propertyName).toString()));
            }
        }
    }
    if (!declaredOverride && !superClassHasProperty && !superInterfaceHasProperty) {
        // nothing to do here, it's just a plain new property
        return;
    }
    ObjectType topInstanceType = superClassHasDeclaredProperty ? superClass.getTopMostDefiningType(propertyName) : null;
    boolean declaredLocally = ctorType.isConstructor() && (ctorType.getPrototype().hasOwnProperty(propertyName) || ctorType.getInstanceType().hasOwnProperty(propertyName));
    if (!declaredOverride && superClassHasDeclaredProperty && declaredLocally && !"__proto__".equals(propertyName)) {
        // @override not present, but the property does override a superclass
        // property
        compiler.report(t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY, propertyName, topInstanceType.toString()));
    }
    // @override is present and we have to check that it is ok
    if (superClassHasDeclaredProperty) {
        // there is a superclass implementation
        JSType superClassPropType = superClass.getInstanceType().getPropertyType(propertyName);
        TemplateTypeMap ctorTypeMap = ctorType.getTypeOfThis().getTemplateTypeMap();
        if (!ctorTypeMap.isEmpty()) {
            superClassPropType = superClassPropType.visit(new TemplateTypeMapReplacer(typeRegistry, ctorTypeMap));
        }
        if (!propertyType.isSubtype(superClassPropType, this.subtypingMode)) {
            compiler.report(t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY_MISMATCH, propertyName, topInstanceType.toString(), superClassPropType.toString(), propertyType.toString()));
        }
    } else if (superInterfaceHasDeclaredProperty) {
        // there is an super interface property
        for (ObjectType interfaceType : ctorType.getExtendedInterfaces()) {
            if (interfaceType.hasProperty(propertyName)) {
                JSType superPropertyType = interfaceType.getPropertyType(propertyName);
                if (!propertyType.isSubtype(superPropertyType, this.subtypingMode)) {
                    topInstanceType = interfaceType.getConstructor().getTopMostDefiningType(propertyName);
                    compiler.report(t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY_MISMATCH, propertyName, topInstanceType.toString(), superPropertyType.toString(), propertyType.toString()));
                }
            }
        }
    } else if (!foundInterfaceProperty && !superClassHasProperty && !superInterfaceHasProperty) {
        // there is no superclass nor interface implementation
        compiler.report(t.makeError(n, UNKNOWN_OVERRIDE, propertyName, ctorType.getInstanceType().toString()));
    }
}
Also used : ObjectType(com.google.javascript.rhino.jstype.ObjectType) TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) JSType(com.google.javascript.rhino.jstype.JSType) TemplateTypeMapReplacer(com.google.javascript.rhino.jstype.TemplateTypeMapReplacer) FunctionType(com.google.javascript.rhino.jstype.FunctionType)

Example 4 with TemplateTypeMap

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

the class TypeValidator method expectInterfaceProperty.

/**
 * Expect that the property in an interface that this type implements is
 * implemented and correctly typed.
 */
private void expectInterfaceProperty(NodeTraversal t, Node n, ObjectType instance, ObjectType implementedInterface, String prop) {
    StaticTypedSlot<JSType> propSlot = instance.getSlot(prop);
    if (propSlot == null) {
        // Not implemented
        String sourceName = n.getSourceFileName();
        sourceName = nullToEmpty(sourceName);
        TypeMismatch.registerMismatch(this.mismatches, this.implicitInterfaceUses, instance, implementedInterface, report(JSError.make(n, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implementedInterface.toString(), instance.toString())));
    } else {
        Node propNode = propSlot.getDeclaration() == null ? null : propSlot.getDeclaration().getNode();
        // Fall back on the constructor node if we can't find a node for the
        // property.
        propNode = propNode == null ? n : propNode;
        JSType found = propSlot.getType();
        found = found.restrictByNotNullOrUndefined();
        JSType required = implementedInterface.getImplicitPrototype().getPropertyType(prop);
        TemplateTypeMap typeMap = implementedInterface.getTemplateTypeMap();
        if (!typeMap.isEmpty()) {
            TemplateTypeMapReplacer replacer = new TemplateTypeMapReplacer(typeRegistry, typeMap);
            required = required.visit(replacer);
        }
        required = required.restrictByNotNullOrUndefined();
        if (!found.isSubtype(required, this.subtypingMode)) {
            // Implemented, but not correctly typed
            FunctionType constructor = implementedInterface.toObjectType().getConstructor();
            JSError err = t.makeError(propNode, HIDDEN_INTERFACE_PROPERTY_MISMATCH, prop, instance.toString(), constructor.getTopMostDefiningType(prop).toString(), required.toString(), found.toString());
            TypeMismatch.registerMismatch(this.mismatches, this.implicitInterfaceUses, found, required, err);
            report(err);
        }
    }
}
Also used : TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) JSType(com.google.javascript.rhino.jstype.JSType) TemplateTypeMapReplacer(com.google.javascript.rhino.jstype.TemplateTypeMapReplacer) Node(com.google.javascript.rhino.Node) FunctionType(com.google.javascript.rhino.jstype.FunctionType)

Example 5 with TemplateTypeMap

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

the class TypeInference method traverseGetElem.

private FlowScope traverseGetElem(Node n, FlowScope scope) {
    scope = traverseChildren(n, scope);
    JSType type = getJSType(n.getFirstChild()).restrictByNotNullOrUndefined();
    TemplateTypeMap typeMap = type.getTemplateTypeMap();
    if (typeMap.hasTemplateType(registry.getObjectElementKey())) {
        n.setJSType(typeMap.getResolvedTemplateType(registry.getObjectElementKey()));
    }
    return dereferencePointer(n.getFirstChild(), scope);
}
Also used : TemplateTypeMap(com.google.javascript.rhino.jstype.TemplateTypeMap) JSType(com.google.javascript.rhino.jstype.JSType)

Aggregations

JSType (com.google.javascript.rhino.jstype.JSType)5 TemplateTypeMap (com.google.javascript.rhino.jstype.TemplateTypeMap)5 FunctionType (com.google.javascript.rhino.jstype.FunctionType)3 ObjectType (com.google.javascript.rhino.jstype.ObjectType)3 TemplateTypeMapReplacer (com.google.javascript.rhino.jstype.TemplateTypeMapReplacer)3 Node (com.google.javascript.rhino.Node)1 BooleanLiteralSet (com.google.javascript.rhino.jstype.BooleanLiteralSet)1 TemplateType (com.google.javascript.rhino.jstype.TemplateType)1 TemplatizedType (com.google.javascript.rhino.jstype.TemplatizedType)1 UnionType (com.google.javascript.rhino.jstype.UnionType)1 Set (java.util.Set)1