use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeInference method evaluateTypeTransformations.
/**
* This function will evaluate the type transformations associated to the
* template types
*/
private Map<TemplateType, JSType> evaluateTypeTransformations(ImmutableList<TemplateType> templateTypes, Map<TemplateType, JSType> inferredTypes) {
Map<String, JSType> typeVars = null;
Map<TemplateType, JSType> result = null;
TypeTransformation ttlObj = null;
for (TemplateType type : templateTypes) {
if (type.isTypeTransformation()) {
// Lazy initialization when the first type transformation is found
if (ttlObj == null) {
ttlObj = new TypeTransformation(compiler, currentScope);
typeVars = buildTypeVariables(inferredTypes);
result = new LinkedHashMap<>();
}
// Evaluate the type transformation expression using the current
// known types for the template type variables
@SuppressWarnings({ "unchecked", "rawtypes" }) JSType transformedType = (JSType) ttlObj.eval(type.getTypeTransformation(), (ImmutableMap) ImmutableMap.copyOf(typeVars));
result.put(type, transformedType);
// Add the transformed type to the type variables
typeVars.put(type.getReferenceName(), transformedType);
}
}
return result;
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class InvocationTemplateTypeMatcher method matchTemplateTypesRecursive.
private void matchTemplateTypesRecursive(JSType paramType, JSType argType) {
if (paramType.isTemplateType()) {
// Recursive base case.
// example: @param {T}
this.recordTemplateMatch(paramType.toMaybeTemplateType(), argType);
return;
}
// Unpack unions.
if (paramType.isUnionType()) {
// example: @param {Array.<T>|NodeList|Arguments|{length:number}}
UnionType unionType = paramType.toMaybeUnionType();
for (JSType alternate : unionType.getAlternates()) {
this.matchTemplateTypesRecursive(alternate, argType);
}
return;
} else if (argType.isUnionType()) {
UnionType unionType = argType.toMaybeUnionType();
for (JSType alternate : unionType.getAlternates()) {
this.matchTemplateTypesRecursive(paramType, alternate);
}
return;
}
if (paramType.isFunctionType()) {
FunctionType paramFunctionType = paramType.toMaybeFunctionType();
FunctionType argFunctionType = argType.restrictByNotNullOrUndefined().collapseUnion().toMaybeFunctionType();
if (argFunctionType != null && argFunctionType.isSubtype(paramType)) {
// infer from return type of the function type
this.matchTemplateTypesRecursive(paramFunctionType.getTypeOfThis(), argFunctionType.getTypeOfThis());
// infer from return type of the function type
this.matchTemplateTypesRecursive(paramFunctionType.getReturnType(), argFunctionType.getReturnType());
// infer from parameter types of the function type
this.matchTemplateTypesFromParameters(paramFunctionType.getParameters().iterator(), argFunctionType.getParameters().iterator());
}
} else if (paramType.isRecordType() && !paramType.isNominalType()) {
// example: @param {{foo:T}}
if (this.seenTypes.add(paramType)) {
ObjectType paramRecordType = paramType.toObjectType();
ObjectType argObjectType = argType.restrictByNotNullOrUndefined().toObjectType();
if (argObjectType != null && !argObjectType.isUnknownType() && !argObjectType.isEmptyType()) {
Set<String> names = paramRecordType.getPropertyNames();
for (String name : names) {
if (paramRecordType.hasOwnProperty(name) && argObjectType.hasProperty(name)) {
this.matchTemplateTypesRecursive(paramRecordType.getPropertyType(name), argObjectType.getPropertyType(name));
}
}
}
this.seenTypes.remove(paramType);
}
} else if (paramType.isTemplatizedType()) {
// example: @param {Array<T>}
TemplatizedType templatizedParamType = paramType.toMaybeTemplatizedType();
int keyCount = templatizedParamType.getTemplateTypes().size();
// types with no type arguments.
if (keyCount == 0) {
return;
}
ObjectType referencedParamType = templatizedParamType.getReferencedType();
JSType argObjectType = argType.restrictByNotNullOrUndefined().collapseUnion();
if (argObjectType.isSubtypeOf(referencedParamType)) {
// If the argument type is a subtype of the parameter type, resolve any
// template types amongst their templatized types.
TemplateTypeMap paramTypeMap = paramType.getTemplateTypeMap();
ImmutableList<TemplateType> keys = paramTypeMap.getTemplateKeys();
TemplateTypeMap argTypeMap = argObjectType.getTemplateTypeMap();
for (int index = keys.size() - keyCount; index < keys.size(); index++) {
TemplateType key = keys.get(index);
this.matchTemplateTypesRecursive(paramTypeMap.getResolvedTemplateType(key), argTypeMap.getResolvedTemplateType(key));
}
}
}
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class JsIterables method maybeBoxIterableOrAsyncIterable.
/**
* Given a type, if it is an iterable or async iterable, will return its template. If not a
* subtype of Iterable|AsyncIterable, returns an object that has no match, and will indicate the
* mismatch. e.g. both {@code number} and {@code number|Iterable} are not subtypes of
* Iterable|AsyncIterable.
*/
static final MaybeBoxedIterableOrAsyncIterable maybeBoxIterableOrAsyncIterable(JSType type, JSTypeRegistry typeRegistry) {
List<JSType> templatedTypes = new ArrayList<>();
// We want to keep null and undefined around because they should cause a mismatch.
if (type.isUnionType()) {
for (JSType alt : type.toMaybeUnionType().getAlternates()) {
alt = alt.isBoxableScalar() ? alt.autoboxesTo() : alt;
boolean isIterable = alt.isSubtypeOf(typeRegistry.getNativeType(ITERABLE_TYPE));
boolean isAsyncIterable = alt.isSubtypeOf(typeRegistry.getNativeType(ASYNC_ITERABLE_TYPE));
if (!isIterable && !isAsyncIterable) {
return new MaybeBoxedIterableOrAsyncIterable(null, alt);
}
TemplateType valueTemplate = isAsyncIterable ? typeRegistry.getAsyncIterableTemplate() : typeRegistry.getIterableTemplate();
templatedTypes.add(alt.getTemplateTypeMap().getResolvedTemplateType(valueTemplate));
}
} else {
JSType autoboxedType = type.isBoxableScalar() ? type.autoboxesTo() : type;
boolean isIterable = autoboxedType.isSubtypeOf(typeRegistry.getNativeType(ITERABLE_TYPE));
boolean isAsyncIterable = autoboxedType.isSubtypeOf(typeRegistry.getNativeType(ASYNC_ITERABLE_TYPE));
if (!isIterable && !isAsyncIterable) {
return new MaybeBoxedIterableOrAsyncIterable(null, autoboxedType);
}
TemplateType templateType = isAsyncIterable ? typeRegistry.getAsyncIterableTemplate() : typeRegistry.getIterableTemplate();
templatedTypes.add(autoboxedType.getTemplateTypeMap().getResolvedTemplateType(templateType));
}
return new MaybeBoxedIterableOrAsyncIterable(typeRegistry.createUnionType(templatedTypes), null);
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeCheck method visitYield.
/**
* Visits a YIELD node.
*/
private void visitYield(NodeTraversal t, Node n) {
JSType jsType = getJSType(t.getEnclosingFunction());
JSType declaredYieldType = getNativeType(UNKNOWN_TYPE);
if (jsType.isFunctionType()) {
FunctionType functionType = jsType.toMaybeFunctionType();
JSType returnType = functionType.getReturnType();
declaredYieldType = JsIterables.getElementType(returnType, typeRegistry);
if (t.getEnclosingFunction().isAsyncGeneratorFunction()) {
// Can yield x|IThenable<x> in an AsyncGenerator<x>, no await needed. Note that we must
// first wrap the type in IThenable as createAsyncReturnableType will map a non-IThenable to
// `?`.
declaredYieldType = Promises.createAsyncReturnableType(typeRegistry, Promises.wrapInIThenable(typeRegistry, declaredYieldType));
}
}
// fetching the yielded value's type
Node valueNode = n.getFirstChild();
JSType actualYieldType;
if (valueNode == null) {
actualYieldType = getNativeType(VOID_TYPE);
valueNode = n;
} else {
actualYieldType = getJSType(valueNode);
}
if (n.isYieldAll()) {
if (t.getEnclosingFunction().isAsyncGeneratorFunction()) {
Optional<JSType> maybeActualYieldType = validator.expectAutoboxesToIterableOrAsyncIterable(n, actualYieldType, "Expression yield* expects an iterable or async iterable");
if (!maybeActualYieldType.isPresent()) {
// don't do any further typechecking of the yield* type.
return;
}
actualYieldType = maybeActualYieldType.get();
} else {
if (!validator.expectAutoboxesToIterable(n, actualYieldType, "Expression yield* expects an iterable")) {
// don't do any further typechecking of the yield* type.
return;
}
TemplateType templateType = typeRegistry.getIterableTemplate();
actualYieldType = actualYieldType.autobox().getTemplateTypeMap().getResolvedTemplateType(templateType);
}
}
// verifying
validator.expectCanAssignTo(valueNode, actualYieldType, declaredYieldType, "Yielded type does not match declared return type.");
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeInference method initializeEnhancedForScope.
private FlowScope initializeEnhancedForScope(Node source, FlowScope output) {
Node item = source.getFirstChild();
Node obj = item.getNext();
FlowScope informed = traverse(obj, output);
final AssignmentType assignmentType;
if (NodeUtil.isNameDeclaration(item)) {
item = item.getFirstChild();
assignmentType = AssignmentType.DECLARATION;
} else {
assignmentType = AssignmentType.ASSIGN;
}
if (item.isDestructuringLhs()) {
item = item.getFirstChild();
}
final JSType newType;
switch(source.getToken()) {
case FOR_IN:
{
// item is assigned a property name, so its type should be string
JSType iterKeyType = getNativeType(STRING_TYPE);
JSType objType = getJSType(obj).autobox();
JSType objIndexType = objType.getTemplateTypeMap().getResolvedTemplateType(registry.getObjectIndexKey());
if (objIndexType != null && !objIndexType.isUnknownType()) {
JSType narrowedKeyType = iterKeyType.getGreatestSubtype(objIndexType);
if (!narrowedKeyType.isEmptyType()) {
iterKeyType = narrowedKeyType;
}
}
newType = iterKeyType;
break;
}
case FOR_OF:
{
// for/of. The type of `item` is the type parameter of the Iterable type.
JSType objType = getJSType(obj).autobox();
TemplateType templateType = registry.getIterableTemplate();
// NOTE: this returns the UNKNOWN_TYPE if objType does not implement Iterable
newType = objType.getTemplateTypeMap().getResolvedTemplateType(templateType);
break;
}
case FOR_AWAIT_OF:
{
// for/await/of. the iterated object is either of the Iterable or AsyncIterable type.
// the type of `item` is the Promise.resolve() type of the object's type parameter.
JSType iterableType = JsIterables.maybeBoxIterableOrAsyncIterable(getJSType(obj), registry).orElse(unknownType);
newType = Promises.getResolvedType(registry, iterableType);
break;
}
default:
throw new IllegalArgumentException("Unexpected source node " + source);
}
// Note that `item` can be an arbitrary LHS expression we need to check.
if (item.isDestructuringPattern()) {
// for (const {x, y} of data) {
informed = traverseDestructuringPattern(item, informed, newType, assignmentType);
} else {
informed = traverse(item, informed);
informed = updateScopeForAssignment(informed, item, newType, assignmentType);
}
return informed;
}
Aggregations