workset_loop:
while (!workset.isEmpty()) {
// TODO(blickly): Fix this infinite loop and remove these counters
Preconditions.checkState(iterations < MAX_ITERATIONS);
Node funNode = workset.removeFirst();
RawNominalType rawNominalType = nominaltypesByNode.get(funNode);
NominalType superClass = rawNominalType.getSuperClass();
Set<String> nonInheritedPropNames = rawNominalType.getAllOwnProps();
if (superClass != null && !superClass.isFinalized()) {
workset.addLast(funNode);
iterations++;
continue workset_loop;
}
for (NominalType superInterf : rawNominalType.getInterfaces()) {
if (!superInterf.isFinalized()) {
workset.addLast(funNode);
iterations++;
continue workset_loop;
}
}
Multimap<String, DeclaredFunctionType> propMethodTypesToProcess =
HashMultimap.create();
Multimap<String, JSType> propTypesToProcess = HashMultimap.create();
// Collect inherited types for extended classes
if (superClass != null) {
Preconditions.checkState(superClass.isFinalized());
// TODO(blickly): Can we optimize this to skip unnecessary iterations?
for (String pname : superClass.getAllPropsOfClass()) {
nonInheritedPropNames.remove(pname);
checkSuperProperty(rawNominalType, superClass, pname,
propMethodTypesToProcess, propTypesToProcess);
}
}
// Collect inherited types for extended/implemented interfaces
for (NominalType superInterf : rawNominalType.getInterfaces()) {
Preconditions.checkState(superInterf.isFinalized());
for (String pname : superInterf.getAllPropsOfInterface()) {
nonInheritedPropNames.remove(pname);
checkSuperProperty(rawNominalType, superInterf, pname,
propMethodTypesToProcess, propTypesToProcess);
}
}
// Munge inherited types of methods
for (String pname : propMethodTypesToProcess.keySet()) {
Collection<DeclaredFunctionType> methodTypes =
propMethodTypesToProcess.get(pname);
Preconditions.checkState(!methodTypes.isEmpty());
PropertyDef localPropDef =
propertyDefs.get(rawNominalType, pname);
// To find the declared type of a method, we must meet declared types
// from all inherited methods.
DeclaredFunctionType superMethodType =
DeclaredFunctionType.meet(methodTypes);
DeclaredFunctionType updatedMethodType =
localPropDef.methodType.withTypeInfoFromSuper(superMethodType);
localPropDef.updateMethodType(updatedMethodType);
propTypesToProcess.put(pname,
JSType.fromFunctionType(updatedMethodType.toFunctionType()));
}
// Check inherited types of all props
add_interface_props:
for (String pname : propTypesToProcess.keySet()) {
Collection<JSType> defs = propTypesToProcess.get(pname);
Preconditions.checkState(!defs.isEmpty());
JSType resultType = JSType.TOP;
for (JSType inheritedType : defs) {
resultType = JSType.meet(resultType, inheritedType);
if (!resultType.isBottom()) {
resultType = inheritedType;
} else {
// TOOD(blickly): Fix this error message to include supertype names
warnings.add(JSError.make(
funNode, TypeCheck.INCOMPATIBLE_EXTENDED_PROPERTY_TYPE,
NodeUtil.getFunctionName(funNode), pname, "", ""));
continue add_interface_props;
}
}
// TODO(dimvar): check if we can have @const props here
rawNominalType.addProtoProperty(pname, resultType, false);
}
// Warn for a prop declared with @override that isn't overriding anything.
for (String pname : nonInheritedPropNames) {
Node defSite = propertyDefs.get(rawNominalType, pname).defSite;
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(defSite);
if (jsdoc != null && jsdoc.isOverride()) {
warnings.add(JSError.make(defSite, TypeCheck.UNKNOWN_OVERRIDE,
pname, rawNominalType.getName()));
}
}
// Finalize nominal type once all properties are added.
rawNominalType.finalizeNominalType();
}
}