@@ -40,8 +40,8 @@ private val unifiedNumberTypeGraphs = mutableMapOf<UnifiedNumberTypeOptions, Dir
40
40
* by calling [DirectedAcyclicGraph.findNearestCommonVertex].
41
41
*
42
42
* @param options See [UnifiedNumberTypeOptions]
43
- * @see getUnifiedNumberClass
44
- * @see unifiedNumberClass
43
+ * @see getUnifiedNumberClassOrNull
44
+ * @see unifiedNumberClassOrNull
45
45
* @see UnifyingNumbers
46
46
*/
47
47
internal fun getUnifiedNumberTypeGraph (
@@ -107,11 +107,11 @@ internal fun getUnifiedNumberClassGraph(
107
107
* If no common class is found, [IllegalStateException] is thrown.
108
108
* @see UnifyingNumbers
109
109
*/
110
- internal fun getUnifiedNumberType (
110
+ internal fun getUnifiedNumberTypeOrNull (
111
111
first : KType ? ,
112
112
second : KType ,
113
113
options : UnifiedNumberTypeOptions = UnifiedNumberTypeOptions .DEFAULT ,
114
- ): KType {
114
+ ): KType ? {
115
115
if (first == null ) return second
116
116
117
117
val firstWithoutNullability = first.withNullability(false )
@@ -121,7 +121,7 @@ internal fun getUnifiedNumberType(
121
121
firstWithoutNullability
122
122
} else {
123
123
getUnifiedNumberTypeGraph(options).findNearestCommonVertex(firstWithoutNullability, secondWithoutNullability)
124
- ? : error( " Can not find common number type for $first and $second " )
124
+ ? : return null
125
125
}
126
126
127
127
return if (first.isMarkedNullable || second.isMarkedNullable) {
@@ -131,20 +131,17 @@ internal fun getUnifiedNumberType(
131
131
}
132
132
}
133
133
134
- /* * @include [getUnifiedNumberType ] */
134
+ /* * @include [getUnifiedNumberTypeOrNull ] */
135
135
@Suppress(" IntroduceWhenSubject" )
136
- internal fun getUnifiedNumberClass (
136
+ internal fun getUnifiedNumberClassOrNull (
137
137
first : KClass <* >? ,
138
138
second : KClass <* >,
139
139
options : UnifiedNumberTypeOptions = UnifiedNumberTypeOptions .DEFAULT ,
140
- ): KClass <* > =
140
+ ): KClass <* >? =
141
141
when {
142
142
first == null -> second
143
-
144
143
first == second -> first
145
-
146
144
else -> getUnifiedNumberClassGraph(options).findNearestCommonVertex(first, second)
147
- ? : error(" Can not find common number type for $first and $second " )
148
145
}
149
146
150
147
/* *
@@ -156,28 +153,28 @@ internal fun getUnifiedNumberClass(
156
153
*
157
154
* @param options See [UnifiedNumberTypeOptions]
158
155
* @return The nearest common numeric type between the input types.
159
- * If no common type is found, it returns [Number] .
156
+ * If no common type is found, it returns `null` .
160
157
* @see UnifyingNumbers
161
158
*/
162
- internal fun Iterable<KType>.unifiedNumberType (
159
+ internal fun Iterable<KType>.unifiedNumberTypeOrNull (
163
160
options : UnifiedNumberTypeOptions = UnifiedNumberTypeOptions .DEFAULT ,
164
- ): KType =
161
+ ): KType ? =
165
162
fold(null as KType ? ) { a, b ->
166
- getUnifiedNumberType (a, b, options)
167
- } ? : typeOf< Number >()
163
+ getUnifiedNumberTypeOrNull (a, b, options) ? : return null
164
+ }
168
165
169
- /* * @include [unifiedNumberType ] */
170
- internal fun Iterable <KClass <* >>.unifiedNumberClass (
166
+ /* * @include [unifiedNumberTypeOrNull ] */
167
+ internal fun Iterable <KClass <* >>.unifiedNumberClassOrNull (
171
168
options : UnifiedNumberTypeOptions = UnifiedNumberTypeOptions .DEFAULT ,
172
- ): KClass <* > =
169
+ ): KClass <* >? =
173
170
fold(null as KClass <* >? ) { a, b ->
174
- getUnifiedNumberClass (a, b, options)
175
- } ? : Number :: class
171
+ getUnifiedNumberClassOrNull (a, b, options) ? : return null
172
+ }
176
173
177
174
/* *
178
175
* Converts the elements of the given iterable of numbers into a common numeric type based on complexity.
179
176
* The common numeric type is determined using the provided [commonNumberType] parameter
180
- * or calculated with [Iterable.unifiedNumberType ] from the iterable's elements if not explicitly specified.
177
+ * or calculated with [Iterable.unifiedNumberTypeOrNull ] from the iterable's elements if not explicitly specified.
181
178
*
182
179
* @param commonNumberType The desired common numeric type to convert the elements to.
183
180
* By default, (or if `null`), this is determined using the types of the elements in the iterable.
@@ -191,7 +188,12 @@ internal fun Iterable<Number?>.convertToUnifiedNumberType(
191
188
options : UnifiedNumberTypeOptions = UnifiedNumberTypeOptions .DEFAULT ,
192
189
commonNumberType : KType ? = null,
193
190
): Iterable <Number ?> {
194
- val commonNumberType = commonNumberType ? : this .types().unifiedNumberType(options)
191
+ val commonNumberType = commonNumberType ? : this .types().let { types ->
192
+ types.unifiedNumberTypeOrNull(options)
193
+ ? : throw IllegalArgumentException (
194
+ " Cannot find unified number type of types: ${types.joinToString { renderType(it) }} " ,
195
+ )
196
+ }
195
197
val converter = createConverter(typeOf<Number >(), commonNumberType)!! as (Number ) -> Number ?
196
198
return map {
197
199
if (it == null ) return @map null
@@ -216,7 +218,12 @@ internal fun Sequence<Number?>.convertToUnifiedNumberType(
216
218
options : UnifiedNumberTypeOptions = UnifiedNumberTypeOptions .DEFAULT ,
217
219
commonNumberType : KType ? = null,
218
220
): Sequence <Number ?> {
219
- val commonNumberType = commonNumberType ? : this .asIterable().types().unifiedNumberType(options)
221
+ val commonNumberType = commonNumberType ? : this .asIterable().types().let { types ->
222
+ types.unifiedNumberTypeOrNull(options)
223
+ ? : throw IllegalArgumentException (
224
+ " Cannot find unified number type of types: ${types.joinToString { renderType(it) }} " ,
225
+ )
226
+ }
220
227
val converter = createConverter(typeOf<Number >(), commonNumberType)!! as (Number ) -> Number ?
221
228
return map {
222
229
if (it == null ) return @map null
@@ -245,7 +252,28 @@ internal val primitiveNumberTypes: Set<KType> =
245
252
typeOf<Double >(),
246
253
)
247
254
248
- internal fun Any.isPrimitiveNumber (): Boolean =
255
+ /* * Returns `true` only when this type is exactly `Number` or `Number?`. */
256
+ @PublishedApi
257
+ internal fun KType.isMixedNumber (): Boolean = this == typeOf<Number >() || this == typeOf<Number ?>()
258
+
259
+ /* *
260
+ * Returns `true` when this type is one of the following (nullable) types:
261
+ * [Byte], [Short], [Int], [Long], [Float], or [Double].
262
+ */
263
+ @PublishedApi
264
+ internal fun KType.isPrimitiveNumber (): Boolean = this .withNullability(false ) in primitiveNumberTypes
265
+
266
+ /* *
267
+ * Returns `true` when this type is one of the following (nullable) types:
268
+ * [Byte], [Short], [Int], [Long], [Float], [Double], or [Number].
269
+ *
270
+ * Careful: Will return `true` for `Number`.
271
+ * This type may arise as a supertype from multiple non-primitive number types.
272
+ */
273
+ @PublishedApi
274
+ internal fun KType.isPrimitiveOrMixedNumber (): Boolean = isPrimitiveNumber() || isMixedNumber()
275
+
276
+ internal fun Number.isPrimitiveNumber (): Boolean =
249
277
this is Byte ||
250
278
this is Short ||
251
279
this is Int ||
0 commit comments