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;
}
}
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);
}
}
}
}
}
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()));
}
}
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);
}
}
}
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);
}
Aggregations