P6capture.Instance nativeCapture = (P6capture.Instance)capture;
// First, try the dispatch cache.
if (dispatchRoutine.MultiDispatchCache != null && nativeCapture.Nameds == null)
{
RakudoObject cacheResult = dispatchRoutine.MultiDispatchCache.Lookup(nativeCapture.Positionals);
if (cacheResult != null)
return cacheResult;
}
// Sort the candidates.
// XXX Cache this in the future.
ArrayList<RakudoObject> sortedCandidates = candidateSort(dispatchRoutine.Dispatchees);
// Now go through the sorted candidates and find the first one that
// matches.
ArrayList<RakudoCodeRef.Instance> possiblesList = new ArrayList<RakudoCodeRef.Instance>();
for (RakudoObject candidateObject : sortedCandidates)
{
// TODO: remove yukky type cast
RakudoCodeRef.Instance candidate = (RakudoCodeRef.Instance)candidateObject;
// If we hit a null, we're at the end of a group.
if (candidate == null)
{
if (possiblesList.size() == 1)
{
// We have an unambiguous first candidate. Cache if possible and
// return it.
if (nativeCapture.Nameds == null)
{
if (dispatchRoutine.MultiDispatchCache == null)
dispatchRoutine.MultiDispatchCache = new DispatchCache();
dispatchRoutine.MultiDispatchCache.Add(nativeCapture.Positionals, possiblesList.get(0));
}
return possiblesList.get(0);
}
else if (possiblesList.size() > 1)
{
// Here is where you'd handle constraints.
throw new UnsupportedOperationException("Ambiguous dispatch: more than one candidate matches");
}
else
{
continue;
}
}
/* Check if it's admissible by arity. */
int numArgs = nativeCapture.Positionals.length;
if (numArgs < candidate.Sig.NumRequiredPositionals ||
numArgs > candidate.Sig.NumPositionals)
continue;
/* Check if it's admissible by type. */
int typeCheckCount = Math.min(numArgs, candidate.Sig.NumPositionals);
boolean typeMismatch = false;
for (int i = 0; i < typeCheckCount; i++) {
RakudoObject arg = nativeCapture.Positionals[i];
RakudoObject type = candidate.Sig.Parameters[i].Type;
if (arg.getSTable().WHAT != type && type != null)
{
typeMismatch = true;
break;
}