Skip to content

Commit

Permalink
[NTI] More changes towards converting DisambiguateProperties to run w…
Browse files Browse the repository at this point in the history
…ith NTI.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=146969416
  • Loading branch information
dimvar authored and blickly committed Feb 9, 2017
1 parent 7394659 commit e1a2d4b
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 58 deletions.
Expand Up @@ -325,7 +325,7 @@ boolean scheduleRenaming(Node node, TypeI type) {
DisambiguateProperties( DisambiguateProperties(
AbstractCompiler compiler, Map<String, CheckLevel> propertiesToErrorFor) { AbstractCompiler compiler, Map<String, CheckLevel> propertiesToErrorFor) {
this.compiler = compiler; this.compiler = compiler;
this.registry = compiler.getTypeRegistry(); this.registry = compiler.getTypeIRegistry();
this.BOTTOM_OBJECT = this.BOTTOM_OBJECT =
this.registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE).toMaybeObjectType(); this.registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE).toMaybeObjectType();
this.invalidatingTypes = new HashSet<>(ImmutableSet.of( this.invalidatingTypes = new HashSet<>(ImmutableSet.of(
Expand Down
5 changes: 5 additions & 0 deletions src/com/google/javascript/jscomp/newtypes/EnumType.java
Expand Up @@ -229,4 +229,9 @@ static boolean areSubtypes(JSType t1, JSType t2, SubtypeCache subSuperMap) {
} }
return true; return true;
} }

@Override
public Collection<JSType> getSubtypesWithProperty(QualifiedName qname) {
return declaredType.getSubtypesWithProperty(qname);
}
} }
46 changes: 36 additions & 10 deletions src/com/google/javascript/jscomp/newtypes/JSType.java
Expand Up @@ -475,7 +475,8 @@ public boolean isEnumElement() {


@Override @Override
public boolean isEnumObject() { public boolean isEnumObject() {
throw new UnsupportedOperationException(); ObjectType obj = getObjTypeIfSingletonObj();
return obj != null && obj.isEnumObject();
} }


public boolean isUnion() { public boolean isUnion() {
Expand Down Expand Up @@ -1652,7 +1653,8 @@ public boolean equals(Object o) {
if (this == o) { if (this == o) {
return true; return true;
} }
Preconditions.checkArgument(o instanceof JSType); Preconditions.checkArgument(o instanceof JSType,
"Expected newtypes.JSType but found %s", o);
JSType t2 = (JSType) o; JSType t2 = (JSType) o;
return getMask() == t2.getMask() && Objects.equals(getObjs(), t2.getObjs()) return getMask() == t2.getMask() && Objects.equals(getObjs(), t2.getObjs())
&& Objects.equals(getEnums(), t2.getEnums()) && Objects.equals(getEnums(), t2.getEnums())
Expand Down Expand Up @@ -1920,27 +1922,41 @@ public final boolean isObjectType() {


@Override @Override
public final boolean isGeneric() { public final boolean isGeneric() {
throw new UnsupportedOperationException(); NominalType nt = getNominalTypeIfSingletonObj();
return nt != null && nt.isGeneric();
} }


@Override @Override
public Collection<ObjectTypeI> getAncestorInterfaces() { public Collection<ObjectTypeI> getAncestorInterfaces() {
throw new UnsupportedOperationException(); FunctionType funType = getFunTypeIfSingletonObj();
if (!funType.isUniqueConstructor() && !funType.isInterfaceDefinition()) {
return ImmutableSet.of();
}
NominalType nt = funType.getInstanceTypeOfCtor().getNominalTypeIfSingletonObj();
ImmutableSet.Builder<ObjectTypeI> builder = new ImmutableSet.Builder<>();
for (NominalType i : nt.getInstantiatedInterfaces()) {
builder.add(this.commonTypes.fromFunctionType(i.getConstructorFunction()));
}
return builder.build();
} }


@Override @Override
public boolean isStructuralInterface() { public boolean isStructuralInterface() {
throw new UnsupportedOperationException(); NominalType nt = getNominalTypeIfSingletonObj();
return nt != null && nt.isStructuralInterface();
} }


@Override @Override
public boolean hasOwnProperty(String propertyName) { public boolean hasOwnProperty(String propertyName) {
throw new UnsupportedOperationException(); ObjectType obj = getObjTypeIfSingletonObj();
return obj != null && obj.hasOwnPropery(new QualifiedName(propertyName));
} }


@Override @Override
public ObjectTypeI getRawType() { public ObjectTypeI getRawType() {
throw new UnsupportedOperationException(); NominalType nt = getNominalTypeIfSingletonObj();
return nt.isGeneric()
? nt.getRawNominalTypeAfterTypeChecking().getInstanceAsJSType() : null;
} }


@Override @Override
Expand All @@ -1954,9 +1970,20 @@ public TypeI getLegacyResolvedType() {
"NTI does not have NamedType. This method should never be called on NTI types."); "NTI does not have NamedType. This method should never be called on NTI types.");
} }


Collection<JSType> getSubtypesWithProperty(QualifiedName qname) {
Collection<JSType> typesWithProp =
TypeWithPropertiesStatics.getSubtypesWithProperty(getEnums(), qname);
typesWithProp.addAll(TypeWithPropertiesStatics.getSubtypesWithProperty(getObjs(), qname));
return typesWithProp;
}

@Override @Override
public TypeI getGreatestSubtypeWithProperty(String propName) { public TypeI getGreatestSubtypeWithProperty(String pname) {
throw new UnsupportedOperationException(); JSType result = this.commonTypes.BOTTOM;
for (JSType t : getSubtypesWithProperty(new QualifiedName(pname))) {
result = join(result, t);
}
return result;
} }


@Override @Override
Expand All @@ -1978,7 +2005,6 @@ public ObjectTypeI getTopDefiningInterface(String propName) {
public FunctionTypeI getOwnerFunction() { public FunctionTypeI getOwnerFunction() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

} }


final class UnionType extends JSType { final class UnionType extends JSType {
Expand Down
9 changes: 9 additions & 0 deletions src/com/google/javascript/jscomp/newtypes/JSTypes.java
Expand Up @@ -416,6 +416,15 @@ public JSType getNativeType(JSTypeNative typeId) {
return getTopObject(); return getTopObject();
case TRUTHY: case TRUTHY:
return TRUTHY; return TRUTHY;
case NO_OBJECT_TYPE:
return JSType.fromObjectType(getBottomObject());
case FUNCTION_PROTOTYPE:
return getFunctionType().getPrototypePropertyOfCtor();
case FUNCTION_INSTANCE_TYPE:
return getFunctionType().getInstanceAsJSType();
case OBJECT_PROTOTYPE:
case TOP_LEVEL_PROTOTYPE:
return getTopObject().getNominalTypeIfSingletonObj().getPrototypePropertyOfCtor();
default: default:
throw new RuntimeException("Native type " + typeId.name() + " not found"); throw new RuntimeException("Native type " + typeId.name() + " not found");
} }
Expand Down
11 changes: 11 additions & 0 deletions src/com/google/javascript/jscomp/newtypes/NominalType.java
Expand Up @@ -60,6 +60,12 @@ public RawNominalType getRawNominalType() {
return this.rawType; return this.rawType;
} }


// This is used for DisambiguateProperties. Do not call during NewTypeInference.
// See note for getRawNominalType.
public RawNominalType getRawNominalTypeAfterTypeChecking() {
return this.rawType;
}

// NOTE(dimvar): we need this to get access to the static properties of the class. // NOTE(dimvar): we need this to get access to the static properties of the class.
// It'd be good if these properties were on the type returned by getConstructorFunction, // It'd be good if these properties were on the type returned by getConstructorFunction,
// but there are some circularity issues when we're computing the namespace types. // but there are some circularity issues when we're computing the namespace types.
Expand Down Expand Up @@ -616,6 +622,11 @@ boolean isPropDefinedOnSubtype(QualifiedName pname) {
return this.rawType.isPropDefinedOnSubtype(pname.getLeftmostName()); return this.rawType.isPropDefinedOnSubtype(pname.getLeftmostName());
} }


Set<JSType> getSubtypesWithProperty(QualifiedName pname) {
Preconditions.checkArgument(pname.isIdentifier());
return this.rawType.getSubtypesWithProperty(pname.getLeftmostName());
}

static boolean equalRawTypes(NominalType n1, NominalType n2) { static boolean equalRawTypes(NominalType n1, NominalType n2) {
return n1.rawType.equals(n2.rawType); return n1.rawType.equals(n2.rawType);
} }
Expand Down
34 changes: 30 additions & 4 deletions src/com/google/javascript/jscomp/newtypes/ObjectType.java
Expand Up @@ -18,12 +18,14 @@


import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import com.google.javascript.jscomp.newtypes.ObjectsBuilder.ResolveConflictsBy; import com.google.javascript.jscomp.newtypes.ObjectsBuilder.ResolveConflictsBy;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
Expand Down Expand Up @@ -907,6 +909,21 @@ private boolean isBottomObject() {
return this == this.commonTypes.getBottomObject(); return this == this.commonTypes.getBottomObject();
} }


