// e.g. the parameter type may be int and the arg type float
// or the parameter type may be String and the arg type class Foo
// reimplement this using type inter-assignability to do the pruning
Class candidateClass = getCandidateArgClass(candidates, i);
Type candidateType;
if (candidateClass != null) {
candidateType = typeGroup.ensureType(candidateClass);
} else {
candidateType = Type.UNDEFINED;
}
Type argType = arguments.get(i).typeCheck(candidateType);
argumentTypes.add(argType);
if (candidateType == Type.UNDEFINED) {
// we had several constructors to choose from
candidates = pruneCandidates(candidates, i, argType.getTargetClass());
}
}
if (candidates.isEmpty()) {
throw new TypeException("ThrowExpression.typeCheck : invalid constructor for target class " + typeName + getPos());
}
if (candidates.size() > 1) {
throw new TypeException("ThrowExpression.typeCheck : ambiguous constructor signature for target class " + typeName + getPos());
}
constructor = candidates.get(0);
// make sure we know the formal parameter types and have included them in the typegroup
paramTypes = new ArrayList<Type>();
Class<?>[] paramClasses = constructor.getParameterTypes();
for (int i = 0; i < arguments.size() ; i++) {
paramTypes.add(typeGroup.ensureType(paramClasses[i]));
}
// expected type should always be void since throw can only occur as a top level action
// however, we need to be sure that the trigering method throws this exception type or
// else that it is a subtype of runtime exception
if (RuntimeException.class.isAssignableFrom(type.getTargetClass())) {
return type;
} else {
Iterator<Type> iterator = typeGroup.getExceptionTypes().iterator();
while (iterator.hasNext()) {
Type exceptionType = iterator.next();
if (Type.dereference(exceptionType).isAssignableFrom(type)) {
// ok we foudn a suitable declaration for the exception
return type;
}
}