public final ImmutableSet<JSType> getTypeParameters() { ImmutableSet.Builder<JSType> params = ImmutableSet.builder(); for (TemplateType type : getTemplateTypeMap().getTemplateKeys()) { params.add(type); } return params.build(); }
private List<String> getTemplateTypeNames(ObjectType objType) { if (objType.getTemplateTypeMap() == null) { return Collections.emptyList(); } return objType .getTemplateTypeMap() .getTemplateKeys() .stream() .map(jsType -> jsType != null ? jsType.getDisplayName() : "") .collect(toCollection(ArrayList::new)); }
/** * Returns the template type argument in this type's map corresponding to the supertype's template * parameter, or the UNKNOWN_TYPE if the supertype template key is not present. * * <p>Note: this only supports arguments that have a singleton list of template keys, and will * throw an exception for arguments with zero or multiple or template keys. */ public JSType getInstantiatedTypeArgument(JSType supertype) { TemplateType templateType = Iterables.getOnlyElement(supertype.getTemplateTypeMap().getTemplateKeys()); return getTemplateTypeMap().getResolvedTemplateType(templateType); } }
private static boolean checkEquivalenceHelper(EquivalenceMethod eqMethod, TemplateTypeMap thisMap, TemplateTypeMap thatMap, EqCache eqCache) { ImmutableList<TemplateType> thisKeys = thisMap.getTemplateKeys(); ImmutableList<TemplateType> thatKeys = thatMap.getTemplateKeys(); for (int i = 0; i < thisKeys.size(); i++) { TemplateType thisKey = thisKeys.get(i); JSType thisType = thisMap.getResolvedTemplateType(thisKey); EquivalenceMatch thisMatch = EquivalenceMatch.NO_KEY_MATCH; for (int j = 0; j < thatKeys.size(); j++) { TemplateType thatKey = thatKeys.get(j); JSType thatType = thatMap.getResolvedTemplateType(thatKey); // Cross-compare every key-value pair in this TemplateTypeMap with // those in that TemplateTypeMap. Update the Equivalence match for both // key-value pairs involved. if (thisKey == thatKey) { EquivalenceMatch newMatchType = EquivalenceMatch.VALUE_MISMATCH; if (thisType.checkEquivalenceHelper(thatType, eqMethod, eqCache)) { newMatchType = EquivalenceMatch.VALUE_MATCH; } if (thisMatch != EquivalenceMatch.VALUE_MATCH) { thisMatch = newMatchType; } } } if (failedEquivalenceCheck(thisMatch, eqMethod)) { return false; } } return true; }
/** Infer the template type from the doc info. */ FunctionTypeBuilder inferTemplateTypeName(@Nullable JSDocInfo info, @Nullable JSType ownerType) { // NOTE: these template type names may override a list // of inherited ones from an overridden function. if (info != null && !maybeUseNativeClassTemplateNames(info)) { ImmutableList<TemplateType> templates = buildTemplateTypesFromJSDocInfo(info, !(isConstructor || isInterface)); if (!templates.isEmpty()) { this.templateTypeNames = templates; } } ImmutableList<TemplateType> ownerTypeKeys = ownerType != null ? ownerType.getTemplateTypeMap().getTemplateKeys() : ImmutableList.of(); if (!templateTypeNames.isEmpty() || !ownerTypeKeys.isEmpty()) { // TODO(sdh): The order of these should be switched to avoid class templates shadowing // method templates, but this currently loosens type checking of arrays more than we'd like. // See http://github.com/google/closure-compiler/issues/2973 registerTemplates( Iterables.concat(templateTypeNames, ownerTypeKeys), contents.getSourceNode()); } return this; }
public ObjectType instantiateGenericsWithUnknown(ObjectType obj) { if (obj.isTemplatizedType()) { ImmutableList.Builder<JSType> unknowns = ImmutableList.builder(); for (TemplateType unused : obj.getTemplateTypeMap().getTemplateKeys()) { unknowns.add(getNativeType(UNKNOWN_TYPE)); } return createTemplatizedType(obj.toMaybeTemplatizedType().getRawType(), unknowns.build()); } return obj; }
if (ownerType != null) { ImmutableList<TemplateType> ownerTypeKeys = ownerType.getTemplateTypeMap().getTemplateKeys(); if (!ownerTypeKeys.isEmpty()) { ImmutableList.Builder<TemplateType> builder = ImmutableList.builder();
private static boolean checkEquivalenceHelper(EquivalenceMethod eqMethod, TemplateTypeMap thisMap, TemplateTypeMap thatMap, EqCache eqCache, SubtypingMode subtypingMode) { ImmutableList<TemplateType> thisKeys = thisMap.getTemplateKeys(); ImmutableList<TemplateType> thatKeys = thatMap.getTemplateKeys();
ImmutableList<TemplateType> keys = fnType.getTemplateTypeMap().getTemplateKeys(); if (keys.isEmpty()) { return false;
/** * Special handling for simple typing returning polymorphic this type in TypeScript. Prefer * `func(): this` instead of `func<T>(this: T): T` when any params are not templatized. */ private boolean shouldSkipEmittingThisTemplateAndParam(FunctionType ftype) { final JSType typeOfThis = ftype.getTypeOfThis(); if (typeOfThis == null || !typeOfThis.isTemplateType() || !typeOfThis.equals(ftype.getReturnType())) { return false; } Iterator<Node> parameters = ftype.getParameters().iterator(); while (parameters.hasNext()) { final JSType paramType = parameters.next().getJSType(); if (!paramType.isTemplatizedType()) { continue; } final TemplateTypeMap templateTypeMap = paramType.getTemplateTypeMap(); for (TemplateType key : templateTypeMap.getTemplateKeys()) { if (templateTypeMap.getResolvedTemplateType(key).equals(typeOfThis)) { return false; } } } return true; }
/** * Returns the type specified in a JSDoc annotation near a GETPROP, NAME, member function, or * object literal key. * * <p>Extracts type information from the {@code @type} tag. */ private JSType getDeclaredTypeInAnnotation(Node node, JSDocInfo info) { checkArgument(info.hasType()); ImmutableList<TemplateType> ownerTypeKeys = ImmutableList.of(); Node ownerNode = NodeUtil.getBestLValueOwner(node); String ownerName = NodeUtil.getBestLValueName(ownerNode); ObjectType ownerType = null; if (ownerName != null) { TypedVar ownerVar = currentScope.getVar(ownerName); if (ownerVar != null) { ownerType = getPrototypeOwnerType(ObjectType.cast(ownerVar.getType())); if (ownerType != null) { ownerTypeKeys = ownerType.getTemplateTypeMap().getTemplateKeys(); } } } StaticTypedScope templateScope = !ownerTypeKeys.isEmpty() ? typeRegistry.createScopeWithTemplates(currentScope, ownerTypeKeys) : currentScope; return info.getType().evaluate(templateScope, typeRegistry); }
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), resolvedTypes, seenTypes); } if (call.hasMoreThanOneChild()) { maybeResolveTemplateTypeFromNodes( fnType.getParameters(), call.getSecondChild().siblings(), resolvedTypes, seenTypes); } return resolvedTypes; }
@Override public final JSType getPropertyType(String name) { if (!hasOwnProperty(name)) { // Define the "call", "apply", and "bind" functions lazily. boolean isCall = "call".equals(name); boolean isBind = "bind".equals(name); if (isCall || isBind) { defineDeclaredProperty(name, getCallOrBindSignature(isCall), source); } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // ECMA-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType(registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty( name, new FunctionBuilder(registry) .withParamsNode(builder.build()) .withReturnType(getReturnType()) .withTemplateKeys(getTemplateTypeMap().getTemplateKeys()) .build(), source); } } return super.getPropertyType(name); }
@Override public JSType getPropertyType(String name) { if (!hasOwnProperty(name)) { // Define the "call", "apply", and "bind" functions lazily. boolean isCall = "call".equals(name); boolean isBind = "bind".equals(name); if (isCall || isBind) { defineDeclaredProperty(name, getCallOrBindSignature(isCall), source); } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // ECMA-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionBuilder(registry) .withParamsNode(builder.build()) .withReturnType(getReturnType()) .withTemplateKeys(getTemplateTypeMap().getTemplateKeys()) .build(), source); } } return super.getPropertyType(name); }
Node createJSCompMakeIteratorCall(Node iterable, Scope scope) { String function = "makeIterator"; Node makeIteratorName = createQName(scope, "$jscomp." + function); // Since createCall (currently) doesn't handle templated functions, fill in the template types // of makeIteratorName manually. if (isAddingTypes() && !makeIteratorName.getJSType().isUnknownType()) { // if makeIteratorName has the unknown type, we must have not injected the required runtime // libraries - hopefully because this is in a test using NonInjectingCompiler. // e.g get `number` from `Iterable<number>` JSType iterableType = iterable .getJSType() .getInstantiatedTypeArgument(getNativeType(JSTypeNative.ITERABLE_TYPE)); JSType makeIteratorType = makeIteratorName.getJSType(); // e.g. replace // function(Iterable<T>): Iterator<T> // with // function(Iterable<number>): Iterator<number> TemplateTypeMap typeMap = registry.createTemplateTypeMap( makeIteratorType.getTemplateTypeMap().getTemplateKeys(), ImmutableList.of(iterableType)); TemplateTypeMapReplacer replacer = new TemplateTypeMapReplacer(registry, typeMap); makeIteratorName.setJSType(makeIteratorType.visit(replacer)); } return createCall(makeIteratorName, iterable); }
Node createJscompArrayFromIteratorCall(Node iterator, Scope scope) { String function = "arrayFromIterator"; Node makeIteratorName = createQName(scope, "$jscomp." + function); // Since createCall (currently) doesn't handle templated functions, fill in the template types // of makeIteratorName manually. if (isAddingTypes() && !makeIteratorName.getJSType().isUnknownType()) { // if makeIteratorName has the unknown type, we must have not injected the required runtime // libraries - hopefully because this is in a test using NonInjectingCompiler. // e.g get `number` from `Iterator<number>` JSType iterableType = iterator .getJSType() .getInstantiatedTypeArgument(getNativeType(JSTypeNative.ITERATOR_TYPE)); JSType makeIteratorType = makeIteratorName.getJSType(); // e.g. replace // function(Iterator<T>): Array<T> // with // function(Iterator<number>): Array<number> TemplateTypeMap typeMap = registry.createTemplateTypeMap( makeIteratorType.getTemplateTypeMap().getTemplateKeys(), ImmutableList.of(iterableType)); TemplateTypeMapReplacer replacer = new TemplateTypeMapReplacer(registry, typeMap); makeIteratorName.setJSType(makeIteratorType.visit(replacer)); } return createCall(makeIteratorName, iterator); }
/** * Get the return value of calling "bind" on this function with the specified number of arguments. * * <p>If -1 is passed, then we will return a result that accepts any parameters. */ public final FunctionType getBindReturnType(int argsToBind) { FunctionBuilder builder = new FunctionBuilder(registry) .withReturnType(getReturnType()) .withTemplateKeys(getTemplateTypeMap().getTemplateKeys()); if (argsToBind >= 0) { Node origParams = getParametersNode(); if (origParams != null) { Node params = origParams.cloneTree(); for (int i = 1; i < argsToBind && params.getFirstChild() != null; i++) { if (params.getFirstChild().isVarArgs()) { break; } params.removeFirstChild(); } builder.withParamsNode(params); } } return builder.build(); }
/** * Get the return value of calling "bind" on this function * with the specified number of arguments. * * If -1 is passed, then we will return a result that accepts * any parameters. */ public FunctionType getBindReturnType(int argsToBind) { FunctionBuilder builder = new FunctionBuilder(registry) .withReturnType(getReturnType()) .withTemplateKeys(getTemplateTypeMap().getTemplateKeys()); if (argsToBind >= 0) { Node origParams = getParametersNode(); if (origParams != null) { Node params = origParams.cloneTree(); for (int i = 1; i < argsToBind && params.getFirstChild() != null; i++) { if (params.getFirstChild().isVarArgs()) { break; } params.removeFirstChild(); } builder.withParamsNode(params); } } return builder.build(); }
new FunctionBuilder(registry) .withReturnType(isCall ? getReturnType() : getBindReturnType(-1)) .withTemplateKeys(getTemplateTypeMap().getTemplateKeys());
FunctionBuilder builder = new FunctionBuilder(registry) .withReturnType(isCall ? getReturnType() : getBindReturnType(-1)) .withTemplateKeys(getTemplateTypeMap().getTemplateKeys());