private static boolean match(@NotNull PyVariadicType expected, @Nullable PyType actual, @NotNull MatchContext context) {
    if (actual == null) {
      return true;
    }
    if (!(actual instanceof PyVariadicType actualVariadic)) {
      return false;
    }
    if (expected instanceof PyUnpackedTupleType expectedUnpackedTupleType) {
      // The actual type is just a TypeVarTuple
      if (!(actualVariadic instanceof PyUnpackedTupleType actualUnpackedTupleType)) {
        return false;
      }
      if (expectedUnpackedTupleType.isUnbound()) {
        PyType repeatedExpectedType = expectedUnpackedTupleType.getElementTypes().get(0);
        if (actualUnpackedTupleType.isUnbound()) {
          return match(repeatedExpectedType, actualUnpackedTupleType.getElementTypes().get(0), context).orElse(false);
        }
        else {
          return ContainerUtil.all(actualUnpackedTupleType.getElementTypes(),
                                   singleActualType -> match(repeatedExpectedType, singleActualType, context).orElse(false));
        }
      }
      else {
        if (actualUnpackedTupleType.isUnbound()) {
          PyType repeatedActualType = actualUnpackedTupleType.getElementTypes().get(0);
          return ContainerUtil.all(expectedUnpackedTupleType.getElementTypes(),
                                   singleExpectedType -> match(singleExpectedType, repeatedActualType, context).orElse(false));
        }
        else {
          return matchTypeParameters(expectedUnpackedTupleType.getElementTypes(), actualUnpackedTupleType.getElementTypes(), context);
        }
      }
    }
    // The expected type is just a TypeVarTuple
    else {
      PyVariadicType substitution = context.mySubstitutions.typeVarTuples.get(expected);
      if (substitution != null && !substitution.equals(PyUnpackedTupleTypeImpl.UNSPECIFIED)) {
        if (expected.equals(actual) || substitution.equals(expected)) {
          return true;
        }
        return context.reversedSubstitutions ? match(actualVariadic, substitution, context) : match(substitution, actualVariadic, context);
      }
      context.mySubstitutions.typeVarTuples.put((PyTypeVarTupleType)expected, actualVariadic);
    }
    return true;
  }
private static boolean match(@NotNull PyVariadicType expected, @Nullable PyType actual, @NotNull MatchContext context)