Skip to content

Commit

Permalink
[NTI] Implement JSType#getSubTypes
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=159773350
  • Loading branch information
shicks authored and blickly committed Jun 22, 2017
1 parent f4d690b commit aa58745
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 60 deletions.
13 changes: 4 additions & 9 deletions src/com/google/javascript/jscomp/AmbiguateProperties.java
Expand Up @@ -30,6 +30,7 @@
import com.google.javascript.jscomp.graph.GraphColoring.GreedyGraphColoring; import com.google.javascript.jscomp.graph.GraphColoring.GreedyGraphColoring;
import com.google.javascript.jscomp.graph.GraphNode; import com.google.javascript.jscomp.graph.GraphNode;
import com.google.javascript.jscomp.graph.SubGraph; import com.google.javascript.jscomp.graph.SubGraph;
import com.google.javascript.rhino.FunctionTypeI;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.TypeI; import com.google.javascript.rhino.TypeI;
import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.FunctionType;
Expand Down Expand Up @@ -337,17 +338,11 @@ private void computeRelatedTypes(JSType type) {


// An instance is related to its subclasses. // An instance is related to its subclasses.
FunctionType constructor = type.toObjectType().getConstructor(); FunctionType constructor = type.toObjectType().getConstructor();
if (constructor != null && constructor.getSubTypes() != null) { if (constructor != null) {
for (FunctionType subType : constructor.getSubTypes()) { for (FunctionTypeI subType : constructor.getSubTypes()) {
addRelatedInstance(subType, related); addRelatedInstance((FunctionType) subType, related);
} }
} }

// An interface is related to its implementors.
for (FunctionType implementor : compiler.getTypeRegistry()
.getDirectImplementors(type.toObjectType())) {
addRelatedInstance(implementor, related);
}
} }


