Skip to content

Commit 976d4d7

Browse files
authored
Merge pull request #882 from Kotlin/contracts
Adding contracts for `Anycol.isValueColumn` etc. for smart-casting
2 parents cc8ae15 + 8fc9dea commit 976d4d7

File tree

11 files changed

+38
-28
lines changed

11 files changed

+38
-28
lines changed

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/DataColumnType.kt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,39 @@
1+
@file:OptIn(ExperimentalContracts::class)
2+
13
package org.jetbrains.kotlinx.dataframe.api
24

35
import org.jetbrains.kotlinx.dataframe.AnyCol
6+
import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup
47
import org.jetbrains.kotlinx.dataframe.columns.ColumnKind
8+
import org.jetbrains.kotlinx.dataframe.columns.FrameColumn
9+
import org.jetbrains.kotlinx.dataframe.columns.ValueColumn
510
import org.jetbrains.kotlinx.dataframe.impl.isNothing
611
import org.jetbrains.kotlinx.dataframe.impl.projectTo
712
import org.jetbrains.kotlinx.dataframe.type
813
import org.jetbrains.kotlinx.dataframe.typeClass
14+
import kotlin.contracts.ExperimentalContracts
15+
import kotlin.contracts.contract
916
import kotlin.reflect.KClass
1017
import kotlin.reflect.KType
1118
import kotlin.reflect.KTypeProjection
1219
import kotlin.reflect.full.isSubclassOf
1320
import kotlin.reflect.full.isSubtypeOf
1421
import kotlin.reflect.typeOf
1522

16-
public fun AnyCol.isColumnGroup(): Boolean = kind() == ColumnKind.Group
23+
public fun AnyCol.isColumnGroup(): Boolean {
24+
contract { returns(true) implies (this@isColumnGroup is ColumnGroup<*>) }
25+
return kind() == ColumnKind.Group
26+
}
1727

18-
public fun AnyCol.isFrameColumn(): Boolean = kind() == ColumnKind.Frame
28+
public fun AnyCol.isFrameColumn(): Boolean {
29+
contract { returns(true) implies (this@isFrameColumn is FrameColumn<*>) }
30+
return kind() == ColumnKind.Frame
31+
}
1932

20-
public fun AnyCol.isValueColumn(): Boolean = kind() == ColumnKind.Value
33+
public fun AnyCol.isValueColumn(): Boolean {
34+
contract { returns(true) implies (this@isValueColumn is ValueColumn<*>) }
35+
return kind() == ColumnKind.Value
36+
}
2137

2238
public fun AnyCol.isSubtypeOf(type: KType): Boolean =
2339
this.type.isSubtypeOf(type) && (!this.type.isMarkedNullable || type.isMarkedNullable)

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/colGroups.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ public interface ColGroupsColumnsSelectionDsl {
212212
@Suppress("UNCHECKED_CAST")
213213
internal fun ColumnsResolver<*>.columnGroupsInternal(
214214
filter: (ColumnGroup<*>) -> Boolean,
215-
): TransformableColumnSet<AnyRow> =
216-
colsInternal { it.isColumnGroup() && filter(it.asColumnGroup()) } as TransformableColumnSet<AnyRow>
215+
): TransformableColumnSet<AnyRow> = colsInternal { it.isColumnGroup() && filter(it) } as TransformableColumnSet<AnyRow>
217216

218217
// endregion

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/select.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,7 @@ internal fun <C, R> SingleColumn<DataRow<C>>.selectInternal(selector: ColumnsSel
252252
"Column ${col.path} is not a ColumnGroup and can thus not be selected from."
253253
}
254254

