Skip to content

Commit

Permalink
[NTI] Simplify the representation of object types, by requiring all o…
Browse files Browse the repository at this point in the history
…bject types to have a non-null nominal type.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=138792860
  • Loading branch information
dimvar authored and blickly committed Nov 11, 2016
1 parent 2e88895 commit 7cf5873
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 156 deletions.
4 changes: 2 additions & 2 deletions src/com/google/javascript/jscomp/GlobalTypeInfo.java
Expand Up @@ -460,7 +460,7 @@ public void process(Node externs, Node root) {
globalThisType = win.getInstanceAsJSType(); globalThisType = win.getInstanceAsJSType();
} else { } else {
// Type the global THIS as a loose object // Type the global THIS as a loose object
globalThisType = this.commonTypes.TOP_OBJECT.withLoose(); globalThisType = this.commonTypes.getTopObject().withLoose();
} }
this.globalScope.setDeclaredType( this.globalScope.setDeclaredType(
(new FunctionTypeBuilder(this.commonTypes)). (new FunctionTypeBuilder(this.commonTypes)).
Expand Down Expand Up @@ -2030,7 +2030,7 @@ private JSType simpleInferExprType(Node n) {
return simpleInferDeclaration( return simpleInferDeclaration(
this.currentScope.getDeclaration(n.getString(), false)); this.currentScope.getDeclaration(n.getString(), false));
case OBJECTLIT: { case OBJECTLIT: {
JSType objLitType = commonTypes.TOP_OBJECT; JSType objLitType = commonTypes.getEmptyObjectLiteral();
for (Node prop : n.children()) { for (Node prop : n.children()) {
JSType propType = simpleInferExprType(prop.getFirstChild()); JSType propType = simpleInferExprType(prop.getFirstChild());
if (propType == null) { if (propType == null) {
Expand Down
13 changes: 4 additions & 9 deletions src/com/google/javascript/jscomp/NewTypeInference.java
Expand Up @@ -411,9 +411,7 @@ void add(JSError warning) {
private JSType NUMBER_OR_STRING; private JSType NUMBER_OR_STRING;
private JSType STRING; private JSType STRING;
private JSType TOP; private JSType TOP;
private JSType TOP_DICT;
private JSType TOP_OBJECT; private JSType TOP_OBJECT;
private JSType TOP_STRUCT;
private JSType TRUE_TYPE; private JSType TRUE_TYPE;
private JSType TRUTHY; private JSType TRUTHY;
private JSType UNDEFINED; private JSType UNDEFINED;
Expand Down Expand Up @@ -466,9 +464,7 @@ public void process(Node externs, Node root) {
this.NUMBER_OR_STRING = this.commonTypes.NUMBER_OR_STRING; this.NUMBER_OR_STRING = this.commonTypes.NUMBER_OR_STRING;
this.STRING = this.commonTypes.STRING; this.STRING = this.commonTypes.STRING;
this.TOP = this.commonTypes.TOP; this.TOP = this.commonTypes.TOP;
this.TOP_DICT = this.commonTypes.TOP_DICT; this.TOP_OBJECT = this.commonTypes.getTopObject();
this.TOP_OBJECT = this.commonTypes.TOP_OBJECT;
this.TOP_STRUCT = this.commonTypes.TOP_STRUCT;
this.TRUE_TYPE = this.commonTypes.TRUE_TYPE; this.TRUE_TYPE = this.commonTypes.TRUE_TYPE;
this.TRUTHY = this.commonTypes.TRUTHY; this.TRUTHY = this.commonTypes.TRUTHY;
this.UNDEFINED = this.commonTypes.UNDEFINED; this.UNDEFINED = this.commonTypes.UNDEFINED;
Expand Down Expand Up @@ -2770,8 +2766,7 @@ private JSType predicateTransformType(
? arrayType : beforeType.removeType(arrayType); ? arrayType : beforeType.removeType(arrayType);
} }
case "isArrayLike": case "isArrayLike":
return TOP_OBJECT.withProperty( return TOP_OBJECT.withProperty(new QualifiedName("length"), NUMBER);
new QualifiedName("length"), NUMBER);
case "boolean": case "boolean":
case "isBoolean": case "isBoolean":
return booleanContext.isTrueOrTruthy() return booleanContext.isTrueOrTruthy()
Expand Down Expand Up @@ -4289,10 +4284,10 @@ private JSType pickReqObjType(Node expr) {
case OBJECTLIT: { case OBJECTLIT: {
JSDocInfo jsdoc = expr.getJSDocInfo(); JSDocInfo jsdoc = expr.getJSDocInfo();
if (jsdoc != null && jsdoc.makesStructs()) { if (jsdoc != null && jsdoc.makesStructs()) {
return TOP_STRUCT; return this.commonTypes.getTopStruct();
} }
if (jsdoc != null && jsdoc.makesDicts()) { if (jsdoc != null && jsdoc.makesDicts()) {
return TOP_DICT; return this.commonTypes.getTopDict();
} }
return this.commonTypes.getEmptyObjectLiteral(); return this.commonTypes.getEmptyObjectLiteral();
} }
Expand Down
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/newtypes/JSType.java
Expand Up @@ -1194,7 +1194,7 @@ public JSType removeType(JSType other) {
commonTypes, commonTypes,
TRUE_MASK | FALSE_MASK | NUMBER_MASK | STRING_MASK TRUE_MASK | FALSE_MASK | NUMBER_MASK | STRING_MASK
| NULL_MASK | UNDEFINED_MASK | NON_SCALAR_MASK, | NULL_MASK | UNDEFINED_MASK | NON_SCALAR_MASK,
ImmutableSet.of(this.commonTypes.TOP_OBJECTTYPE), null, NO_ENUMS); ImmutableSet.of(this.commonTypes.getTopObjectType()), null, NO_ENUMS);
return almostTop.removeType(other); return almostTop.removeType(other);
} }
int newMask = getMask() & ~otherMask; int newMask = getMask() & ~otherMask;
Expand Down
Expand Up @@ -419,7 +419,7 @@ private JSType getNamedTypeHelper(
// at least not warn about inexistent properties on it, so we type it // at least not warn about inexistent properties on it, so we type it
// as @dict. // as @dict.
return maybeMakeNullable(n.hasChildren() return maybeMakeNullable(n.hasChildren()
? this.commonTypes.TOP_DICT : this.commonTypes.TOP_OBJECT); ? this.commonTypes.getTopDict() : this.commonTypes.getTopObject());
default: default:
return lookupTypeByName(typeName, n, registry, outerTypeParameters); return lookupTypeByName(typeName, n, registry, outerTypeParameters);
} }
Expand Down Expand Up @@ -598,7 +598,7 @@ private void fillInFunTypeBuilder(
} else if (child.getToken() == Token.NEW) { } else if (child.getToken() == Token.NEW) {
Node newTypeNode = child.getFirstChild(); Node newTypeNode = child.getFirstChild();
JSType t = getThisOrNewType(newTypeNode, registry, typeParameters); JSType t = getThisOrNewType(newTypeNode, registry, typeParameters);
if (!t.isSubtypeOf(this.commonTypes.TOP_OBJECT) if (!t.isSubtypeOf(this.commonTypes.getTopObject())
&& (!t.hasTypeVariable() || t.hasScalar())) { && (!t.hasTypeVariable() || t.hasScalar())) {
warnings.add(JSError.make( warnings.add(JSError.make(
newTypeNode, NEW_EXPECTS_OBJECT_OR_TYPEVAR, t.toString())); newTypeNode, NEW_EXPECTS_OBJECT_OR_TYPEVAR, t.toString()));
Expand Down
68 changes: 47 additions & 21 deletions src/com/google/javascript/jscomp/newtypes/JSTypes.java
Expand Up @@ -75,12 +75,13 @@ public final class JSTypes {
public final JSType UNDEFINED; public final JSType UNDEFINED;
public final JSType UNKNOWN; public final JSType UNKNOWN;


final ObjectType TOP_OBJECTTYPE; private ObjectType topObjectType;
final PersistentMap<String, Property> BOTTOM_PROPERTY_MAP; final PersistentMap<String, Property> BOTTOM_PROPERTY_MAP;
final ObjectType BOTTOM_OBJECT; private JSType topObject;
public final JSType TOP_OBJECT; private ObjectType looseTopObject;
public final JSType TOP_STRUCT; private JSType topStruct;
public final JSType TOP_DICT; private JSType topDict;
private ObjectType bottomObject;


// Corresponds to Function, which is a subtype and supertype of all functions. // Corresponds to Function, which is a subtype and supertype of all functions.
final FunctionType QMARK_FUNCTION; final FunctionType QMARK_FUNCTION;
Expand Down Expand Up @@ -164,16 +165,7 @@ private JSTypes(boolean inCompatibilityMode) {
this.BOTTOM_FUNCTION = Preconditions.checkNotNull(functions.get("BOTTOM_FUNCTION")); this.BOTTOM_FUNCTION = Preconditions.checkNotNull(functions.get("BOTTOM_FUNCTION"));
this.TOP_FUNCTION = Preconditions.checkNotNull(functions.get("TOP_FUNCTION")); this.TOP_FUNCTION = Preconditions.checkNotNull(functions.get("TOP_FUNCTION"));
this.LOOSE_TOP_FUNCTION = Preconditions.checkNotNull(functions.get("LOOSE_TOP_FUNCTION")); this.LOOSE_TOP_FUNCTION = Preconditions.checkNotNull(functions.get("LOOSE_TOP_FUNCTION"));

this.BOTTOM_PROPERTY_MAP = PersistentMap.of("_", Property.make(this.BOTTOM, this.BOTTOM)); this.BOTTOM_PROPERTY_MAP = PersistentMap.of("_", Property.make(this.BOTTOM, this.BOTTOM));
Map<String, ObjectType> objects = ObjectType.createInitialObjectTypes(this);
this.TOP_OBJECTTYPE = Preconditions.checkNotNull(objects.get("TOP_OBJECTTYPE"));
this.TOP_OBJECT = JSType.fromObjectType(this.TOP_OBJECTTYPE);
this.TOP_STRUCT = JSType.fromObjectType(
Preconditions.checkNotNull(objects.get("TOP_STRUCT")));
this.TOP_DICT = JSType.fromObjectType(
Preconditions.checkNotNull(objects.get("TOP_DICT")));
this.BOTTOM_OBJECT = Preconditions.checkNotNull(objects.get("BOTTOM_OBJECT"));


this.allowMethodsAsFunctions = inCompatibilityMode; this.allowMethodsAsFunctions = inCompatibilityMode;
this.looseSubtypingForLooseObjects = inCompatibilityMode; this.looseSubtypingForLooseObjects = inCompatibilityMode;
Expand Down Expand Up @@ -288,6 +280,14 @@ public NominalType getObjectType() {
return this.builtinObject == null ? null : this.builtinObject.getAsNominalType(); return this.builtinObject == null ? null : this.builtinObject.getAsNominalType();
} }


ObjectType getTopObjectType() {
return this.topObjectType;
}

ObjectType getLooseTopObjectType() {
return this.looseTopObject;
}

public NominalType getLiteralObjNominalType() { public NominalType getLiteralObjNominalType() {
return this.literalObject == null ? null : this.literalObject.getAsNominalType(); return this.literalObject == null ? null : this.literalObject.getAsNominalType();
} }
Expand All @@ -296,6 +296,22 @@ public JSType getEmptyObjectLiteral() {
return this.literalObject == null ? null : this.literalObject.getInstanceAsJSType(); return this.literalObject == null ? null : this.literalObject.getInstanceAsJSType();
} }


public JSType getTopObject() {
return topObject;
}

public JSType getTopStruct() {
return this.topStruct;
}

public JSType getTopDict() {
return this.topDict;
}

ObjectType getBottomObject() {
return this.bottomObject;
}

public NominalType getIObjectType() { public NominalType getIObjectType() {
return this.iObject == null ? null : this.iObject.getAsNominalType(); return this.iObject == null ? null : this.iObject.getAsNominalType();
} }
Expand Down Expand Up @@ -345,18 +361,15 @@ public JSType getStringInstance() {
} }


ObjectType getNumberInstanceObjType() { ObjectType getNumberInstanceObjType() {
return numberInstanceObjtype != null return numberInstanceObjtype != null ? numberInstanceObjtype : this.topObjectType;
? numberInstanceObjtype : this.TOP_OBJECTTYPE;
} }


ObjectType getBooleanInstanceObjType() { ObjectType getBooleanInstanceObjType() {
return booleanInstanceObjtype != null return booleanInstanceObjtype != null ? booleanInstanceObjtype : this.topObjectType;
? booleanInstanceObjtype : this.TOP_OBJECTTYPE;
} }


ObjectType getStringInstanceObjType() { ObjectType getStringInstanceObjType() {
return stringInstanceObjtype != null return stringInstanceObjtype != null ? stringInstanceObjtype : this.topObjectType;
? stringInstanceObjtype : this.TOP_OBJECTTYPE;
} }


public JSType getArgumentsArrayType() { public JSType getArgumentsArrayType() {
Expand Down Expand Up @@ -389,7 +402,7 @@ public JSType getNativeType(JSTypeNative typeId) {
case ARRAY_TYPE: case ARRAY_TYPE:
return getArrayInstance(); return getArrayInstance();
case OBJECT_TYPE: case OBJECT_TYPE:
return TOP_OBJECT; return getTopObject();
case TRUTHY: case TRUTHY:
return TRUTHY; return TRUTHY;
default: default:
Expand All @@ -406,7 +419,20 @@ public void setFunctionType(RawNominalType builtinFunction) {
} }


public void setObjectType(RawNominalType builtinObject) { public void setObjectType(RawNominalType builtinObject) {
NominalType builtinObjectNT = builtinObject.getAsNominalType();
this.builtinObject = builtinObject; this.builtinObject = builtinObject;
this.topObjectType = builtinObject.getInstanceAsJSType().getObjTypeIfSingletonObj();
this.looseTopObject = ObjectType.makeObjectType(
this, builtinObjectNT, PersistentMap.<String, Property>create(),
null, null, true, ObjectKind.UNRESTRICTED);
this.topObject = JSType.fromObjectType(this.topObjectType);
this.topStruct = JSType.fromObjectType(ObjectType.makeObjectType(
this, builtinObjectNT, PersistentMap.<String, Property>create(),
null, null, false, ObjectKind.STRUCT));
this.topDict = JSType.fromObjectType(ObjectType.makeObjectType(
this, builtinObjectNT, PersistentMap.<String, Property>create(),
null, null, false, ObjectKind.DICT));
this.bottomObject = ObjectType.createBottomObject(this);
} }


public void setLiteralObjNominalType(RawNominalType literalObject) { public void setLiteralObjNominalType(RawNominalType literalObject) {
Expand Down

0 comments on commit 7cf5873

Please sign in to comment.