public void visit(Tree.CaseTypes that) {
super.visit(that);
//this forces every case to be a subtype of the
//enumerated type, so that we can make use of the
//enumerated type is equivalent to its cases
TypeDeclaration td = (TypeDeclaration) that.getScope();
//TODO: get rid of this awful hack:
List<ProducedType> cases = td.getCaseTypes();
td.setCaseTypes(null);
if (td instanceof TypeParameter) {
for (Tree.StaticType t: that.getTypes()) {
for (Tree.StaticType ot: that.getTypes()) {
if (t==ot) break;
checkCasesDisjoint(t.getTypeModel(), ot.getTypeModel(), ot);
}
}
}
else {
Set<TypeDeclaration> typeSet = new HashSet<TypeDeclaration>();
for (Tree.StaticType st: that.getTypes()) {
ProducedType type = st.getTypeModel();
TypeDeclaration ctd = type.getDeclaration();
if (type!=null && ctd!=null) {
type = type.resolveAliases();
ctd = type.getDeclaration();
if (!typeSet.add(ctd)) {
//this error is not really truly necessary
st.addError("duplicate case type: '" +
ctd.getName(unit) +
"' of '" + td.getName() + "'");
}
if (!(ctd instanceof TypeParameter)) {
//it's not a self type
if (checkDirectSubtype(td, st, type)) {
checkAssignable(type, td.getType(), st,
getCaseTypeExplanation(td, type));
}
//note: this is a better, faster way to call
// validateEnumeratedSupertypeArguments()
// but unfortunately it winds up displaying
// the error on the wrong node, confusing
// the user
/*ProducedType supertype = type.getDeclaration().getType().getSupertype(td);
validateEnumeratedSupertypeArguments(t, type.getDeclaration(), supertype);*/
}
if (ctd instanceof ClassOrInterface && st instanceof Tree.SimpleType) {
Tree.TypeArgumentList tal = ((Tree.SimpleType) st).getTypeArgumentList();
if (tal!=null) {
List<Tree.Type> args = tal.getTypes();
List<TypeParameter> typeParameters = ctd.getTypeParameters();
for (int i=0; i<args.size() && i<typeParameters.size(); i++) {
Tree.Type arg = args.get(i);
TypeParameter typeParameter = ctd.getTypeParameters().get(i);
ProducedType argType = arg.getTypeModel();
if (argType!=null) {
TypeDeclaration argTypeDec = argType.getDeclaration();
if (argTypeDec instanceof TypeParameter) {
if (!((TypeParameter) argTypeDec).getDeclaration().equals(td)) {
arg.addError("type argument is not a type parameter of the enumerated type: '" +
argTypeDec.getName() + "' is not a type parameter of '" + td.getName());
}
}
else if (typeParameter.isCovariant()) {
checkAssignable(typeParameter.getType(), argType, arg,
"type argument not an upper bound of the type parameter");
}
else if (typeParameter.isContravariant()) {
checkAssignable(argType, typeParameter.getType(), arg,
"type argument not a lower bound of the type parameter");
}
else {
arg.addError("type argument is not a type parameter of the enumerated type: '" +
argTypeDec.getName() + "'");
}
}
}
}
}