[KLIB] Fix references to type made from TypeParameter in KotlinMangler
- promote ABI version
This commit is contained in:
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
|
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsMangler
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerForBE
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
import org.jetbrains.kotlin.ir.types.isUnit
|
||||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||||
|
|
||||||
fun <T> mapToKey(declaration: T): String {
|
fun <T> mapToKey(declaration: T): String {
|
||||||
return with(JsMangler) {
|
return with(JsManglerForBE) {
|
||||||
if (declaration is IrDeclaration && isPublic(declaration)) {
|
if (declaration is IrDeclaration && isPublic(declaration)) {
|
||||||
declaration.hashedMangle.toString()
|
declaration.hashedMangle.toString()
|
||||||
} else if (declaration is Signature) {
|
} else if (declaration is Signature) {
|
||||||
@@ -32,7 +32,7 @@ fun <T> mapToKey(declaration: T): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsMangler.isPublic(declaration: IrDeclaration) =
|
fun JsManglerForBE.isPublic(declaration: IrDeclaration) =
|
||||||
declaration.isExported() && declaration !is IrScript && declaration !is IrVariable && declaration !is IrValueParameter
|
declaration.isExported() && declaration !is IrScript && declaration !is IrVariable && declaration !is IrValueParameter
|
||||||
|
|
||||||
class NameTable<T>(
|
class NameTable<T>(
|
||||||
|
|||||||
+98
-36
@@ -6,7 +6,9 @@
|
|||||||
package org.jetbrains.kotlin.backend.common.serialization
|
package org.jetbrains.kotlin.backend.common.serialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
@@ -98,24 +100,52 @@ abstract class KotlinManglerImpl : KotlinMangler {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
|
private fun IrTypeParameter.effectiveParent(): IrDeclaration = when (val irParent = parent) {
|
||||||
|
is IrClass -> irParent
|
||||||
|
is IrConstructor -> irParent
|
||||||
|
is IrSimpleFunction -> irParent.correspondingPropertySymbol?.owner ?: irParent
|
||||||
|
else -> error("Unexpected type parameter container")
|
||||||
|
}
|
||||||
|
|
||||||
protected fun acyclicTypeMangler(visited: MutableSet<IrTypeParameter>, type: IrType): String {
|
private fun collectTypeParameterContainers(element: IrElement): List<IrDeclaration> {
|
||||||
val descriptor = (type.classifierOrNull as? IrTypeParameterSymbol)?.owner
|
val result = mutableListOf<IrDeclaration>()
|
||||||
if (descriptor != null) {
|
|
||||||
val upperBounds = if (visited.contains(descriptor)) "" else {
|
|
||||||
|
|
||||||
visited.add(descriptor)
|
tailrec fun collectTypeParameterContainersImpl(element: IrElement) {
|
||||||
|
when (element) {
|
||||||
descriptor.superTypes.map {
|
is IrConstructor -> result += element
|
||||||
val bound = acyclicTypeMangler(visited, it)
|
is IrSimpleFunction -> result.add(element.correspondingPropertySymbol?.owner ?: element)
|
||||||
if (bound == "kotlin.Any?") "" else "_$bound"
|
is IrProperty -> result += element
|
||||||
}.joinToString("")
|
is IrClass -> result += element
|
||||||
|
else -> return
|
||||||
}
|
}
|
||||||
return "#GENERIC${if (type.isMarkedNullable()) "?" else ""}$upperBounds"
|
|
||||||
|
collectTypeParameterContainersImpl((element as IrDeclaration).parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hashString = type.getClass()?.run { fqNameForIrSerialization.asString() } ?: "<dynamic>"
|
collectTypeParameterContainersImpl(element)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mapTypeParameterContainers(element: IrElement): Map<IrDeclaration, Int> {
|
||||||
|
return collectTypeParameterContainers(element).mapIndexed { i, d -> d to i }.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
|
||||||
|
|
||||||
|
protected open fun mangleTypeParameter(typeParameter: IrTypeParameter, typeParameterNamer: (IrTypeParameter) -> String): String {
|
||||||
|
return typeParameterNamer(typeParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun acyclicTypeMangler(type: IrType, typeParameterNamer: (IrTypeParameter) -> String): String {
|
||||||
|
|
||||||
|
var hashString = type.classifierOrNull?.let {
|
||||||
|
when (it) {
|
||||||
|
is IrClassSymbol -> it.owner.fqNameForIrSerialization.asString()
|
||||||
|
is IrTypeParameterSymbol -> mangleTypeParameter(it.owner, typeParameterNamer)
|
||||||
|
else -> error("Unexpected type constructor")
|
||||||
|
}
|
||||||
|
} ?: "<dynamic>"
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
is IrSimpleType -> {
|
is IrSimpleType -> {
|
||||||
@@ -126,7 +156,7 @@ abstract class KotlinManglerImpl : KotlinMangler {
|
|||||||
is IrTypeProjection -> {
|
is IrTypeProjection -> {
|
||||||
val variance = it.variance.label
|
val variance = it.variance.label
|
||||||
val projection = if (variance == "") "" else "${variance}_"
|
val projection = if (variance == "") "" else "${variance}_"
|
||||||
projection + acyclicTypeMangler(visited, it.type)
|
projection + acyclicTypeMangler(it.type, typeParameterNamer)
|
||||||
}
|
}
|
||||||
else -> error(it)
|
else -> error(it)
|
||||||
}
|
}
|
||||||
@@ -142,32 +172,51 @@ abstract class KotlinManglerImpl : KotlinMangler {
|
|||||||
return hashString
|
return hashString
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun typeToHashString(type: IrType) = acyclicTypeMangler(mutableSetOf(), type)
|
protected fun typeToHashString(type: IrType, typeParameterNamer: (IrTypeParameter) -> String) =
|
||||||
|
acyclicTypeMangler(type, typeParameterNamer)
|
||||||
|
|
||||||
val IrValueParameter.extensionReceiverNamePart: String
|
fun IrValueParameter.extensionReceiverNamePart(typeParameterNamer: (IrTypeParameter) -> String): String =
|
||||||
get() = "@${typeToHashString(this.type)}."
|
"@${typeToHashString(this.type, typeParameterNamer)}."
|
||||||
|
|
||||||
open val IrFunction.argsPart
|
open fun IrFunction.valueParamsPart(typeParameterNamer: (IrTypeParameter) -> String): String {
|
||||||
get() = this.valueParameters.map {
|
return this.valueParameters.map {
|
||||||
"${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}"
|
"${typeToHashString(it.type, typeParameterNamer)}${if (it.isVararg) "_VarArg" else ""}"
|
||||||
}.joinToString(";")
|
}.joinToString(";")
|
||||||
|
}
|
||||||
|
|
||||||
open val IrFunction.signature: String
|
open fun IrFunction.typeParamsPart(typeParameters: List<IrTypeParameter>, typeParameterNamer: (IrTypeParameter) -> String): String {
|
||||||
get() {
|
if (typeParameters.isEmpty()) return ""
|
||||||
val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
|
|
||||||
val argsPart = this.argsPart
|
fun mangleTypeParameter(index: Int, typeParameter: IrTypeParameter): String {
|
||||||
// Distinguish value types and references - it's needed for calling virtual methods through bridges.
|
// We use type parameter index instead of name since changing name is not a binary-incompatible change
|
||||||
// Also is function has type arguments - frontend allows exactly matching overrides.
|
return typeParameter.superTypes.joinToString("&", "$index<", ">") {
|
||||||
val signatureSuffix =
|
acyclicTypeMangler(it, typeParameterNamer)
|
||||||
when {
|
}
|
||||||
this.typeParameters.isNotEmpty() -> "Generic"
|
|
||||||
returnType.isInlined -> "ValueType"
|
|
||||||
!returnType.isUnitOrNullableUnit() -> typeToHashString(returnType)
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
return "$extensionReceiverPart($argsPart)$signatureSuffix"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return typeParameters.withIndex().joinToString(";", "{", "}") { (i, tp) ->
|
||||||
|
mangleTypeParameter(i, tp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun IrFunction.signature(typeParameterNamer: (IrTypeParameter) -> String): String {
|
||||||
|
val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart(typeParameterNamer) ?: ""
|
||||||
|
val valueParamsPart = this.valueParamsPart(typeParameterNamer)
|
||||||
|
// Distinguish value types and references - it's needed for calling virtual methods through bridges.
|
||||||
|
// Also is function has type arguments - frontend allows exactly matching overrides.
|
||||||
|
val signatureSuffix =
|
||||||
|
when {
|
||||||
|
this.typeParameters.isNotEmpty() -> "Generic"
|
||||||
|
returnType.isInlined -> "ValueType"
|
||||||
|
!returnType.isUnitOrNullableUnit() -> typeToHashString(returnType, typeParameterNamer)
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val typesParamsPart = this.typeParamsPart(typeParameters, typeParameterNamer)
|
||||||
|
|
||||||
|
return "$extensionReceiverPart($valueParamsPart)$typesParamsPart$signatureSuffix"
|
||||||
|
}
|
||||||
|
|
||||||
open val IrFunction.platformSpecificFunctionName: String? get() = null
|
open val IrFunction.platformSpecificFunctionName: String? get() = null
|
||||||
|
|
||||||
// TODO: rename to indicate that it has signature included
|
// TODO: rename to indicate that it has signature included
|
||||||
@@ -175,8 +224,15 @@ abstract class KotlinManglerImpl : KotlinMangler {
|
|||||||
get() {
|
get() {
|
||||||
// TODO: Again. We can't call super in children, so provide a hook for now.
|
// TODO: Again. We can't call super in children, so provide a hook for now.
|
||||||
this.platformSpecificFunctionName?.let { return it }
|
this.platformSpecificFunctionName?.let { return it }
|
||||||
|
|
||||||
|
val typeContainerMap = mapTypeParameterContainers(this)
|
||||||
|
val typeParameterNamer: (IrTypeParameter) -> String = {
|
||||||
|
val eParent = it.effectiveParent()
|
||||||
|
"${typeContainerMap[eParent] ?: error("No parent for ${it.render()}")}:${it.index}"
|
||||||
|
}
|
||||||
|
|
||||||
val name = this.name.mangleIfInternal(this.module, this.visibility)
|
val name = this.name.mangleIfInternal(this.module, this.visibility)
|
||||||
return "$name$signature"
|
return "$name${signature(typeParameterNamer)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
override val Long.isSpecial: Boolean
|
override val Long.isSpecial: Boolean
|
||||||
@@ -257,7 +313,13 @@ abstract class KotlinManglerImpl : KotlinMangler {
|
|||||||
|
|
||||||
private val IrProperty.symbolName: String
|
private val IrProperty.symbolName: String
|
||||||
get() {
|
get() {
|
||||||
val extensionReceiver: String = getter?.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
|
val typeContainerMap = mapTypeParameterContainers(this)
|
||||||
|
val typeParameterNamer: (IrTypeParameter) -> String = {
|
||||||
|
val eParent = it.effectiveParent()
|
||||||
|
"${typeContainerMap[eParent] ?: error("No parent for ${it.render()}")}:${it.index}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val extensionReceiver: String = getter?.extensionReceiverParameter?.extensionReceiverNamePart(typeParameterNamer) ?: ""
|
||||||
|
|
||||||
val containingDeclarationPart = parent.fqNameForIrSerialization.let {
|
val containingDeclarationPart = parent.fqNameForIrSerialization.let {
|
||||||
if (it.isRoot) "" else "$it."
|
if (it.isRoot) "" else "$it."
|
||||||
|
|||||||
+9
-2
@@ -6,12 +6,19 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.KotlinManglerImpl
|
import org.jetbrains.kotlin.backend.common.serialization.KotlinManglerImpl
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.cityHash64
|
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.util.isInlined
|
import org.jetbrains.kotlin.ir.util.isInlined
|
||||||
|
|
||||||
object JsMangler : KotlinManglerImpl() {
|
abstract class AbstractJsMangler : KotlinManglerImpl() {
|
||||||
override val IrType.isInlined: Boolean
|
override val IrType.isInlined: Boolean
|
||||||
get() = this.isInlined()
|
get() = this.isInlined()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object JsMangler : AbstractJsMangler()
|
||||||
|
|
||||||
|
object JsManglerForBE : AbstractJsMangler() {
|
||||||
|
|
||||||
|
override fun mangleTypeParameter(typeParameter: IrTypeParameter, typeParameterNamer: (IrTypeParameter) -> String): String =
|
||||||
|
typeParameter.name.asString()
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ fun String.parseKonanAbiVersion(): KotlinAbiVersion {
|
|||||||
|
|
||||||
data class KotlinAbiVersion(val version: Int) {
|
data class KotlinAbiVersion(val version: Int) {
|
||||||
companion object {
|
companion object {
|
||||||
val CURRENT = KotlinAbiVersion(21)
|
val CURRENT = KotlinAbiVersion(22)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString() = "$version"
|
override fun toString() = "$version"
|
||||||
|
|||||||
+5
@@ -4477,6 +4477,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/inlineMultiModule/topLevelNestedInline.kt");
|
runTest("js/js.translator/testData/box/inlineMultiModule/topLevelNestedInline.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeParametersMangling.kt")
|
||||||
|
public void testTypeParametersMangling() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/inlineMultiModule/typeParametersMangling.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("typealiases.kt")
|
@TestMetadata("typealiases.kt")
|
||||||
public void testTypealiases() throws Exception {
|
public void testTypealiases() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/inlineMultiModule/typealiases.kt");
|
runTest("js/js.translator/testData/box/inlineMultiModule/typealiases.kt");
|
||||||
|
|||||||
+5
@@ -4492,6 +4492,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/inlineMultiModule/topLevelNestedInline.kt");
|
runTest("js/js.translator/testData/box/inlineMultiModule/topLevelNestedInline.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeParametersMangling.kt")
|
||||||
|
public void testTypeParametersMangling() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/inlineMultiModule/typeParametersMangling.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("typealiases.kt")
|
@TestMetadata("typealiases.kt")
|
||||||
public void testTypealiases() throws Exception {
|
public void testTypealiases() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/inlineMultiModule/typealiases.kt");
|
runTest("js/js.translator/testData/box/inlineMultiModule/typealiases.kt");
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// EXPECTED_REACHABLE_NODES: 1286
|
||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
class C<V>(val v: V) {
|
||||||
|
|
||||||
|
fun <R1, R2: List<R1>> reduce(reducer: (reduction: V) -> R2) {}
|
||||||
|
fun <R1, R2: List<R1>> reduce(reducer: (reduction: R1) -> R2) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val c = C(42)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user