use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeInference method inferTemplatedTypesForCall.
/**
* For functions that use template types, specialize the function type for the call target based
* on the call-site specific arguments. Specifically, this enables inference to set the type of
* any function literal parameters based on these inferred types.
*/
private boolean inferTemplatedTypesForCall(Node n, FunctionType fnType, FlowScope scope) {
ImmutableList<TemplateType> keys = fnType.getTemplateTypeMap().getTemplateKeys();
if (keys.isEmpty()) {
return false;
}
// Try to infer the template types
Map<TemplateType, JSType> bindings = new InvocationTemplateTypeMatcher(this.registry, fnType, scope.getTypeOfThis(), n).match();
Map<TemplateType, JSType> inferred = new LinkedHashMap<>();
for (TemplateType key : keys) {
inferred.put(key, bindings.getOrDefault(key, unknownType));
}
// If the inferred type doesn't satisfy the template bound, swap to using the bound. This
// ensures errors will be reported in type-checking.
inferred.replaceAll((k, v) -> v.isSubtypeOf(k.getBound()) ? v : k.getBound());
// Try to infer the template types using the type transformations
Map<TemplateType, JSType> typeTransformations = evaluateTypeTransformations(keys, inferred, scope);
if (typeTransformations != null) {
inferred.putAll(typeTransformations);
}
// Replace all template types. If we couldn't find a replacement, we
// replace it with UNKNOWN.
TemplateTypeReplacer replacer = TemplateTypeReplacer.forInference(registry, inferred);
Node callTarget = n.getFirstChild();
FunctionType replacementFnType = fnType.visit(replacer).toMaybeFunctionType();
checkNotNull(replacementFnType);
callTarget.setJSType(replacementFnType);
n.setJSType(replacementFnType.getReturnType());
return replacer.hasMadeReplacement();
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeInference method maybeResolveTemplatedType.
private void maybeResolveTemplatedType(JSType paramType, JSType argType, Map<TemplateType, JSType> resolvedTypes, Set<JSType> seenTypes) {
if (paramType.isTemplateType()) {
// example: @param {T}
resolvedTemplateType(resolvedTypes, paramType.toMaybeTemplateType(), argType);
} else if (paramType.isUnionType()) {
// example: @param {Array.<T>|NodeList|Arguments|{length:number}}
UnionType unionType = paramType.toMaybeUnionType();
for (JSType alernative : unionType.getAlternates()) {
maybeResolveTemplatedType(alernative, argType, resolvedTypes, seenTypes);
}
} else 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
maybeResolveTemplatedType(paramFunctionType.getTypeOfThis(), argFunctionType.getTypeOfThis(), resolvedTypes, seenTypes);
// infer from return type of the function type
maybeResolveTemplatedType(paramFunctionType.getReturnType(), argFunctionType.getReturnType(), resolvedTypes, seenTypes);
// infer from parameter types of the function type
maybeResolveTemplateTypeFromNodes(paramFunctionType.getParameters(), argFunctionType.getParameters(), resolvedTypes, seenTypes);
}
} else if (paramType.isRecordType() && !paramType.isNominalType()) {
// example: @param {{foo:T}}
if (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)) {
maybeResolveTemplatedType(paramRecordType.getPropertyType(name), argObjectType.getPropertyType(name), resolvedTypes, seenTypes);
}
}
}
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) {
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);
maybeResolveTemplatedType(paramTypeMap.getResolvedTemplateType(key), argTypeMap.getResolvedTemplateType(key), resolvedTypes, seenTypes);
}
}
}
}
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class FunctionTypeBuilder method inferInheritance.
/**
* Infer the role of the function (whether it's a constructor or interface)
* and what it inherits from in JSDocInfo.
*/
FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
if (info != null) {
isConstructor = info.isConstructor();
isInterface = info.isInterface();
isAbstract = info.isAbstract();
makesStructs = info.makesStructs();
makesDicts = info.makesDicts();
if (makesStructs && !(isConstructor || isInterface)) {
reportWarning(CONSTRUCTOR_REQUIRED, "@struct", formatFnName());
} else if (makesDicts && !isConstructor) {
reportWarning(CONSTRUCTOR_REQUIRED, "@dict", formatFnName());
}
// 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();
// 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
// the template values of the constructor/interface
// Class template types, which can be used in the scope of a constructor
// definition.
ImmutableList<String> typeParameters = info.getTemplateTypeNames();
if (!typeParameters.isEmpty() && (isConstructor || isInterface)) {
ImmutableList.Builder<TemplateType> builder = ImmutableList.builder();
for (String typeParameter : typeParameters) {
builder.add(typeRegistry.createTemplateType(typeParameter));
}
classTemplateTypeNames = builder.build();
typeRegistry.setTemplateTypeNames(classTemplateTypeNames);
}
}
// base type
if (info.hasBaseType()) {
if (isConstructor) {
JSType maybeBaseType = info.getBaseType().evaluate(scope, typeRegistry);
if (maybeBaseType != null && maybeBaseType.setValidator(new ExtendedTypeValidator())) {
baseType = (ObjectType) maybeBaseType;
}
} else {
reportWarning(EXTENDS_WITHOUT_TYPEDEF, formatFnName());
}
}
// Implemented interfaces (for constructors only).
if (info.getImplementedInterfaceCount() > 0) {
if (isConstructor) {
implementedInterfaces = new ArrayList<>();
Set<JSType> baseInterfaces = new HashSet<>();
for (JSTypeExpression t : info.getImplementedInterfaces()) {
JSType maybeInterType = t.evaluate(scope, typeRegistry);
if (maybeInterType != null && maybeInterType.setValidator(new ImplementedTypeValidator())) {
// Disallow implementing the same base (not templatized) interface
// type more than once.
JSType baseInterface = maybeInterType;
if (baseInterface.toMaybeTemplatizedType() != null) {
baseInterface = baseInterface.toMaybeTemplatizedType().getReferencedType();
}
if (!baseInterfaces.add(baseInterface)) {
reportWarning(SAME_INTERFACE_MULTIPLE_IMPLEMENTS, baseInterface.toString());
}
implementedInterfaces.add((ObjectType) maybeInterType);
}
}
} else if (isInterface) {
reportWarning(TypeCheck.CONFLICTING_IMPLEMENTED_TYPE, formatFnName());
} else {
reportWarning(CONSTRUCTOR_REQUIRED, "@implements", formatFnName());
}
}
// We've already emitted a warning if this is not an interface.
if (isInterface) {
extendedInterfaces = new ArrayList<>();
for (JSTypeExpression t : info.getExtendedInterfaces()) {
JSType maybeInterfaceType = t.evaluate(scope, typeRegistry);
if (maybeInterfaceType != null && maybeInterfaceType.setValidator(new ExtendedTypeValidator())) {
extendedInterfaces.add((ObjectType) maybeInterfaceType);
}
}
}
}
return this;
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeInference method inferTemplatedTypesForCall.
/**
* For functions that use template types, specialize the function type for
* the call target based on the call-site specific arguments.
* Specifically, this enables inference to set the type of any function
* literal parameters based on these inferred types.
*/
private boolean inferTemplatedTypesForCall(Node n, FunctionType fnType) {
ImmutableList<TemplateType> keys = fnType.getTemplateTypeMap().getTemplateKeys();
if (keys.isEmpty()) {
return false;
}
// Try to infer the template types
Map<TemplateType, JSType> rawInferrence = inferTemplateTypesFromParameters(fnType, n);
Map<TemplateType, JSType> inferred = Maps.newIdentityHashMap();
for (TemplateType key : keys) {
JSType type = rawInferrence.get(key);
if (type == null) {
type = unknownType;
}
inferred.put(key, type);
}
// Try to infer the template types using the type transformations
Map<TemplateType, JSType> typeTransformations = evaluateTypeTransformations(keys, inferred);
if (typeTransformations != null) {
inferred.putAll(typeTransformations);
}
// Replace all template types. If we couldn't find a replacement, we
// replace it with UNKNOWN.
TemplateTypeReplacer replacer = new TemplateTypeReplacer(registry, inferred);
Node callTarget = n.getFirstChild();
FunctionType replacementFnType = fnType.visit(replacer).toMaybeFunctionType();
checkNotNull(replacementFnType);
callTarget.setJSType(replacementFnType);
n.setJSType(replacementFnType.getReturnType());
return replacer.madeChanges;
}
use of com.google.javascript.rhino.jstype.TemplateType in project closure-compiler by google.
the class TypeInference method inferTemplateTypesFromParameters.
private Map<TemplateType, JSType> inferTemplateTypesFromParameters(FunctionType fnType, Node call) {
if (fnType.getTemplateTypeMap().getTemplateKeys().isEmpty()) {
return Collections.emptyMap();
}
Map<TemplateType, JSType> resolvedTypes = Maps.newIdentityHashMap();
Set<JSType> seenTypes = Sets.newIdentityHashSet();
Node callTarget = call.getFirstChild();
if (NodeUtil.isGet(callTarget)) {
Node obj = callTarget.getFirstChild();
maybeResolveTemplatedType(fnType.getTypeOfThis(), getJSType(obj).restrictByNotNullOrUndefined(), resolvedTypes, seenTypes);
}
if (call.hasMoreThanOneChild()) {
maybeResolveTemplateTypeFromNodes(fnType.getParameters(), call.getSecondChild().siblings(), resolvedTypes, seenTypes);
}
return resolvedTypes;
}
Aggregations