Skip to content

Commit

Permalink
Expand FunctionBuilder to allow setting the implicit prototype
Browse files Browse the repository at this point in the history
Also does some cleanup:
  * Convert most calls to the FunctionType constructor to instead use FunctionBuilder
  * Add parameter name comments to the remainder of constructor calls
  * Fix lint warnings on CONST_CASE local vars in JSTypeRegistry

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=197667790
  • Loading branch information
shicks authored and brad4d committed May 23, 2018
1 parent 3c8d3e9 commit 9ea58a8
Show file tree
Hide file tree
Showing 13 changed files with 464 additions and 513 deletions.
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/js/es6/object/entries.js
Expand Up @@ -26,7 +26,7 @@ $jscomp.polyfill('Object.entries', function(orig) {
* *
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
* *
* @param {!IObject<KEY, VALUE>} obj * @param {!Object<KEY, VALUE>} obj
* @return {!Array<!Array<KEY|VALUE>>} * @return {!Array<!Array<KEY|VALUE>>}
* @template KEY, VALUE * @template KEY, VALUE
*/ */
Expand Down
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/js/es6/object/values.js
Expand Up @@ -25,7 +25,7 @@ $jscomp.polyfill('Object.values', function(orig) {
* *
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
* *
* @param {!IObject<KEY, VALUE>} obj * @param {!Object<KEY, VALUE>} obj
* @return {!Array<VALUE>} * @return {!Array<VALUE>}
* @template KEY, VALUE * @template KEY, VALUE
*/ */
Expand Down
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/resources.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions src/com/google/javascript/rhino/jstype/ErrorFunctionType.java
Expand Up @@ -51,18 +51,18 @@ class ErrorFunctionType extends FunctionType {
super( super(
registry, registry,
name, name,
null, /* source= */ null,
registry.createArrowType( registry.createArrowType(
registry.createOptionalParameters( registry.createOptionalParameters(
registry.getNativeType(ALL_TYPE), registry.getNativeType(ALL_TYPE),
registry.getNativeType(ALL_TYPE), registry.getNativeType(ALL_TYPE),
registry.getNativeType(ALL_TYPE)), registry.getNativeType(ALL_TYPE)),
null), null),
null, /* typeOfThis= */ null,
null, /* templateTypeMap= */ null,
FunctionType.Kind.CONSTRUCTOR, FunctionType.Kind.CONSTRUCTOR,
true, /* nativeType= */ true,
false); /* isAbstract= */ false);


// NOTE(nicksantos): Errors have the weird behavior in that they can // NOTE(nicksantos): Errors have the weird behavior in that they can
// be called as functions, and they will return instances of themselves. // be called as functions, and they will return instances of themselves.
Expand Down
117 changes: 100 additions & 17 deletions src/com/google/javascript/rhino/jstype/FunctionBuilder.java
Expand Up @@ -52,17 +52,24 @@
* @author nicksantos@google.com (Nick Santos) * @author nicksantos@google.com (Nick Santos)
*/ */
public final class FunctionBuilder { public final class FunctionBuilder {

// Bit masks for various boolean properties
private static final int IS_ABSTRACT = 0x1;
private static final int IS_NATIVE = 0x2;
private static final int INFERRED_RETURN_TYPE = 0x4;
private static final int RETURNS_OWN_INSTANCE_TYPE = 0x8;

private final JSTypeRegistry registry; private final JSTypeRegistry registry;
private String name = null; private String name = null;
private Node sourceNode = null; private Node sourceNode = null;
private Node parametersNode = null; private Node parametersNode = null;
private JSType returnType = null; private JSType returnType = null;
private JSType typeOfThis = null; private JSType typeOfThis = null;
private ObjectType implicitPrototype = null;
private ObjectType setPrototypeBasedOn = null;
private TemplateTypeMap templateTypeMap = null; private TemplateTypeMap templateTypeMap = null;
private boolean inferredReturnType = false; private Kind kind = Kind.ORDINARY;
private boolean isConstructor = false; private int properties = 0;
private boolean isNativeType = false;
private boolean isAbstract = false;


public FunctionBuilder(JSTypeRegistry registry) { public FunctionBuilder(JSTypeRegistry registry) {
this.registry = registry; this.registry = registry;
Expand All @@ -88,6 +95,14 @@ public FunctionBuilder withParamsNode(Node parametersNode) {
return this; return this;
} }


/**
* Set the parameters of the function type with a specially-formatted node.
*/
FunctionBuilder withEmptyParams() {
this.parametersNode = registry.createEmptyParams();
return this;
}

/** Set the return type. */ /** Set the return type. */
public FunctionBuilder withReturnType(JSType returnType) { public FunctionBuilder withReturnType(JSType returnType) {
this.returnType = returnType; this.returnType = returnType;
Expand All @@ -97,14 +112,21 @@ public FunctionBuilder withReturnType(JSType returnType) {
/** Set the return type and whether it's inferred. */ /** Set the return type and whether it's inferred. */
public FunctionBuilder withReturnType(JSType returnType, boolean inferred) { public FunctionBuilder withReturnType(JSType returnType, boolean inferred) {
this.returnType = returnType; this.returnType = returnType;
this.inferredReturnType = inferred; this.properties =
inferred ? this.properties | INFERRED_RETURN_TYPE : this.properties & ~INFERRED_RETURN_TYPE;
return this;
}

/** Set the return type to be a constructor's own instance type. */
FunctionBuilder withReturnsOwnInstanceType() {
this.properties = this.properties | RETURNS_OWN_INSTANCE_TYPE;
return this; return this;
} }


/** Sets an inferred return type. */ /** Sets an inferred return type. */
public FunctionBuilder withInferredReturnType(JSType returnType) { public FunctionBuilder withInferredReturnType(JSType returnType) {
this.returnType = returnType; this.returnType = returnType;
this.inferredReturnType = true; this.properties = this.properties | INFERRED_RETURN_TYPE;
return this; return this;
} }


Expand All @@ -121,49 +143,110 @@ public FunctionBuilder withTemplateKeys(
return this; return this;
} }


/** Set whether this is a constructor. */ /** Set the template name. */
public FunctionBuilder setIsConstructor(boolean isConstructor) { public FunctionBuilder withTemplateKeys(TemplateType... templateKeys) {
this.isConstructor = isConstructor; this.templateTypeMap = registry.createTemplateTypeMap(ImmutableList.copyOf(templateKeys), null);
return this;
}

FunctionBuilder withExtendedTemplate(TemplateType key, JSType value) {
this.templateTypeMap =
templateTypeMap.extend(
registry.createTemplateTypeMap(ImmutableList.of(key), ImmutableList.of(value)));
return this;
}

FunctionBuilder withTemplateTypeMap(TemplateTypeMap templateTypeMap) {
this.templateTypeMap = templateTypeMap;
return this;
}

/** Set the function kind. */
FunctionBuilder withKind(FunctionType.Kind kind) {
this.kind = kind;
return this;
}

/** Make this a constructor. */
public FunctionBuilder forConstructor() {
this.kind = FunctionType.Kind.CONSTRUCTOR;
return this;
}

/** Make this an interface. */
public FunctionBuilder forInterface() {
this.kind = FunctionType.Kind.INTERFACE;
this.parametersNode = registry.createEmptyParams();
return this; return this;
} }


/** Make this a native type. */ /** Make this a native type. */
FunctionBuilder forNativeType() { FunctionBuilder forNativeType() {
this.isNativeType = true; this.properties = this.properties | IS_NATIVE;
return this; return this;
} }


/** Mark abstract method. */ /** Mark abstract method. */
public FunctionBuilder withIsAbstract(boolean isAbstract) { public FunctionBuilder withIsAbstract(boolean isAbstract) {
this.isAbstract = isAbstract; this.properties = isAbstract ? this.properties | IS_ABSTRACT : this.properties & ~IS_ABSTRACT;
return this;
}

/** Set the implicit prototype of the function. */
public FunctionBuilder withImplicitPrototype(ObjectType implicitPrototype) {
this.implicitPrototype = implicitPrototype;
return this;
}

/** Set the prototype property of a constructor. */
public FunctionBuilder withPrototypeBasedOn(ObjectType setPrototypeBasedOn) {
this.setPrototypeBasedOn = setPrototypeBasedOn;
return this; return this;
} }


/** Copies all the information from another function type. */ /** Copies all the information from another function type. */
public FunctionBuilder copyFromOtherFunction(FunctionType otherType) { public FunctionBuilder copyFromOtherFunction(FunctionType otherType) {
int isNative = otherType.isNativeObjectType() ? IS_NATIVE : 0;
int isAbstract = otherType.isAbstract() ? IS_ABSTRACT : 0;
int inferredReturnType = otherType.isReturnTypeInferred() ? INFERRED_RETURN_TYPE : 0;
this.name = otherType.getReferenceName(); this.name = otherType.getReferenceName();
this.sourceNode = otherType.getSource(); this.sourceNode = otherType.getSource();
this.parametersNode = otherType.getParametersNode(); this.parametersNode = otherType.getParametersNode();
this.returnType = otherType.getReturnType(); this.returnType = otherType.getReturnType();
this.typeOfThis = otherType.getTypeOfThis(); this.typeOfThis = otherType.getTypeOfThis();
this.templateTypeMap = otherType.getTemplateTypeMap(); this.templateTypeMap = otherType.getTemplateTypeMap();
this.isConstructor = otherType.isConstructor(); this.kind = otherType.getKind();
this.isNativeType = otherType.isNativeObjectType(); this.properties = isNative | isAbstract | inferredReturnType;
this.isAbstract = otherType.isAbstract(); this.implicitPrototype = otherType.getImplicitPrototype();
return this; return this;
} }


/** Construct a new function type. */ /** Construct a new function type. */
public FunctionType build() { public FunctionType build() {
return new FunctionType( // TODO(sdh): Should we do any validation here?
boolean inferredReturnType = (properties & INFERRED_RETURN_TYPE) != 0;
boolean isNative = (properties & IS_NATIVE) != 0;
boolean isAbstract = (properties & IS_ABSTRACT) != 0;
boolean returnsOwnInstanceType = (properties & RETURNS_OWN_INSTANCE_TYPE) != 0;
FunctionType ft = new FunctionType(
registry, registry,
name, name,
sourceNode, sourceNode,
new ArrowType(registry, parametersNode, returnType, inferredReturnType), new ArrowType(registry, parametersNode, returnType, inferredReturnType),
typeOfThis, typeOfThis,
templateTypeMap, templateTypeMap,
isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY, kind,
isNativeType, isNative,
isAbstract); isAbstract);
if (implicitPrototype != null) {
ft.setImplicitPrototype(implicitPrototype);
}
if (setPrototypeBasedOn != null) {
ft.setPrototypeBasedOn(setPrototypeBasedOn);
}
if (returnsOwnInstanceType) {
ft.getInternalArrowType().returnType = ft.getInstanceType();
}
return ft;
} }
} }
43 changes: 15 additions & 28 deletions src/com/google/javascript/rhino/jstype/FunctionType.java
Expand Up @@ -186,14 +186,6 @@ private enum PropAccess {
this.isAbstract = isAbstract; this.isAbstract = isAbstract;
} }


/** Creates an instance for a function that is an interface. */
static FunctionType forInterface(
JSTypeRegistry registry, String name, Node source, TemplateTypeMap typeParameters) {
ArrowType arrowType = new ArrowType(registry, new Node(Token.PARAM_LIST), null);
return new FunctionType(
registry, name, source, arrowType, null, typeParameters, Kind.INTERFACE, false, false);
}

@Override @Override
public final boolean isInstanceType() { public final boolean isInstanceType() {
// The universal constructor is its own instance, bizarrely. It overrides // The universal constructor is its own instance, bizarrely. It overrides
Expand All @@ -216,6 +208,10 @@ public final boolean isOrdinaryFunction() {
return kind == Kind.ORDINARY; return kind == Kind.ORDINARY;
} }


final Kind getKind() {
return kind;
}

/** /**
* When a class B inherits from A and A is annotated as a struct, then B automatically gets the * When a class B inherits from A and A is annotated as a struct, then B automatically gets the
* annotation, even if B's constructor is not explicitly annotated. * annotation, even if B's constructor is not explicitly annotated.
Expand Down Expand Up @@ -854,16 +850,11 @@ private FunctionType tryMergeFunctionPiecewise(FunctionType other, boolean least


boolean newReturnTypeInferred = call.returnTypeInferred || other.call.returnTypeInferred; boolean newReturnTypeInferred = call.returnTypeInferred || other.call.returnTypeInferred;


return new FunctionType( return new FunctionBuilder(registry)
registry, .withParamsNode(newParamsNode)
null, .withReturnType(newReturnType, newReturnTypeInferred)
null, .withTypeOfThis(newTypeOfThis)
new ArrowType(registry, newParamsNode, newReturnType, newReturnTypeInferred), .build();
newTypeOfThis,
null,
Kind.ORDINARY,
false,
false);
} }


/** /**
Expand Down Expand Up @@ -1444,16 +1435,12 @@ public final boolean acceptsArguments(List<? extends JSType> argumentTypes) {
/** Create a new constructor with the parameters and return type stripped. */ /** Create a new constructor with the parameters and return type stripped. */
public final FunctionType forgetParameterAndReturnTypes() { public final FunctionType forgetParameterAndReturnTypes() {
FunctionType result = FunctionType result =
new FunctionType( new FunctionBuilder(registry)
registry, .withName(getReferenceName())
getReferenceName(), .withSourceNode(source)
source, .withTypeOfThis(getInstanceType())
registry.createArrowType(null, null), .withKind(kind)
getInstanceType(), .build();
null,
kind,
false,
false);
result.setPrototypeBasedOn(getInstanceType()); result.setPrototypeBasedOn(getInstanceType());
return result; return result;
} }
Expand Down

0 comments on commit 9ea58a8

Please sign in to comment.