Fix vararg argument mapping for generic args convertor

This commit is contained in:
Ilya Chernikov
2018-11-20 18:07:05 +01:00
parent 6b20ef0208
commit 5602bcf9e1
2 changed files with 38 additions and 15 deletions
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.script
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import kotlin.reflect.*
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.jvm.jvmErasure
@@ -160,18 +159,6 @@ private class StringArgsConverter : ArgsConverter<String> {
override fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<String>, restArgsIt: Iterator<NamedArgument<String>>): ArgsConverter.Result {
fun convertAnyArray(classifier: KClassifier?, args: Sequence<String?>): Any? =
when (classifier) {
String::class -> args.toList().toTypedArray()
is KClass<*> -> classifier.constructors.firstNotNullResult { ctor ->
try {
args.map { ctor.call(it) }.toList().toTypedArray()
}
catch (e: Exception) { null }
}
else -> null
}
fun convertPrimitivesArray(type: KType, args: Sequence<String?>): Any? =
when (type.classifier) {
IntArray::class -> args.map { it?.toIntOrNull() }
@@ -228,9 +215,42 @@ private class AnyArgsConverter : ArgsConverter<Any> {
?: ArgsConverter.Result.Failure
}
override fun tryConvertVararg(parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>): ArgsConverter.Result =
ArgsConverter.Result.Failure
override fun tryConvertVararg(
parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>
): ArgsConverter.Result {
val parameterType = parameter.type
if (parameterType.jvmErasure.java.isArray) {
val argsSequence = sequenceOf(firstArg.value) + restArgsIt.asSequence().map { it.value }
val arrayElementType = parameterType.arguments.firstOrNull()?.type
val arrayArgCandidate = convertAnyArray(arrayElementType?.classifier, argsSequence)
if (arrayArgCandidate != null)
return ArgsConverter.Result.Success(arrayArgCandidate)
}
return ArgsConverter.Result.Failure
}
override fun tryConvertTail(parameter: KParameter, firstArg: NamedArgument<Any>, restArgsIt: Iterator<NamedArgument<Any>>): ArgsConverter.Result =
tryConvertSingle(parameter, firstArg)
}
@Suppress("UNCHECKED_CAST")
private inline fun <reified T> convertAnyArray(classifier: KClassifier?, args: Sequence<T?>): Any? =
if (classifier == T::class) args.toList().toTypedArray() // simple case
else convertAnyArrayImpl<T>(classifier, args)
private fun <T> convertAnyArrayImpl(classifier: KClassifier?, args: Sequence<T?>): Any? {
val elementClass = (classifier as? KClass<*>) ?: return null
val argsList = args.toList()
val result = java.lang.reflect.Array.newInstance(elementClass.java, argsList.size)
argsList.forEachIndexed { idx, arg ->
try {
java.lang.reflect.Array.set(result, idx, arg)
} catch (e: IllegalArgumentException) {
return@convertAnyArrayImpl null
}
}
return result
}
@@ -74,6 +74,9 @@ class ArgsToParamsMatchingTest {
assertParamMapsEquals(tryCreateCallableMappingFromNamedArgs(::notNullNumber, listOf(null to 42)),
"n" to 42)
Assert.assertNull(tryCreateCallableMappingFromNamedArgs(::notNullNumber, listOf(null to "42")))
assertParamMapsEquals(tryCreateCallableMappingFromNamedArgs(::varargStrings, listOf("a", "b", "c").map { null to it }),
"s" to arrayOf("a", "b", "c"))
}
}