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

Abierto
#2,133 1 comentario 2 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@Kanish2002 ya está trabajando en esto.

Desde el 11/10/2026.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
67/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
kotlin
Área
backend

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.
Lenguaje dominante
Kotlin
Estrellas
1.1k
Forks
87
Merge medio
2 d 21 h
PR fusionados (30 d)
40

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Kotlin/dataframe

Todos los issues de Kotlin/dataframe

Issues similares

Más issues de Kotlin

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.