Як прикрити непотрібну перевірку нуля, створену Котліном?


9

Розглянемо наступний мінімальний приклад Котліна:

fun <U> someWrapper(supplier: () -> U): () -> (U) {
    return { supplier() }
}

fun foo(taskExecutor: TaskExecutor): Int {
    val future = CompletableFuture.supplyAsync(someWrapper {
        42
    }, taskExecutor::execute)
    return future.join()
}

@Test
public void shouldFoo() {
    assertThat(foo(), is(42));
}

У мене в Якоко є правила покриття філій, які не відповідають коду, вказаному вище, кажучи, що 1 з 2 гілок не охоплюється в рядку someWrapperвиклику. На жаль, для мене не є можливим виключити всі класи, з яких someWrapperвикликається.

Дивлячись на декомпільований код Java:

public final int foo(TaskExecutor taskExecutor) {
    Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
    if (var10000 != null) {
        Object var2 = var10000;
        var10000 = new Foo$sam$java_util_function_Supplier$0((Function0)var2);
    }

    Supplier var3 = (Supplier)var10000;
    Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
        // $FF: synthetic method
        // $FF: bridge method
        public Object invoke(Object var1) {
        this.invoke((Runnable)var1);
        return Unit.INSTANCE;
        }

        public final void invoke(Runnable p1) {
        ((TaskExecutor)this.receiver).execute(p1);
        }

        public final KDeclarationContainer getOwner() {
        return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
        }

        public final String getName() {
        return "execute";
        }

        public final String getSignature() {
        return "execute(Ljava/lang/Runnable;)V";
        }
    });
    CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor$0(var4)));
    var10000 = future.join();
    Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
    return ((Number)var10000).intValue();
}

Я думаю, проблема полягає в тому, що if (var10000 != null)галузь, яка навіть відмічена IDE, є непотрібною (завжди правдою).

Чи можна якось відрегулювати код таким чином, щоб можна було охопити всі гілки, наприклад. переконуючись, що компілятор не генерує цю зайву нульову перевірку? Я можу змінити код обох foo(..)і до someWrapper(..)тих пір, поки можу поставити прикрашену лямбда.

Я використовую Kotlin 1.3.50 та Jacoco 0.8.4.

EDIT.

Одне очевидне вирішення - це витягнути supplyAsync(someWrapper { ... })до якогось класу утиліти та виключити лише цей клас, тобто:

fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
    return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}

Це було б досить добре для мене, хоча мені все ще цікаво, чому галузь додає Котлін, де немає жодної гілки.


Я отримую Type inference failedпри спробі зробити ваш зразок коду компіляцією. Було б чудово, якби ви могли надати зразок коду, який працює поза коробкою! Наприклад, taskExecutorі controllerє невідомими.
Енселік

@Enselic додав невеликі зміни, щоб видалити відволікаючі помилки. Я не збираюся розширювати його далі до повноцінного коду, оскільки цього має бути достатньо, щоб зрозуміти цю ідею.
BKE

1
Дивлячись на те, як JaCoCo прогресивно пристосовується для підтримки Котліна (див. Github.com/jacoco/jacoco/release та шукає "доданий компілятором Kotlin"), я думаю, що це лише ще одна прогалина, яка рано чи пізно має бути виправлена. Якщо ви відчуваєте серйозність щодо перевищення рівня покриття, пропоную повідомити про проблему.
PiotrK

Відповіді:


1

Якщо значення повернення someWrapperмає бути використане лише як екземпляр Supplier, тоді ви можете видалити непотрібну нульову перевірку, явно використовуючи Supplierяк тип повернення.

fun <U> someWrapper(supplier: () -> U): Supplier<U> {
    return Supplier { supplier() }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.