boolean (int curParam, int curArg, int notOptional) { boolean skipOptionals = false; int startParam = curParam; if (notOptional > args.length - curArg) return false; if (notOptional == args.length - curArg) skipOptionals = true; while (curArg < args.length) { if (skipOptionals) { while (curParam < paramLength && params[curParam].isOptional()) curParam++; } if (curParam == paramLength) break; if (params[curParam].isOptional()) { if (isAssignableByConversion(params[curParam].getType(), types[curArg], context) && isApplicableInternal(curParam + 1, curArg + 1, notOptional)) { map[curParam] = new ArgInfo<>(args[curArg], types[curArg]); return true; } skipOptionals = true; } else { if (!isAssignableByConversion(params[curParam].getType(), types[curArg], context)) { for (int i = startParam; i < curParam; i++) map[i] = null; return false; } map[curParam] = new ArgInfo<>(args[curArg], types[curArg]); notOptional--; curArg++; curParam++; } } List<Arg> varargs = new ArrayList<>(); for (; curArg < args.length; curArg++) { if (!isAssignableByConversion(vararg, types[curArg], context)) { for (int i = startParam; i < curParam; i++) map[i] = null; return false; } varargs.add(args[curArg]); } map[paramLength] = new ArgInfo<>(varargs, true, new PsiEllipsisType(vararg)); return true; }