/** Is this type exactly the same type as the given type? */ public boolean isExactly(ProducedType type) { if (getDeclaration() instanceof BottomType) { return type.getDeclaration() instanceof BottomType; } else if (getDeclaration() instanceof UnionType) { List<ProducedType> cases = getCaseTypes(); if (type.getDeclaration() instanceof UnionType) { List<ProducedType> otherCases = type.getCaseTypes(); if (cases.size() != otherCases.size()) { return false; } else { for (ProducedType c : cases) { boolean found = false; for (ProducedType oc : otherCases) { if (c.isExactly(oc)) { found = true; break; } } if (!found) { return false; } } return true; } } else if (cases.size() == 1) { ProducedType st = cases.get(0); return st.isExactly(type); } else { return false; } } else if (getDeclaration() instanceof IntersectionType) { List<ProducedType> types = getSatisfiedTypes(); if (type.getDeclaration() instanceof IntersectionType) { List<ProducedType> otherTypes = type.getSatisfiedTypes(); if (types.size() != otherTypes.size()) { return false; } else { for (ProducedType c : types) { boolean found = false; for (ProducedType oc : otherTypes) { if (c.isExactly(oc)) { found = true; break; } } if (!found) { return false; } } return true; } } else if (types.size() == 1) { ProducedType st = types.get(0); return st.isExactly(type); } else { return false; } } else if (type.getDeclaration() instanceof UnionType) { List<ProducedType> otherCases = type.getCaseTypes(); if (otherCases.size() == 1) { ProducedType st = otherCases.get(0); return this.isExactly(st); } else { return false; } } else if (type.getDeclaration() instanceof IntersectionType) { List<ProducedType> otherTypes = type.getSatisfiedTypes(); if (otherTypes.size() == 1) { ProducedType st = otherTypes.get(0); return this.isExactly(st); } else { return false; } } else { if (!type.getDeclaration().equals(getDeclaration())) { return false; } else { ProducedType qt = getQualifyingType(); ProducedType tqt = type.getQualifyingType(); if (qt == null) { if (tqt != null) { return false; } } else { if (tqt == null) { return false; } else { TypeDeclaration totd = (TypeDeclaration) type.getDeclaration().getContainer(); ProducedType tqts = tqt.getSupertype(totd); TypeDeclaration otd = (TypeDeclaration) getDeclaration().getContainer(); ProducedType qts = qt.getSupertype(otd); if (!qts.isExactly(tqts)) { return false; } } } for (TypeParameter p : getDeclaration().getTypeParameters()) { ProducedType arg = getTypeArguments().get(p); ProducedType otherArg = type.getTypeArguments().get(p); if (arg == null || otherArg == null) { return false; /*throw new RuntimeException( "Missing type argument for: " + p.getName() + " of " + getDeclaration().getName());*/ } else if (!arg.isExactly(otherArg)) { return false; } } return true; } } }
/** Is this type a subtype of the given type? Ignore a certain self type constraint. */ public boolean isSubtypeOf(ProducedType type, TypeDeclaration selfTypeToIgnore) { if (getDeclaration() instanceof BottomType) { return true; } else if (type.getDeclaration() instanceof BottomType) { return false; } else if (getDeclaration() instanceof UnionType) { for (ProducedType ct : getInternalCaseTypes()) { if (ct == null || !ct.isSubtypeOf(type, selfTypeToIgnore)) { return false; } } return true; } else if (type.getDeclaration() instanceof UnionType) { for (ProducedType ct : type.getInternalCaseTypes()) { if (ct != null && isSubtypeOf(ct, selfTypeToIgnore)) { return true; } } return false; } else if (type.getDeclaration() instanceof IntersectionType) { for (ProducedType ct : type.getInternalSatisfiedTypes()) { if (ct != null && !isSubtypeOf(ct, selfTypeToIgnore)) { return false; } } return true; } else if (getDeclaration() instanceof IntersectionType) { for (ProducedType ct : getInternalSatisfiedTypes()) { if (ct == null || ct.isSubtypeOf(type, selfTypeToIgnore)) { return true; } } return false; } else { ProducedType st = getSupertype(type.getDeclaration(), selfTypeToIgnore); if (st == null) { return false; } else { ProducedType stqt = st.getQualifyingType(); ProducedType tqt = type.getQualifyingType(); if (stqt == null) { if (tqt != null) { // probably extraneous! return false; } } else { if (tqt == null) { // probably extraneous! return false; } else { // note that the qualifying type of the // given type may be an invariant subtype // of the type that declares the member // type, as long as it doesn't refine the // member type TypeDeclaration totd = (TypeDeclaration) type.getDeclaration().getContainer(); ProducedType tqts = tqt.getSupertype(totd); if (!stqt.isSubtypeOf(tqts)) { return false; } } } for (TypeParameter p : type.getDeclaration().getTypeParameters()) { ProducedType arg = st.getTypeArguments().get(p); ProducedType otherArg = type.getTypeArguments().get(p); if (arg == null || otherArg == null) { /*throw new RuntimeException("Missing type argument for type parameter: " + p.getName() + " of " + type.getDeclaration().getName());*/ return false; } else if (p.isCovariant()) { if (!arg.isSubtypeOf(otherArg)) { return false; } } else if (p.isContravariant()) { if (!otherArg.isSubtypeOf(arg)) { return false; } } else { if (!arg.isExactly(otherArg)) { return false; } } } return true; } } }