/** /**
Expand Down
9 changes: 5 additions & 4 deletions src/com/google/javascript/jscomp/DisambiguateProperties.java
Expand Up @@ -17,6 +17,7 @@


import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;


import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
Expand Down Expand Up @@ -779,6 +780,7 @@ private Map<TypeI, String> buildPropNames(Property prop) {
} }


/** Returns a map from field name to types for which it will be renamed. */ /** Returns a map from field name to types for which it will be renamed. */
@VisibleForTesting
Multimap<String, Collection<TypeI>> getRenamedTypesForTesting() { Multimap<String, Collection<TypeI>> getRenamedTypesForTesting() {
Multimap<String, Collection<TypeI>> ret = HashMultimap.create(); Multimap<String, Collection<TypeI>> ret = HashMultimap.create();
for (Map.Entry<String, Property> entry : properties.entrySet()) { for (Map.Entry<String, Property> entry : properties.entrySet()) {
Expand Down Expand Up @@ -886,11 +888,10 @@ private Iterable<? extends TypeI> getTypeAlternatives(TypeI type) {
return type.getUnionMembers(); return type.getUnionMembers();
} else { } else {
ObjectTypeI objType = type.toMaybeObjectType(); ObjectTypeI objType = type.toMaybeObjectType();
if (objType != null FunctionTypeI constructor = objType != null ? objType.getConstructor() : null;
&& objType.getConstructor() != null if (constructor != null && constructor.isInterface()) {
&& objType.getConstructor().isInterface()) {
List<TypeI> list = new ArrayList<>(); List<TypeI> list = new ArrayList<>();
for (FunctionTypeI impl : objType.getDirectImplementors()) { for (FunctionTypeI impl : constructor.getSubTypes()) {
list.add(impl.getInstanceType()); list.add(impl.getInstanceType());
} }
return list.isEmpty() ? null : list; return list.isEmpty() ? null : list;
Expand Down
25 changes: 11 additions & 14 deletions src/com/google/javascript/jscomp/newtypes/JSType.java
Expand Up @@ -1856,8 +1856,17 @@ public final Node getSource() {
} }


@Override @Override
public final List<? extends FunctionTypeI> getSubTypes() { public final Collection<FunctionTypeI> getSubTypes() {
throw new UnsupportedOperationException("getSubTypes not implemented yet"); Preconditions.checkState(this.isConstructor() || this.isInterface());
ImmutableList.Builder<FunctionTypeI> result = ImmutableList.builder();
NominalType nt =
getFunTypeIfSingletonObj().getInstanceTypeOfCtor().getNominalTypeIfSingletonObj();
if (nt != null) {
for (RawNominalType rawType : nt.getSubtypes()) {
result.add(this.commonTypes.fromFunctionType(rawType.getConstructorFunction()));
}
}
return result.build();
} }


@Override @Override
Expand Down Expand Up @@ -2182,18 +2191,6 @@ public final TypeI getGreatestSubtypeWithProperty(String pname) {
return joinManyTypes(this.commonTypes, getSubtypesWithProperty(new QualifiedName(pname))); return joinManyTypes(this.commonTypes, getSubtypesWithProperty(new QualifiedName(pname)));
} }


@Override
public final Collection<JSType> getDirectImplementors() {
Set<JSType> result = new HashSet<>();
NominalType nt = getNominalTypeIfSingletonObj();
if (nt != null) {
for (RawNominalType rawType : nt.getSubtypes()) {
result.add(this.commonTypes.fromFunctionType(rawType.getConstructorFunction()));
}
}
return result;
}

@Override @Override
public final ObjectTypeI getPrototypeProperty() { public final ObjectTypeI getPrototypeProperty() {
return getProp(new QualifiedName("prototype")); return getProp(new QualifiedName("prototype"));
Expand Down
9 changes: 5 additions & 4 deletions src/com/google/javascript/rhino/FunctionTypeI.java
Expand Up @@ -76,11 +76,12 @@ public interface FunctionTypeI extends TypeI {
Node getSource(); Node getSource();


/** /**
* Returns a list of types that are subtypes of this type. This is only * Returns an iterable of direct types that are subtypes of this type.
* valid for constructor functions, and may be null. This allows a downward * This is only valid for constructors and interfaces, and will not be
* traversal of the subtype graph. * null. This allows a downward traversal of the subtype graph.
*/ */
List<? extends FunctionTypeI> getSubTypes(); // TODO(sdh): change the name to getDirectSubTypes()
Iterable<FunctionTypeI> getSubTypes();


/** Gets the type of {@code this} in this function. */ /** Gets the type of {@code this} in this function. */
TypeI getTypeOfThis(); TypeI getTypeOfThis();
Expand Down
3 changes: 0 additions & 3 deletions src/com/google/javascript/rhino/ObjectTypeI.java
Expand Up @@ -40,7 +40,6 @@
package com.google.javascript.rhino; package com.google.javascript.rhino;


import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.Collection;


/** /**
* @author blickly@google.com (Ben Lickly) * @author blickly@google.com (Ben Lickly)
Expand Down Expand Up @@ -133,8 +132,6 @@ public interface ObjectTypeI extends TypeI {
*/ */
TypeI getLegacyResolvedType(); TypeI getLegacyResolvedType();


Collection<? extends FunctionTypeI> getDirectImplementors();

/** /**
* Given an interface and a property, finds a top-most super interface * Given an interface and a property, finds a top-most super interface
* that has the property defined (including this interface). * that has the property defined (including this interface).
Expand Down
21 changes: 10 additions & 11 deletions src/com/google/javascript/rhino/jstype/FunctionType.java
Expand Up @@ -48,6 +48,7 @@
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.ErrorReporter;
import com.google.javascript.rhino.FunctionTypeI; import com.google.javascript.rhino.FunctionTypeI;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
Expand Down Expand Up @@ -150,7 +151,7 @@ private enum PropAccess { ANY, STRUCT, DICT }
* The types which are subtypes of this function. It is only relevant for * The types which are subtypes of this function. It is only relevant for
* constructors and may be {@code null}. * constructors and may be {@code null}.
*/ */
private List<FunctionType> subTypes; private List<FunctionTypeI> subTypes;


/** Creates an instance for a function that might be a constructor. */ /** Creates an instance for a function that might be a constructor. */
FunctionType( FunctionType(
Expand Down Expand Up @@ -1246,8 +1247,8 @@ public void clearCachedValues() {
super.clearCachedValues(); super.clearCachedValues();


if (subTypes != null) { if (subTypes != null) {
for (FunctionType subType : subTypes) { for (FunctionTypeI subType : subTypes) {
subType.clearCachedValues(); ((FunctionType) subType).clearCachedValues();
} }
} }


Expand All @@ -1262,14 +1263,11 @@ public void clearCachedValues() {
} }
} }


/**
* Returns a list of types that are subtypes of this type. This is only valid
* for constructor functions, and may be null. This allows a downward
* traversal of the subtype graph.
*/
@Override @Override
public List<FunctionType> getSubTypes() { public Iterable<FunctionTypeI> getSubTypes() {
return subTypes; return Iterables.concat(
subTypes != null ? subTypes : ImmutableList.<FunctionTypeI>of(),
this.registry.getDirectImplementors(this));
} }


@Override @Override
Expand Down Expand Up @@ -1318,8 +1316,9 @@ JSType resolveInternal(ErrorReporter t, StaticTypedScope<JSType> scope) {


if (subTypes != null) { if (subTypes != null) {
for (int i = 0; i < subTypes.size(); i++) { for (int i = 0; i < subTypes.size(); i++) {
FunctionType subType = (FunctionType) subTypes.get(i);
subTypes.set( subTypes.set(
i, JSType.toMaybeFunctionType(subTypes.get(i).resolve(t, scope))); i, JSType.toMaybeFunctionType(subType.resolve(t, scope)));
} }
} }


Expand Down
5 changes: 3 additions & 2 deletions src/com/google/javascript/rhino/jstype/JSTypeRegistry.java
Expand Up @@ -56,6 +56,7 @@
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.ErrorReporter;
import com.google.javascript.rhino.FunctionTypeI;
import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.JSTypeExpression; import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
Expand Down Expand Up @@ -184,7 +185,7 @@ public class JSTypeRegistry implements TypeIRegistry {
new HashMap<>(); new HashMap<>();


// A map from interface name to types that implement it. // A map from interface name to types that implement it.
private final Multimap<String, FunctionType> interfaceToImplementors = private final Multimap<String, FunctionTypeI> interfaceToImplementors =
LinkedHashMultimap.create(); LinkedHashMultimap.create();


// All the unresolved named types. // All the unresolved named types.
Expand Down Expand Up @@ -954,7 +955,7 @@ void registerTypeImplementingInterface(
* be returned. {@code interfaceInstance} must be an ObjectType for the * be returned. {@code interfaceInstance} must be an ObjectType for the
* instance of the interface. * instance of the interface.
*/ */
public Collection<FunctionType> getDirectImplementors(ObjectType interfaceInstance) { public Collection<FunctionTypeI> getDirectImplementors(ObjectType interfaceInstance) {
return interfaceToImplementors.get(interfaceInstance.getReferenceName()); return interfaceToImplementors.get(interfaceInstance.getReferenceName());
} }


Expand Down
8 changes: 1 addition & 7 deletions src/com/google/javascript/rhino/jstype/ObjectType.java
Expand Up @@ -53,7 +53,6 @@
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.ObjectTypeI; import com.google.javascript.rhino.ObjectTypeI;
import com.google.javascript.rhino.TypeI; import com.google.javascript.rhino.TypeI;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
Expand Down Expand Up @@ -253,7 +252,7 @@ public boolean hasReferenceName() {
} }


@Override @Override
public boolean isUnknownObject() { public final boolean isUnknownObject() {
return !hasReferenceName(); return !hasReferenceName();
} }


Expand Down Expand Up @@ -316,11 +315,6 @@ public ObjectType getTopDefiningInterface(String propertyName) {
return foundType; return foundType;
} }


@Override
public Collection<FunctionType> getDirectImplementors() {
return this.registry.getDirectImplementors(this);
}

/** /**
* Gets the implicit prototype (a.k.a. the {@code [[Prototype]]} property). * Gets the implicit prototype (a.k.a. the {@code [[Prototype]]} property).
*/ */
Expand Down
16 changes: 16 additions & 0 deletions test/com/google/javascript/jscomp/AmbiguatePropertiesTest.java
Expand Up @@ -687,6 +687,22 @@ public void testExtendsInterface() {
test(js, output); test(js, output);
} }


public void testInterfaceWithSubInterfaceAndDirectImplementors() {
test(
LINE_JOINER.join(
"/** @interface */ function Foo(){};",
"Foo.prototype.foo = function(){};",
"/** @interface @extends {Foo} */ function Bar(){};",
"/** @suppress {checkTypes}\n @constructor @implements {Foo} */ function Baz(){};",
"Baz.prototype.baz = function(){};"),
LINE_JOINER.join(
"/** @interface */ function Foo(){};",
"Foo.prototype.b = function(){};",
"/** @interface @extends {Foo} */ function Bar(){};",
"/** @suppress {checkTypes}\n @constructor @implements {Foo} */ function Baz(){};",
"Baz.prototype.a = function(){};"));
}

public void testFunctionSubType() { public void testFunctionSubType() {
String js = LINE_JOINER.join( String js = LINE_JOINER.join(
"Function.prototype.a = 1;", "Function.prototype.a = 1;",
Expand Down
11 changes: 11 additions & 0 deletions test/com/google/javascript/jscomp/DisambiguatePropertiesTest.java
Expand Up @@ -1297,6 +1297,17 @@ public void testInterface_noDirectImplementors() {
+ " b=[[Foo.prototype, I.prototype], [Z.prototype]]}"); + " b=[[Foo.prototype, I.prototype], [Z.prototype]]}");
} }


public void testInterface_subInterfaceAndDirectImplementors() {
String js = LINE_JOINER.join(
"/** @interface */ function I() {};",
"I.prototype.a;",
"/** @constructor @implements {I} */ function Foo() {};",
"Foo.prototype.a;",
"/** @interface @extends {I} */ function Bar() {};",
"Bar.prototype.a;");
testSets(js, "{a=[[Bar.prototype, Foo.prototype, I.prototype]]}");
}

public void testInterfaceOfSuperclass() { public void testInterfaceOfSuperclass() {
String js = "" String js = ""
+ "/** @interface */ function I() {};\n" + "/** @interface */ function I() {};\n"
Expand Down
10 changes: 7 additions & 3 deletions test/com/google/javascript/jscomp/FunctionTypeBuilderTest.java
Expand Up @@ -18,6 +18,8 @@


import static com.google.javascript.rhino.testing.BaseJSTypeTestCase.ALL_NATIVE_EXTERN_TYPES; import static com.google.javascript.rhino.testing.BaseJSTypeTestCase.ALL_NATIVE_EXTERN_TYPES;


import com.google.common.collect.ImmutableList;
import com.google.javascript.rhino.FunctionTypeI;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.ObjectType; import com.google.javascript.rhino.jstype.ObjectType;
Expand Down Expand Up @@ -139,9 +141,11 @@ public void testInlineJsDoc2() throws Exception {
public void testExternSubTypes() throws Exception { public void testExternSubTypes() throws Exception {
testSame(ALL_NATIVE_EXTERN_TYPES, ""); testSame(ALL_NATIVE_EXTERN_TYPES, "");


List<FunctionType> subtypes = ((ObjectType) getLastCompiler() List<FunctionTypeI> subtypes =
.getTypeRegistry().getType("Error")).getConstructor().getSubTypes(); ImmutableList.copyOf(
for (FunctionType type : subtypes) { ((ObjectType) getLastCompiler().getTypeRegistry().getType("Error"))
.getConstructor().getSubTypes());
for (FunctionTypeI type : subtypes) {
String typeName = type.getInstanceType().toString(); String typeName = type.getInstanceType().toString();
FunctionType typeInRegistry = ((ObjectType) getLastCompiler() FunctionType typeInRegistry = ((ObjectType) getLastCompiler()
.getTypeRegistry().getType(typeName)).getConstructor(); .getTypeRegistry().getType(typeName)).getConstructor();
Expand Down
7 changes: 4 additions & 3 deletions test/com/google/javascript/rhino/jstype/JSTypeTest.java
Expand Up @@ -51,6 +51,7 @@
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.SimpleErrorReporter; import com.google.javascript.rhino.SimpleErrorReporter;
import com.google.javascript.rhino.Token; import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.TypeI;
import com.google.javascript.rhino.jstype.JSType.TypePair; import com.google.javascript.rhino.jstype.JSType.TypePair;
import com.google.javascript.rhino.testing.AbstractStaticScope; import com.google.javascript.rhino.testing.AbstractStaticScope;
import com.google.javascript.rhino.testing.Asserts; import com.google.javascript.rhino.testing.Asserts;
Expand Down Expand Up @@ -6365,9 +6366,9 @@ public void testCanCastTo() {
} }


private static boolean containsType( private static boolean containsType(
Iterable<? extends JSType> types, JSType type) { Iterable<? extends TypeI> types, JSType type) {
for (JSType alt : types) { for (TypeI alt : types) {
if (alt.isEquivalentTo(type)) { if (alt.equals(type)) {
return true; return true;
} }
} }
Expand Down

0 comments on commit aa58745

Please sign in to comment.