`Infer.Type` KDoc calls the given type an "upper bound", which it is not
@Jolanrensen is already working on this.
Since Sep 17, 2026.
- Dominant language
- Kotlin
- Stars
- 1.1k
- Forks
- 83
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 30
Description
Infer.Type KDoc calls the given type an "upper bound", which it is not
core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/typeConversions.kt:259
Infer
[DataColumn.type]and[DataColumn.hasNulls]from actual[DataColumn.values]
using an optionally provided base type as an upper bound.
The base type is not a bound. Whenever the column has values, the inferred type comes from
them alone and the given type leaves no trace — not even as a bound the result must satisfy.
It survives only for an empty column.
Reproducing test
Passes on master today; every line below contradicts the wording above.
@Test
fun `Infer Type does not treat the given type as an upper bound`() {
val age = columnOf(15, 45, 20)
// `String` is not a supertype of `Int`, yet the call succeeds and the bound leaves no trace
age.map(typeOf<String>(), Infer.Type) { it }.type() shouldBe typeOf<Int>()
// it does not bound a type argument either
val lists = columnOf(listOf(1, 2), listOf(3))
lists.map(typeOf<List<Number>>(), Infer.Type) { it }.type() shouldBe typeOf<List<Int>>()
// the only case where the given type survives: there are no values to derive one from
columnOf(*emptyArray<Int>()).map(typeOf<String>(), Infer.Type) { it }.type() shouldBe typeOf<String>()
}
typeOf<Number>(), typeOf<Boolean>() and typeOf<Any>() all give kotlin.Int here too.
Why
Iterable<KClass<*>>.createType (core/.../impl/TypeUtils.kt:182-196):
val upperClass = upperBound.classifier as KClass<*>
val baseClass = filter { it.isSubclassOf(upperClass) }.withMostSuperclasses() ?: withMostSuperclasses()
if (baseClass == null) {
upperBound.withNullability(nullable)
} else {
upperBound.projectTo(baseClass).withNullability(nullable)
}
When no actual class fits upperBound, the ?: falls back to the most-derived actual class and
projectTo discards the bound. baseClass == null — the one branch that keeps upperBound — is
reachable only when there are no values.
Scope
typeConversions.kt is shared by many operations, so the fix is documentation-only: describe the
parameter as a fallback for an empty column, not as an upper bound. The same wording was corrected
in api/map.kt and docs/StardustDocs/topics/map.md in #2066; this KDoc is where it was copied from.
Suggested wording
Infer
[DataColumn.type]and[DataColumn.hasNulls]from actual[DataColumn.values].
An optionally provided base type is used only when there are no values to infer from;
it does not constrain the inferred type.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.