[JS IR] Fix IC invalidation for fake override inline functions
The patch enables the direct dependency between fake override inline function and its implementation from the base class. Because klibs do not keep a signature of fake override implementation, incremental cache can not use the signature index, therefore the signature is serialized to a cache file as is. ^KT-51896 Fixed
This commit is contained in:
committed by
Space
parent
c6299ee277
commit
644447db84
@@ -8,10 +8,10 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrFragmentAndBinaryAst
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
|
||||
@@ -238,6 +238,16 @@ class CacheUpdater(
|
||||
return exportedSymbols
|
||||
}
|
||||
|
||||
private fun resolveFakeOverrideInlineFunction(symbol: IrSymbol): IdSignature? {
|
||||
return (symbol.owner as? IrSimpleFunction)?.let { overridable ->
|
||||
if (overridable.isFakeOverride && overridable.isInline) {
|
||||
overridable.resolveFakeOverride()?.symbol?.signature
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun rebuildDirtySourceMetadata(
|
||||
jsIrLinker: JsIrLinker,
|
||||
loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>,
|
||||
@@ -253,12 +263,15 @@ class CacheUpdater(
|
||||
val libSrcFile = KotlinSourceFile(fileDeserializer.file)
|
||||
|
||||
val reachableSignatures = fileDeserializer.symbolDeserializer.signatureDeserializer.signatureToIndexMapping()
|
||||
val allImplementedSignatures = fileDeserializer.symbolDeserializer.deserializedSymbols.keys
|
||||
val allImplementedSymbols = fileDeserializer.symbolDeserializer.deserializedSymbols
|
||||
val maybeImportedSignatures = reachableSignatures.keys.toMutableSet()
|
||||
for (signature in allImplementedSignatures) {
|
||||
for ((signature, symbol) in allImplementedSymbols) {
|
||||
if (signature in reachableSignatures) {
|
||||
idSignatureToFile[signature] = lib to libSrcFile
|
||||
maybeImportedSignatures.remove(signature)
|
||||
|
||||
val resolvedSignature = resolveFakeOverrideInlineFunction(symbol) ?: continue
|
||||
maybeImportedSignatures.add(resolvedSignature)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,14 @@ internal inline fun File.useCodedOutput(f: CodedOutputStream.() -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun icError(msg: String): Nothing = error("IC internal error: $msg")
|
||||
|
||||
internal fun notFoundIcError(what: String, libFile: KotlinLibraryFile? = null, srcFile: KotlinSourceFile? = null): Nothing {
|
||||
internal fun icError(what: String, libFile: KotlinLibraryFile? = null, srcFile: KotlinSourceFile? = null): Nothing {
|
||||
val filePath = listOfNotNull(libFile?.path, srcFile?.path).joinToString(":") { File(it).name }
|
||||
val msg = if (filePath.isEmpty()) what else "$what for $filePath"
|
||||
icError("can not find $msg")
|
||||
error("IC internal error: $msg")
|
||||
}
|
||||
|
||||
internal fun notFoundIcError(what: String, libFile: KotlinLibraryFile? = null, srcFile: KotlinSourceFile? = null): Nothing {
|
||||
icError("can not find $what", libFile, srcFile)
|
||||
}
|
||||
|
||||
internal inline fun <E> buildListUntil(to: Int, builderAction: MutableList<E>.(Int) -> Unit): List<E> {
|
||||
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||
|
||||
private enum class IdSignatureProtoType(val id: Int) {
|
||||
DECLARED_SIGNATURE(0),
|
||||
COMMON_SIGNATURE(1),
|
||||
COMPOSITE_SIGNATURE(2),
|
||||
ACCESSOR_SIGNATURE(3);
|
||||
}
|
||||
|
||||
internal fun CodedOutputStream.writeIdSignature(signature: IdSignature, signatureToIndexMapper: (IdSignature) -> Int?) {
|
||||
val index = signatureToIndexMapper(signature)
|
||||
if (index != null) {
|
||||
writeInt32NoTag(IdSignatureProtoType.DECLARED_SIGNATURE.id)
|
||||
writeInt32NoTag(index)
|
||||
return
|
||||
}
|
||||
|
||||
when (signature) {
|
||||
is IdSignature.CommonSignature -> {
|
||||
writeInt32NoTag(IdSignatureProtoType.COMMON_SIGNATURE.id)
|
||||
writeStringNoTag(signature.packageFqName)
|
||||
writeStringNoTag(signature.declarationFqName)
|
||||
val id = signature.id
|
||||
if (id != null) {
|
||||
writeBoolNoTag(true)
|
||||
writeFixed64NoTag(id)
|
||||
} else {
|
||||
writeBoolNoTag(false)
|
||||
}
|
||||
writeInt64NoTag(signature.mask)
|
||||
}
|
||||
is IdSignature.CompositeSignature -> {
|
||||
writeInt32NoTag(IdSignatureProtoType.COMPOSITE_SIGNATURE.id)
|
||||
writeIdSignature(signature.container, signatureToIndexMapper)
|
||||
writeIdSignature(signature.inner, signatureToIndexMapper)
|
||||
}
|
||||
is IdSignature.AccessorSignature -> {
|
||||
writeInt32NoTag(IdSignatureProtoType.ACCESSOR_SIGNATURE.id)
|
||||
writeIdSignature(signature.propertySignature, signatureToIndexMapper)
|
||||
writeIdSignature(signature.accessorSignature, signatureToIndexMapper)
|
||||
}
|
||||
else -> {
|
||||
icError("can not write $signature signature")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun CodedInputStream.readIdSignature(indexToSignatureMapper: (Int) -> IdSignature): IdSignature {
|
||||
when (val signatureType = readInt32()) {
|
||||
IdSignatureProtoType.DECLARED_SIGNATURE.id -> {
|
||||
return indexToSignatureMapper(readInt32())
|
||||
}
|
||||
IdSignatureProtoType.COMMON_SIGNATURE.id -> {
|
||||
val packageFqName = readString()
|
||||
val declarationFqName = readString()
|
||||
val id = if (readBool()) {
|
||||
readFixed64()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val mask = readInt64()
|
||||
return IdSignature.CommonSignature(packageFqName, declarationFqName, id, mask)
|
||||
}
|
||||
IdSignatureProtoType.COMPOSITE_SIGNATURE.id -> {
|
||||
val containerSignature = readIdSignature(indexToSignatureMapper)
|
||||
val innerSignature = readIdSignature(indexToSignatureMapper)
|
||||
return IdSignature.CompositeSignature(containerSignature, innerSignature)
|
||||
}
|
||||
IdSignatureProtoType.ACCESSOR_SIGNATURE.id -> {
|
||||
val propertySignature = readIdSignature(indexToSignatureMapper)
|
||||
val accessorSignature = readIdSignature(indexToSignatureMapper)
|
||||
if (accessorSignature !is IdSignature.CommonSignature) {
|
||||
icError("can not read accessor signature")
|
||||
}
|
||||
return IdSignature.AccessorSignature(propertySignature, accessorSignature)
|
||||
}
|
||||
else -> {
|
||||
icError("can not read signature type $signatureType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun CodedInputStream.skipIdSignature() {
|
||||
when (val signatureType = readInt32()) {
|
||||
IdSignatureProtoType.DECLARED_SIGNATURE.id -> {
|
||||
readInt32()
|
||||
}
|
||||
IdSignatureProtoType.COMMON_SIGNATURE.id -> {
|
||||
readString()
|
||||
readString()
|
||||
if (readBool()) {
|
||||
readFixed64()
|
||||
}
|
||||
readInt64()
|
||||
}
|
||||
IdSignatureProtoType.COMPOSITE_SIGNATURE.id -> {
|
||||
skipIdSignature()
|
||||
skipIdSignature()
|
||||
}
|
||||
IdSignatureProtoType.ACCESSOR_SIGNATURE.id -> {
|
||||
skipIdSignature()
|
||||
skipIdSignature()
|
||||
}
|
||||
else -> {
|
||||
icError("can not skip signature type $signatureType")
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-12
@@ -165,10 +165,10 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
private fun fetchSourceFileMetadata(srcFile: KotlinSourceFile, loadSignatures: Boolean) =
|
||||
kotlinLibrarySourceFileMetadata.getOrPut(srcFile) {
|
||||
val signatureToIndexMapping = signatureToIndexMappingFromMetadata.getOrPut(srcFile) { mutableMapOf() }
|
||||
fun IdSignatureDeserializer.deserializeIdSignatureAndSave(index: Int): IdSignature {
|
||||
val signature = deserializeIdSignature(index)
|
||||
fun CodedInputStream.deserializeIdSignatureAndSave(deserializer: IdSignatureDeserializer) = readIdSignature { index ->
|
||||
val signature = deserializer.deserializeIdSignature(index)
|
||||
signatureToIndexMapping[signature] = index
|
||||
return signature
|
||||
signature
|
||||
}
|
||||
|
||||
val deserializer: IdSignatureDeserializer by lazy {
|
||||
@@ -181,9 +181,9 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
val depends = buildMapUntil(readInt32()) {
|
||||
val dependencySrcFile = KotlinSourceFile.fromProtoStream(this@useCodedInputIfExists)
|
||||
val dependencySignatures = if (loadSignatures) {
|
||||
buildSetUntil(readInt32()) { add(deserializer.deserializeIdSignatureAndSave(readInt32())) }
|
||||
buildSetUntil(readInt32()) { add(deserializeIdSignatureAndSave(deserializer)) }
|
||||
} else {
|
||||
repeat(readInt32()) { readInt32() }
|
||||
repeat(readInt32()) { skipIdSignature() }
|
||||
emptySet()
|
||||
}
|
||||
put(dependencySrcFile, dependencySignatures)
|
||||
@@ -196,7 +196,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
|
||||
val importedInlineFunctions = if (loadSignatures) {
|
||||
buildMapUntil(readInt32()) {
|
||||
val signature = deserializer.deserializeIdSignatureAndSave(readInt32())
|
||||
val signature = deserializeIdSignatureAndSave(deserializer)
|
||||
val transitiveHash = ICHash.fromProtoStream(this@useCodedInputIfExists)
|
||||
put(signature, transitiveHash)
|
||||
}
|
||||
@@ -220,10 +220,8 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
}
|
||||
|
||||
val signatureToIndexMappingSaved = signatureToIndexMappingFromMetadata[srcFile] ?: emptyMap()
|
||||
fun serializeSignature(signature: IdSignature): Int {
|
||||
val index = signatureToIndexMapping[signature] ?: signatureToIndexMappingSaved[signature]
|
||||
return index ?: notFoundIcError("signature $signature", libraryFile, srcFile)
|
||||
}
|
||||
fun CodedOutputStream.serializeIdSignature(signature: IdSignature) =
|
||||
writeIdSignature(signature) { signatureToIndexMapping[it] ?: signatureToIndexMappingSaved[it] }
|
||||
|
||||
headerCacheFile.useCodedOutput {
|
||||
fun writeDepends(depends: KotlinSourceFileMap<Set<IdSignature>>) {
|
||||
@@ -235,7 +233,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
dependencySrcFile.toProtoStream(this)
|
||||
writeInt32NoTag(signatures.size)
|
||||
for (signature in signatures) {
|
||||
writeInt32NoTag(serializeSignature(signature))
|
||||
serializeIdSignature(signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,7 +244,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) {
|
||||
|
||||
writeInt32NoTag(sourceFileMetadata.importedInlineFunctions.size)
|
||||
for ((signature, transitiveHash) in sourceFileMetadata.importedInlineFunctions) {
|
||||
writeInt32NoTag(serializeSignature(signature))
|
||||
serializeIdSignature(signature)
|
||||
transitiveHash.toProtoStream(this)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -37,7 +38,13 @@ class InlineFunctionTransitiveHashCalculator {
|
||||
if (declaration in flatHashes) {
|
||||
return
|
||||
}
|
||||
flatHashes[declaration] = declaration.irElementHashForIC()
|
||||
|
||||
flatHashes[declaration] = if (declaration.isFakeOverride) {
|
||||
declaration.resolveFakeOverride()?.irElementHashForIC()
|
||||
?: icError("can not resolve fake override for ${declaration.render()}")
|
||||
} else {
|
||||
declaration.irElementHashForIC()
|
||||
}
|
||||
}
|
||||
// go deeper since local inline special declarations (like a reference adaptor) may appear
|
||||
declaration.acceptChildren(this, null)
|
||||
@@ -61,10 +68,7 @@ class InlineFunctionTransitiveHashCalculator {
|
||||
override fun visitCall(expression: IrCall, data: MutableSet<IrFunction>) {
|
||||
val callee = expression.symbol.owner
|
||||
if (callee.isInline) {
|
||||
// TODO: do not ignore fake overrides after KT-51896
|
||||
if (!callee.isFakeOverride) {
|
||||
data += callee
|
||||
}
|
||||
data += callee
|
||||
inlineFunctionCallDepth += 1
|
||||
}
|
||||
expression.acceptChildren(this, data)
|
||||
|
||||
+18
-3
@@ -80,9 +80,24 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/exportsThroughInlineFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("fakeOverride")
|
||||
public void testFakeOverride() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverride/");
|
||||
@TestMetadata("fakeOverrideInheritance")
|
||||
public void testFakeOverrideInheritance() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInheritance/");
|
||||
}
|
||||
|
||||
@TestMetadata("fakeOverrideInlineExtension")
|
||||
public void testFakeOverrideInlineExtension() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineExtension/");
|
||||
}
|
||||
|
||||
@TestMetadata("fakeOverrideInlineFunction")
|
||||
public void testFakeOverrideInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("fakeOverrideInlineProperty")
|
||||
public void testFakeOverrideInlineProperty() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineProperty/");
|
||||
}
|
||||
|
||||
@TestMetadata("fastPath1")
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun funA() = "a-0"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun funA() = "a-1"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
abstract class AbstractClassB : AbstractClassA() {
|
||||
inline fun funB() = "b-0 ${funA()}"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
abstract class AbstractClassB : AbstractClassA() {
|
||||
inline fun funB() = "b-2"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
abstract class AbstractClassC : AbstractClassB() {
|
||||
inline fun funC() = "c-0 ${funB()}"
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
STEP 0:
|
||||
modifications:
|
||||
U : A.0.kt -> A.kt
|
||||
U : B.0.kt -> B.kt
|
||||
U : C.0.kt -> C.kt
|
||||
added file: A.kt, B.kt, C.kt
|
||||
STEP 1:
|
||||
modifications:
|
||||
U : A.1.kt -> A.kt
|
||||
modified ir: A.kt
|
||||
updated inline imports: B.kt, C.kt
|
||||
STEP 2:
|
||||
modifications:
|
||||
U : B.2.kt -> B.kt
|
||||
modified ir: B.kt
|
||||
updated inline imports: C.kt
|
||||
STEP 3:
|
||||
modifications:
|
||||
U : A.0.kt -> A.kt
|
||||
modified ir: A.kt
|
||||
STEP 4:
|
||||
modifications:
|
||||
U : B.0.kt -> B.kt
|
||||
modified ir: B.kt
|
||||
updated inline imports: C.kt
|
||||
STEP 5:
|
||||
modifications:
|
||||
U : A.1.kt -> A.kt
|
||||
modified ir: A.kt
|
||||
updated inline imports: B.kt, C.kt
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
class ClassABC: AbstractClassC() {
|
||||
inline fun testA() = funA()
|
||||
inline fun testB() = funB()
|
||||
inline fun testC() = funC()
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
fun box(stepId: Int): String {
|
||||
val a = ClassABC()
|
||||
when (stepId) {
|
||||
0, 4 -> {
|
||||
if (a.testA() != "a-0") return "Fail testA()"
|
||||
if (a.testB() != "b-0 a-0") return "Fail testB()"
|
||||
if (a.testC() != "c-0 b-0 a-0") return "Fail testC()"
|
||||
}
|
||||
1, 5 -> {
|
||||
if (a.testA() != "a-1") return "Fail testA()"
|
||||
if (a.testB() != "b-0 a-1") return "Fail testB()"
|
||||
if (a.testC() != "c-0 b-0 a-1") return "Fail testC()"
|
||||
}
|
||||
2 -> {
|
||||
if (a.testA() != "a-1") return "Fail testA()"
|
||||
if (a.testB() != "b-2") return "Fail testB()"
|
||||
if (a.testC() != "c-0 b-2") return "Fail testC()"
|
||||
}
|
||||
3 -> {
|
||||
if (a.testA() != "a-0") return "Fail testA()"
|
||||
if (a.testB() != "b-2") return "Fail testB()"
|
||||
if (a.testC() != "c-0 b-2") return "Fail testC()"
|
||||
}
|
||||
else -> return "Unknown"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
STEP 0:
|
||||
dependencies: lib1
|
||||
added file: m.kt, classABC.kt
|
||||
STEP 1..5:
|
||||
dependencies: lib1
|
||||
updated inline imports: m.kt, classABC.kt
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
MODULES: lib1, main
|
||||
|
||||
STEP 0:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
STEP 1..5:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun String.fakeOverrideExtension() = "${this} fakeOverrideExtension 0"
|
||||
|
||||
inline val String.fakeOverrideGetProperty
|
||||
get() = "${this} fakeOverrideGetProperty 0"
|
||||
|
||||
inline var String.fakeOverrideSetProperty: String
|
||||
get() = "${savedString} fakeOverrideSetProperty getter 0"
|
||||
set(str) {
|
||||
savedString = "${str} fakeOverrideSetProperty setter 0"
|
||||
}
|
||||
|
||||
var savedString = ""
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun String.fakeOverrideExtension() = "${this} fakeOverrideExtension 1"
|
||||
|
||||
inline val String.fakeOverrideGetProperty
|
||||
get() = "${this} fakeOverrideGetProperty 0"
|
||||
|
||||
inline var String.fakeOverrideSetProperty: String
|
||||
get() = "${savedString} fakeOverrideSetProperty getter 0"
|
||||
set(str) {
|
||||
savedString = "${str} fakeOverrideSetProperty setter 0"
|
||||
}
|
||||
|
||||
var savedString = ""
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun String.fakeOverrideExtension() = "${this} fakeOverrideExtension 1"
|
||||
|
||||
inline val String.fakeOverrideGetProperty
|
||||
get() = "${this} fakeOverrideGetProperty 2"
|
||||
|
||||
inline var String.fakeOverrideSetProperty: String
|
||||
get() = "${savedString} fakeOverrideSetProperty getter 0"
|
||||
set(str) {
|
||||
savedString = "${str} fakeOverrideSetProperty setter 0"
|
||||
}
|
||||
|
||||
var savedString = ""
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun String.fakeOverrideExtension() = "${this} fakeOverrideExtension 1"
|
||||
|
||||
inline val String.fakeOverrideGetProperty
|
||||
get() = "${this} fakeOverrideGetProperty 2"
|
||||
|
||||
inline var String.fakeOverrideSetProperty: String
|
||||
get() = "${savedString} fakeOverrideSetProperty getter 0"
|
||||
set(str) {
|
||||
savedString = "${str} fakeOverrideSetProperty setter 3"
|
||||
}
|
||||
|
||||
var savedString = "empty"
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
abstract class AbstractClassA {
|
||||
inline fun String.fakeOverrideExtension() = "${this} fakeOverrideExtension 1"
|
||||
|
||||
inline val String.fakeOverrideGetProperty
|
||||
get() = "${this} fakeOverrideGetProperty 2"
|
||||
|
||||
inline var String.fakeOverrideSetProperty: String
|
||||
get() = "${savedString} fakeOverrideSetProperty getter 4"
|
||||
set(str) {
|
||||
savedString = "${str} fakeOverrideSetProperty setter 3"
|
||||
}
|
||||
|
||||
var savedString = ""
|
||||
}
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
STEP 0:
|
||||
modifications:
|
||||
U : l1.0.kt -> l1.kt
|
||||
added file: l1.kt
|
||||
STEP 1:
|
||||
modifications:
|
||||
U : l1.1.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
STEP 2:
|
||||
modifications:
|
||||
U : l1.2.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
STEP 3:
|
||||
modifications:
|
||||
U : l1.3.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
STEP 4:
|
||||
modifications:
|
||||
U : l1.4.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
class ClassA: AbstractClassA() {
|
||||
inline fun testExtension() = "testExtension".fakeOverrideExtension()
|
||||
inline fun testGetProperty() = "testGetProperty".fakeOverrideGetProperty
|
||||
|
||||
inline fun testSetPropertySetter(): String {
|
||||
"test".fakeOverrideSetProperty = "testSetPropertySetter"
|
||||
return savedString;
|
||||
}
|
||||
|
||||
inline fun testSetPropertyGetter() = "test".fakeOverrideSetProperty
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fun box(stepId: Int): String {
|
||||
val a = ClassA()
|
||||
when (stepId) {
|
||||
0 -> {
|
||||
if (a.testExtension() != "testExtension fakeOverrideExtension 0") return "Fail extension"
|
||||
if (a.testGetProperty() != "testGetProperty fakeOverrideGetProperty 0") return "Fail getProperty"
|
||||
if (a.testSetPropertySetter() != "testSetPropertySetter fakeOverrideSetProperty setter 0") return "Fail setPropertySetter"
|
||||
if (a.testSetPropertyGetter() != "testSetPropertySetter fakeOverrideSetProperty setter 0 fakeOverrideSetProperty getter 0") return a.testSetPropertyGetter()
|
||||
}
|
||||
1 -> {
|
||||
if (a.testExtension() != "testExtension fakeOverrideExtension 1") return "Fail extension"
|
||||
if (a.testGetProperty() != "testGetProperty fakeOverrideGetProperty 0") return "Fail getProperty"
|
||||
if (a.testSetPropertySetter() != "testSetPropertySetter fakeOverrideSetProperty setter 0") return "Fail setPropertySetter"
|
||||
if (a.testSetPropertyGetter() != "testSetPropertySetter fakeOverrideSetProperty setter 0 fakeOverrideSetProperty getter 0") return a.testSetPropertyGetter()
|
||||
}
|
||||
2 -> {
|
||||
if (a.testExtension() != "testExtension fakeOverrideExtension 1") return "Fail extension"
|
||||
if (a.testGetProperty() != "testGetProperty fakeOverrideGetProperty 2") return "Fail getProperty"
|
||||
if (a.testSetPropertySetter() != "testSetPropertySetter fakeOverrideSetProperty setter 0") return "Fail setPropertySetter"
|
||||
if (a.testSetPropertyGetter() != "testSetPropertySetter fakeOverrideSetProperty setter 0 fakeOverrideSetProperty getter 0") return a.testSetPropertyGetter()
|
||||
}
|
||||
3 -> {
|
||||
if (a.testExtension() != "testExtension fakeOverrideExtension 1") return "Fail extension"
|
||||
if (a.testGetProperty() != "testGetProperty fakeOverrideGetProperty 2") return "Fail getProperty"
|
||||
if (a.testSetPropertySetter() != "testSetPropertySetter fakeOverrideSetProperty setter 3") return "Fail setPropertySetter"
|
||||
if (a.testSetPropertyGetter() != "testSetPropertySetter fakeOverrideSetProperty setter 3 fakeOverrideSetProperty getter 0") return a.testSetPropertyGetter()
|
||||
}
|
||||
4 -> {
|
||||
if (a.testExtension() != "testExtension fakeOverrideExtension 1") return "Fail extension"
|
||||
if (a.testGetProperty() != "testGetProperty fakeOverrideGetProperty 2") return "Fail getProperty"
|
||||
if (a.testSetPropertySetter() != "testSetPropertySetter fakeOverrideSetProperty setter 3") return "Fail setPropertySetter"
|
||||
if (a.testSetPropertyGetter() != "testSetPropertySetter fakeOverrideSetProperty setter 3 fakeOverrideSetProperty getter 4") return a.testSetPropertyGetter()
|
||||
}
|
||||
else -> return "Unknown"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
STEP 0:
|
||||
dependencies: lib1
|
||||
added file: m.kt, classA.kt
|
||||
STEP 1..4:
|
||||
dependencies: lib1
|
||||
updated inline imports: m.kt, classA.kt
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
MODULES: lib1, main
|
||||
|
||||
STEP 0:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
STEP 1..4:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
STEP 0:
|
||||
dependencies: lib1
|
||||
added file: l2.kt
|
||||
STEP 1..2:
|
||||
STEP 1:
|
||||
dependencies: lib1
|
||||
updated inline imports: l2.kt
|
||||
STEP 2:
|
||||
dependencies: lib1
|
||||
+4
-4
@@ -23,12 +23,12 @@ fun box(stepId: Int): String {
|
||||
if (callIt(b::fakeOverrideFunction) != 0) return "Fail 0-6"
|
||||
}
|
||||
1 -> {
|
||||
if (a.test2() != null) return "Fail 1-1" // TODO: test2() must return "OTHER 2", should be fixed in KT-51896
|
||||
if (b.test2() != null) return "Fail 1-2" // TODO: test2() must return "OTHER 1", should be fixed in KT-51896
|
||||
if (a.test2() != "OTHER 2") return "Fail 1-1"
|
||||
if (b.test2() != "OTHER 1") return "Fail 1-2"
|
||||
}
|
||||
2 -> {
|
||||
if (a.fakeOverrideFunction() != 0) return "Fail 2-1" // TODO: fakeOverrideFunction() must return 2, should be fixed in KT-51896
|
||||
if (b.fakeOverrideFunction() != 0) return "Fail 2-2" // TODO: fakeOverrideFunction() must return 2, should be fixed in KT-51896
|
||||
if (a.fakeOverrideFunction() != 2) return "Fail 2-1"
|
||||
if (b.fakeOverrideFunction() != 2) return "Fail 2-2"
|
||||
|
||||
if (callIt(a::fakeOverrideFunction) != 2) return "Fail 2-3"
|
||||
if (callIt(b::fakeOverrideFunction) != 2) return "Fail 2-4"
|
||||
+1
@@ -3,3 +3,4 @@ STEP 0:
|
||||
added file: m.kt
|
||||
STEP 1..2:
|
||||
dependencies: lib1, lib2
|
||||
updated inline imports: m.kt
|
||||
+5
-2
@@ -3,6 +3,9 @@ MODULES: lib1, lib2, main
|
||||
STEP 0:
|
||||
libs: lib1, lib2, main
|
||||
dirty js: lib1, lib2, main
|
||||
STEP 1..2:
|
||||
STEP 1:
|
||||
libs: lib1, lib2, main
|
||||
dirty js: lib1
|
||||
dirty js: lib1, lib2, main
|
||||
STEP 2:
|
||||
libs: lib1, lib2, main
|
||||
dirty js: lib1, main
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
abstract class AbstractClassA {
|
||||
inline val propertyWithGetter: String
|
||||
get() = "0"
|
||||
|
||||
inline var propertyWithSetter: String
|
||||
get() = savedStr
|
||||
set(str) {
|
||||
savedStr = "$str 0"
|
||||
}
|
||||
|
||||
var savedStr = "empty"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
abstract class AbstractClassA {
|
||||
inline val propertyWithGetter: String
|
||||
get() = "1"
|
||||
|
||||
inline var propertyWithSetter: String
|
||||
get() = savedStr
|
||||
set(str) {
|
||||
savedStr = "$str 0"
|
||||
}
|
||||
|
||||
var savedStr = "empty"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
abstract class AbstractClassA {
|
||||
inline val propertyWithGetter: String
|
||||
get() = "1"
|
||||
|
||||
inline var propertyWithSetter: String
|
||||
get() = savedStr
|
||||
set(str) {
|
||||
savedStr = "$str 2"
|
||||
}
|
||||
|
||||
var savedStr = "empty"
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
STEP 0:
|
||||
modifications:
|
||||
U : l1.0.kt -> l1.kt
|
||||
added file: l1.kt
|
||||
STEP 1:
|
||||
modifications:
|
||||
U : l1.1.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
STEP 2:
|
||||
modifications:
|
||||
U : l1.2.kt -> l1.kt
|
||||
modified ir: l1.kt
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
class ClassA: AbstractClassA() {
|
||||
inline fun testPropertyWithGetter() = propertyWithGetter
|
||||
|
||||
inline fun testPropertyWithSetter(): String {
|
||||
propertyWithSetter = "test"
|
||||
return savedStr
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
fun box(stepId: Int): String {
|
||||
val a = ClassA()
|
||||
when (stepId) {
|
||||
0 -> {
|
||||
if (a.testPropertyWithGetter() != "0") return "Fail testPropertyWithGetter()"
|
||||
if (a.testPropertyWithSetter() != "test 0") return "Fail testPropertyWithSetter()"
|
||||
}
|
||||
1 -> {
|
||||
if (a.testPropertyWithGetter() != "1") return "Fail testPropertyWithGetter()"
|
||||
if (a.testPropertyWithSetter() != "test 0") return "Fail testPropertyWithSetter()"
|
||||
}
|
||||
2 -> {
|
||||
if (a.testPropertyWithGetter() != "1") return "Fail testPropertyWithGetter()"
|
||||
if (a.testPropertyWithSetter() != "test 2") return "Fail testPropertyWithSetter()"
|
||||
}
|
||||
else -> return "Unknown"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
STEP 0:
|
||||
dependencies: lib1
|
||||
added file: m.kt, classA.kt
|
||||
STEP 1..2:
|
||||
dependencies: lib1
|
||||
updated inline imports: m.kt, classA.kt
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
MODULES: lib1, main
|
||||
|
||||
STEP 0:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
STEP 1..2:
|
||||
libs: lib1, main
|
||||
dirty js: lib1, main
|
||||
Reference in New Issue
Block a user