void addTypeToUnion( ProducedType ct, Map<TypeParameter, ProducedType> substitutions, List<ProducedType> types) { if (ct == null) { types.add(null); } else { addToUnion(types, substitute(ct, substitutions)); } }
/** * Eliminate the given type from the union type. (Performs a set complement operation.) Note that * this operation is not robust and only works if this is a union of the given type with some * other types that don't involve the given type. */ public ProducedType minus(ClassOrInterface ci) { if (getDeclaration().equals(ci)) { return new BottomType(getDeclaration().getUnit()).getType(); } else if (getDeclaration() instanceof UnionType) { List<ProducedType> types = new ArrayList<ProducedType>(); for (ProducedType ct : getCaseTypes()) { if (ct.getSupertype(ci) == null) { addToUnion(types, ct.minus(ci)); } } UnionType ut = new UnionType(getDeclaration().getUnit()); ut.setCaseTypes(types); return ut.getType(); } else { return this; } }
private ProducedType getCommonSupertype( final List<ProducedType> caseTypes, TypeDeclaration dec, final TypeDeclaration selfTypeToIgnore) { // now try to construct a common produced // type that is a common supertype by taking // the type args and unioning them List<ProducedType> args = new ArrayList<ProducedType>(); for (TypeParameter tp : dec.getTypeParameters()) { List<ProducedType> list2 = new ArrayList<ProducedType>(); ProducedType result; if (tp.isContravariant()) { for (ProducedType pt : caseTypes) { ProducedType st = pt.getSupertype(dec, selfTypeToIgnore); if (st == null) { return null; } addToIntersection(list2, st.getTypeArguments().get(tp)); } IntersectionType it = new IntersectionType(getDeclaration().getUnit()); it.setSatisfiedTypes(list2); result = it.canonicalize().getType(); } else { for (ProducedType pt : caseTypes) { ProducedType st = pt.getSupertype(dec, selfTypeToIgnore); if (st == null) { return null; } addToUnion(list2, st.getTypeArguments().get(tp)); } UnionType ut = new UnionType(getDeclaration().getUnit()); ut.setCaseTypes(list2); result = ut.getType(); } args.add(result); } // check that the unioned type args // satisfy the type constraints for (int i = 0; i < args.size(); i++) { TypeParameter tp = dec.getTypeParameters().get(i); for (ProducedType ub : tp.getSatisfiedTypes()) { if (!args.get(i).isSubtypeOf(ub)) { return null; } } } // recurse to the qualifying type ProducedType outerType; if (dec.isMember()) { TypeDeclaration outer = (TypeDeclaration) dec.getContainer(); List<ProducedType> list = new ArrayList<ProducedType>(); for (ProducedType pt : caseTypes) { ProducedType st = pt.getQualifyingType().getSupertype(outer, null); list.add(st); } outerType = getCommonSupertype(list, outer, null); } else { outerType = null; } // make the resulting type ProducedType candidateResult = dec.getProducedType(outerType, args); // check the the resulting type is *really* // a subtype (take variance into account) for (ProducedType pt : caseTypes) { if (!pt.isSubtypeOf(candidateResult)) { return null; } } return candidateResult; }