255-
col.asColumnGroup()
256-
.getColumnsWithPaths(selector as ColumnsSelector<*, R>)
255+
col.getColumnsWithPaths(selector as ColumnsSelector<*, R>)
257256
.map { it.changePath(col.path + it.path) }
258257
} ?: emptyList()
259258
}

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/valueCols.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,6 @@ public interface ValueColsColumnsSelectionDsl {
179179
* @return A [TransformableColumnSet] containing the value columns that satisfy the filter.
180180
*/
181181
internal fun ColumnsResolver<*>.valueColumnsInternal(filter: (ValueColumn<*>) -> Boolean): TransformableColumnSet<*> =
182-
colsInternal { it.isValueColumn() && filter(it.asValueColumn()) }
182+
colsInternal { it.isValueColumn() && filter(it) }
183183

184184
// endregion

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/DataFrameReceiver.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import org.jetbrains.kotlinx.dataframe.ColumnSelector
44
import org.jetbrains.kotlinx.dataframe.DataColumn
55
import org.jetbrains.kotlinx.dataframe.DataFrame
66
import org.jetbrains.kotlinx.dataframe.DataRow
7-
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
87
import org.jetbrains.kotlinx.dataframe.api.asDataColumn
98
import org.jetbrains.kotlinx.dataframe.api.cast
109
import org.jetbrains.kotlinx.dataframe.api.isColumnGroup
@@ -78,7 +77,9 @@ internal open class DataFrameReceiver<T>(
7877
DataColumn.createColumnGroup("", df).addPath(emptyPath())
7978

8079
override fun columns() =
81-
df.columns().map { if (it.isColumnGroup()) ColumnGroupWithParent(null, it.asColumnGroup()) else it }
80+
df.columns().map {
81+
if (it.isColumnGroup()) ColumnGroupWithParent(null, it) else it
82+
}
8283

8384
override fun columnNames() = df.columnNames()
8485

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/convertTo.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import org.jetbrains.kotlinx.dataframe.api.Infer
1515
import org.jetbrains.kotlinx.dataframe.api.add
1616
import org.jetbrains.kotlinx.dataframe.api.all
1717
import org.jetbrains.kotlinx.dataframe.api.allNulls
18-
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
1918
import org.jetbrains.kotlinx.dataframe.api.concat
2019
import org.jetbrains.kotlinx.dataframe.api.convertTo
2120
import org.jetbrains.kotlinx.dataframe.api.emptyDataFrame
21+
import org.jetbrains.kotlinx.dataframe.api.isColumnGroup
2222
import org.jetbrains.kotlinx.dataframe.api.isEmpty
2323
import org.jetbrains.kotlinx.dataframe.api.map
2424
import org.jetbrains.kotlinx.dataframe.api.name
@@ -197,14 +197,12 @@ internal fun AnyFrame.convertToImpl(
197197

198198
else -> originalColumn
199199
}
200-
require(column.kind == ColumnKind.Group) {
200+
require(column.isColumnGroup()) {
201201
"Column `${column.name}` is ${column.kind} and can not be converted to `ColumnGroup`"
202202
}
203-
val columnGroup = column.asColumnGroup()
204-
205203
DataColumn.createColumnGroup(
206204
name = column.name(),
207-
df = columnGroup.convertToSchema(
205+
df = column.convertToSchema(
208206
schema = (targetSchema as ColumnSchema.Group).schema,
209207
path = columnPath,
210208
),

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/join.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import org.jetbrains.kotlinx.dataframe.api.JoinDsl
99
import org.jetbrains.kotlinx.dataframe.api.JoinType
1010
import org.jetbrains.kotlinx.dataframe.api.allowLeftNulls
1111
import org.jetbrains.kotlinx.dataframe.api.allowRightNulls
12-
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
1312
import org.jetbrains.kotlinx.dataframe.api.getColumnsWithPaths
1413
import org.jetbrains.kotlinx.dataframe.api.indices
1514
import org.jetbrains.kotlinx.dataframe.api.isColumnGroup
@@ -86,9 +85,11 @@ internal fun <A, B> DataFrame<A>.joinImpl(
8685
val leftCol = leftJoinColumns[i]
8786
val rightCol = rightJoinColumns[i]
8887
if (leftCol.isColumnGroup() && rightCol.isColumnGroup()) {
89-
val leftColumns = getColumnsWithPaths { leftCol.asColumnGroup().colsAtAnyDepth { !it.isColumnGroup() } }
88+
val leftColumns = getColumnsWithPaths {
89+
leftCol.colsAtAnyDepth { !it.isColumnGroup() }
90+
}
9091
val rightColumns = other.getColumnsWithPaths {
91-
rightCol.asColumnGroup().colsAtAnyDepth { !it.isColumnGroup() }
92+
rightCol.colsAtAnyDepth { !it.isColumnGroup() }
9293
}
9394

9495
val leftPrefixLength = leftCol.path.size

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/parse.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,7 @@ internal fun <T> DataFrame<T>.parseImpl(options: ParserOptions?, columns: Column
414414
it.isFrameColumn() -> it.cast<AnyFrame?>().parse(options)
415415

416416
it.isColumnGroup() ->
417-
it.asColumnGroup()
418-
.parse(options) { all() }
417+
it.parse(options) { all() }
419418
.asColumnGroup(it.name())
420419
.asDataColumn()
421420

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/ColumnAccessorImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.jetbrains.kotlinx.dataframe.impl.columns
22

33
import org.jetbrains.kotlinx.dataframe.AnyRow
4-
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
54
import org.jetbrains.kotlinx.dataframe.api.cast
65
import org.jetbrains.kotlinx.dataframe.api.isColumnGroup
76
import org.jetbrains.kotlinx.dataframe.api.toPath
@@ -29,7 +28,7 @@ internal class ColumnAccessorImpl<T>(val path: ColumnPath) : ColumnAccessor<T> {
2928
"Column '${path.subList(0, i + 1).joinToString(".")}' is not a column group.",
3029
)
3130
} else {
32-
col.asColumnGroup()
31+
col
3332
}
3433
}
3534
// resolve the last column of the path

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/tree/Utils.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,10 @@ internal fun Iterable<ColumnWithPath<*>>.flattenRecursively(): List<ColumnWithPa
8585
cols.forEach {
8686
result.add(it)
8787
val path = it.path
88-
if (it.data.isColumnGroup()) {
88+
val data = it.data
89+
if (data.isColumnGroup()) {
8990
flattenRecursively(
90-
it.data.asColumnGroup()
91-
.columns()
92-
.map { it.addPath(path + it.name()) },
91+
data.columns().map { it.addPath(path + it.name()) },
9392
)
9493
}
9594
}

0 commit comments

Comments
 (0)