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