public boolean isVariableArrity() { int numFormals; if ((numFormals = formalTypes().size()) > 0) { Type last = (Type) formalTypes().get(numFormals - 1); if (last instanceof JL5ArrayType) { JL5ArrayType lastAsArr = (JL5ArrayType) last; if (lastAsArr.isVarargs()) return true; } } return false; }
public boolean callValid(Type thisType, List<Type> argTypes, Context context) { JL5TypeSystem ts = (JL5TypeSystem) typeSystem(); List<Type> l1 = this.formalTypes(); List<Type> l2 = argTypes; if ((l1.size() == 0) && (l2.size() != 0)) return false; Iterator<Type> itCallee = l1.iterator(); Iterator<Type> itCaller = l2.iterator(); // caller can either: // - have one argument less than callee (last argument of // callee is a varargs and caller do not provide a value) // - have same number of args. The last arg being either // - same type as the last arg of callee // - or same type as the last arg of callee which is a varargs array // - or an array of same type as the last arg of callee (which could be a varargs array) // - have more args, then: // - last args of callee must be a varargs array // - all extra args provided by the caller must match // the varargs array type of the callee. while (itCallee.hasNext() && itCaller.hasNext()) { Type t1 = itCallee.next(); Type t2 = itCaller.next(); // Varargs can be used only in the final argument position // When we reach the final argument, we check if it is varargs array. if (!itCallee.hasNext() && t1.isArray() && ((JL5ArrayType) t1).isVarargs()) { JL5ArrayType vartype = (JL5ArrayType) t1; // Every arguments remaining in the second iterator must match the type // of the varargs array if (!itCaller.hasNext()) { // if we also reached the last element of the caller, // check if the type matches or if it is an array return ts.isImplicitCastValid(t2, vartype, context) || ts.isImplicitCastValid(t2, vartype.base(), context); } else { // There are several arguments left, they should all match the callee's varargs array // type. while (itCaller.hasNext()) { // eat up actual args if (!ts.isImplicitCastValid(t2, vartype.base(), context)) { return false; } t2 = itCaller.next(); } } } else { if (!ts.isImplicitCastValid(t2, t1, context)) { return false; } } } // Caller provided less args than the callee has, which is legal // if callee is a variable arity method if (itCallee.hasNext() && isVariableArrity()) { itCallee.next(); } // and we've reached callee's last arg. return !(itCallee.hasNext() || itCaller.hasNext()); }