Support having primary type parameter other than T in generated code

With some limitations: the primary parameter cannot have constraints for now.
This commit is contained in:
Ilya Gorbunov
2018-08-20 21:01:52 +03:00
parent 929064dfa7
commit 751e844258
@@ -57,6 +57,7 @@ class MemberBuilder(
var infix: Boolean = false; private set
var operator: Boolean = false; private set
val typeParams = mutableListOf<String>()
var primaryTypeParameter: String? = null; private set
var customReceiver: String? = null; private set
var receiverAsterisk: Boolean = false // TODO: rename to genericStarProjection
var toNullableT: Boolean = false
@@ -97,8 +98,12 @@ class MemberBuilder(
@Deprecated("Use specialFor", ReplaceWith("specialFor(*fs) { returns(run(valueBuilder)) }"))
fun returns(vararg fs: Family, valueBuilder: () -> String) = specialFor(*fs) { returns(run(valueBuilder)) }
fun typeParam(typeParameterName: String) {
fun typeParam(typeParameterName: String, primary: Boolean = false) {
typeParams += typeParameterName
if (primary) {
check(primaryTypeParameter == null)
primaryTypeParameter = typeParameterName
}
}
fun annotation(annotation: String) {
@@ -171,7 +176,7 @@ class MemberBuilder(
}
val returnType = returns ?: throw RuntimeException("No return type specified for $signature")
val primaryTypeParameter = this.primaryTypeParameter ?: "T"
fun renderType(expression: String, receiver: String, self: String): String {
val t = StringTokenizer(expression, " \t\n,:()<>?.", true)
@@ -210,12 +215,12 @@ class MemberBuilder(
"TCollection" -> {
when (family) {
CharSequences, Strings -> "Appendable"
else -> renderType("MutableCollection<in T>", receiver, self)
else -> renderType("MutableCollection<in $primaryTypeParameter>", receiver, self)
}
}
"T" -> {
primaryTypeParameter -> {
when (family) {
Generic -> "T"
Generic -> primaryTypeParameter
CharSequences, Strings -> "Char"
Maps -> "Map.Entry<K, V>"
else -> primitive?.name ?: token
@@ -223,13 +228,13 @@ class MemberBuilder(
}
"TRange" -> {
when (family) {
Generic -> "Range<T>"
Generic -> "Range<$primaryTypeParameter>"
else -> primitive!!.name + "Range"
}
}
"TProgression" -> {
when (family) {
Generic -> "Progression<out T>"
Generic -> "Progression<out $primaryTypeParameter>"
else -> primitive!!.name + "Progression"
}
}
@@ -240,7 +245,7 @@ class MemberBuilder(
return answer.toString()
}
val isAsteriskOrT = if (receiverAsterisk) "*" else "T"
val isAsteriskOrT = if (receiverAsterisk) "*" else primaryTypeParameter
val self = (when (family) {
Iterables -> "Iterable<$isAsteriskOrT>"
Collections -> "Collection<$isAsteriskOrT>"
@@ -248,8 +253,8 @@ class MemberBuilder(
Maps -> "Map<out K, V>"
Sets -> "Set<$isAsteriskOrT>"
Sequences -> "Sequence<$isAsteriskOrT>"
InvariantArraysOfObjects -> "Array<T>"
ArraysOfObjects -> "Array<${isAsteriskOrT.replace("T", "out T")}>"
InvariantArraysOfObjects -> "Array<$primaryTypeParameter>"
ArraysOfObjects -> "Array<${isAsteriskOrT.replace(primaryTypeParameter, "out $primaryTypeParameter")}>"
Strings -> "String"
CharSequences -> "CharSequence"
Ranges -> "ClosedRange<$isAsteriskOrT>"
@@ -257,7 +262,7 @@ class MemberBuilder(
RangesOfPrimitives -> primitive?.let { it.name + "Range" } ?: throw IllegalArgumentException("Primitive range should specify primitive type")
ProgressionsOfPrimitives -> primitive?.let { it.name + "Progression" } ?: throw IllegalArgumentException("Primitive progression should specify primitive type")
Primitives -> primitive?.let { it.name } ?: throw IllegalArgumentException("Primitive should specify primitive type")
Generic -> "T"
Generic -> primaryTypeParameter
})
val receiver = (customReceiver ?: self).let { renderType(it, it, self) }
@@ -268,8 +273,8 @@ class MemberBuilder(
val parameters = typeParams.mapTo(mutableListOf()) { parseTypeParameter(it.renderType()) }
if (family == Generic) {
if (parameters.none { it.name == "T" })
parameters.add(TypeParameter("T"))
if (parameters.none { it.name == primaryTypeParameter })
parameters.add(TypeParameter(primaryTypeParameter))
return parameters
} else if (primitive == null && family != Strings && family != CharSequences) {
val mentionedTypes = parseTypeRef(receiver).mentionedTypes() + parameters.flatMap { it.mentionedTypeRefs() }
@@ -283,7 +288,7 @@ class MemberBuilder(
return parameters
} else {
// substituted T is no longer a parameter
val renderedT = "T".renderType()
val renderedT = primaryTypeParameter.renderType()
return parameters.filterNot { it.name == renderedT }
}
}
@@ -318,7 +323,7 @@ class MemberBuilder(
if (!f.isPrimitiveSpecialization && primitive != null) {
platformName
?.replace("<T>", primitive!!.name)
?.replace("<$primaryTypeParameter>", primitive!!.name)
?.let { platformName -> builder.append("@kotlin.jvm.JvmName(\"${platformName}\")\n") }
}