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); } } } } }
/** * Check that this type can appear at a position, given the variance of the position (covariant, * contravariant, or invariant.) * * @param covariant true for a covariant position * @param contravariant true for a contravariant position * @param declaration TODO! * @return a list of type parameters which appear in illegal positions */ public List<TypeParameter> checkVariance( boolean covariant, boolean contravariant, Declaration declaration) { List<TypeParameter> errors = new ArrayList<TypeParameter>(); checkVariance(covariant, contravariant, declaration, errors); return errors; }