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
*
* @param {!IObject<KEY, VALUE>} obj
* @param {!Object<KEY, VALUE>} obj
* @return {!Array<!Array<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
*
* @param {!IObject<KEY, VALUE>} obj
* @param {!Object<KEY, VALUE>} obj
* @return {!Array<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(
registry,
name,
null,
/* source= */ null,
registry.createArrowType(
registry.createOptionalParameters(
registry.getNativeType(ALL_TYPE),
registry.getNativeType(ALL_TYPE),
registry.getNativeType(ALL_TYPE)),
null),
null,
null,
/* typeOfThis= */ null,
/* templateTypeMap= */ null,
FunctionType.Kind.CONSTRUCTOR,
true,
false);
/* nativeType= */ true,
/* isAbstract= */ false);

// NOTE(nicksantos): Errors have the weird behavior in that they can
// 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)
*/
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 String name = null;
private Node sourceNode = null;
private Node parametersNode = null;
private JSType returnType = null;
private JSType typeOfThis = null;
private ObjectType implicitPrototype = null;
private ObjectType setPrototypeBasedOn = null;
private TemplateTypeMap templateTypeMap = null;
private boolean inferredReturnType = false;
private boolean isConstructor = false;
private boolean isNativeType = false;
private boolean isAbstract = false;
private Kind kind = Kind.ORDINARY;
private int properties = 0;

public FunctionBuilder(JSTypeRegistry registry) {
this.registry = registry;
Expand All @@ -88,6 +95,14 @@ public FunctionBuilder withParamsNode(Node parametersNode) {
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. */
public FunctionBuilder withReturnType(JSType returnType) {
this.returnType = returnType;
Expand All @@ -97,14 +112,21 @@ public FunctionBuilder withReturnType(JSType returnType) {
/** Set the return type and whether it's inferred. */
public FunctionBuilder withReturnType(JSType returnType, boolean inferred) {
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;
}

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

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

/** Set whether this is a constructor. */
public FunctionBuilder setIsConstructor(boolean isConstructor) {
this.isConstructor = isConstructor;
/** Set the template name. */
public FunctionBuilder withTemplateKeys(TemplateType... templateKeys) {
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;
}

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

/** Mark abstract method. */
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;
}

/** Copies all the information from another function type. */
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.sourceNode = otherType.getSource();
this.parametersNode = otherType.getParametersNode();
this.returnType = otherType.getReturnType();
this.typeOfThis = otherType.getTypeOfThis();
this.templateTypeMap = otherType.getTemplateTypeMap();
this.isConstructor = otherType.isConstructor();
this.isNativeType = otherType.isNativeObjectType();
this.isAbstract = otherType.isAbstract();
this.kind = otherType.getKind();
this.properties = isNative | isAbstract | inferredReturnType;
this.implicitPrototype = otherType.getImplicitPrototype();
return this;
}

/** Construct a new function type. */
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,
name,
sourceNode,
new ArrowType(registry, parametersNode, returnType, inferredReturnType),
typeOfThis,
templateTypeMap,
isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY,
isNativeType,
kind,
isNative,
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;
}

/** 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
public final boolean isInstanceType() {
// The universal constructor is its own instance, bizarrely. It overrides
Expand All @@ -216,6 +208,10 @@ public final boolean isOrdinaryFunction() {
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
* 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;

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

/**
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. */
public final FunctionType forgetParameterAndReturnTypes() {
FunctionType result =
new FunctionType(
registry,
getReferenceName(),
source,
registry.createArrowType(null, null),
getInstanceType(),
null,
kind,
false,
false);
new FunctionBuilder(registry)
.withName(getReferenceName())
.withSourceNode(source)
.withTypeOfThis(getInstanceType())
.withKind(kind)
.build();
result.setPrototypeBasedOn(getInstanceType());
return result;
}
Expand Down

0 comments on commit 9ea58a8

Please sign in to comment.