Skip to content

Commit

Permalink
Create 'IObject', 'Generator' and 'Iterator' built-in types
Browse files Browse the repository at this point in the history
This is in preparation for natively typechecking generators

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=188896429
  • Loading branch information
lauraharker authored and blickly committed Mar 13, 2018
1 parent 6970e2a commit d043337
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 37 deletions.
16 changes: 10 additions & 6 deletions src/com/google/javascript/jscomp/FunctionTypeBuilder.java
Expand Up @@ -354,12 +354,16 @@ FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
reportWarning(CONSTRUCTOR_REQUIRED, "@dict", formatFnName());
}

if (typeRegistry.isTemplatedBuiltin(fnName, info)) {
// This case is only for setting template types
// for IObject<KEY1, VALUE1>.
// In the (old) type system, there should be only one unique template
// type for <KEY1> and <VALUE1> respectively
classTemplateTypeNames = typeRegistry.getTemplateTypesOfBuiltin(fnName);
// TODO(b/74253232): maybeGetNativeTypesOfBuiltin should also handle cases where a local type
// declaration shadows a templatized native type.
ImmutableList<TemplateType> nativeClassTemplateTypeNames =
typeRegistry.maybeGetTemplateTypesOfBuiltin(fnName);
ImmutableList<String> infoTemplateTypeNames = info.getTemplateTypeNames();
// TODO(b/73386087): Make infoTemplateTypeNames.size() == nativeClassTemplateTypeName.size() a
// Preconditions check. It currently fails for "var symbol" in the externs.
if (nativeClassTemplateTypeNames != null
&& infoTemplateTypeNames.size() == nativeClassTemplateTypeNames.size()) {
classTemplateTypeNames = nativeClassTemplateTypeNames;
typeRegistry.setTemplateTypeNames(classTemplateTypeNames);
} else {
// Otherwise, create new template type for
Expand Down
4 changes: 4 additions & 0 deletions src/com/google/javascript/jscomp/TypedScopeCreator.java
Expand Up @@ -28,8 +28,10 @@
import static com.google.javascript.rhino.jstype.JSTypeNative.ERROR_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.EVAL_ERROR_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.FUNCTION_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.GENERATOR_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.GLOBAL_THIS;
import static com.google.javascript.rhino.jstype.JSTypeNative.ITERABLE_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.ITERATOR_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.NULL_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE;
Expand Down Expand Up @@ -404,7 +406,9 @@ TypedScope createInitialScope(Node root) {
declareNativeFunctionType(s, ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, EVAL_ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, FUNCTION_FUNCTION_TYPE);
declareNativeFunctionType(s, GENERATOR_FUNCTION_TYPE);
declareNativeFunctionType(s, ITERABLE_FUNCTION_TYPE);
declareNativeFunctionType(s, ITERATOR_FUNCTION_TYPE);
declareNativeFunctionType(s, NUMBER_OBJECT_FUNCTION_TYPE);
declareNativeFunctionType(s, OBJECT_FUNCTION_TYPE);
declareNativeFunctionType(s, RANGE_ERROR_FUNCTION_TYPE);
Expand Down
5 changes: 5 additions & 0 deletions src/com/google/javascript/rhino/jstype/JSTypeNative.java
Expand Up @@ -95,15 +95,20 @@ public enum JSTypeNative {
FUNCTION_INSTANCE_TYPE, // equivalent to U2U_CONSTRUCTOR_TYPE
FUNCTION_PROTOTYPE,

GENERATOR_FUNCTION_TYPE,
GENERATOR_TYPE,

I_ITERABLE_RESULT_TYPE,
ITERABLE_FUNCTION_TYPE,
ITERABLE_TYPE,
ITERATOR_FUNCTION_TYPE,
ITERATOR_TYPE,

I_TEMPLATE_ARRAY_TYPE,

I_OBJECT_FUNCTION_TYPE,
I_OBJECT_TYPE,

NULL_TYPE,

NUMBER_TYPE,
Expand Down
91 changes: 65 additions & 26 deletions src/com/google/javascript/rhino/jstype/JSTypeRegistry.java
Expand Up @@ -108,6 +108,12 @@ public class JSTypeRegistry implements TypeIRegistry {
/** The template variable corresponding to the VALUE type in {@code Iterable<VALUE>} */
private TemplateType iterableTemplate;

/** The template variable corresponding to the VALUE type in {@code Iterator<VALUE>} */
private TemplateType iteratorTemplate;

/** The template variable corresponding to the VALUE type in {@code Generator<VALUE>} */
private TemplateType generatorTemplate;

/**
* The template variable in {@code Array<T>}
*/
Expand Down Expand Up @@ -250,33 +256,16 @@ public TemplateType getObjectIndexKey() {
return this.iObjectIndexTemplateKey;
}

/**
* Check if a function declaration is one of the templated builitin contructor/interfaces,
* namely one of IObject, IArrayLike, or Array
* @param fnName the function's name
* @param info the JSDoc from the function declaration
*/
public boolean isTemplatedBuiltin(String fnName, JSDocInfo info) {
ImmutableList<TemplateType> requiredTemplateTypes = getTemplateTypesOfBuiltin(fnName);
ImmutableList<String> infoTemplateTypeNames = info.getTemplateTypeNames();
return requiredTemplateTypes != null
&& infoTemplateTypeNames.size() == requiredTemplateTypes.size();
}

/**
* @return return an immutable list of template types of the given builtin.
*/
public ImmutableList<TemplateType> getTemplateTypesOfBuiltin(String fnName) {
switch (fnName) {
case "IObject":
return ImmutableList.of(iObjectIndexTemplateKey, iObjectElementTemplateKey);
case "Array":
return ImmutableList.of(arrayElementTemplateKey);
case "Iterable":
return ImmutableList.of(iterableTemplate);
default:
return null;
/** @return return an immutable list of template types of the given builtin. */
public ImmutableList<TemplateType> maybeGetTemplateTypesOfBuiltin(String fnName) {
JSType type = getType(null, fnName);
ObjectType objType = type == null ? null : type.toObjectType();
if (objType != null && objType.isNativeObjectType()) {
ImmutableList<TemplateType> templateKeys =
objType.getTemplateTypeMap().getUnfilledTemplateKeys();
return templateKeys;
}
return null;
}

public ErrorReporter getErrorReporter() {
Expand Down Expand Up @@ -326,7 +315,10 @@ private void initializeBuiltInTypes() {
// Template Types
iObjectIndexTemplateKey = new TemplateType(this, "IObject#KEY1");
iObjectElementTemplateKey = new TemplateType(this, I_OBJECT_ELEMENT_TEMPLATE);
// These should match the template type name in externs files.
arrayElementTemplateKey = new TemplateType(this, "T");
iteratorTemplate = new TemplateType(this, "VALUE");
generatorTemplate = new TemplateType(this, "VALUE");
iterableTemplate = new TemplateType(this, "VALUE");

// Top Level Prototype (the One)
Expand All @@ -337,6 +329,22 @@ private void initializeBuiltInTypes() {
new PrototypeObjectType(this, null, null, true, null);
registerNativeType(JSTypeNative.TOP_LEVEL_PROTOTYPE, TOP_LEVEL_PROTOTYPE);

// IObject
FunctionType iObjectFunctionType =
new FunctionType(
this,
"IObject",
null,
createArrowType(),
null,
createTemplateTypeMap(
ImmutableList.of(iObjectIndexTemplateKey, iObjectElementTemplateKey), null),
Kind.INTERFACE,
true,
false);
registerNativeType(JSTypeNative.I_OBJECT_FUNCTION_TYPE, iObjectFunctionType);
registerNativeType(JSTypeNative.I_OBJECT_TYPE, iObjectFunctionType.getInstanceType());

// Object
FunctionType OBJECT_FUNCTION_TYPE =
new FunctionType(
Expand Down Expand Up @@ -429,6 +437,34 @@ private void initializeBuiltInTypes() {
registerNativeType(JSTypeNative.ITERABLE_FUNCTION_TYPE, iterableFunctionType);
registerNativeType(JSTypeNative.ITERABLE_TYPE, iterableFunctionType.getInstanceType());

FunctionType iteratorFunctionType =
new FunctionType(
this,
"Iterator",
null,
createArrowType(),
null,
createTemplateTypeMap(ImmutableList.of(iteratorTemplate), null),
Kind.INTERFACE,
true,
false);
registerNativeType(JSTypeNative.ITERATOR_FUNCTION_TYPE, iteratorFunctionType);
registerNativeType(JSTypeNative.ITERATOR_TYPE, iteratorFunctionType.getInstanceType());

FunctionType generatorFunctionType =
new FunctionType(
this,
"Generator",
null,
createArrowType(),
null,
createTemplateTypeMap(ImmutableList.of(generatorTemplate), null),
Kind.INTERFACE,
true,
false);
registerNativeType(JSTypeNative.GENERATOR_FUNCTION_TYPE, generatorFunctionType);
registerNativeType(JSTypeNative.GENERATOR_TYPE, generatorFunctionType.getInstanceType());

// Boolean
FunctionType BOOLEAN_OBJECT_FUNCTION_TYPE =
new FunctionType(
Expand Down Expand Up @@ -781,7 +817,10 @@ private void initializeRegistry() {
register(getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE));
register(getNativeType(JSTypeNative.BOOLEAN_TYPE));
register(getNativeType(JSTypeNative.ITERABLE_TYPE));
register(getNativeType(JSTypeNative.ITERATOR_TYPE));
register(getNativeType(JSTypeNative.GENERATOR_TYPE));
register(getNativeType(JSTypeNative.DATE_TYPE));
register(getNativeType(JSTypeNative.I_OBJECT_TYPE));
register(getNativeType(JSTypeNative.NULL_TYPE));
register(getNativeType(JSTypeNative.NULL_TYPE), "Null");
register(getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE));
Expand Down
4 changes: 2 additions & 2 deletions test/com/google/javascript/jscomp/CompilerTestCase.java
Expand Up @@ -422,8 +422,8 @@ public abstract class CompilerTestCase extends TestCase {
"Iterable.prototype[Symbol.iterator] = function() {};",
"/** @type {number} */ var NaN;",
"/**",
" * @constructor",
" * @implements {IteratorIterable<VALUE>}",
" * @interface",
" * @extends {IteratorIterable<VALUE>}",
" * @template VALUE",
" */",
"function Generator() {}",
Expand Down
4 changes: 2 additions & 2 deletions test/com/google/javascript/jscomp/IntegrationTestCase.java
Expand Up @@ -216,8 +216,8 @@ abstract class IntegrationTestCase extends TestCase {
"function Arguments() {}",
"",
"/**",
" * @constructor",
" * @implements {IteratorIterable<VALUE>}",
" * @interface",
" * @extends {IteratorIterable<VALUE>}",
" * @template VALUE",
" */",
"function Generator() {}",
Expand Down
48 changes: 47 additions & 1 deletion test/com/google/javascript/jscomp/TypeCheckTest.java
Expand Up @@ -75,7 +75,7 @@ public void setUp() throws Exception {
@Override
protected CompilerOptions getDefaultOptions() {
CompilerOptions options = super.getDefaultOptions();
options.setLanguageIn(LanguageMode.ECMASCRIPT_2015);
options.setLanguageIn(LanguageMode.ECMASCRIPT_2017);
options.setLanguageOut(LanguageMode.ECMASCRIPT5);
return options;
}
Expand Down Expand Up @@ -5654,6 +5654,52 @@ public void testIArrayLikeAccess2() {
+ "required: null");
}

// These test the template types in the built-in Iterator/Iterable/Generator are set up correctly
public void testIteratorAccess1() {
testTypes(
lines(
"/** ",
" * @param {!Iterator<T>} x",
" * @return {T}",
" * @template T",
"*/",
"function f(x) { return x[0]; }",
"function g(/** !Generator<string> */ x) {",
" var /** null */ y = f(x);",
"}"),
"initializing variable\n" + "found : string\n" + "required: null");
}

public void testIterableAccess1() {
testTypes(
lines(
"/** ",
" * @param {!Iterable<T>} x",
" * @return {T}",
" * @template T",
"*/",
"function f(x) { return x[0]; }",
"function g(/** !Generator<string> */ x) {",
" var /** null */ y = f(x);",
"}"),
"initializing variable\n" + "found : string\n" + "required: null");
}

public void testIteratorIterableAccess1() {
testTypes(
lines(
"/** ",
" * @param {!IteratorIterable<T>} x",
" * @return {T}",
" * @template T",
"*/",
"function f(x) { return x[0]; }",
"function g(/** !Generator<string> */ x) {",
" var /** null */ y = f(x);",
"}"),
"initializing variable\n" + "found : string\n" + "required: null");
}

public void testArrayAccess1() {
testTypes("var a = []; var b = a['hi'];",
"restricted index type\n" +
Expand Down
12 changes: 12 additions & 0 deletions test/com/google/javascript/rhino/jstype/JSTypeRegistryTest.java
Expand Up @@ -42,7 +42,9 @@
import static com.google.javascript.rhino.jstype.JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.BOOLEAN_OBJECT_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.BOOLEAN_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.GENERATOR_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.ITERABLE_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.ITERATOR_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.NULL_TYPE;
import static com.google.javascript.rhino.jstype.JSTypeNative.NULL_VOID;
import static com.google.javascript.rhino.jstype.JSTypeNative.NUMBER_TYPE;
Expand Down Expand Up @@ -71,6 +73,16 @@ public void testGetBuiltInType_iterable() {
assertTypeEquals(typeRegistry.getNativeType(ITERABLE_TYPE), typeRegistry.getType("Iterable"));
}

public void testGetBuiltInType_iterator() {
JSTypeRegistry typeRegistry = new JSTypeRegistry(null);
assertTypeEquals(typeRegistry.getNativeType(ITERATOR_TYPE), typeRegistry.getType("Iterator"));
}

public void testGetBuiltInType_generator() {
JSTypeRegistry typeRegistry = new JSTypeRegistry(null);
assertTypeEquals(typeRegistry.getNativeType(GENERATOR_TYPE), typeRegistry.getType("Generator"));
}

public void testGetDeclaredType() {
JSTypeRegistry typeRegistry = new JSTypeRegistry(null);
JSType type = typeRegistry.createAnonymousObjectType(null);
Expand Down

0 comments on commit d043337

Please sign in to comment.