use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class FunctionTypeBuilder method provideDefaultReturnType.
/**
* Sets the returnType for this function using very basic type inference.
*/
private void provideDefaultReturnType() {
if (contents.getSourceNode() != null && contents.getSourceNode().isAsyncGeneratorFunction()) {
// Set the return type of a generator function to:
// @return {!AsyncGenerator<?>}
ObjectType generatorType = typeRegistry.getNativeObjectType(ASYNC_GENERATOR_TYPE);
returnType = typeRegistry.createTemplatizedType(generatorType, typeRegistry.getNativeType(UNKNOWN_TYPE));
return;
} else if (contents.getSourceNode() != null && contents.getSourceNode().isGeneratorFunction()) {
// Set the return type of a generator function to:
// @return {!Generator<?>}
ObjectType generatorType = typeRegistry.getNativeObjectType(GENERATOR_TYPE);
returnType = typeRegistry.createTemplatizedType(generatorType, typeRegistry.getNativeType(UNKNOWN_TYPE));
return;
}
JSType inferredReturnType = typeRegistry.getNativeType(UNKNOWN_TYPE);
if (!contents.mayHaveNonEmptyReturns() && !contents.mayHaveSingleThrow() && !contents.mayBeFromExterns()) {
// Infer return types for non-generator functions.
// We need to be extremely conservative about this, because of two
// competing needs.
// 1) If we infer the return type of f too widely, then we won't be able
// to assign f to other functions.
// 2) If we infer the return type of f too narrowly, then we won't be
// able to override f in subclasses.
// So we only infer in cases where the user doesn't expect to write
// @return annotations--when it's very obvious that the function returns
// nothing.
inferredReturnType = typeRegistry.getNativeType(VOID_TYPE);
returnTypeInferred = true;
}
if (contents.getSourceNode() != null && contents.getSourceNode().isAsyncFunction()) {
// Set the return type of an async function:
// @return {!Promise<?>} or @return {!Promise<undefined>}
ObjectType promiseType = typeRegistry.getNativeObjectType(PROMISE_TYPE);
returnType = typeRegistry.createTemplatizedType(promiseType, inferredReturnType);
} else {
returnType = inferredReturnType;
}
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class FunctionTypeBuilder method buildTemplateTypesFromJSDocInfo.
private ImmutableList<TemplateType> buildTemplateTypesFromJSDocInfo(JSDocInfo info, boolean allowTypeTransformations) {
ImmutableMap<String, JSTypeExpression> infoTypeKeys = info.getTemplateTypes();
ImmutableMap<String, Node> infoTypeTransformations = info.getTypeTransformations();
if (infoTypeKeys.isEmpty() && infoTypeTransformations.isEmpty()) {
return ImmutableList.of();
}
// Temporarily bootstrap the template environment with unbound (unknown bound) template types
List<TemplateType> unboundedTemplates = new ArrayList<>();
for (String templateKey : infoTypeKeys.keySet()) {
unboundedTemplates.add(typeRegistry.createTemplateType(templateKey));
}
this.templateScope = typeRegistry.createScopeWithTemplates(templateScope, unboundedTemplates);
// Evaluate template type bounds with bootstrapped environment and reroute the bounds to these
ImmutableList.Builder<TemplateType> templates = ImmutableList.builder();
Map<TemplateType, JSType> templatesToBounds = new LinkedHashMap<>();
for (Map.Entry<String, JSTypeExpression> entry : infoTypeKeys.entrySet()) {
JSTypeExpression expr = entry.getValue();
JSType typeBound = typeRegistry.evaluateTypeExpression(entry.getValue(), templateScope);
// treatment in the future, since "unknown" is currently used as a proxy for "implicit".
if (expr.isExplicitUnknownTemplateBound()) {
reportError(TEMPLATE_TYPE_ILLEGAL_BOUND, String.valueOf(typeBound), entry.getKey());
}
TemplateType template = typeRegistry.getType(templateScope, entry.getKey()).toMaybeTemplateType();
if (template != null) {
templatesToBounds.put(template, typeBound);
} else {
templatesToBounds.put(typeRegistry.createTemplateType(entry.getKey(), typeBound), typeBound);
}
}
for (Map.Entry<TemplateType, JSType> entry : templatesToBounds.entrySet()) {
TemplateType template = entry.getKey();
JSType bound = entry.getValue();
template.setBound(bound);
templates.add(template);
}
for (Map.Entry<String, Node> entry : infoTypeTransformations.entrySet()) {
if (allowTypeTransformations) {
templates.add(typeRegistry.createTemplateTypeWithTransformation(entry.getKey(), entry.getValue()));
} else {
reportWarning(TEMPLATE_TRANSFORMATION_ON_CLASS, entry.getKey());
}
}
ImmutableList<TemplateType> builtTemplates = templates.build();
for (TemplateType template : builtTemplates) {
if (template.containsCycle()) {
reportError(RhinoErrorReporter.PARSE_ERROR, "Cycle detected in inheritance chain of type " + template.getReferenceName());
}
}
return builtTemplates;
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class FunctionTypeBuilder method getOrCreateConstructor.
/**
* Returns a constructor function either by returning it from the
* registry if it exists or creating and registering a new type. If
* there is already a type, then warn if the existing type is
* different than the one we are creating, though still return the
* existing function if possible. The primary purpose of this is
* that registering a constructor will fail for all built-in types
* that are initialized in {@link JSTypeRegistry}. We a) want to
* make sure that the type information specified in the externs file
* matches what is in the registry and b) annotate the externs with
* the {@link JSType} from the registry so that there are not two
* separate JSType objects for one type.
*/
private FunctionType getOrCreateConstructor() {
FunctionType fnType = this.createDefaultBuilder().forConstructor().withParameters(parameters).withReturnType(returnType).withConstructorTemplateKeys(constructorTemplateTypeNames).withIsAbstract(isAbstract).build();
if (makesStructs) {
fnType.setStruct();
} else if (makesDicts) {
fnType.setDict();
} else if (makesUnrestricted) {
fnType.setExplicitUnrestricted();
}
// There are two cases where this type already exists in the current scope:
// 1. The type is a built-in that we initalized in JSTypeRegistry and is also defined in
// externs.
// 2. Cases like "class C {} C = class {}"
// See https://github.com/google/closure-compiler/issues/2928 for some related bugs.
JSType existingType = typeRegistry.getType(declarationScope, fnName);
if (existingType != null) {
boolean isInstanceObject = existingType.isInstanceType();
if (isInstanceObject || fnName.equals("Function")) {
FunctionType existingFn = isInstanceObject ? existingType.toObjectType().getConstructor() : typeRegistry.getNativeFunctionType(FUNCTION_FUNCTION_TYPE);
if (existingFn.getSource() == null) {
existingFn.setSource(contents.getSourceNode());
}
if (!existingFn.hasEqualCallType(fnType)) {
reportWarning(TYPE_REDEFINITION, formatFnName(), fnType.toString(), existingFn.toString());
}
// another function (since we don't set its prototype in JSTypeRegistry)
if (existingFn.isNativeObjectType()) {
maybeSetBaseType(existingFn);
}
return existingFn;
} else {
// We fall through and return the created type, even though it will fail
// to register. We have no choice as we have to return a function. We
// issue an error elsewhere though, so the user should fix it.
}
}
maybeSetBaseType(fnType);
//
if (!syntacticFnName.isEmpty() && !syntacticFnName.startsWith("this.")) {
typeRegistry.declareTypeForExactScope(declarationScope, syntacticFnName, fnType.getInstanceType());
}
return fnType;
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class FunctionTypeBuilder method inferParameterTypes.
/**
* Infer the parameter types from the list of parameter names and the JSDoc info.
*/
FunctionTypeBuilder inferParameterTypes(@Nullable Node paramsParent, @Nullable JSDocInfo info) {
if (paramsParent == null) {
if (info == null) {
return this;
} else {
return inferParameterTypes(info);
}
}
// arguments
final Iterator<Parameter> oldParameters;
Parameter oldParameterType = null;
if (parameters != null) {
oldParameters = parameters.iterator();
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
} else {
oldParameters = Collections.emptyIterator();
}
FunctionParamBuilder builder = new FunctionParamBuilder(typeRegistry);
boolean warnedAboutArgList = false;
Set<String> allJsDocParams = (info == null) ? new HashSet<>() : new HashSet<>(info.getParameterNames());
boolean isVarArgs = false;
int paramIndex = 0;
for (Node param = paramsParent.getFirstChild(); param != null; param = param.getNext()) {
boolean isOptionalParam = false;
final Node paramLhs;
if (param.isRest()) {
isVarArgs = true;
paramLhs = param.getOnlyChild();
} else if (param.isDefaultValue()) {
// The first child is the actual positional parameter
paramLhs = checkNotNull(param.getFirstChild(), param);
isOptionalParam = true;
} else {
isVarArgs = isVarArgsParameterByConvention(param);
isOptionalParam = isOptionalParameterByConvention(param);
paramLhs = param;
}
String paramName = null;
if (paramLhs.isName()) {
paramName = paramLhs.getString();
} else {
checkState(paramLhs.isDestructuringPattern());
// third JSDoc parameter.
if (info != null) {
paramName = info.getParameterNameAt(paramIndex);
}
}
allJsDocParams.remove(paramName);
// type from JSDocInfo
JSType parameterType = null;
if (info != null && info.hasParameterType(paramName)) {
JSTypeExpression parameterTypeExpression = info.getParameterType(paramName);
parameterType = parameterTypeExpression.evaluate(templateScope, typeRegistry);
isOptionalParam = isOptionalParam || parameterTypeExpression.isOptionalArg();
isVarArgs = isVarArgs || parameterTypeExpression.isVarArgs();
} else if (paramLhs.getJSDocInfo() != null && paramLhs.getJSDocInfo().hasType()) {
JSTypeExpression parameterTypeExpression = paramLhs.getJSDocInfo().getType();
parameterType = parameterTypeExpression.evaluate(templateScope, typeRegistry);
isOptionalParam = parameterTypeExpression.isOptionalArg();
isVarArgs = parameterTypeExpression.isVarArgs();
} else if (oldParameterType != null && oldParameterType.getJSType() != null) {
parameterType = oldParameterType.getJSType();
isOptionalParam = oldParameterType.isOptional();
isVarArgs = oldParameterType.isVariadic();
} else {
parameterType = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
warnedAboutArgList |= addParameter(builder, parameterType, warnedAboutArgList, isOptionalParam, isVarArgs);
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
paramIndex++;
}
// Copy over any old parameters that aren't in the param list.
if (!isVarArgs) {
while (oldParameterType != null && !isVarArgs) {
builder.newParameterFrom(oldParameterType);
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
}
}
for (String inexistentName : allJsDocParams) {
reportWarning(INEXISTENT_PARAM, inexistentName, formatFnName());
}
parameters = builder.build();
return this;
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class ExpressionDecomposer method rewriteCallExpression.
/**
* Rewrite the call so "this" is preserved.
*
* <pre>a.b(c);</pre>
*
* becomes:
*
* <pre>
* var temp1 = a; var temp0 = temp1.b;
* temp0.call(temp1,c);
* </pre>
*/
private void rewriteCallExpression(Node call, DecompositionState state) {
checkArgument(call.isCall(), call);
Node first = call.getFirstChild();
checkArgument(NodeUtil.isNormalGet(first), first);
// Find the type of (fn expression).call
JSType fnCallType = null;
if (astFactory.isAddingTypes()) {
JSType fnType = first.getJSType();
fnCallType = fnType.isFunctionType() ? fnType.toMaybeFunctionType().getPropertyType("call") : unknownType;
}
// Extracts the expression representing the function to call. For example:
// "a['b'].c" from "a['b'].c()"
Node getVarNode = extractExpression(first, state.extractBeforeStatement);
state.extractBeforeStatement = getVarNode;
// Extracts the object reference to be used as "this". For example:
// "a['b']" from "a['b'].c"
Node getExprNode = getVarNode.getFirstFirstChild();
checkArgument(NodeUtil.isNormalGet(getExprNode), getExprNode);
final Node origThisValue = getExprNode.getFirstChild();
final Node functionNameNode = getVarNode.getFirstChild().cloneNode();
final Node receiverNode;
if (origThisValue.isThis()) {
// No need to create a variable for `this`, just clone it.
receiverNode = origThisValue.cloneNode();
} else if (origThisValue.isSuper()) {
// Original callee was like `super.prop(args)`.
// The correct way to call the value `super.prop` from a temporary variable is
// `tmpVar.call(this, args)`, so just create a `this` here.
receiverNode = astFactory.createThis(type(origThisValue)).srcref(origThisValue);
} else {
final Node thisVarNode = extractExpression(origThisValue, state.extractBeforeStatement);
state.extractBeforeStatement = thisVarNode;
receiverNode = thisVarNode.getFirstChild().cloneNode();
}
// CALL
// GETPROP "call"
// functionName
// thisName
// original-parameter1
// original-parameter2
// ...
// Reuse the existing CALL node instead of creating a new one to avoid breaking InlineFunction's
// bookkeeping. See b/124253050.
call.removeFirstChild();
call.addChildToFront(receiverNode);
call.addChildToFront(astFactory.createGetProp(functionNameNode, "call", type(fnCallType, StandardColors.TOP_OBJECT)).srcrefTreeIfMissing(call));
call.putBooleanProp(Node.FREE_CALL, false);
}
Aggregations