Allow receiver to be generic type constrained by SELF. Receiver itself now can be referenced with RECEIVER.

This commit is contained in:
Ilya Gorbunov
2016-10-01 03:51:11 +03:00
parent 5a25bd5e2d
commit 65a7410eca
@@ -257,14 +257,15 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
fun build(builder: Appendable, f: Family, primitive: PrimitiveType?) { fun build(builder: Appendable, f: Family, primitive: PrimitiveType?) {
val returnType = returns[f] ?: throw RuntimeException("No return type specified for $signature") val returnType = returns[f] ?: throw RuntimeException("No return type specified for $signature")
fun renderType(expression: String, receiver: 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)
val answer = StringBuilder() val answer = StringBuilder()
while (t.hasMoreTokens()) { while (t.hasMoreTokens()) {
val token = t.nextToken() val token = t.nextToken()
answer.append(when (token) { answer.append(when (token) {
"SELF" -> receiver "RECEIVER" -> receiver
"SELF" -> self
"PRIMITIVE" -> primitive?.name ?: token "PRIMITIVE" -> primitive?.name ?: token
"SUM" -> { "SUM" -> {
when (primitive) { when (primitive) {
@@ -293,7 +294,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
"TCollection" -> { "TCollection" -> {
when (f) { when (f) {
CharSequences, Strings -> "Appendable" CharSequences, Strings -> "Appendable"
else -> renderType("MutableCollection<in T>", receiver) else -> renderType("MutableCollection<in T>", receiver, self)
} }
} }
"T" -> { "T" -> {
@@ -324,7 +325,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
} }
val isAsteriskOrT = if (receiverAsterisk[f] == true) "*" else "T" val isAsteriskOrT = if (receiverAsterisk[f] == true) "*" else "T"
val receiver = (customReceiver[f] ?: when (f) { val self = (when (f) {
Iterables -> "Iterable<$isAsteriskOrT>" Iterables -> "Iterable<$isAsteriskOrT>"
Collections -> "Collection<$isAsteriskOrT>" Collections -> "Collection<$isAsteriskOrT>"
Lists -> "List<$isAsteriskOrT>" Lists -> "List<$isAsteriskOrT>"
@@ -341,12 +342,14 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
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 -> "T"
}).let { renderType(it, it) } })
fun String.renderType(): String = renderType(this, receiver) val receiver = (customReceiver[f] ?: self).let { renderType(it, it, self) }
fun String.renderType(): String = renderType(this, receiver, self)
fun effectiveTypeParams(): List<TypeParameter> { fun effectiveTypeParams(): List<TypeParameter> {
val parameters = typeParams.mapTo(mutableListOf()) { parseTypeParameter(it) } val parameters = typeParams.mapTo(mutableListOf()) { parseTypeParameter(it.renderType()) }
if (f == Generic) { if (f == Generic) {
if (parameters.none { it.name == "T" }) if (parameters.none { it.name == "T" })
@@ -364,9 +367,9 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
return parameters return parameters
} else { } else {
// remove T as parameter // substituted T is no longer a parameter
// TODO: Substitute primitive or String instead of T in other parameters from effective types not from original typeParams val renderedT = "T".renderType()
return parameters.filterNot { it.name == "T" } return parameters.filterNot { it.name == renderedT }
} }
} }
@@ -418,7 +421,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") {
val types = effectiveTypeParams() val types = effectiveTypeParams()
if (!types.isEmpty()) { if (!types.isEmpty()) {
builder.append(types.joinToString(separator = ", ", prefix = "<", postfix = "> ", transform = { it.original }).renderType()) builder.append(types.joinToString(separator = ", ", prefix = "<", postfix = "> ", transform = { it.original }))
} }
val receiverType = (if (toNullableT) receiver.replace("T>", "T?>") else receiver).renderType() val receiverType = (if (toNullableT) receiver.replace("T>", "T?>") else receiver).renderType()