// We never infer properties as optional on loose objects, // and we don't warn about possibly inexistent properties. boolean isLooseSubtypeOf(ObjectType other) { Preconditions.checkState(isLoose || other.isLoose); if (other == TOP_OBJECT) { return true; } if (!isLoose) { if (!objectKind.isSubtypeOf(other.objectKind)) { return false; } for (String pname : other.props.keySet()) { QualifiedName qname = new QualifiedName(pname); if (!mayHaveProp(qname) || !getProp(qname).isSubtypeOf(other.getProp(qname))) { return false; } } } else { // this is loose, other may be loose for (String pname : props.keySet()) { QualifiedName qname = new QualifiedName(pname); if (other.mayHaveProp(qname) && !getProp(qname).isSubtypeOf(other.getProp(qname))) { return false; } } } if (other.fn == null) { return this.fn == null || other.isLoose(); } else if (this.fn == null) { return isLoose; } return fn.isLooseSubtypeOf(other.fn); }
public boolean mayHaveProp(QualifiedName qname) { if (objs == null) { return false; } for (ObjectType o : objs) { if (o.mayHaveProp(qname)) { return true; } } return false; }
public JSType getProp(QualifiedName qname) { if (isBottom() || isUnknown()) { return UNKNOWN; } Preconditions.checkState(objs != null); JSType ptype = BOTTOM; for (ObjectType o : objs) { if (o.mayHaveProp(qname)) { ptype = join(ptype, o.getProp(qname)); } } if (ptype.isBottom()) { return null; } return ptype; }