// 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); }