private static CompletableFuture<Void> findAnyBaseType(@Nullable Type type,
                                                         Function<? super Type, ? extends CompletableFuture<Boolean>> checker,
                                                         CompletableFuture<Type> res) {
    if (type == null || res.isDone()) {
      return completedFuture(null);
    }

    // check self
    CompletableFuture<Void> self = checker.apply(type).thenAccept(r -> {
      if (r) {
        res.complete(type);
      }
    });

    // check base types
    if (type instanceof ClassType) {
      return allOf(
        self,
        superclass((ClassType)type).thenCompose(s -> findAnyBaseType(s, checker, res)),
        interfaces((ClassType)type).thenCompose(
          interfaces -> allOf(interfaces.stream().map(i -> findAnyBaseType(i, checker, res)).toArray(CompletableFuture[]::new))));
    }

    if (type instanceof InterfaceType) {
      return allOf(
        self,
        superinterfaces((InterfaceType)type).thenCompose(
          interfaces -> allOf(interfaces.stream().map(i -> findAnyBaseType(i, checker, res)).toArray(CompletableFuture[]::new))));
    }

    return self;
  }
private static CompletableFuture<Void> findAnyBaseType(@Nullable Type type,
                                                         Function<? super Type, ? extends CompletableFuture<Boolean>> checker,
                                                         CompletableFuture<Type> res)