private void checkVariance( boolean covariant, boolean contravariant, Declaration declaration, List<TypeParameter> errors) { // TODO: fix this to allow reporting multiple errors! if (getDeclaration() instanceof TypeParameter) { TypeParameter tp = (TypeParameter) getDeclaration(); boolean ok = tp.getDeclaration().equals(declaration) || ((covariant || !tp.isCovariant()) && (contravariant || !tp.isContravariant())); if (!ok) { // a covariant type parameter appears in a contravariant location, or // a contravariant type parameter appears in a covariant location. errors.add(tp); } } else if (getDeclaration() instanceof UnionType) { for (ProducedType ct : getCaseTypes()) { ct.checkVariance(covariant, contravariant, declaration, errors); } } else if (getDeclaration() instanceof IntersectionType) { for (ProducedType ct : getSatisfiedTypes()) { ct.checkVariance(covariant, contravariant, declaration, errors); } } else { for (TypeParameter tp : getDeclaration().getTypeParameters()) { ProducedType pt = getTypeArguments().get(tp); if (pt != null) { if (tp.isCovariant()) { pt.checkVariance(covariant, contravariant, declaration, errors); } else if (tp.isContravariant()) { if (covariant | contravariant) { pt.checkVariance(!covariant, !contravariant, declaration, errors); } else { // else if we are in a nonvariant position, it stays nonvariant pt.checkVariance(covariant, contravariant, declaration, errors); } } else { pt.checkVariance(false, false, declaration, errors); } } } } }
/** * Determine if this is a decidable supertype, i.e. if it obeys the restriction that types with * contravariant type parameters may only appear in covariant positions. * * @return a list of type parameters which appear in illegal positions */ public List<TypeDeclaration> checkDecidability() { List<TypeDeclaration> errors = new ArrayList<TypeDeclaration>(); for (TypeParameter tp : getDeclaration().getTypeParameters()) { ProducedType pt = getTypeArguments().get(tp); if (pt != null) { pt.checkDecidability(tp.isCovariant(), tp.isContravariant(), errors); } } return errors; }
private void checkDecidability( boolean covariant, boolean contravariant, List<TypeDeclaration> errors) { if (getDeclaration() instanceof TypeParameter) { // nothing to do } else if (getDeclaration() instanceof UnionType) { for (ProducedType ct : getCaseTypes()) { ct.checkDecidability(covariant, contravariant, errors); } } else if (getDeclaration() instanceof IntersectionType) { for (ProducedType ct : getSatisfiedTypes()) { ct.checkDecidability(covariant, contravariant, errors); } } else { for (TypeParameter tp : getDeclaration().getTypeParameters()) { if (!covariant && tp.isContravariant()) { // a type with contravariant parameters appears at // a contravariant location in satisfies / extends errors.add(getDeclaration()); } ProducedType pt = getTypeArguments().get(tp); if (pt != null) { if (tp.isCovariant()) { pt.checkDecidability(covariant, contravariant, errors); } else if (tp.isContravariant()) { if (covariant | contravariant) { pt.checkDecidability(!covariant, !contravariant, errors); } else { // else if we are in a nonvariant position, it stays nonvariant pt.checkDecidability(covariant, contravariant, errors); } } else { pt.checkDecidability(false, false, errors); } } } } }
/** 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; } } }