`toDataFrame` drops the `?` of a type parameter inside a property type: `List<V?>` becomes `List<Int>`

オープン
#2,133 コメント 1 件 リアクション 2 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@Kanish2002 がすでに取り組んでいます。

2026年10月11日 から。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
67/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
kotlin
領域
backend

調査の方向性

Start with core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/TypeUtils.kt, especially KType.replace, and compare its nullable-type handling with KType.substitute in core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/toSequence.kt. The issue names the affected tests in core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/toDataFrame.kt (CreateDataFrameTests) and suggests adding coverage for top-level nullability and projectUpTo inference. Done when those cases pass and :core:test passes.

索引モデルが issue の本文から書いたものです。

説明

bug

For a generic class with a property of type List<V?>, toDataFrame() on ListBox<Int> gives the column
type List<Int>, although the lists contain null. The expected type is List<Int?>.

class ListBox<V>(val items: List<V?>)

val df = listOf(ListBox<Int>(listOf(1, null))).toDataFrame()

df["items"].type() // kotlin.collections.List<kotlin.Int>, expected kotlin.collections.List<kotlin.Int?>

The same happens with toDataFrame(maxDepth = 10).

Actual output of the tests below:

org.opentest4j.AssertionFailedError: expected:<kotlin.collections.List<kotlin.Int?>> but was:<kotlin.collections.List<kotlin.Int>>

A top-level V? is not affected: for class NullableBox<V>(val value: V?), toDataFrame() gives Int for
NullableBox<Int>(1) and Int? for NullableBox<Int>(null), because the nullability of the column is computed
from its values.

Tests

In core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/toDataFrame.kt (CreateDataFrameTests),
@Ignored until this is fixed:

@Test
fun `nullable type parameter inside a property type keeps its nullability`() {
    class ListBox<V>(val items: List<V?>)

    val df = listOf(ListBox<Int>(listOf(1, null))).toDataFrame()

    // `items` is `List<V?>`, so for `ListBox<Int>` it is `List<Int?>`.
    df["items"].type() shouldBe typeOf<List<Int?>>()
}

@Test
fun `nullable type parameter inside a property type keeps its nullability with maxDepth`() {
    class ListBox<V>(val items: List<V?>)

    val df = listOf(ListBox<Int>(listOf(1, null))).toDataFrame(maxDepth = 10)

    df["items"].type() shouldBe typeOf<List<Int?>>()
}

Cause

internal fun KType.replace(substitution: Map<KTypeParameter, KType?>) in
core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/TypeUtils.kt replaces a type parameter with its
type argument, but does not keep the ? of the use:

is KTypeParameter -> substitution[clazz] ?: this

So V? with V = Int becomes Int, and List<V?> becomes List<Int>. toDataFrame calls it for every
property type (impl/api/toDataFrame.kt, property.returnType.replace(substitution)).

#2128 fixed the same bug for toList/toListOf with a private copy, KType.substitute in
core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/toSequence.kt, which keeps the ?. Now the two
reverse operations disagree on the nullability of a type parameter use.

Suggested fix

Keep the ? in replace:

is KTypeParameter -> substitution[clazz]
    ?.let { if (isMarkedNullable) it.withNullability(true) else it }
    ?: this

Then remove substitute from impl/api/toSequence.kt and call replace there.

With this change, both tests above pass, and all :core:test tests pass (checked with
-Pkotlin.dataframe.debug=true).

Risk

replace is also used by projectUpTo, which takes part in type inference: the common type of values
(TypeUtils.kt, Utils.kt), createTypeUsing, and the element type of iterable properties in toDataFrame.
The result changes only where a type parameter is used with ? — in a property type (List<V?>) or in a
supertype (class MyList<T> : List<T?>). No existing test covers these cases, so the fix should add:

  • the two tests above, without @Ignore;
  • a test that a top-level V? property keeps its current type (Int / Int? by values);
  • a test of type inference for a class with T? in a supertype, which goes through projectUpTo.
主要言語
Kotlin
スター
1.1k
フォーク
87
平均マージ
2日 21時間
マージ済み PR(30日)
40

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Kotlin/dataframe のほかの issue

Kotlin/dataframe の issue をすべて見る

似ている issue

Kotlin の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。