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(
AbstractCompiler compiler, Map<String, CheckLevel> propertiesToErrorFor) {
this.compiler = compiler;
this.registry = compiler.getTypeRegistry();
this.registry = compiler.getTypeIRegistry();
this.BOTTOM_OBJECT =
this.registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE).toMaybeObjectType();
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;
}

@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
public boolean isEnumObject() {
throw new UnsupportedOperationException();
ObjectType obj = getObjTypeIfSingletonObj();
return obj != null && obj.isEnumObject();
}

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

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

@Override
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
public boolean isStructuralInterface() {
throw new UnsupportedOperationException();
NominalType nt = getNominalTypeIfSingletonObj();
return nt != null && nt.isStructuralInterface();
}

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

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

@Override
Expand All @@ -1954,9 +1970,20 @@ public TypeI getLegacyResolvedType() {
"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
public TypeI getGreatestSubtypeWithProperty(String propName) {
throw new UnsupportedOperationException();
public TypeI getGreatestSubtypeWithProperty(String pname) {
JSType result = this.commonTypes.BOTTOM;
for (JSType t : getSubtypesWithProperty(new QualifiedName(pname))) {
result = join(result, t);
}
return result;
}

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

}

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

// 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.
// 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.
Expand Down Expand Up @@ -616,6 +622,11 @@ boolean isPropDefinedOnSubtype(QualifiedName pname) {
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) {
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.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import com.google.javascript.jscomp.newtypes.ObjectsBuilder.ResolveConflictsBy;
import com.google.javascript.rhino.Node;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -907,6 +909,21 @@ private boolean isBottomObject() {
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) {
Preconditions.checkState(areRelatedNominalTypes(obj1.nominalType, obj2.nominalType));
if (obj1.isTopObject() || obj2.isBottomObject()) {
Expand Down Expand Up @@ -1121,10 +1138,9 @@ private Property getLeftmostProp(QualifiedName qname) {
return null;
}

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

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

@Override
public boolean hasConstantProp(QualifiedName qname) {
Preconditions.checkArgument(qname.isIdentifier());
Expand Down Expand Up @@ -1404,4 +1425,9 @@ public boolean equals(Object o) {
public int hashCode() {
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.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
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)) {
return true;
return ImmutableSet.of(getInstanceAsJSType());
}
HashSet<JSType> typesWithProp = new HashSet<>();
for (RawNominalType subtype : this.subtypes) {
if (subtype.isPropDefinedOnSubtype(pname)) {
return true;
}
typesWithProp.addAll(subtype.getSubtypesWithProperty(pname));
}
return false;
return typesWithProp;
}

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

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

package com.google.javascript.jscomp.newtypes;

import java.util.Collection;

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

/** Return whether this type contains a constant property */
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;

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.
Expand Down Expand Up @@ -58,6 +61,18 @@ static JSType getDeclaredProp(
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(
ImmutableSet<? extends TypeWithProperties> types, QualifiedName qname) {
if (types == null) {
Expand Down

0 comments on commit e1a2d4b

Please sign in to comment.