boolean isEnumObject() {
if (!this.nominalType.isLiteralObject()) {
return false;
}
EnumType e = null;
for (Property p : this.props.values()) {
JSType t = p.getType();
if (t.isEnumElement()) {
e = Iterables.getOnlyElement(t.getEnums());
break;
}
}
return e != null && this.equals(e.toJSType().getObjTypeIfSingletonObj());
}

static ObjectType meet(ObjectType obj1, ObjectType obj2) { static ObjectType meet(ObjectType obj1, ObjectType obj2) {
Preconditions.checkState(areRelatedNominalTypes(obj1.nominalType, obj2.nominalType)); Preconditions.checkState(areRelatedNominalTypes(obj1.nominalType, obj2.nominalType));
if (obj1.isTopObject() || obj2.isBottomObject()) { if (obj1.isTopObject() || obj2.isBottomObject()) {
Expand Down Expand Up @@ -1121,10 +1138,9 @@ private Property getLeftmostProp(QualifiedName qname) {
return null; return null;
} }


// NOTE(aravindpg): This method is currently only used to obtain the defsite of an own prop, and // NOTE(aravindpg): This method deliberately does not return the more specialized version of
// deliberately does not return the more specialized version of a property if it is already // a property if it is already present on the nominal type. This may be unsuitable from a
// present on the nominal type. This may be unsuitable from a typing point of view. Revisit if // typing point of view. Revisit if needed.
// needed.
private Property getLeftmostOwnProp(QualifiedName qname) { private Property getLeftmostOwnProp(QualifiedName qname) {
String pname = qname.getLeftmostName(); String pname = qname.getLeftmostName();
Property p = props.get(pname); Property p = props.get(pname);
Expand Down Expand Up @@ -1178,6 +1194,11 @@ public boolean hasProp(QualifiedName qname) {
return p != null; return p != null;
} }


boolean hasOwnPropery(QualifiedName qname) {
Preconditions.checkArgument(qname.isIdentifier());
return getLeftmostOwnProp(qname) != null;
}

@Override @Override
public boolean hasConstantProp(QualifiedName qname) { public boolean hasConstantProp(QualifiedName qname) {
Preconditions.checkArgument(qname.isIdentifier()); Preconditions.checkArgument(qname.isIdentifier());
Expand Down Expand Up @@ -1404,4 +1425,9 @@ public boolean equals(Object o) {
public int hashCode() { public int hashCode() {
return Objects.hash(this.fn, this.ns, this.props, this.nominalType); return Objects.hash(this.fn, this.ns, this.props, this.nominalType);
} }

@Override
public Collection<JSType> getSubtypesWithProperty(QualifiedName qname) {
return this.nominalType.getSubtypesWithProperty(qname);
}
} }
16 changes: 10 additions & 6 deletions src/com/google/javascript/jscomp/newtypes/RawNominalType.java
Expand Up @@ -24,6 +24,7 @@
import com.google.javascript.jscomp.NodeUtil; import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
Expand Down Expand Up @@ -253,16 +254,19 @@ private void addSubtype(RawNominalType subtype) {
} }
} }


boolean isPropDefinedOnSubtype(String pname) { Set<JSType> getSubtypesWithProperty(String pname) {
if (mayHaveProp(pname)) { if (mayHaveProp(pname)) {
return true; return ImmutableSet.of(getInstanceAsJSType());
} }
HashSet<JSType> typesWithProp = new HashSet<>();
for (RawNominalType subtype : this.subtypes) { for (RawNominalType subtype : this.subtypes) {
if (subtype.isPropDefinedOnSubtype(pname)) { typesWithProp.addAll(subtype.getSubtypesWithProperty(pname));
return true;
}
} }
return false; return typesWithProp;
}

boolean isPropDefinedOnSubtype(String pname) {
return !getSubtypesWithProperty(pname).isEmpty();
} }


boolean hasAncestorInterface(RawNominalType ancestor) { boolean hasAncestorInterface(RawNominalType ancestor) {
Expand Down
Expand Up @@ -16,6 +16,8 @@


package com.google.javascript.jscomp.newtypes; package com.google.javascript.jscomp.newtypes;


import java.util.Collection;

/** /**
* A type that can contain properties, * A type that can contain properties,
* such as an ObjectType, NominalType, or a Namespace. * such as an ObjectType, NominalType, or a Namespace.
Expand All @@ -35,4 +37,10 @@ interface TypeWithProperties {


/** Return whether this type contains a constant property */ /** Return whether this type contains a constant property */
boolean hasConstantProp(QualifiedName qname); boolean hasConstantProp(QualifiedName qname);

/**
* Return all topmost subtypes of this type that have the given property.
* If the type itself has the property then only this type is included in the result.
*/
Collection<JSType> getSubtypesWithProperty(QualifiedName qname);
} }
Expand Up @@ -17,6 +17,9 @@
package com.google.javascript.jscomp.newtypes; package com.google.javascript.jscomp.newtypes;


import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;


/** /**
* Static methods that operate on {@code TypeWithProperties} instances. * Static methods that operate on {@code TypeWithProperties} instances.
Expand Down Expand Up @@ -58,6 +61,18 @@ static JSType getDeclaredProp(
return ptype; return ptype;
} }


static Collection<JSType> getSubtypesWithProperty(
ImmutableSet<? extends TypeWithProperties> types, QualifiedName qname) {
if (types == null) {
return ImmutableSet.of();
}
Set<JSType> typesWithProp = new HashSet<>();
for (TypeWithProperties t : types) {
typesWithProp.addAll(t.getSubtypesWithProperty(qname));
}
return typesWithProp;
}

static boolean mayHaveProp( static boolean mayHaveProp(
ImmutableSet<? extends TypeWithProperties> types, QualifiedName qname) { ImmutableSet<? extends TypeWithProperties> types, QualifiedName qname) {
if (types == null) { if (types == null) {
Expand Down

0 comments on commit e1a2d4b

Please sign in to comment.