/** Set the prototype without doing any sanity checks. */ private boolean setPrototypeNoCheck(ObjectType prototype, Node propertyNode) { ObjectType oldPrototype = prototypeSlot == null ? null : (ObjectType) prototypeSlot.getType(); boolean replacedPrototype = oldPrototype != null; this.prototypeSlot = new Property("prototype", prototype, true, propertyNode == null ? source : propertyNode); prototype.setOwnerFunction(this); if (oldPrototype != null) { // Disassociating the old prototype makes this easier to debug-- // we don't have to worry about two prototypes running around. oldPrototype.setOwnerFunction(null); } if (isConstructor() || isInterface()) { FunctionType superClass = getSuperClassConstructor(); if (superClass != null) { superClass.addSubType(this); } if (isInterface()) { for (ObjectType interfaceType : getExtendedInterfaces()) { if (interfaceType.getConstructor() != null) { interfaceType.getConstructor().addSubType(this); } } } } if (replacedPrototype) { clearCachedValues(); } return true; }
/** * Given a constructor or an interface type, get its superclass constructor or {@code null} if * none exists. */ public FunctionType getSuperClassConstructor() { Preconditions.checkArgument(isConstructor() || isInterface()); ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return null; } return maybeSuperInstanceType.getConstructor(); }
private void addRelatedExtendedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!set.add(instance)) { return; } for (ObjectType interfaceType : constructor.getExtendedInterfaces()) { addRelatedExtendedInterfaces(interfaceType, set); } } }
@Override public boolean isSubtype(JSType that) { if (JSType.isSubtypeHelper(this, that)) { return true; } // Union types if (that.isUnionType()) { // The static {@code JSType.isSubtype} check already decomposed // union types, so we don't need to check those again. return false; } // record types if (that.isRecordType()) { return RecordType.isSubtype(this, that.toMaybeRecordType()); } // Interfaces // Find all the interfaces implemented by this class and compare each one // to the interface instance. ObjectType thatObj = that.toObjectType(); ObjectType thatCtor = thatObj == null ? null : thatObj.getConstructor(); if (thatCtor != null && thatCtor.isInterface()) { Iterable<ObjectType> thisInterfaces = getCtorImplementedInterfaces(); for (ObjectType thisInterface : thisInterfaces) { if (thisInterface.isSubtype(that)) { return true; } } } if (getConstructor() != null && getConstructor().isInterface()) { for (ObjectType thisInterface : getCtorExtendedInterfaces()) { if (thisInterface.isSubtype(that)) { return true; } } } // other prototype based objects if (isUnknownType() || implicitPrototypeChainIsUnknown()) { // If unsure, say 'yes', to avoid spurious warnings. // TODO(user): resolve the prototype chain completely in all cases, // to avoid guessing. return true; } return this.isImplicitPrototype(thatObj); }