Boolean castCastToHelper(JSType thisType, JSType thatType) { if (thatType.isUnknownType() || thatType.isAllType() || thatType.isNoObjectType() // TODO(johnlenz): restrict to objects || thatType.isNoType()) { return true; } else if (thisType.isRecordType() || thatType.isRecordType()) { return true; // TODO(johnlenz): are there any misuses we can catch? } else if (isInterface(thisType) || isInterface(thatType)) { return true; // TODO(johnlenz): are there any misuses we can catch? } else if (thatType.isEnumElementType()) { return thisType.visit(this, thatType.toMaybeEnumElementType().getPrimitiveType()); } else if (thatType.isUnionType()) { return canCastToUnion(thisType, thatType.toMaybeUnionType()); } else if (thatType.isFunctionType()) { return canCastToFunction(thisType, thatType.toMaybeFunctionType()); } else if (thatType.isTemplatizedType()) { // TODO(johnlenz): once the templated type work is finished, // restrict the type parameters. return thisType.visit(this, thatType.toMaybeTemplatizedType().getReferencedTypeInternal()); } return thisType.isSubtypeOf(thatType) || thatType.isSubtypeOf(thisType); }
private boolean isAliasedClassOrInterface(TypedVar symbol, JSType type) { // Confusingly typedefs are constructors. However, they cannot be aliased AFAICT. if (type.isNoType()) return false; if (!type.isConstructor() && !type.isInterface()) return false; String symbolName = symbol.getName(); String typeName = type.getDisplayName(); // Turns out that for aliases the symbol and type name differ. return !symbolName.equals(typeName) || KNOWN_CLASS_ALIASES.containsKey(symbolName); }
public final String toNonNullAnnotationString() { return !isUnknownType() && !isTemplateType() && !isRecordType() && isObject() ? "!" + toAnnotationString() : toAnnotationString(); }
@Override public final JSType collapseUnion() { if (referencedType.isUnionType()) { return referencedType.collapseUnion(); } return this; }
private static boolean isObjectLiteralThatCanBeSkipped(JSType t) { t = t.restrictByNotNullOrUndefined(); return t.isRecordType() || t.isLiteralObject(); }
private String getName(JSType type) { if (type.isInstanceType()) { return ((ObjectType) type).getReferenceName(); } else if (type.isNullType() || type.isBooleanValueType() || type.isNumberValueType() || type.isStringValueType() || type.isVoidType()) { return type.toString(); } else { // Type unchecked at runtime, so we don't care about the sorting order. return ""; } } };
final StringBuilder appendAsNonNull(StringBuilder sb, boolean forAnnotations) { if (forAnnotations && isObject() && !isUnknownType() && !isTemplateType() && !isRecordType() && !isFunctionType() && !isUnionType() && !isLiteralObject()) { sb.append("!"); } return appendTo(sb, forAnnotations); }
/** * Returns the type that best represents the instance type for {@code type}. * * <ul> * <li>Prototype type => The instance type having that prototype * <li>Instance type => The type * <li>Constructor type => The type that constructor instantiates * <li>Object-literal type => The type * </ul> */ @Nullable private static ObjectType instanceTypeFor(JSType type) { if (type == null) { return null; } else if (type.isUnionType()) { return null; // A union has no meaningful instance type. } else if (type.isInstanceType() || type.isUnknownType()) { return type.toMaybeObjectType(); } else if (type.isConstructor() || type.isInterface()) { return type.toMaybeFunctionType().getInstanceType(); } else if (type.isFunctionPrototypeType()) { return instanceTypeFor(type.toMaybeObjectType().getOwnerFunction()); } return type.toMaybeObjectType(); }
private boolean evalTypePredicate(Node ttlAst, NameResolver nameResolver) { JSType[] params = evalTypeParams(ttlAst, nameResolver); String name = getCallName(ttlAst); Keywords keyword = nameToKeyword(name); switch (keyword) { case EQ: return params[0].isEquivalentTo(params[1]); case SUB: return params[0].isSubtype(params[1]); case ISCTOR: return params[0].isConstructor(); case ISTEMPLATIZED: return params[0].isTemplatizedType(); case ISRECORD: return params[0].isRecordType(); case ISUNKNOWN: return params[0].isUnknownType() || params[0].isCheckedUnknownType(); default: throw new IllegalStateException( "Invalid type predicate in the type transformation"); } }
private boolean isDefaultExport(TypedVar symbol) { if (symbol.getType() == null) return true; ObjectType otype = symbol.getType().toMaybeObjectType(); if (otype != null && otype.getOwnPropertyNames().size() == 0) return true; return !symbol.getType().isObject() || symbol.getType().isInterface() || symbol.getType().isInstanceType() || symbol.getType().isEnumType() || symbol.getType().isFunctionType() || isTypedef(symbol.getType()); }
@Test public void test_types() throws IOException { compile("types_param.js"); ClassReference reference = model.getClassReference("Foo"); JSType jsType1 = getJSType("test1", true, "arg1"); JSType jsType2 = getJSType("test2", true, "arg1"); JSType jsType3 = getJSType("test3", true, "arg1"); JSType jsType4 = getJSType("test4", true, "arg1"); JSType jsType5 = getJSType("test5", true, "arg1"); JSType jsType6 = getJSType("test6", true, "arg1"); assertTrue(jsType1.isString()); assertTrue(jsType2.isUnionType()); assertTrue(jsType3.isRecordType()); assertTrue(jsType4.isUnionType()); assertTrue(jsType5.isInstanceType()); assertTrue(jsType6.isFunctionType()); assertEquals("String", JSTypeUtils.toParamTypeString(reference.getStaticMethod("test1"), "arg1")); assertEquals("foo.bar.Baz", JSTypeUtils.toParamTypeString(reference.getStaticMethod("test2"), "arg1")); assertEquals("Object /* {myNum: number, myObject: ?} */", JSTypeUtils.toParamTypeString(reference.getStaticMethod("test3"), "arg1")); assertEquals("Number", JSTypeUtils.toParamTypeString(reference.getStaticMethod("test4"), "arg1")); assertEquals("Object", JSTypeUtils.toParamTypeString(reference.getStaticMethod("test5"), "arg1")); assertEquals("Function /* function(string, boolean): ? */", JSTypeUtils.toParamTypeString(reference.getStaticMethod("test6"), "arg1")); }
@Override public void matchConstraint(JSType constraint) { // We only want to match constraints on anonymous types. if (hasReferenceName()) { return; } // Handle the case where the constraint object is a record type. // // param constraint {{prop: (number|undefined)}} // function f(constraint) {} // f({}); // // We want to modify the object literal to match the constraint, by // taking any each property on the record and trying to match // properties on this object. if (constraint.isRecordType()) { matchRecordTypeConstraint(constraint.toObjectType()); } else if (constraint.isUnionType()) { for (JSType alt : constraint.toMaybeUnionType().getAlternates()) { if (alt.isRecordType()) { matchRecordTypeConstraint(alt.toObjectType()); } } } }
/** * Whether the typedef should be emitted by name or by the type it is defining. * * <p>Because, we do not access the original type signature, the replacement is done for all * references of the type (through the typedef or direct). Thus it is undesirable to always emit * by name. For example: * * <pre> * \@constructor A; * \@typedef {A} B; * \@const {A} var a; * </pre> * * If we emit the name, we would emit `var a: B;`, which is undesirable (consider A being string). * * <p>For now, only emit by name typedefs that are unlikely to have more than one name referring * to them - record types, templatized types and function types. */ private boolean shouldEmitTypedefByName(JSType realType) { return realType.isRecordType() || realType.isTemplatizedType() || realType.isFunctionType(); }
private ObjectType getThisTypeForCollectingProperties() { Node rootNode = scope.getRootNode(); if (rootNode.isFromExterns()) return null; JSType type = rootNode.getJSType(); if (type == null || !type.isFunctionType()) return null; FunctionType fnType = type.toMaybeFunctionType(); JSType fnThisType = fnType.getTypeOfThis(); return fnThisType.isUnknownType() ? null : fnThisType.toObjectType(); }
/** * @return true if n MUST be a prototype name reference. */ private boolean isPrototypeNameReference(Node n) { if (!n.isGetProp()) { return false; } JSType type = getType(n.getFirstChild()); if (type.isUnknownType() || type.isUnionType()) { return false; } return (type.isInstanceType() || type.autoboxesTo() != null); }
private static boolean containsForwardDeclaredUnresolvedName(JSType type) { if (type.isUnionType()) { for (JSType alt : type.toMaybeUnionType().getAlternates()) { if (containsForwardDeclaredUnresolvedName(alt)) { return true; } } } return type.isNoResolvedType(); }
private JSType evalInstanceOf(Node ttlAst, NameResolver nameResolver) { JSType type = evalInternal(getCallArgument(ttlAst, 0), nameResolver); if (type.isUnknownType() || !type.isConstructor()) { reportWarning(ttlAst, INVALID_CTOR, type.getDisplayName()); return getUnknownType(); } return type.toMaybeFunctionType().getInstanceType(); }
@Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType() && !that.isUnionType()) { for (int i = 0; i < alternatesRetainingStructuralSubtypes.size(); i++) { JSType alternate = alternatesRetainingStructuralSubtypes.get(i); if (!alternate.isUnknownType() && that.isSubtypeOf(alternate)) { return this; } } } return JSType.getLeastSupertype(this, that); }
@Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType() && !that.isUnionType()) { for (JSType alternate : alternatesWithoutStucturalTyping) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } } } return getLeastSupertype(this, that); }
private boolean isEs6ClassConstructor(JSType type) { return type.isFunctionType() && type.toMaybeFunctionType().getSource() != null && type.toMaybeFunctionType().getSource().isClass(); }