use of com.google.javascript.jscomp.newtypes.RawNominalType in project closure-compiler by google.
the class GlobalTypeInfoCollector method process.
@Override
public void process(Node externs, Node root) {
checkNotNull(warnings, "Cannot rerun GlobalTypeInfoCollector.process");
checkArgument(externs == null || externs.isRoot());
checkArgument(root.isRoot(), "Root must be ROOT, but is %s", root.getToken());
this.compiler.setMostRecentTypechecker(MostRecentTypechecker.NTI);
NTIScope globalScope = new NTIScope(root, null, ImmutableList.<String>of(), getCommonTypes());
globalScope.addUnknownTypeNames(this.globalTypeInfo.getUnknownTypeNames());
this.globalTypeInfo.setGlobalScope(globalScope);
this.scopes.add(globalScope);
// Processing of a scope is split into many separate phases, and it's not
// straightforward to remember which phase does what.
// (1) Find names of classes, interfaces, typedefs, enums, and namespaces
// defined in the global scope.
CollectNamedTypes rootCnt = new CollectNamedTypes(globalScope);
NodeTraversal.traverseEs6(this.compiler, externs, this.orderedExterns);
rootCnt.collectNamedTypesInExterns();
defineObjectAndFunctionIfMissing();
NodeTraversal.traverseEs6(compiler, root, rootCnt);
// (2) Determine the type represented by each typedef and each enum
globalScope.resolveTypedefs(getTypeParser());
globalScope.resolveEnums(getTypeParser());
// (3) Repeat steps 1-2 for all the other scopes (outer-to-inner)
for (int i = 1; i < this.scopes.size(); i++) {
NTIScope s = this.scopes.get(i);
CollectNamedTypes cnt = new CollectNamedTypes(s);
NodeTraversal.traverseEs6(compiler, s.getBody(), cnt);
s.resolveTypedefs(getTypeParser());
s.resolveEnums(getTypeParser());
if (NewTypeInference.measureMem) {
NewTypeInference.updatePeakMem();
}
}
// (4) The bulk of the global-scope processing happens here:
// - Create scopes for functions
// - Declare properties on types
ProcessScope rootPs = new ProcessScope(globalScope);
if (externs != null) {
NodeTraversal.traverseEs6(compiler, externs, rootPs);
}
NodeTraversal.traverseEs6(compiler, root, rootPs);
// (5) Things that must happen after the traversal of the scope
rootPs.finishProcessingScope();
// (6) Repeat steps 4-5 for all the other scopes (outer-to-inner)
for (int i = 1; i < this.scopes.size(); i++) {
NTIScope s = this.scopes.get(i);
ProcessScope ps = new ProcessScope(s);
NodeTraversal.traverseEs6(compiler, s.getBody(), ps);
ps.finishProcessingScope();
if (NewTypeInference.measureMem) {
NewTypeInference.updatePeakMem();
}
}
// (7) Adjust types of properties based on inheritance information.
// Report errors in the inheritance chain. Do Window last.
Collection<RawNominalType> windows = new ArrayList<>();
for (Map.Entry<Node, RawNominalType> entry : nominaltypesByNode.entrySet()) {
RawNominalType rawType = entry.getValue();
if (this.window != null && rawType.hasAncestorClass(this.window)) {
windows.add(rawType);
continue;
}
checkAndFreezeNominalType(rawType);
}
JSType globalThisType = null;
if (this.window != null) {
// Copy properties from window to Window.prototype, because sometimes
// people pass window around rather than using it directly.
Namespace winNs = globalScope.getNamespace(WINDOW_INSTANCE);
if (winNs != null) {
winNs.copyWindowProperties(getCommonTypes(), this.window);
}
for (RawNominalType rawType : windows) {
checkAndFreezeNominalType(rawType);
}
if (winNs != null) {
((NamespaceLit) winNs).setWindowType(this.window.getAsNominalType());
// Type the global THIS as window
globalThisType = winNs.toJSType();
}
}
if (globalThisType == null) {
// Type the global THIS as a loose object
globalThisType = getCommonTypes().getTopObject().withLoose();
}
getCommonTypes().setGlobalThis(globalThisType);
globalScope.setDeclaredType((new FunctionTypeBuilder(getCommonTypes())).addReceiverType(globalThisType).buildDeclaration());
this.globalTypeInfo.setRawNominalTypes(nominaltypesByNode.values());
nominaltypesByNode = null;
propertyDefs = null;
for (NTIScope s : this.scopes) {
s.freezeScope();
}
this.simpleInference.setScopesAreFrozen();
// Traverse the externs and annotate them with types.
// Only works for the top level, not inside function bodies.
NodeTraversal.traverseEs6(this.compiler, externs, new NodeTraversal.AbstractShallowCallback() {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isQualifiedName()) {
Declaration d = getGlobalScope().getDeclaration(QualifiedName.fromNode(n), false);
JSType type = simpleInferDeclaration(d);
if (type == null) {
type = simpleInferExpr(n, getGlobalScope());
}
// Type-based passes expect the externs to be annotated, so use ? when type is null.
n.setTypeI(type != null ? type : getCommonTypes().UNKNOWN);
}
}
});
Map<Node, String> unknownTypes = getTypeParser().getUnknownTypesMap();
for (Map.Entry<Node, String> unknownTypeEntry : unknownTypes.entrySet()) {
this.warnings.add(JSError.make(unknownTypeEntry.getKey(), UNRECOGNIZED_TYPE_NAME, unknownTypeEntry.getValue()));
}
// package, so we collect its warnings here.
for (JSError warning : getTypeParser().getWarnings()) {
this.warnings.add(warning);
}
this.warnings = null;
this.funNameGen = null;
reorderScopesForNTI();
this.compiler.setExternProperties(ImmutableSet.copyOf(getExternPropertyNames()));
}
use of com.google.javascript.jscomp.newtypes.RawNominalType in project closure-compiler by google.
the class GlobalTypeInfoCollector method defineObjectAndFunctionIfMissing.
private void defineObjectAndFunctionIfMissing() {
JSTypes commonTypes = getCommonTypes();
if (commonTypes.getObjectType() == null) {
commonTypes.setObjectType(dummyRawTypeForMissingExterns("Object"));
}
if (commonTypes.getLiteralObjNominalType() == null) {
RawNominalType objLitRawType = dummyRawTypeForMissingExterns(JSTypes.OBJLIT_CLASS_NAME);
objLitRawType.addSuperClass(commonTypes.getObjectType());
commonTypes.setLiteralObjNominalType(objLitRawType);
}
if (commonTypes.getFunctionType() == null) {
commonTypes.setFunctionType(dummyRawTypeForMissingExterns("Function"));
}
}
use of com.google.javascript.jscomp.newtypes.RawNominalType in project closure-compiler by google.
the class GlobalTypeInfoCollector method checkAndFreezeNominalType.
/**
* Reconcile the properties of this nominal type with the properties it inherits from its
* supertypes, and then freeze the type.
*
* NOTE(dimvar): The logic is somewhat convoluted, but I'm not sure how to make it clearer.
* There is just a lot of case analysis involved.
*
* - Collect all super definitions of methods and other properties.
* - During the collection process, warn when a property on this type is not a subtype of
* an inherited property on the supertype.
* - If there are multiple inherited definitions for a property, meet them to find a single
* inherited type. If they meet to bottom, warn.
* - If this type has its own definition of the property, and not just inherits it, adjust the
* type of the local definition based on the inherited property type.
*/
private void checkAndFreezeNominalType(RawNominalType rawType) {
if (rawType.isFrozen()) {
return;
}
checkState(inProgressFreezes.add(rawType), "Cycle in freeze order: %s (%s)", rawType, inProgressFreezes);
NominalType superClass = rawType.getSuperClass();
Set<String> nonInheritedPropNames = rawType.getAllNonInheritedProps();
if (superClass != null && !superClass.isFrozen()) {
checkAndFreezeNominalType(superClass.getRawNominalType());
}
for (NominalType superInterf : rawType.getInterfaces()) {
if (!superInterf.isFrozen()) {
checkAndFreezeNominalType(superInterf.getRawNominalType());
}
}
// If this type defines a method m, collect all inherited definitions of m here in order
// to possibly adjust the type of m.
Multimap<String, DeclaredFunctionType> superMethodTypes = LinkedHashMultimap.create();
// For each property p on this type, regardless of whether it is defined on the type or just
// inherited, collect all inherited definitions of p here.
Multimap<String, JSType> superPropTypes = LinkedHashMultimap.create();
// Collect inherited types for extended classes
if (superClass != null) {
checkState(superClass.isFrozen());
// TODO(blickly): Can we optimize this to skip unnecessary iterations?
for (String pname : superClass.getPropertyNames()) {
if (superClass.isAbstractClass() && superClass.hasAbstractMethod(pname) && !rawType.isAbstractClass() && !rawType.mayHaveOwnNonStrayProp(pname)) {
warnings.add(JSError.make(rawType.getDefSite(), ABSTRACT_METHOD_NOT_IMPLEMENTED_IN_CONCRETE_CLASS, pname, superClass.getName()));
}
nonInheritedPropNames.remove(pname);
checkSuperProperty(rawType, superClass, pname, superMethodTypes, superPropTypes);
}
}
// Collect inherited types for extended/implemented interfaces
for (NominalType superInterf : rawType.getInterfaces()) {
checkState(superInterf.isFrozen());
for (String pname : superInterf.getPropertyNames()) {
nonInheritedPropNames.remove(pname);
checkSuperProperty(rawType, superInterf, pname, superMethodTypes, superPropTypes);
}
}
// Munge inherited types of methods
for (String pname : superMethodTypes.keySet()) {
Collection<DeclaredFunctionType> methodTypes = superMethodTypes.get(pname);
checkState(!methodTypes.isEmpty());
PropertyDef localPropDef = checkNotNull(propertyDefs.get(rawType, pname));
// To find the declared type of a method, we must meet declared types
// from all inherited methods.
DeclaredFunctionType superMethodType = DeclaredFunctionType.meet(methodTypes);
DeclaredFunctionType localMethodType = localPropDef.methodType;
boolean getsTypeFromParent = getsTypeInfoFromParentMethod(localPropDef);
if (superMethodType == null) {
// If the inherited types are not compatible, pick one.
superMethodType = methodTypes.iterator().next();
} else if (getsTypeFromParent && localMethodType.getMaxArity() > superMethodType.getMaxArity()) {
// When getsTypeFromParent is true, we miss the invalid override earlier, so we check here.
warnings.add(JSError.make(localPropDef.defSite, INVALID_PROP_OVERRIDE, pname, superMethodType.toFunctionType().toString(), localMethodType.toFunctionType().toString()));
}
DeclaredFunctionType updatedMethodType = localMethodType.withTypeInfoFromSuper(superMethodType, getsTypeFromParent);
localPropDef.updateMethodType(updatedMethodType);
superPropTypes.put(pname, getCommonTypes().fromFunctionType(updatedMethodType.toFunctionType()));
}
// Check inherited types of all properties
for (String pname : superPropTypes.keySet()) {
Collection<JSType> defs = superPropTypes.get(pname);
checkState(!defs.isEmpty());
JSType inheritedPropType = getCommonTypes().TOP;
for (JSType inheritedType : defs) {
inheritedPropType = JSType.meet(inheritedPropType, inheritedType);
if (inheritedPropType.isBottom()) {
warnings.add(JSError.make(rawType.getDefSite(), ANCESTOR_TYPES_HAVE_INCOMPATIBLE_PROPERTIES, rawType.getName(), pname, defs.toString()));
break;
}
}
// Adjust the type of the local property definition based on the inherited type.
PropertyDef localPropDef = propertyDefs.get(rawType, pname);
if (localPropDef != null) {
JSType updatedPropType;
if (localPropDef.methodType == null) {
JSType t = rawType.getInstancePropDeclaredType(pname);
updatedPropType = t == null ? inheritedPropType : t.specialize(inheritedPropType);
} else {
// When the property is a method, the local type already includes the meet of the
// inherited types, from the earlier loop. We don't use inheritedPropType in this branch,
// because if the inherited method type has static properties (e.g., framework-specific
// passes can add such properties), we don't want to inherit these.
FunctionType ft = localPropDef.methodType.toFunctionType();
updatedPropType = getCommonTypes().fromFunctionType(ft);
}
// TODO(dimvar): check if we can have @const props here
rawType.addProtoProperty(pname, null, updatedPropType, false);
}
}
// Warn when inheriting from incompatible IObject types
if (rawType.inheritsFromIObject()) {
JSType wrapped = rawType.getInstanceAsJSType();
if (wrapped.getIndexType() == null) {
warnings.add(JSError.make(rawType.getDefSite(), ANCESTOR_TYPES_HAVE_INCOMPATIBLE_PROPERTIES, rawType.getName(), "IObject<K,V>#index", "the keys K have types that can't be joined."));
} else if (wrapped.getIndexedType() == null) {
warnings.add(JSError.make(rawType.getDefSite(), ANCESTOR_TYPES_HAVE_INCOMPATIBLE_PROPERTIES, rawType.getName(), "IObject<K,V>#index", "the values V should have a common subtype."));
}
}
// Warn for a prop declared with @override that isn't overriding anything.
for (String pname : nonInheritedPropNames) {
PropertyDef propDef = propertyDefs.get(rawType, pname);
if (propDef != null) {
Node propDefsite = propDef.defSite;
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(propDefsite);
if (jsdoc != null && jsdoc.isOverride()) {
warnings.add(JSError.make(propDefsite, UNKNOWN_OVERRIDE, pname, rawType.getName()));
}
}
}
// Freeze nominal type once all properties are added.
rawType.freeze();
if (rawType.isBuiltinObject()) {
NominalType literalObj = getCommonTypes().getLiteralObjNominalType();
if (!literalObj.isFrozen()) {
literalObj.getRawNominalType().freeze();
}
}
inProgressFreezes.remove(rawType);
}
use of com.google.javascript.jscomp.newtypes.RawNominalType in project closure-compiler by google.
the class SimpleInference method inferPrototypeProperty.
private JSType inferPrototypeProperty(Node recv, String pname, NTIScope scope) {
QualifiedName recvQname = QualifiedName.fromNode(recv);
Declaration decl = scope.getDeclaration(recvQname, false);
if (decl != null) {
Namespace ns = decl.getNamespace();
if (ns instanceof RawNominalType) {
return ((RawNominalType) ns).getProtoPropDeclaredType(pname);
}
}
return null;
}
Aggregations