use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class TypeInference method tightenTypesAfterAssertions.
private FlowScope tightenTypesAfterAssertions(FlowScope scope, Node callNode) {
Node left = callNode.getFirstChild();
Node firstParam = left.getNext();
AssertionFunctionSpec assertionFunctionSpec = assertionFunctionsMap.get(left.getQualifiedName());
if (assertionFunctionSpec == null || firstParam == null) {
return scope;
}
Node assertedNode = assertionFunctionSpec.getAssertedParam(firstParam);
if (assertedNode == null) {
return scope;
}
JSType assertedType = assertionFunctionSpec.getAssertedOldType(callNode, registry);
String assertedNodeName = assertedNode.getQualifiedName();
JSType narrowed;
// Handle assertions that enforce expressions evaluate to true.
if (assertedType == null) {
// Handle arbitrary expressions within the assert.
scope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(assertedNode, scope, true);
// Build the result of the assertExpression
narrowed = getJSType(assertedNode).restrictByNotNullOrUndefined();
} else {
// Handle assertions that enforce expressions are of a certain type.
JSType type = getJSType(assertedNode);
if (assertedType.isUnknownType() || type.isUnknownType()) {
narrowed = assertedType;
} else {
narrowed = type.getGreatestSubtype(assertedType);
}
if (assertedNodeName != null && type.differsFrom(narrowed)) {
scope = narrowScope(scope, assertedNode, narrowed);
}
}
callNode.setJSType(narrowed);
return scope;
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class TypeInference method updateScopeForTypeChange.
/**
* Updates the scope according to the result of a type change, like
* an assignment or a type cast.
*/
private void updateScopeForTypeChange(FlowScope scope, Node left, JSType leftType, JSType resultType) {
checkNotNull(resultType);
Node right = NodeUtil.getRValueOfLValue(left);
if (isPossibleMixinApplication(left, right)) {
addMissingInterfaceProperties(leftType);
}
switch(left.getToken()) {
case NAME:
String varName = left.getString();
TypedVar var = currentScope.getVar(varName);
JSType varType = var == null ? null : var.getType();
boolean isVarDeclaration = left.hasChildren() && varType != null && !var.isTypeInferred() && var.getNameNode() != null;
boolean isTypelessConstDecl = isVarDeclaration && NodeUtil.isConstantDeclaration(compiler.getCodingConvention(), var.getJSDocInfo(), var.getNameNode()) && !(var.getJSDocInfo() != null && var.getJSDocInfo().hasType());
// When looking at VAR initializers for declared VARs, we tend
// to use the declared type over the type it's being
// initialized to in the global scope.
//
// For example,
// /** @param {number} */ var f = goog.abstractMethod;
// it's obvious that the programmer wants you to use
// the declared function signature, not the inferred signature.
//
// Or,
// /** @type {Object.<string>} */ var x = {};
// the one-time anonymous object on the right side
// is as narrow as it can possibly be, but we need to make
// sure we back-infer the <string> element constraint on
// the left hand side, so we use the left hand side.
boolean isVarTypeBetter = isVarDeclaration && // Makes it easier to check for NPEs.
!resultType.isNullType() && !resultType.isVoidType() && // because this type was computed from the RHS
!isTypelessConstDecl;
if (isVarTypeBetter) {
redeclareSimpleVar(scope, left, varType);
} else {
redeclareSimpleVar(scope, left, resultType);
}
left.setJSType(resultType);
if (var != null && var.isTypeInferred()) {
JSType oldType = var.getType();
var.setType(oldType == null ? resultType : oldType.getLeastSupertype(resultType));
} else if (isTypelessConstDecl) {
// /** @const */ var x = y;
// should be redeclared, so that the type of y
// gets propagated to inner scopes.
var.setType(resultType);
}
break;
case GETPROP:
if (left.isQualifiedName()) {
String qualifiedName = left.getQualifiedName();
boolean declaredSlotType = false;
JSType rawObjType = left.getFirstChild().getJSType();
if (rawObjType != null) {
ObjectType objType = ObjectType.cast(rawObjType.restrictByNotNullOrUndefined());
if (objType != null) {
String propName = left.getLastChild().getString();
declaredSlotType = objType.isPropertyTypeDeclared(propName);
}
}
JSType safeLeftType = leftType == null ? unknownType : leftType;
scope.inferQualifiedSlot(left, qualifiedName, safeLeftType, resultType, declaredSlotType);
}
left.setJSType(resultType);
ensurePropertyDefined(left, resultType);
break;
default:
break;
}
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class TypeInference method traverseNew.
private FlowScope traverseNew(Node n, FlowScope scope) {
scope = traverseChildren(n, scope);
Node constructor = n.getFirstChild();
JSType constructorType = constructor.getJSType();
JSType type = null;
if (constructorType != null) {
constructorType = constructorType.restrictByNotNullOrUndefined();
if (constructorType.isUnknownType()) {
type = unknownType;
} else {
FunctionType ct = constructorType.toMaybeFunctionType();
if (ct == null && constructorType instanceof FunctionType) {
// If constructorType is a NoObjectType, then toMaybeFunctionType will
// return null. But NoObjectType implements the FunctionType
// interface, precisely because it can validly construct objects.
ct = (FunctionType) constructorType;
}
if (ct != null && ct.isConstructor()) {
backwardsInferenceFromCallSite(n, ct);
// If necessary, create a TemplatizedType wrapper around the instance
// type, based on the types of the constructor parameters.
ObjectType instanceType = ct.getInstanceType();
Map<TemplateType, JSType> inferredTypes = inferTemplateTypesFromParameters(ct, n);
if (inferredTypes.isEmpty()) {
type = instanceType;
} else {
type = registry.createTemplatizedType(instanceType, inferredTypes);
}
}
}
}
n.setJSType(type);
return scope;
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class TypeInference method traverseSuper.
private void traverseSuper(Node superNode) {
// We only need to handle cases of super() constructor calls for now.
// All super.method() uses are transpiled away before this pass.
JSType jsType = functionScope.getRootNode().getJSType();
FunctionType constructorType = (jsType == null) ? null : jsType.toMaybeFunctionType();
FunctionType superConstructorType = (constructorType == null) ? null : constructorType.getSuperClassConstructor();
if (superConstructorType != null) {
// Treat super() like a function with the same signature as the
// superclass constructor, but don't require 'new' or 'this'.
superNode.setJSType(new FunctionBuilder(registry).copyFromOtherFunction(superConstructorType).setIsConstructor(false).withIsAbstract(//
false).withTypeOfThis(null).build());
} else {
superNode.setJSType(unknownType);
}
}
use of com.google.javascript.rhino.jstype.JSType in project closure-compiler by google.
the class TypeInference method traverseCatch.
/**
* Any value can be thrown, so it's really impossible to determine the type
* of a CATCH param. Treat it as the UNKNOWN type.
*/
private FlowScope traverseCatch(Node catchNode, FlowScope scope) {
Node name = catchNode.getFirstChild();
JSType type;
// If the catch expression name was declared in the catch use that type,
// otherwise use "unknown".
JSDocInfo info = name.getJSDocInfo();
if (info != null && info.hasType()) {
type = info.getType().evaluate(currentScope, registry);
} else {
type = getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
redeclareSimpleVar(scope, name, type);
name.setJSType(type);
return scope;
}
Aggregations