use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder in project closure-compiler by google.
the class GlobalTypeInfoCollector method process.
@Override
public void process(Node externs, Node root) {
checkNotNull(warnings, "Cannot rerun GlobalTypeInfoCollector.process");
checkArgument(externs == null || externs.isRoot());
checkArgument(root.isRoot(), "Root must be ROOT, but is %s", root.getToken());
this.compiler.setMostRecentTypechecker(MostRecentTypechecker.NTI);
NTIScope globalScope = new NTIScope(root, null, ImmutableList.<String>of(), getCommonTypes());
globalScope.addUnknownTypeNames(this.globalTypeInfo.getUnknownTypeNames());
this.globalTypeInfo.setGlobalScope(globalScope);
this.scopes.add(globalScope);
// Processing of a scope is split into many separate phases, and it's not
// straightforward to remember which phase does what.
// (1) Find names of classes, interfaces, typedefs, enums, and namespaces
// defined in the global scope.
CollectNamedTypes rootCnt = new CollectNamedTypes(globalScope);
NodeTraversal.traverseEs6(this.compiler, externs, this.orderedExterns);
rootCnt.collectNamedTypesInExterns();
defineObjectAndFunctionIfMissing();
NodeTraversal.traverseEs6(compiler, root, rootCnt);
// (2) Determine the type represented by each typedef and each enum
globalScope.resolveTypedefs(getTypeParser());
globalScope.resolveEnums(getTypeParser());
// (3) Repeat steps 1-2 for all the other scopes (outer-to-inner)
for (int i = 1; i < this.scopes.size(); i++) {
NTIScope s = this.scopes.get(i);
CollectNamedTypes cnt = new CollectNamedTypes(s);
NodeTraversal.traverseEs6(compiler, s.getBody(), cnt);
s.resolveTypedefs(getTypeParser());
s.resolveEnums(getTypeParser());
if (NewTypeInference.measureMem) {
NewTypeInference.updatePeakMem();
}
}
// (4) The bulk of the global-scope processing happens here:
// - Create scopes for functions
// - Declare properties on types
ProcessScope rootPs = new ProcessScope(globalScope);
if (externs != null) {
NodeTraversal.traverseEs6(compiler, externs, rootPs);
}
NodeTraversal.traverseEs6(compiler, root, rootPs);
// (5) Things that must happen after the traversal of the scope
rootPs.finishProcessingScope();
// (6) Repeat steps 4-5 for all the other scopes (outer-to-inner)
for (int i = 1; i < this.scopes.size(); i++) {
NTIScope s = this.scopes.get(i);
ProcessScope ps = new ProcessScope(s);
NodeTraversal.traverseEs6(compiler, s.getBody(), ps);
ps.finishProcessingScope();
if (NewTypeInference.measureMem) {
NewTypeInference.updatePeakMem();
}
}
// (7) Adjust types of properties based on inheritance information.
// Report errors in the inheritance chain. Do Window last.
Collection<RawNominalType> windows = new ArrayList<>();
for (Map.Entry<Node, RawNominalType> entry : nominaltypesByNode.entrySet()) {
RawNominalType rawType = entry.getValue();
if (this.window != null && rawType.hasAncestorClass(this.window)) {
windows.add(rawType);
continue;
}
checkAndFreezeNominalType(rawType);
}
JSType globalThisType = null;
if (this.window != null) {
// Copy properties from window to Window.prototype, because sometimes
// people pass window around rather than using it directly.
Namespace winNs = globalScope.getNamespace(WINDOW_INSTANCE);
if (winNs != null) {
winNs.copyWindowProperties(getCommonTypes(), this.window);
}
for (RawNominalType rawType : windows) {
checkAndFreezeNominalType(rawType);
}
if (winNs != null) {
((NamespaceLit) winNs).setWindowType(this.window.getAsNominalType());
// Type the global THIS as window
globalThisType = winNs.toJSType();
}
}
if (globalThisType == null) {
// Type the global THIS as a loose object
globalThisType = getCommonTypes().getTopObject().withLoose();
}
getCommonTypes().setGlobalThis(globalThisType);
globalScope.setDeclaredType((new FunctionTypeBuilder(getCommonTypes())).addReceiverType(globalThisType).buildDeclaration());
this.globalTypeInfo.setRawNominalTypes(nominaltypesByNode.values());
nominaltypesByNode = null;
propertyDefs = null;
for (NTIScope s : this.scopes) {
s.freezeScope();
}
this.simpleInference.setScopesAreFrozen();
// Traverse the externs and annotate them with types.
// Only works for the top level, not inside function bodies.
NodeTraversal.traverseEs6(this.compiler, externs, new NodeTraversal.AbstractShallowCallback() {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isQualifiedName()) {
Declaration d = getGlobalScope().getDeclaration(QualifiedName.fromNode(n), false);
JSType type = simpleInferDeclaration(d);
if (type == null) {
type = simpleInferExpr(n, getGlobalScope());
}
// Type-based passes expect the externs to be annotated, so use ? when type is null.
n.setTypeI(type != null ? type : getCommonTypes().UNKNOWN);
}
}
});
Map<Node, String> unknownTypes = getTypeParser().getUnknownTypesMap();
for (Map.Entry<Node, String> unknownTypeEntry : unknownTypes.entrySet()) {
this.warnings.add(JSError.make(unknownTypeEntry.getKey(), UNRECOGNIZED_TYPE_NAME, unknownTypeEntry.getValue()));
}
// package, so we collect its warnings here.
for (JSError warning : getTypeParser().getWarnings()) {
this.warnings.add(warning);
}
this.warnings = null;
this.funNameGen = null;
reorderScopesForNTI();
this.compiler.setExternProperties(ImmutableSet.copyOf(getExternPropertyNames()));
}
use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder in project closure-compiler by google.
the class NewTypeInference method analyzeLooseCallNodeBwd.
private EnvTypePair analyzeLooseCallNodeBwd(Node callNode, TypeEnv outEnv, JSType retType) {
checkArgument(callNode.isCall() || callNode.isNew());
checkNotNull(retType);
Node callee = callNode.getFirstChild();
TypeEnv tmpEnv = outEnv;
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
Node target = callNode.getFirstChild();
for (Node arg = callNode.getLastChild(); arg != target; arg = arg.getPrevious()) {
EnvTypePair pair = analyzeExprBwd(arg, tmpEnv);
JSType argType = pair.type;
tmpEnv = pair.env;
// May wait until FWD to get more precise argument types.
builder.addReqFormalToFront(isImpreciseType(argType) ? BOTTOM : argType);
}
JSType looseRetType = retType.isUnknown() ? BOTTOM : retType;
JSType looseFunctionType = commonTypes.fromFunctionType(builder.addRetType(looseRetType).addLoose().buildFunction());
println("loose function type is ", looseFunctionType);
EnvTypePair calleePair = analyzeExprBwd(callee, tmpEnv, looseFunctionType);
return new EnvTypePair(calleePair.env, retType);
}
use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder in project closure-compiler by google.
the class NewTypeInference method createSummary.
private void createSummary(NTIScope fn) {
Node fnRoot = fn.getRoot();
checkArgument(!fnRoot.isFromExterns());
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
TypeEnv entryEnv = getEntryTypeEnv();
TypeEnv exitEnv = getExitTypeEnv();
DeclaredFunctionType declType = fn.getDeclaredFunctionType();
int reqArity = declType.getRequiredArity();
int optArity = declType.getOptionalArity();
if (declType.isGeneric()) {
builder.addTypeParameters(declType.getTypeParameters());
}
// Every trailing undeclared formal whose inferred type is ?
// or contains undefined can be marked as optional.
List<String> formals = fn.getFormals();
for (int i = reqArity - 1; i >= 0; i--) {
JSType formalType = declType.getFormalType(i);
if (formalType != null) {
break;
}
String formalName = formals.get(i);
formalType = getTypeAfterFwd(formalName, entryEnv, exitEnv);
if (formalType.isUnknown() || UNDEFINED.isSubtypeOf(formalType)) {
reqArity--;
} else {
break;
}
}
// Collect types of formals in the builder
int i = 0;
for (String formalName : formals) {
JSType formalType = declType.getFormalType(i);
if (formalType == null) {
formalType = getTypeAfterFwd(formalName, entryEnv, exitEnv);
}
if (i < reqArity) {
builder.addReqFormal(formalType);
} else if (i < optArity) {
builder.addOptFormal(formalType);
}
i++;
}
if (declType.hasRestFormals()) {
builder.addRestFormals(declType.getFormalType(i));
}
for (String outer : fn.getOuterVars()) {
println("Free var ", outer, " going in summary");
builder.addOuterVarPrecondition(outer, envGetType(entryEnv, outer));
}
builder.addNominalType(declType.getNominalType());
builder.addReceiverType(declType.getReceiverType());
builder.addAbstract(declType.isAbstract());
addRetTypeAndWarn(fn, exitEnv, declType, builder);
JSType summary = commonTypes.fromFunctionType(builder.buildFunction());
println("Function summary for ", fn.getReadableName());
println("\t", summary);
summary = changeTypeIfFunctionNamespace(fn, summary);
summaries.put(fn, summary);
maybeSetTypeI(fnRoot, summary);
Node fnNameNode = NodeUtil.getNameNode(fnRoot);
if (fnNameNode != null) {
maybeSetTypeI(fnNameNode, summary);
}
}
use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder in project closure-compiler by google.
the class NewTypeInference method analyzeFunctionBindFwd.
private EnvTypePair analyzeFunctionBindFwd(Node call, TypeEnv inEnv) {
checkArgument(call.isCall());
Bind bindComponents = this.convention.describeFunctionBind(call, true, false);
Node boundFunNode = bindComponents.target;
EnvTypePair pair = analyzeExprFwd(boundFunNode, inEnv);
TypeEnv env = pair.env;
FunctionType boundFunType = pair.type.getFunTypeIfSingletonObj();
if (!pair.type.isSubtypeOf(commonTypes.topFunction())) {
warnings.add(JSError.make(boundFunNode, GOOG_BIND_EXPECTS_FUNCTION, pair.type.toString()));
}
// For some function types, we don't know enough to handle .bind specially.
if (boundFunType == null || boundFunType.isTopFunction() || boundFunType.isQmarkFunction() || boundFunType.isLoose()) {
return analyzeInvocationArgsFwdWhenError(call, env);
}
if (boundFunType.isSomeConstructorOrInterface()) {
warnings.add(JSError.make(call, CANNOT_BIND_CTOR));
return new EnvTypePair(env, UNKNOWN);
}
// Check if the receiver argument is there
int callChildCount = call.getChildCount();
if ((NodeUtil.isGoogBind(call.getFirstChild()) && callChildCount <= 2) || (!NodeUtil.isGoogPartial(call.getFirstChild()) && callChildCount == 1)) {
warnings.add(JSError.make(call, WRONG_ARGUMENT_COUNT, getReadableCalleeName(call.getFirstChild()), "0", "1", ""));
}
// Check that there are not too many of the other arguments
int maxArity = boundFunType.hasRestFormals() ? Integer.MAX_VALUE : boundFunType.getMaxArity();
int numArgs = bindComponents.getBoundParameterCount();
if (numArgs > maxArity) {
warnings.add(JSError.make(call, WRONG_ARGUMENT_COUNT, getReadableCalleeName(call.getFirstChild()), Integer.toString(numArgs), "0", " and at most " + maxArity));
return analyzeInvocationArgsFwdWhenError(call, inEnv);
}
// If the bound function is polymorphic, we only support the case where we
// can completely calculate the type instantiation at the .bind call site.
// We don't support splitting the instantiation between call sites.
//
Node receiver = bindComponents.thisValue;
if (boundFunType.isGeneric()) {
Map<String, JSType> typeMap = calcTypeInstantiationFwd(call, receiver, bindComponents.parameters, boundFunType, env);
boundFunType = boundFunType.instantiateGenerics(typeMap);
}
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
if (receiver != null) {
// receiver is null for goog.partial
JSType reqThisType = boundFunType.getThisType();
if (reqThisType == null || boundFunType.isSomeConstructorOrInterface()) {
reqThisType = JSType.join(NULL, TOP_OBJECT);
}
pair = analyzeExprFwd(receiver, env, reqThisType);
env = pair.env;
if (!pair.type.isSubtypeOf(reqThisType)) {
warnings.add(JSError.make(call, INVALID_THIS_TYPE_IN_BIND, errorMsgWithTypeDiff(reqThisType, pair.type)));
} else {
instantiateGoogBind(call.getFirstChild(), pair.type);
}
}
Iterable<Node> parametersIterable = bindComponents.parameters == null ? ImmutableList.<Node>of() : bindComponents.parameters.siblings();
// We are passing an arraylist but don't do deferred checks for bind.
env = analyzeInvocationArgumentsFwd(call, parametersIterable, boundFunType, new ArrayList<JSType>(), env);
// For any formal not bound here, add it to the resulting function type.
for (int j = numArgs; j < boundFunType.getMaxArityWithoutRestFormals(); j++) {
JSType formalType = boundFunType.getFormalType(j);
if (boundFunType.isRequiredArg(j)) {
builder.addReqFormal(formalType);
} else {
builder.addOptFormal(formalType);
}
}
if (boundFunType.hasRestFormals()) {
builder.addRestFormals(boundFunType.getRestFormalsType());
}
return new EnvTypePair(env, commonTypes.fromFunctionType(builder.addRetType(boundFunType.getReturnType()).buildFunction()));
}
use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder in project closure-compiler by google.
the class NewTypeInference method analyzeLooseCallNodeFwd.
private EnvTypePair analyzeLooseCallNodeFwd(Node callNode, TypeEnv inEnv, JSType requiredType) {
checkArgument(callNode.isCall() || callNode.isNew());
Node callee = callNode.getFirstChild();
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
TypeEnv tmpEnv = inEnv;
for (Node arg = callee.getNext(); arg != null; arg = arg.getNext()) {
EnvTypePair pair = analyzeExprFwd(arg, tmpEnv);
tmpEnv = pair.env;
builder.addReqFormal(pair.type);
}
JSType looseRetType = requiredType.isUnknown() ? BOTTOM : requiredType;
JSType looseFunctionType = commonTypes.fromFunctionType(builder.addRetType(looseRetType).addLoose().buildFunction());
// Unsound if the arguments and callee have interacting side effects
EnvTypePair calleePair = analyzeExprFwd(callee, tmpEnv, commonTypes.topFunction(), looseFunctionType);
FunctionType calleeType = calleePair.type.getFunType();
JSType result = calleeType.getReturnType();
return new EnvTypePair(calleePair.env, isImpreciseType(result) ? requiredType : result);
}
Aggregations