[JS IR] IC improvements
- Reuse a built fragment - Use cache for saving built JS code
This commit is contained in:
committed by
Space
parent
f8ae097e50
commit
9952d43252
@@ -286,23 +286,22 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
messageCollector.report(INFO, arguments.cacheDirectories ?: "")
|
messageCollector.report(INFO, arguments.cacheDirectories ?: "")
|
||||||
|
|
||||||
if (icCaches.isNotEmpty()) {
|
if (icCaches.isNotEmpty()) {
|
||||||
|
|
||||||
val beforeIc2Js = System.currentTimeMillis()
|
val beforeIc2Js = System.currentTimeMillis()
|
||||||
|
|
||||||
val moduleKind = configurationJs[JSConfigurationKeys.MODULE_KIND]!!
|
val jsExecutableProducer = JsExecutableProducer(
|
||||||
|
mainModuleName = moduleName,
|
||||||
val translationMode = TranslationMode.fromFlags(false, arguments.irPerModule, false)
|
moduleKind = configurationJs[JSConfigurationKeys.MODULE_KIND]!!,
|
||||||
|
sourceMapsInfo = SourceMapsInfo.from(configurationJs),
|
||||||
val compiledModule = generateJsFromAst(
|
caches = icCaches,
|
||||||
moduleName,
|
|
||||||
moduleKind,
|
|
||||||
SourceMapsInfo.from(configurationJs),
|
|
||||||
setOf(translationMode),
|
|
||||||
icCaches,
|
|
||||||
relativeRequirePath = true
|
relativeRequirePath = true
|
||||||
)
|
)
|
||||||
|
|
||||||
val outputs = compiledModule.outputs.values.single()
|
val outputs = jsExecutableProducer.buildExecutable(
|
||||||
|
multiModule = arguments.irPerModule,
|
||||||
|
rebuildCallback = { rebuiltModule ->
|
||||||
|
messageCollector.report(INFO, "IC module builder rebuilt module [${File(rebuiltModule).name}]")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
outputFile.write(outputs)
|
outputFile.write(outputs)
|
||||||
outputs.dependencies.forEach { (name, content) ->
|
outputs.dependencies.forEach { (name, content) ->
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaserState
|
|||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ic.ArtifactCache
|
import org.jetbrains.kotlin.ir.backend.js.ic.ArtifactCache
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ic.KLibArtifact
|
import org.jetbrains.kotlin.ir.backend.js.ic.JsMultiModuleCache
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ic.ModuleArtifact
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors
|
||||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||||
@@ -25,7 +24,6 @@ import org.jetbrains.kotlin.ir.util.noUnboundLeft
|
|||||||
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
|
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||||
@@ -99,9 +97,11 @@ fun compileWithIC(
|
|||||||
module.files.filter { it.fileEntry.name in dirties }
|
module.files.filter { it.fileEntry.name in dirties }
|
||||||
} ?: module.files
|
} ?: module.files
|
||||||
|
|
||||||
val ast = transformer.generateBinaryAst(dirtyFiles, allModules)
|
val astAndFragments = transformer.generateBinaryAst(dirtyFiles, allModules)
|
||||||
|
astAndFragments.forEach {
|
||||||
ast.entries.forEach { (path, bytes) -> artifactCache.saveBinaryAst(path, bytes) }
|
artifactCache.saveFragment(it.srcPath, it.fragment)
|
||||||
|
artifactCache.saveBinaryAst(it.srcPath, it.binaryAst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lowerPreservingTags(modules: Iterable<IrModuleFragment>, context: JsIrBackendContext, phaseConfig: PhaseConfig, controller: WholeWorldStageController) {
|
fun lowerPreservingTags(modules: Iterable<IrModuleFragment>, context: JsIrBackendContext, phaseConfig: PhaseConfig, controller: WholeWorldStageController) {
|
||||||
@@ -117,38 +117,3 @@ fun lowerPreservingTags(modules: Iterable<IrModuleFragment>, context: JsIrBacken
|
|||||||
|
|
||||||
controller.currentStage = pirLowerings.size + 1
|
controller.currentStage = pirLowerings.size + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
fun generateJsFromAst(
|
|
||||||
mainModuleName: String,
|
|
||||||
moduleKind: ModuleKind,
|
|
||||||
sourceMapsInfo: SourceMapsInfo?,
|
|
||||||
translationModes: Set<TranslationMode>,
|
|
||||||
caches: List<KLibArtifact>,
|
|
||||||
relativeRequirePath: Boolean = false,
|
|
||||||
): CompilerResult {
|
|
||||||
fun compilationOutput(multiModule: Boolean): CompilationOutputs {
|
|
||||||
val deserializer = JsIrAstDeserializer()
|
|
||||||
val jsIrProgram = JsIrProgram(caches.map { cacheArtifact ->
|
|
||||||
JsIrModule(
|
|
||||||
cacheArtifact.moduleName.safeModuleName,
|
|
||||||
sanitizeName(cacheArtifact.moduleName.safeModuleName),
|
|
||||||
cacheArtifact.fileArtifacts.sortedBy { it.srcFilePath }.mapNotNull { srcFileArtifact ->
|
|
||||||
srcFileArtifact.astFileArtifact.fetchBinaryAst()?.let { deserializer.deserialize(ByteArrayInputStream(it)) }
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return generateWrappedModuleBody(
|
|
||||||
multiModule = multiModule,
|
|
||||||
mainModuleName = mainModuleName,
|
|
||||||
moduleKind = moduleKind,
|
|
||||||
jsIrProgram,
|
|
||||||
sourceMapsInfo = sourceMapsInfo,
|
|
||||||
relativeRequirePath = relativeRequirePath,
|
|
||||||
generateScriptModule = false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return CompilerResult(translationModes.associate { it to compilationOutput(it.perModule) }, null)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,29 +5,52 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrModule
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class SrcFileArtifact(val srcFilePath: String, astArtifactFilePath: String, astBinaryData: ByteArray?) {
|
class SrcFileArtifact(val srcFilePath: String, private val fragment: JsIrProgramFragment?, private val astArtifact: File? = null) {
|
||||||
class Artifact(private val artifactFilePath: String, private var binaryData: ByteArray?) {
|
fun loadJsIrFragment(deserializer: JsIrAstDeserializer): JsIrProgramFragment? {
|
||||||
fun fetchBinaryAst(): ByteArray? {
|
if (fragment != null) {
|
||||||
if (binaryData == null) {
|
return fragment
|
||||||
binaryData = File(artifactFilePath).ifExists { readBytes() }
|
}
|
||||||
}
|
return astArtifact?.ifExists { readBytes() }?.let {
|
||||||
return binaryData
|
deserializer.deserialize(ByteArrayInputStream(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val astFileArtifact = Artifact(astArtifactFilePath, astBinaryData)
|
fun isModified() = fragment != null
|
||||||
}
|
}
|
||||||
|
|
||||||
class KLibArtifact(val moduleName: String, val fileArtifacts: List<SrcFileArtifact>)
|
class ModuleArtifact(
|
||||||
|
moduleName: String,
|
||||||
|
val fileArtifacts: List<SrcFileArtifact>,
|
||||||
|
val artifactsDir: File? = null,
|
||||||
|
val forceRebuildJs: Boolean = false
|
||||||
|
) {
|
||||||
|
val moduleSafeName = moduleName.safeModuleName
|
||||||
|
|
||||||
|
fun loadJsIrModule(): JsIrModule {
|
||||||
|
val deserializer = JsIrAstDeserializer()
|
||||||
|
val fragments = fileArtifacts.sortedBy { it.srcFilePath }.mapNotNull { it.loadJsIrFragment(deserializer) }
|
||||||
|
return JsIrModule(moduleSafeName, moduleSafeName, fragments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ArtifactCache {
|
abstract class ArtifactCache {
|
||||||
protected val binaryAsts = mutableMapOf<String, ByteArray>()
|
protected val binaryAsts = mutableMapOf<String, ByteArray>()
|
||||||
|
protected val fragments = mutableMapOf<String, JsIrProgramFragment>()
|
||||||
|
|
||||||
fun saveBinaryAst(srcPath: String, astData: ByteArray) {
|
fun saveBinaryAst(srcPath: String, binaryAst: ByteArray) {
|
||||||
binaryAsts[srcPath] = astData
|
binaryAsts[srcPath] = binaryAst
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun fetchArtifacts(): KLibArtifact
|
fun saveFragment(srcPath: String, fragment: JsIrProgramFragment) {
|
||||||
|
fragments[srcPath] = fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun fetchArtifacts(): ModuleArtifact
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.ic
|
package org.jetbrains.kotlin.ir.backend.js.ic
|
||||||
|
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CrossModuleReferences
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
@@ -99,3 +100,23 @@ internal fun KotlinLibrary.fingerprint(fileIndex: Int) = HashCalculatorForIC().a
|
|||||||
update(declarations(fileIndex))
|
update(declarations(fileIndex))
|
||||||
update(bodies(fileIndex))
|
update(bodies(fileIndex))
|
||||||
}.finalize()
|
}.finalize()
|
||||||
|
|
||||||
|
internal fun CrossModuleReferences.crossModuleReferencesHashForIC() = HashCalculatorForIC().apply {
|
||||||
|
for (importedModule in importedModules) {
|
||||||
|
update(importedModule.externalName)
|
||||||
|
update(importedModule.internalName.toString())
|
||||||
|
}
|
||||||
|
for (exportFrom in transitiveJsExportFrom) {
|
||||||
|
update(exportFrom.toString())
|
||||||
|
}
|
||||||
|
for (tag in exports.keys.sorted()) {
|
||||||
|
update(tag)
|
||||||
|
update(exports[tag]!!)
|
||||||
|
}
|
||||||
|
for (tag in imports.keys.sorted()) {
|
||||||
|
val import = imports[tag]!!
|
||||||
|
update(tag)
|
||||||
|
update(import.exportedAs)
|
||||||
|
update(import.moduleExporter.toString())
|
||||||
|
}
|
||||||
|
}.finalize()
|
||||||
|
|||||||
+11
-3
@@ -36,6 +36,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) :
|
|||||||
private enum class CacheState { NON_LOADED, FETCHED_FOR_DEPENDENCY, FETCHED_FULL }
|
private enum class CacheState { NON_LOADED, FETCHED_FOR_DEPENDENCY, FETCHED_FULL }
|
||||||
|
|
||||||
private var state = CacheState.NON_LOADED
|
private var state = CacheState.NON_LOADED
|
||||||
|
private var forceRebuildJs = false
|
||||||
|
|
||||||
private val cacheDir = File(cachePath)
|
private val cacheDir = File(cachePath)
|
||||||
private val signatureToIdMapping = mutableMapOf<String, Map<IdSignature, Int>>()
|
private val signatureToIdMapping = mutableMapOf<String, Map<IdSignature, Int>>()
|
||||||
@@ -232,10 +233,12 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) :
|
|||||||
|
|
||||||
private fun clearCacheAfterCommit() {
|
private fun clearCacheAfterCommit() {
|
||||||
state = CacheState.FETCHED_FOR_DEPENDENCY
|
state = CacheState.FETCHED_FOR_DEPENDENCY
|
||||||
|
forceRebuildJs = deletedSrcFiles.isNotEmpty()
|
||||||
signatureToIdMapping.clear()
|
signatureToIdMapping.clear()
|
||||||
usedInlineFunctions.clear()
|
usedInlineFunctions.clear()
|
||||||
srcFilesInOrderFromKLib = emptyList()
|
srcFilesInOrderFromKLib = emptyList()
|
||||||
deletedSrcFiles = emptySet()
|
deletedSrcFiles = emptySet()
|
||||||
|
binaryAsts.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun commitCacheForRemovedSrcFiles() {
|
fun commitCacheForRemovedSrcFiles() {
|
||||||
@@ -255,11 +258,14 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) :
|
|||||||
clearCacheAfterCommit()
|
clearCacheAfterCommit()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchArtifacts() = KLibArtifact(
|
override fun fetchArtifacts() = ModuleArtifact(
|
||||||
moduleName = cacheFastInfo.moduleName ?: error("Internal error: missing module name"),
|
moduleName = cacheFastInfo.moduleName ?: error("Internal error: missing module name"),
|
||||||
fileArtifacts = fingerprints.keys.map {
|
fileArtifacts = fingerprints.keys.map {
|
||||||
SrcFileArtifact(it, getBinaryAstPath(it).absolutePath, binaryAsts[it])
|
SrcFileArtifact(it, fragments[it], getBinaryAstPath(it))
|
||||||
})
|
},
|
||||||
|
artifactsDir = cacheDir,
|
||||||
|
forceRebuildJs = forceRebuildJs
|
||||||
|
)
|
||||||
|
|
||||||
fun invalidate() {
|
fun invalidate() {
|
||||||
cacheDir.deleteRecursively()
|
cacheDir.deleteRecursively()
|
||||||
@@ -268,6 +274,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) :
|
|||||||
usedInlineFunctions.clear()
|
usedInlineFunctions.clear()
|
||||||
fingerprints.clear()
|
fingerprints.clear()
|
||||||
binaryAsts.clear()
|
binaryAsts.clear()
|
||||||
|
fragments.clear()
|
||||||
cacheFastInfo = CacheFastInfo()
|
cacheFastInfo = CacheFastInfo()
|
||||||
srcFilesInOrderFromKLib = emptyList()
|
srcFilesInOrderFromKLib = emptyList()
|
||||||
deletedSrcFiles = emptySet()
|
deletedSrcFiles = emptySet()
|
||||||
@@ -280,6 +287,7 @@ class IncrementalCache(private val library: KotlinLibrary, cachePath: String) :
|
|||||||
usedInlineFunctions.remove(srcPath)
|
usedInlineFunctions.remove(srcPath)
|
||||||
fingerprints.remove(srcPath)
|
fingerprints.remove(srcPath)
|
||||||
binaryAsts.remove(srcPath)
|
binaryAsts.remove(srcPath)
|
||||||
|
fragments.remove(srcPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinLibrary.filesAndSigReaders(): List<Pair<String, IdSignatureDeserializer>> {
|
private fun KotlinLibrary.filesAndSigReaders(): List<Pair<String, IdSignatureDeserializer>> {
|
||||||
|
|||||||
+35
-19
@@ -7,10 +7,13 @@ package org.jetbrains.kotlin.ir.backend.js.ic
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||||
import org.jetbrains.kotlin.ir.util.file
|
import org.jetbrains.kotlin.ir.util.file
|
||||||
|
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
@@ -29,50 +32,63 @@ class InlineFunctionFlatHashBuilder : IrElementVisitorVoid {
|
|||||||
declaration.acceptChildren(this, null)
|
declaration.acceptChildren(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val flatHashes = mutableMapOf<IrSimpleFunction, ICHash>()
|
private val flatHashes = mutableMapOf<IrFunction, ICHash>()
|
||||||
|
|
||||||
fun getFlatHashes() = flatHashes
|
fun getFlatHashes() = flatHashes
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InlineFunctionHashProvider {
|
interface InlineFunctionHashProvider {
|
||||||
fun hashForExternalFunction(declaration: IrSimpleFunction): ICHash?
|
fun hashForExternalFunction(declaration: IrFunction): ICHash?
|
||||||
}
|
}
|
||||||
|
|
||||||
class InlineFunctionHashBuilder(
|
class InlineFunctionHashBuilder(
|
||||||
private val hashProvider: InlineFunctionHashProvider,
|
private val hashProvider: InlineFunctionHashProvider,
|
||||||
private val flatHashes: Map<IrSimpleFunction, ICHash>
|
private val flatHashes: Map<IrFunction, ICHash>
|
||||||
) {
|
) {
|
||||||
private val inlineFunctionCallGraph: MutableMap<IrSimpleFunction, Set<IrSimpleFunction>> = mutableMapOf()
|
private val inlineFunctionCallGraph: MutableMap<IrFunction, Set<IrFunction>> = mutableMapOf()
|
||||||
|
|
||||||
private inner class GraphBuilder : IrElementVisitor<Unit, MutableSet<IrSimpleFunction>> {
|
private inner class GraphBuilder : IrElementVisitor<Unit, MutableSet<IrFunction>> {
|
||||||
|
var inlineFunctionCallDepth: Int = 0
|
||||||
|
|
||||||
override fun visitElement(element: IrElement, data: MutableSet<IrSimpleFunction>) {
|
override fun visitElement(element: IrElement, data: MutableSet<IrFunction>) {
|
||||||
element.acceptChildren(this, data)
|
element.acceptChildren(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: MutableSet<IrSimpleFunction>) {
|
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: MutableSet<IrFunction>) {
|
||||||
val newGraph = mutableSetOf<IrSimpleFunction>()
|
val newGraph = mutableSetOf<IrFunction>()
|
||||||
inlineFunctionCallGraph[declaration] = newGraph
|
inlineFunctionCallGraph[declaration] = newGraph
|
||||||
declaration.acceptChildren(this, newGraph)
|
declaration.acceptChildren(this, newGraph)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall, data: MutableSet<IrFunction>) {
|
||||||
override fun visitCall(expression: IrCall, data: MutableSet<IrSimpleFunction>) {
|
|
||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
|
|
||||||
if (callee.isInline) {
|
if (callee.isInline) {
|
||||||
data.add(callee)
|
data += callee
|
||||||
|
inlineFunctionCallDepth += 1
|
||||||
}
|
}
|
||||||
|
expression.acceptChildren(this, data)
|
||||||
|
if (callee.isInline) {
|
||||||
|
inlineFunctionCallDepth -= 1
|
||||||
|
if (inlineFunctionCallDepth < 0) {
|
||||||
|
error("Internal error: inline function calls depth inconsistency")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionReference(expression: IrFunctionReference, data: MutableSet<IrFunction>) {
|
||||||
|
val reference = expression.symbol.owner
|
||||||
|
if (inlineFunctionCallDepth > 0 && reference.isInline) {
|
||||||
|
data += reference
|
||||||
|
}
|
||||||
expression.acceptChildren(this, data)
|
expression.acceptChildren(this, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class InlineFunctionHashProcessor {
|
private inner class InlineFunctionHashProcessor {
|
||||||
private val computedHashes = mutableMapOf<IrSimpleFunction, ICHash>()
|
private val computedHashes = mutableMapOf<IrFunction, ICHash>()
|
||||||
private val processingFunctions = mutableSetOf<IrSimpleFunction>()
|
private val processingFunctions = mutableSetOf<IrFunction>()
|
||||||
|
|
||||||
private fun processInlineFunction(f: IrSimpleFunction): ICHash = computedHashes.getOrPut(f) {
|
private fun processInlineFunction(f: IrFunction): ICHash = computedHashes.getOrPut(f) {
|
||||||
if (!processingFunctions.add(f)) {
|
if (!processingFunctions.add(f)) {
|
||||||
error("Inline circle through function ${f.render()} detected")
|
error("Inline circle through function ${f.render()} detected")
|
||||||
}
|
}
|
||||||
@@ -86,14 +102,14 @@ class InlineFunctionHashBuilder(
|
|||||||
functionInlineHash
|
functionInlineHash
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processCallee(callee: IrSimpleFunction): ICHash {
|
private fun processCallee(callee: IrFunction): ICHash {
|
||||||
if (callee in flatHashes) {
|
if (callee in flatHashes) {
|
||||||
return processInlineFunction(callee)
|
return processInlineFunction(callee)
|
||||||
}
|
}
|
||||||
return hashProvider.hashForExternalFunction(callee) ?: error("Internal error: No hash found for ${callee.render()}")
|
return hashProvider.hashForExternalFunction(callee) ?: error("Internal error: No hash found for ${callee.render()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun process(): Map<IrSimpleFunction, ICHash> {
|
fun process(): Map<IrFunction, ICHash> {
|
||||||
for ((f, callees) in inlineFunctionCallGraph.entries) {
|
for ((f, callees) in inlineFunctionCallGraph.entries) {
|
||||||
if (f.isInline) {
|
if (f.isInline) {
|
||||||
processInlineFunction(f)
|
processInlineFunction(f)
|
||||||
@@ -105,12 +121,12 @@ class InlineFunctionHashBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildHashes(dirtyFiles: Collection<IrFile>): Map<IrSimpleFunction, ICHash> {
|
fun buildHashes(dirtyFiles: Collection<IrFile>): Map<IrFunction, ICHash> {
|
||||||
dirtyFiles.forEach { it.acceptChildren(GraphBuilder(), mutableSetOf()) }
|
dirtyFiles.forEach { it.acceptChildren(GraphBuilder(), mutableSetOf()) }
|
||||||
return InlineFunctionHashProcessor().process()
|
return InlineFunctionHashProcessor().process()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildInlineGraph(computedHashed: Map<IrSimpleFunction, ICHash>): Map<IrFile, Map<IdSignature, ICHash>> {
|
fun buildInlineGraph(computedHashed: Map<IrFunction, ICHash>): Map<IrFile, Map<IdSignature, ICHash>> {
|
||||||
val perFileInlineGraph = inlineFunctionCallGraph.entries.groupBy({ it.key.file }) {
|
val perFileInlineGraph = inlineFunctionCallGraph.entries.groupBy({ it.key.file }) {
|
||||||
it.value
|
it.value
|
||||||
}
|
}
|
||||||
|
|||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.backend.js.CompilationOutputs
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
|
|
||||||
|
class JsExecutableProducer(
|
||||||
|
private val mainModuleName: String,
|
||||||
|
private val moduleKind: ModuleKind,
|
||||||
|
private val sourceMapsInfo: SourceMapsInfo?,
|
||||||
|
private val caches: List<ModuleArtifact>,
|
||||||
|
private val relativeRequirePath: Boolean
|
||||||
|
) {
|
||||||
|
fun buildExecutable(multiModule: Boolean, rebuildCallback: (String) -> Unit = {}) = if (multiModule) {
|
||||||
|
buildMultiModuleExecutable(rebuildCallback)
|
||||||
|
} else {
|
||||||
|
buildSingleModuleExecutable(rebuildCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildSingleModuleExecutable(rebuildCallback: (String) -> Unit): CompilationOutputs {
|
||||||
|
val program = JsIrProgram(caches.map { cacheArtifact -> cacheArtifact.loadJsIrModule() })
|
||||||
|
val out = generateSingleWrappedModuleBody(
|
||||||
|
moduleName = mainModuleName,
|
||||||
|
moduleKind = moduleKind,
|
||||||
|
fragments = program.modules.flatMap { it.fragments },
|
||||||
|
sourceMapsInfo = sourceMapsInfo,
|
||||||
|
generateScriptModule = false,
|
||||||
|
generateCallToMain = true
|
||||||
|
)
|
||||||
|
rebuildCallback(mainModuleName)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildMultiModuleExecutable(rebuildCallback: (String) -> Unit): CompilationOutputs {
|
||||||
|
val jsMultiModuleCache = JsMultiModuleCache(caches)
|
||||||
|
val cachedProgram = jsMultiModuleCache.loadProgramHeadersFromCache()
|
||||||
|
|
||||||
|
val resolver = CrossModuleDependenciesResolver(cachedProgram.map { it.jsIrHeader })
|
||||||
|
val crossModuleReferences = resolver.resolveCrossModuleDependencies(relativeRequirePath)
|
||||||
|
|
||||||
|
jsMultiModuleCache.loadRequiredJsIrModules(crossModuleReferences)
|
||||||
|
|
||||||
|
fun JsMultiModuleCache.CachedModuleInfo.compileModule(moduleName: String, generateCallToMain: Boolean): CompilationOutputs {
|
||||||
|
if (jsIrHeader.associatedModule == null) {
|
||||||
|
val compilationOutputs = jsMultiModuleCache.fetchCompiledJsCode(artifact)
|
||||||
|
if (compilationOutputs != null) {
|
||||||
|
return compilationOutputs
|
||||||
|
}
|
||||||
|
jsIrHeader.associatedModule = artifact.loadJsIrModule()
|
||||||
|
}
|
||||||
|
val associatedModule = jsIrHeader.associatedModule ?: error("Internal error: cannot load module $moduleName")
|
||||||
|
val crossRef = crossModuleReferences[jsIrHeader] ?: error("Internal error: cannot find cross references for module $moduleName")
|
||||||
|
crossRef.initJsImportsForModule(associatedModule)
|
||||||
|
|
||||||
|
val compiledModule = generateSingleWrappedModuleBody(
|
||||||
|
moduleName = moduleName,
|
||||||
|
moduleKind = moduleKind,
|
||||||
|
associatedModule.fragments,
|
||||||
|
sourceMapsInfo = sourceMapsInfo,
|
||||||
|
generateScriptModule = false,
|
||||||
|
generateCallToMain = generateCallToMain,
|
||||||
|
crossModuleReferences = crossRef
|
||||||
|
)
|
||||||
|
jsMultiModuleCache.commitCompiledJsCode(artifact, compiledModule)
|
||||||
|
rebuildCallback(moduleName)
|
||||||
|
return compiledModule
|
||||||
|
}
|
||||||
|
|
||||||
|
val cachedMainModule = cachedProgram.last()
|
||||||
|
val mainModule = cachedMainModule.compileModule(mainModuleName, true)
|
||||||
|
|
||||||
|
val cachedOtherModules = cachedProgram.dropLast(1)
|
||||||
|
val dependencies = cachedOtherModules.map {
|
||||||
|
it.jsIrHeader.externalModuleName to it.compileModule(it.jsIrHeader.externalModuleName, false)
|
||||||
|
}
|
||||||
|
return CompilationOutputs(mainModule.jsCode, mainModule.jsProgram, mainModule.sourceMap, dependencies)
|
||||||
|
}
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* 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.backend.js.CompilationOutputs
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CrossModuleReferences
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrModuleHeader
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class JsMultiModuleCache(private val moduleArtifacts: List<ModuleArtifact>) {
|
||||||
|
companion object {
|
||||||
|
private const val cacheModuleHeader = "cache.module.header.info"
|
||||||
|
private const val cacheJsModuleFile = "cache.module.js"
|
||||||
|
private const val cacheJsMapModuleFile = "cache.module.js.map"
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class NameType(val typeMask: Int) {
|
||||||
|
DEFINITIONS(0b01), NAME_BINDINGS(0b10)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CachedModuleInfo(val artifact: ModuleArtifact, val jsIrHeader: JsIrModuleHeader, var crossModuleReferencesHash: ICHash = ICHash())
|
||||||
|
|
||||||
|
private val headerToCachedInfo = mutableMapOf<JsIrModuleHeader, CachedModuleInfo>()
|
||||||
|
|
||||||
|
private fun ModuleArtifact.fetchModuleInfo() = File(artifactsDir, cacheModuleHeader).useCodedInputIfExists {
|
||||||
|
val definitions = mutableSetOf<String>()
|
||||||
|
val nameBindings = mutableMapOf<String, String>()
|
||||||
|
|
||||||
|
val crossModuleReferencesHash = ICHash.fromProtoStream(this)
|
||||||
|
val hasJsExports = readBool()
|
||||||
|
repeat(readInt32()) {
|
||||||
|
val tag = readString()
|
||||||
|
val mask = readInt32()
|
||||||
|
if (mask and NameType.DEFINITIONS.typeMask != 0) {
|
||||||
|
definitions += tag
|
||||||
|
}
|
||||||
|
if (mask and NameType.NAME_BINDINGS.typeMask != 0) {
|
||||||
|
nameBindings[tag] = readString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CachedModuleInfo(
|
||||||
|
artifact = this@fetchModuleInfo,
|
||||||
|
jsIrHeader = JsIrModuleHeader(moduleSafeName, moduleSafeName, definitions, nameBindings, hasJsExports, null),
|
||||||
|
crossModuleReferencesHash = crossModuleReferencesHash
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CachedModuleInfo.commitModuleInfo() = artifact.artifactsDir?.let { cacheDir ->
|
||||||
|
File(cacheDir, cacheModuleHeader).useCodedOutput {
|
||||||
|
val names = mutableMapOf<String, Pair<Int, String?>>()
|
||||||
|
for ((tag, name) in jsIrHeader.nameBindings) {
|
||||||
|
names[tag] = NameType.NAME_BINDINGS.typeMask to name
|
||||||
|
}
|
||||||
|
for (tag in jsIrHeader.definitions) {
|
||||||
|
val maskAndName = names[tag]
|
||||||
|
names[tag] = ((maskAndName?.first ?: 0) or NameType.DEFINITIONS.typeMask) to maskAndName?.second
|
||||||
|
}
|
||||||
|
crossModuleReferencesHash.toProtoStream(this)
|
||||||
|
writeBoolNoTag(jsIrHeader.hasJsExports)
|
||||||
|
writeInt32NoTag(names.size)
|
||||||
|
for ((tag, maskAndName) in names) {
|
||||||
|
writeStringNoTag(tag)
|
||||||
|
writeInt32NoTag(maskAndName.first)
|
||||||
|
if (maskAndName.second != null) {
|
||||||
|
writeStringNoTag(maskAndName.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchCompiledJsCode(artifact: ModuleArtifact) = artifact.artifactsDir?.let { cacheDir ->
|
||||||
|
val jsCode = File(cacheDir, cacheJsModuleFile).ifExists { readText() }
|
||||||
|
val sourceMap = File(cacheDir, cacheJsMapModuleFile).ifExists { readText() }
|
||||||
|
jsCode?.let { CompilationOutputs(it, null, sourceMap) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun commitCompiledJsCode(artifact: ModuleArtifact, compilationOutputs: CompilationOutputs) = artifact.artifactsDir?.let { cacheDir ->
|
||||||
|
val jsCodeCache = File(cacheDir, cacheJsModuleFile).apply { recreate() }
|
||||||
|
jsCodeCache.writeText(compilationOutputs.jsCode)
|
||||||
|
val jsMapCache = File(cacheDir, cacheJsMapModuleFile)
|
||||||
|
if (compilationOutputs.sourceMap != null) {
|
||||||
|
jsMapCache.recreate()
|
||||||
|
jsMapCache.writeText(compilationOutputs.sourceMap)
|
||||||
|
} else {
|
||||||
|
jsMapCache.ifExists { delete() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadProgramHeadersFromCache(): List<CachedModuleInfo> {
|
||||||
|
return moduleArtifacts.map { artifact ->
|
||||||
|
fun loadModuleInfo() = CachedModuleInfo(artifact, artifact.loadJsIrModule().makeModuleHeader())
|
||||||
|
val actualInfo = when {
|
||||||
|
artifact.forceRebuildJs -> loadModuleInfo()
|
||||||
|
artifact.fileArtifacts.any { it.isModified() } -> loadModuleInfo()
|
||||||
|
else -> artifact.fetchModuleInfo() ?: loadModuleInfo()
|
||||||
|
}
|
||||||
|
headerToCachedInfo[actualInfo.jsIrHeader] = actualInfo
|
||||||
|
actualInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadRequiredJsIrModules(crossModuleReferences: Map<JsIrModuleHeader, CrossModuleReferences>) {
|
||||||
|
for ((header, references) in crossModuleReferences) {
|
||||||
|
val cachedInfo = headerToCachedInfo[header] ?: error("Internal error: cannot find artifact for module ${header.moduleName}")
|
||||||
|
val actualCrossModuleHash = references.crossModuleReferencesHashForIC()
|
||||||
|
if (header.associatedModule == null && cachedInfo.crossModuleReferencesHash != actualCrossModuleHash) {
|
||||||
|
header.associatedModule = cachedInfo.artifact.loadJsIrModule()
|
||||||
|
}
|
||||||
|
header.associatedModule?.let {
|
||||||
|
cachedInfo.crossModuleReferencesHash = actualCrossModuleHash
|
||||||
|
cachedInfo.commitModuleInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ internal fun File.recreate() {
|
|||||||
createNewFile()
|
createNewFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun File.useCodedInputIfExists(f: CodedInputStream.() -> Unit) = ifExists {
|
internal inline fun <T> File.useCodedInputIfExists(f: CodedInputStream.() -> T) = ifExists {
|
||||||
CodedInputStream.newInstance(FileInputStream(this)).f()
|
CodedInputStream.newInstance(FileInputStream(this)).f()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.*
|
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.lower.serialization.ir.JsIrLinker
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
@@ -144,7 +144,7 @@ class CacheUpdater(
|
|||||||
}.getFlatHashes()
|
}.getFlatHashes()
|
||||||
|
|
||||||
val hashProvider = object : InlineFunctionHashProvider {
|
val hashProvider = object : InlineFunctionHashProvider {
|
||||||
override fun hashForExternalFunction(declaration: IrSimpleFunction): ICHash? {
|
override fun hashForExternalFunction(declaration: IrFunction): ICHash? {
|
||||||
return declaration.symbol.signature?.let { cleanInlineHashes[it] }
|
return declaration.symbol.signature?.let { cleanInlineHashes[it] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ class CacheUpdater(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun actualizeCaches(callback: (CacheUpdateStatus, String) -> Unit): List<KLibArtifact> {
|
fun actualizeCaches(callback: (CacheUpdateStatus, String) -> Unit): List<ModuleArtifact> {
|
||||||
val libraries = loadLibraries()
|
val libraries = loadLibraries()
|
||||||
val dependencyGraph = buildDependenciesGraph(libraries)
|
val dependencyGraph = buildDependenciesGraph(libraries)
|
||||||
val configHash = compilerConfiguration.configHashForIC()
|
val configHash = compilerConfiguration.configHashForIC()
|
||||||
|
|||||||
+8
-10
@@ -125,7 +125,9 @@ class IrModuleToJsTransformerTmp(
|
|||||||
return CompilerResult(result, dts)
|
return CompilerResult(result, dts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateBinaryAst(files: Iterable<IrFile>, allModules: Iterable<IrModuleFragment>): Map<String, ByteArray> {
|
class SrcFileFragmentAndBinaryAst(val srcPath: String, val fragment: JsIrProgramFragment, val binaryAst: ByteArray)
|
||||||
|
|
||||||
|
fun generateBinaryAst(files: Iterable<IrFile>, allModules: Iterable<IrModuleFragment>): List<SrcFileFragmentAndBinaryAst> {
|
||||||
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
|
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
|
||||||
|
|
||||||
val exportData = files.associate { file ->
|
val exportData = files.associate { file ->
|
||||||
@@ -139,18 +141,14 @@ class IrModuleToJsTransformerTmp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val serializer = JsIrAstSerializer()
|
val serializer = JsIrAstSerializer()
|
||||||
|
return files.map { f ->
|
||||||
val result = mutableMapOf<String, ByteArray>()
|
|
||||||
files.forEach { f ->
|
|
||||||
val exports = exportData[f]!! // TODO
|
val exports = exportData[f]!! // TODO
|
||||||
val fragment = generateProgramFragment(f, exports, minimizedMemberNames = false)
|
val fragment = generateProgramFragment(f, exports, minimizedMemberNames = false)
|
||||||
val output = ByteArrayOutputStream()
|
val output = ByteArrayOutputStream()
|
||||||
serializer.serialize(fragment, output)
|
serializer.serialize(fragment, output)
|
||||||
val binaryAst = output.toByteArray()
|
val binaryAst = output.toByteArray()
|
||||||
result[f.fileEntry.name] = binaryAst
|
SrcFileFragmentAndBinaryAst(f.fileEntry.name, fragment, binaryAst)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExportModelGenerator.generateExportWithExternals(irFile: IrFile): List<ExportedDeclaration> {
|
private fun ExportModelGenerator.generateExportWithExternals(irFile: IrFile): List<ExportedDeclaration> {
|
||||||
@@ -330,7 +328,7 @@ class IrModuleToJsTransformerTmp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateWrappedModuleBody(
|
private fun generateWrappedModuleBody(
|
||||||
multiModule: Boolean,
|
multiModule: Boolean,
|
||||||
mainModuleName: String,
|
mainModuleName: String,
|
||||||
moduleKind: ModuleKind,
|
moduleKind: ModuleKind,
|
||||||
@@ -383,7 +381,7 @@ fun generateWrappedModuleBody(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateSingleWrappedModuleBody(
|
fun generateSingleWrappedModuleBody(
|
||||||
moduleName: String,
|
moduleName: String,
|
||||||
moduleKind: ModuleKind,
|
moduleKind: ModuleKind,
|
||||||
fragments: List<JsIrProgramFragment>,
|
fragments: List<JsIrProgramFragment>,
|
||||||
@@ -458,4 +456,4 @@ class SourceMapsInfo(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+97
-60
@@ -27,111 +27,148 @@ class JsIrProgramFragment(val packageFqn: String) {
|
|||||||
class JsIrModule(
|
class JsIrModule(
|
||||||
val moduleName: String,
|
val moduleName: String,
|
||||||
val externalModuleName: String,
|
val externalModuleName: String,
|
||||||
val fragments: List<JsIrProgramFragment>,
|
val fragments: List<JsIrProgramFragment>
|
||||||
)
|
) {
|
||||||
|
fun makeModuleHeader(): JsIrModuleHeader {
|
||||||
|
val nameBindings = mutableMapOf<String, String>()
|
||||||
|
val definitions = mutableSetOf<String>()
|
||||||
|
var hasJsExports = false
|
||||||
|
for (fragment in fragments) {
|
||||||
|
hasJsExports = hasJsExports || !fragment.exports.isEmpty
|
||||||
|
for ((tag, name) in fragment.nameBindings.entries) {
|
||||||
|
nameBindings[tag] = name.toString()
|
||||||
|
}
|
||||||
|
definitions += fragment.definitions
|
||||||
|
}
|
||||||
|
return JsIrModuleHeader(moduleName, externalModuleName, definitions, nameBindings, hasJsExports, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsIrModuleHeader(
|
||||||
|
val moduleName: String,
|
||||||
|
val externalModuleName: String,
|
||||||
|
val definitions: Set<String>,
|
||||||
|
val nameBindings: Map<String, String>,
|
||||||
|
val hasJsExports: Boolean,
|
||||||
|
var associatedModule: JsIrModule?
|
||||||
|
) {
|
||||||
|
val externalNames: Set<String> by lazy { nameBindings.keys - definitions }
|
||||||
|
}
|
||||||
|
|
||||||
class JsIrProgram(val modules: List<JsIrModule>) {
|
class JsIrProgram(val modules: List<JsIrModule>) {
|
||||||
val mainModule = modules.last()
|
val mainModule = modules.last()
|
||||||
val otherModules = modules.dropLast(1)
|
val otherModules = modules.dropLast(1)
|
||||||
|
|
||||||
fun crossModuleDependencies(relativeRequirePath: Boolean): Map<JsIrModule, CrossModuleReferences> {
|
fun crossModuleDependencies(relativeRequirePath: Boolean): Map<JsIrModule, CrossModuleReferences> {
|
||||||
val moduleToBuilder = modules.associateWith { JsIrModuleCrossModuleReferecenceBuilder(it, relativeRequirePath) }
|
val resolver = CrossModuleDependenciesResolver(modules.map { it.makeModuleHeader() })
|
||||||
|
val crossModuleReferences = resolver.resolveCrossModuleDependencies(relativeRequirePath)
|
||||||
|
return crossModuleReferences.entries.associate {
|
||||||
|
val module = it.key.associatedModule ?: error("Internal error: module ${it.key.moduleName} is not loaded")
|
||||||
|
it.value.initJsImportsForModule(module)
|
||||||
|
module to it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CrossModuleDependenciesResolver(private val headers: List<JsIrModuleHeader>) {
|
||||||
|
fun resolveCrossModuleDependencies(relativeRequirePath: Boolean): Map<JsIrModuleHeader, CrossModuleReferences> {
|
||||||
|
val headerToBuilder = headers.associateWith { JsIrModuleCrossModuleReferecenceBuilder(it, relativeRequirePath) }
|
||||||
val definitionModule = mutableMapOf<String, JsIrModuleCrossModuleReferecenceBuilder>()
|
val definitionModule = mutableMapOf<String, JsIrModuleCrossModuleReferecenceBuilder>()
|
||||||
|
|
||||||
moduleToBuilder[mainModule]!!.transitiveJsExportFrom = otherModules
|
val mainModuleHeader = headers.last()
|
||||||
for (module in modules) {
|
val otherModuleHeaders = headers.dropLast(1)
|
||||||
val moduleBuilder = moduleToBuilder[module]!!
|
headerToBuilder[mainModuleHeader]!!.transitiveJsExportFrom = otherModuleHeaders
|
||||||
for (fragment in module.fragments) {
|
|
||||||
for (definition in fragment.definitions) {
|
for (header in headers) {
|
||||||
require(definition !in definitionModule) { "Duplicate definition: $definition" }
|
val builder = headerToBuilder[header]!!
|
||||||
definitionModule[definition] = moduleBuilder
|
for (definition in header.definitions) {
|
||||||
}
|
require(definition !in definitionModule) { "Duplicate definition: $definition" }
|
||||||
|
definitionModule[definition] = builder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (module in modules) {
|
for (header in headers) {
|
||||||
val moduleBuilder = moduleToBuilder[module]!!
|
val builder = headerToBuilder[header]!!
|
||||||
for (fragment in module.fragments) {
|
for (tag in header.externalNames) {
|
||||||
for (tag in fragment.nameBindings.keys) {
|
val fromModuleBuilder = definitionModule[tag] ?: continue // TODO error?
|
||||||
val fromModuleBuilder = definitionModule[tag] ?: continue // TODO error?
|
|
||||||
if (fromModuleBuilder == moduleBuilder) continue
|
|
||||||
|
|
||||||
moduleBuilder.imports += CrossModuleRef(fromModuleBuilder, tag)
|
builder.imports += CrossModuleRef(fromModuleBuilder, tag)
|
||||||
fromModuleBuilder.exports += tag
|
fromModuleBuilder.exports += tag
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return modules.associateWith { moduleToBuilder[it]!!.buildCrossModuleRefs() }
|
return headers.associateWith { headerToBuilder[it]!!.buildCrossModuleRefs() }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.prettyTag() = takeWhile { c -> c != '|' }
|
||||||
|
|
||||||
private class CrossModuleRef(val module: JsIrModuleCrossModuleReferecenceBuilder, val tag: String)
|
private class CrossModuleRef(val module: JsIrModuleCrossModuleReferecenceBuilder, val tag: String)
|
||||||
|
|
||||||
|
private class JsIrModuleCrossModuleReferecenceBuilder(val header: JsIrModuleHeader, val relativeRequirePath: Boolean) {
|
||||||
private class JsIrModuleCrossModuleReferecenceBuilder(val module: JsIrModule, val relativeRequirePath: Boolean) {
|
|
||||||
val imports = mutableListOf<CrossModuleRef>()
|
val imports = mutableListOf<CrossModuleRef>()
|
||||||
val exports = mutableSetOf<String>()
|
val exports = mutableSetOf<String>()
|
||||||
var transitiveJsExportFrom = emptyList<JsIrModule>()
|
var transitiveJsExportFrom = emptyList<JsIrModuleHeader>()
|
||||||
|
|
||||||
private lateinit var exportNames: Map<String, String> // tag -> index
|
private lateinit var exportNames: Map<String, String> // tag -> index
|
||||||
|
|
||||||
private fun buildUniqueNames() {
|
private fun buildExportNames() {
|
||||||
val result = mutableMapOf<String, String>()
|
|
||||||
|
|
||||||
var index = 0
|
var index = 0
|
||||||
|
exportNames = exports.sorted().associateWith { index++.toJsIdentifier() }
|
||||||
exports.sorted().forEach { tag ->
|
|
||||||
result[tag] = index++.toJsIdentifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
exportNames = result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildCrossModuleRefs(): CrossModuleReferences {
|
fun buildCrossModuleRefs(): CrossModuleReferences {
|
||||||
buildUniqueNames()
|
buildExportNames()
|
||||||
|
val importedModules = mutableMapOf<JsIrModuleHeader, JsImportedModule>()
|
||||||
|
|
||||||
val importedModules = mutableMapOf<JsIrModule, JsImportedModule>()
|
fun import(moduleHeader: JsIrModuleHeader): JsName {
|
||||||
|
return importedModules.getOrPut(moduleHeader) {
|
||||||
fun JsIrModule.import(): JsName {
|
val jsModuleName = JsName(moduleHeader.moduleName, false)
|
||||||
return importedModules.getOrPut(this) {
|
JsImportedModule(moduleHeader.externalModuleName, jsModuleName, null, relativeRequirePath)
|
||||||
val moduleName = JsName(moduleName, false)
|
|
||||||
JsImportedModule(externalModuleName, moduleName, null, relativeRequirePath)
|
|
||||||
}.internalName
|
}.internalName
|
||||||
}
|
}
|
||||||
|
|
||||||
val tagToName = module.fragments.flatMap { it.nameBindings.entries }.associate { it.key to it.value }
|
val resultImports = imports.associate { crossModuleRef ->
|
||||||
|
val tag = crossModuleRef.tag
|
||||||
val resultImports = imports.associate {
|
require(crossModuleRef.module::exportNames.isInitialized) {
|
||||||
val tag = it.tag
|
|
||||||
require(it.module::exportNames.isInitialized) {
|
|
||||||
// This situation appears in case of a dependent module redefine a symbol (function) from their dependency
|
// This situation appears in case of a dependent module redefine a symbol (function) from their dependency
|
||||||
"Cross module dependency resolution failed due to symbol '${tag.takeWhile { c -> c != '|' }}' redefinition"
|
"Cross module dependency resolution failed due to symbol '${tag.prettyTag()}' redefinition"
|
||||||
}
|
}
|
||||||
val exportedAs = it.module.exportNames[tag]!!
|
val exportedAs = crossModuleRef.module.exportNames[tag]!!
|
||||||
val importedAs = tagToName[tag]!!
|
val moduleName = import(crossModuleRef.module.header)
|
||||||
val moduleName = it.module.module.import()
|
|
||||||
|
|
||||||
val importStatement = JsVars.JsVar(importedAs, JsNameRef(exportedAs, ReservedJsNames.makeCrossModuleNameRef(moduleName)))
|
tag to CrossModuleImport(exportedAs, moduleName)
|
||||||
|
|
||||||
tag to importStatement
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val transitiveExport = transitiveJsExportFrom.mapNotNull {
|
val transitiveExport = transitiveJsExportFrom.mapNotNull {
|
||||||
it.fragments.find { f -> !f.exports.isEmpty }?.run { it.import() }
|
if (it.hasJsExports) import(it) else null
|
||||||
}
|
}
|
||||||
return CrossModuleReferences(importedModules.values.toList(), resultImports, exportNames, transitiveExport)
|
return CrossModuleReferences(importedModules.values.toList(), transitiveExport, exportNames, resultImports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CrossModuleImport(val exportedAs: String, val moduleExporter: JsName)
|
||||||
|
|
||||||
class CrossModuleReferences(
|
class CrossModuleReferences(
|
||||||
val importedModules: List<JsImportedModule>, // additional Kotlin imported modules
|
val importedModules: List<JsImportedModule>, // additional Kotlin imported modules
|
||||||
val imports: Map<String, JsVars.JsVar>, // tag -> import statement
|
val transitiveJsExportFrom: List<JsName>, // the list of modules which provide their js exports for transitive export
|
||||||
val exports: Map<String, String>, // tag -> index
|
val exports: Map<String, String>, // tag -> index
|
||||||
val transitiveJsExportFrom: List<JsName> // the list of modules which provide their js exports for transitive export
|
val imports: Map<String, CrossModuleImport>, // tag -> import statement
|
||||||
) {
|
) {
|
||||||
companion object {
|
// built from imports
|
||||||
val Empty = CrossModuleReferences(listOf(), emptyMap(), emptyMap(), emptyList())
|
var jsImports = emptyMap<String, JsVars.JsVar>() // tag -> import statement
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun initJsImportsForModule(module: JsIrModule) {
|
||||||
|
val tagToName = module.fragments.flatMap { it.nameBindings.entries }.associate { it.key to it.value }
|
||||||
|
jsImports = imports.entries.associate {
|
||||||
|
val importedAs = tagToName[it.key] ?: error("Internal error: cannot find imported name for symbol ${it.key.prettyTag()}")
|
||||||
|
val exportRef = JsNameRef(it.value.exportedAs, ReservedJsNames.makeCrossModuleNameRef(it.value.moduleExporter))
|
||||||
|
it.key to JsVars.JsVar(importedAs, exportRef)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
companion object {
|
||||||
|
val Empty = CrossModuleReferences(listOf(), emptyList(), emptyMap(), emptyMap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -56,7 +56,7 @@ class Merger(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((tag, jsVar) in crossModuleReferences.imports) {
|
for ((tag, jsVar) in crossModuleReferences.jsImports) {
|
||||||
val importName = nameMap[tag] ?: error("Missing name for declaration '$tag'")
|
val importName = nameMap[tag] ?: error("Missing name for declaration '$tag'")
|
||||||
|
|
||||||
importStatements.putIfAbsent(tag, JsVars(JsVars.JsVar(importName, jsVar.initExpression)))
|
importStatements.putIfAbsent(tag, JsVars(JsVars.JsVar(importName, jsVar.initExpression)))
|
||||||
@@ -302,4 +302,4 @@ class Merger(
|
|||||||
this += statements
|
this += statements
|
||||||
endRegion()
|
endRegion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import java.util.regex.Pattern
|
|||||||
|
|
||||||
class ProjectInfo(val name: String, val modules: List<String>, val steps: List<ProjectBuildStep>, val muted: Boolean) {
|
class ProjectInfo(val name: String, val modules: List<String>, val steps: List<ProjectBuildStep>, val muted: Boolean) {
|
||||||
|
|
||||||
class ProjectBuildStep(val id: Int, val order: List<String>)
|
class ProjectBuildStep(val id: Int, val order: List<String>, val dirtyJS: List<String>)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModuleInfo(val moduleName: String) {
|
class ModuleInfo(val moduleName: String) {
|
||||||
@@ -52,14 +52,15 @@ class ModuleInfo(val moduleName: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class StepDirectives(val mnemonic: String) {
|
enum class StepDirectives(val mnemonic: String) {
|
||||||
FAST_PATH_UPDATE("FP")
|
FAST_PATH_UPDATE("FP"),
|
||||||
|
UNUSED_MODULE("UNUSED")
|
||||||
}
|
}
|
||||||
|
|
||||||
const val MODULES_LIST = "MODULES"
|
const val MODULES_LIST = "MODULES"
|
||||||
const val PROJECT_INFO_FILE = "project.info"
|
const val PROJECT_INFO_FILE = "project.info"
|
||||||
const val MODULE_INFO_FILE = "module.info"
|
const val MODULE_INFO_FILE = "module.info"
|
||||||
|
|
||||||
private val STEP_PATTERN = Pattern.compile("^\\s*STEP\\s+(\\d+)\\s*:?$")
|
private val STEP_PATTERN = Pattern.compile("^\\s*STEP\\s+(\\d+)\\.*(\\d+)?\\s*:?$")
|
||||||
|
|
||||||
private val MODIFICATION_PATTERN = Pattern.compile("^([UD])\\s*:(.+)$")
|
private val MODIFICATION_PATTERN = Pattern.compile("^([UD])\\s*:(.+)$")
|
||||||
|
|
||||||
@@ -94,11 +95,14 @@ abstract class InfoParser<Info>(protected val infoFile: File) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.splitAndTrim() = split(",").map { it.trim() }.filter { it.isNotBlank() }
|
||||||
|
|
||||||
class ProjectInfoParser(infoFile: File) : InfoParser<ProjectInfo>(infoFile) {
|
class ProjectInfoParser(infoFile: File) : InfoParser<ProjectInfo>(infoFile) {
|
||||||
|
|
||||||
|
|
||||||
private fun parseStep(stepId: Int): ProjectInfo.ProjectBuildStep {
|
private fun parseSteps(firstId: Int, lastId: Int): List<ProjectInfo.ProjectBuildStep> {
|
||||||
val order = mutableListOf<String>()
|
val order = mutableListOf<String>()
|
||||||
|
val dirtyJS = mutableListOf<String>()
|
||||||
|
|
||||||
loop { line ->
|
loop { line ->
|
||||||
val splitIndex = line.indexOf(':')
|
val splitIndex = line.indexOf(':')
|
||||||
@@ -113,10 +117,13 @@ class ProjectInfoParser(infoFile: File) : InfoParser<ProjectInfo>(infoFile) {
|
|||||||
|
|
||||||
++lineCounter
|
++lineCounter
|
||||||
|
|
||||||
|
|
||||||
when (op) {
|
when (op) {
|
||||||
"libs" -> {
|
"libs" -> {
|
||||||
val args = splitted[1]
|
order += splitted[1].splitAndTrim()
|
||||||
args.split(",").filter { it.isNotBlank() }.forEach { order.add(it.trim()) }
|
}
|
||||||
|
"dirty js" -> {
|
||||||
|
dirtyJS += splitted[1].splitAndTrim()
|
||||||
}
|
}
|
||||||
else -> println(diagnosticMessage("Unknown op $op", line))
|
else -> println(diagnosticMessage("Unknown op $op", line))
|
||||||
}
|
}
|
||||||
@@ -124,7 +131,7 @@ class ProjectInfoParser(infoFile: File) : InfoParser<ProjectInfo>(infoFile) {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProjectInfo.ProjectBuildStep(stepId, order)
|
return (firstId..lastId).map { ProjectInfo.ProjectBuildStep(it, order, dirtyJS) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(entryName: String): ProjectInfo {
|
override fun parse(entryName: String): ProjectInfo {
|
||||||
@@ -148,14 +155,15 @@ class ProjectInfoParser(infoFile: File) : InfoParser<ProjectInfo>(infoFile) {
|
|||||||
|
|
||||||
when {
|
when {
|
||||||
op == MODULES_LIST -> {
|
op == MODULES_LIST -> {
|
||||||
val arguments = splitted[1]
|
libraries += splitted[1].splitAndTrim()
|
||||||
arguments.split(",").filter { it.isNotBlank() }.forEach { libraries.add(it.trim()) }
|
|
||||||
}
|
}
|
||||||
op.matches(STEP_PATTERN.toRegex()) -> {
|
op.matches(STEP_PATTERN.toRegex()) -> {
|
||||||
val m = STEP_PATTERN.matcher(op)
|
val m = STEP_PATTERN.matcher(op)
|
||||||
if (!m.matches()) throwSyntaxError(line)
|
if (!m.matches()) throwSyntaxError(line)
|
||||||
val stepId = Integer.parseInt(m.group(1))
|
|
||||||
steps.add(parseStep(stepId))
|
val firstId = Integer.parseInt(m.group(1))
|
||||||
|
val lastId = m.group(2)?.let { Integer.parseInt(it) } ?: firstId
|
||||||
|
steps += parseSteps(firstId, lastId)
|
||||||
}
|
}
|
||||||
else -> println(diagnosticMessage("Unknown op $op", line))
|
else -> println(diagnosticMessage("Unknown op $op", line))
|
||||||
}
|
}
|
||||||
@@ -202,7 +210,7 @@ class ModuleInfoParser(infoFile: File) : InfoParser<ModuleInfo>(infoFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseStep(stepId: Int): ModuleInfo.ModuleStep {
|
private fun parseSteps(firstId: Int, lastId: Int): List<ModuleInfo.ModuleStep> {
|
||||||
val dependencies = mutableSetOf<String>()
|
val dependencies = mutableSetOf<String>()
|
||||||
val dirtyFiles = mutableSetOf<String>()
|
val dirtyFiles = mutableSetOf<String>()
|
||||||
val modifications = mutableListOf<ModuleInfo.Modification>()
|
val modifications = mutableListOf<ModuleInfo.Modification>()
|
||||||
@@ -227,7 +235,7 @@ class ModuleInfoParser(infoFile: File) : InfoParser<ModuleInfo>(infoFile) {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModuleInfo.ModuleStep(stepId, dependencies, dirtyFiles, modifications, directives)
|
return (firstId..lastId).map { ModuleInfo.ModuleStep(it, dependencies, dirtyFiles, modifications, directives) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(entryName: String): ModuleInfo {
|
override fun parse(entryName: String): ModuleInfo {
|
||||||
@@ -237,8 +245,9 @@ class ModuleInfoParser(infoFile: File) : InfoParser<ModuleInfo>(infoFile) {
|
|||||||
lineCounter++
|
lineCounter++
|
||||||
val stepMatcher = STEP_PATTERN.matcher(line)
|
val stepMatcher = STEP_PATTERN.matcher(line)
|
||||||
if (stepMatcher.matches()) {
|
if (stepMatcher.matches()) {
|
||||||
val id = Integer.parseInt(stepMatcher.group(1))
|
val firstId = Integer.parseInt(stepMatcher.group(1))
|
||||||
result.steps.add(parseStep(id))
|
val lastId = stepMatcher.group(2)?.let { Integer.parseInt(it) } ?: firstId
|
||||||
|
result.steps += parseSteps(firstId, lastId)
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,6 +366,7 @@ projectTest("wasmTest", true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
projectTest("invalidationTest", jUnitMode = JUnitMode.JUnit4) {
|
projectTest("invalidationTest", jUnitMode = JUnitMode.JUnit4) {
|
||||||
|
setupV8()
|
||||||
workingDir = rootDir
|
workingDir = rootDir
|
||||||
|
|
||||||
include("org/jetbrains/kotlin/incremental/*")
|
include("org/jetbrains/kotlin/incremental/*")
|
||||||
|
|||||||
@@ -16,25 +16,37 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
|||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.backend.js.WholeWorldStageController
|
import org.jetbrains.kotlin.ir.backend.js.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.generateKLib
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||||
import org.jetbrains.kotlin.ir.backend.js.prepareAnalyzedSourceModule
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.SourceMapsInfo
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
||||||
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
||||||
import org.jetbrains.kotlin.test.util.JUnit4Assertions
|
import org.jetbrains.kotlin.test.util.JUnit4Assertions
|
||||||
|
import org.junit.ComparisonFailure
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.io.path.createTempDirectory
|
import kotlin.io.path.createTempDirectory
|
||||||
|
|
||||||
private var stdlibCacheDir: File? = null
|
|
||||||
|
|
||||||
abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
||||||
|
companion object {
|
||||||
|
private const val TEST_DATA_DIR_PATH = "js/js.translator/testData/"
|
||||||
|
|
||||||
|
private const val stdlibAlias = "stdlib"
|
||||||
|
private const val stdlibModuleName = "kotlin"
|
||||||
|
private val stdlibKlibPath = File(System.getProperty("kotlin.js.stdlib.klib.path") ?: error("Please set stdlib path")).canonicalPath
|
||||||
|
private var stdlibCacheDir: File? = null
|
||||||
|
|
||||||
|
private const val boxFunctionName = "box"
|
||||||
|
}
|
||||||
|
|
||||||
override fun createEnvironment(): KotlinCoreEnvironment {
|
override fun createEnvironment(): KotlinCoreEnvironment {
|
||||||
return KotlinCoreEnvironment.createForTests(TestDisposable(), CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
return KotlinCoreEnvironment.createForTests(TestDisposable(), CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||||
}
|
}
|
||||||
@@ -47,36 +59,24 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
return ModuleInfoParser(infoFile).parse(moduleName)
|
return ModuleInfoParser(infoFile).parse(moduleName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
private fun emptyChecker(
|
|
||||||
currentModule: IrModuleFragment,
|
|
||||||
dependencies: Collection<IrModuleFragment>,
|
|
||||||
deserializer: JsIrLinker,
|
|
||||||
configuration: CompilerConfiguration,
|
|
||||||
dirtyFiles: Collection<String>?, // if null consider the whole module dirty
|
|
||||||
artifactCache: ArtifactCache,
|
|
||||||
exportedDeclarations: Set<FqName>,
|
|
||||||
mainArguments: List<String>?,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initializeStdlibCache() {
|
private fun initializeStdlibCache() {
|
||||||
if (stdlibCacheDir != null) return
|
if (stdlibCacheDir != null) return
|
||||||
val cacheDir = createTempDirectory().toFile()
|
val cacheDir = createTempDirectory().toFile()
|
||||||
cacheDir.deleteOnExit()
|
cacheDir.deleteOnExit()
|
||||||
|
|
||||||
val configuration = createConfiguration("stdlib")
|
val cacheUpdater = CacheUpdater(
|
||||||
|
|
||||||
actualizeCacheForModuleWithPrepare(
|
|
||||||
stdlibKlibPath,
|
stdlibKlibPath,
|
||||||
cacheDir.canonicalPath,
|
|
||||||
configuration,
|
|
||||||
listOf(stdlibKlibPath),
|
listOf(stdlibKlibPath),
|
||||||
emptyList(),
|
createConfiguration(stdlibAlias),
|
||||||
IrFactoryImpl,
|
listOf(cacheDir.canonicalPath),
|
||||||
null, // TODO: mainArguments
|
{ IrFactoryImplForJsIC(WholeWorldStageController()) },
|
||||||
::emptyChecker
|
null,
|
||||||
|
::buildCacheForModuleFiles
|
||||||
)
|
)
|
||||||
|
cacheUpdater.actualizeCaches { updateStatus, updatedModule ->
|
||||||
|
JUnit4Assertions.assertEquals(stdlibKlibPath, updatedModule) { "incorrect std klib path" }
|
||||||
|
JUnit4Assertions.assertTrue(updateStatus is CacheUpdateStatus.Dirty) { "std klib should be rebuilt" }
|
||||||
|
}
|
||||||
|
|
||||||
stdlibCacheDir = cacheDir
|
stdlibCacheDir = cacheDir
|
||||||
}
|
}
|
||||||
@@ -104,70 +104,213 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
|
|
||||||
initializeWorkingDir(projectInfo, testDirectory, sourceDir, buildDir)
|
initializeWorkingDir(projectInfo, testDirectory, sourceDir, buildDir)
|
||||||
|
|
||||||
executeProjectSteps(projectInfo, modulesInfos, testDirectory, sourceDir, buildDir)
|
ProjectStepsExecutor(projectInfo, modulesInfos, testDirectory, sourceDir, buildDir).execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val stdlibKlibPath = System.getProperty("kotlin.js.stdlib.klib.path") ?: error("Please set stdlib path")
|
|
||||||
|
|
||||||
private val String.artifactName: String get() = "$this.klib"
|
|
||||||
|
|
||||||
private fun resolveModuleArtifact(moduleName: String, buildDir: File): File {
|
private fun resolveModuleArtifact(moduleName: String, buildDir: File): File {
|
||||||
if (moduleName == "stdlib") return File(stdlibKlibPath)
|
if (moduleName == stdlibAlias) return File(stdlibKlibPath)
|
||||||
return File(File(buildDir, moduleName), moduleName.artifactName)
|
return File(File(buildDir, moduleName), "$moduleName.klib")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveModuleCache(moduleName: String, buildDir: File): File {
|
private fun resolveModuleCache(moduleName: String, buildDir: File): File {
|
||||||
if (moduleName == "stdlib") return stdlibCacheDir ?: error("stdlib cache corruption")
|
if (moduleName == stdlibAlias) return stdlibCacheDir ?: error("stdlib cache corruption")
|
||||||
return File(File(buildDir, moduleName), "cache")
|
return File(File(buildDir, moduleName), "cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createConfiguration(moduleName: String): CompilerConfiguration {
|
private fun createConfiguration(moduleName: String): CompilerConfiguration {
|
||||||
val copy = environment.configuration.copy()
|
val copy = environment.configuration.copy()
|
||||||
copy.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
copy.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||||
|
copy.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||||
return copy
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeProjectSteps(
|
private inner class ProjectStepsExecutor(
|
||||||
projectInfo: ProjectInfo,
|
private val projectInfo: ProjectInfo,
|
||||||
moduleInfos: Map<String, ModuleInfo>,
|
private val moduleInfos: Map<String, ModuleInfo>,
|
||||||
testDir: File,
|
private val testDir: File,
|
||||||
sourceDir: File,
|
private val sourceDir: File,
|
||||||
buildDir: File
|
private val buildDir: File
|
||||||
) {
|
) {
|
||||||
for (projStep in projectInfo.steps) {
|
private inner class TestStepInfo(
|
||||||
for (module in projStep.order) {
|
val moduleName: String,
|
||||||
val moduleTestDir = File(testDir, module)
|
val modulePath: String,
|
||||||
val moduleSourceDir = File(sourceDir, module)
|
val icCacheDir: String,
|
||||||
val moduleInfo = moduleInfos[module] ?: error("No module info found for $module")
|
val directives: Set<StepDirectives>,
|
||||||
val moduleStep = moduleInfo.steps[projStep.id]
|
val dirtyFiles: List<String> = emptyList(),
|
||||||
val deletedFiles = mutableListOf<File>()
|
val deletedFiles: List<String> = emptyList()
|
||||||
for (modification in moduleStep.modifications) {
|
)
|
||||||
modification.execute(moduleTestDir, moduleSourceDir) { deletedFiles.add(it) }
|
|
||||||
|
private fun setupTestStep(projStepId: Int, module: String): TestStepInfo {
|
||||||
|
val moduleTestDir = File(testDir, module)
|
||||||
|
val moduleSourceDir = File(sourceDir, module)
|
||||||
|
val moduleInfo = moduleInfos[module] ?: error("No module info found for $module")
|
||||||
|
val moduleStep = moduleInfo.steps[projStepId]
|
||||||
|
val deletedFiles = mutableListOf<File>()
|
||||||
|
for (modification in moduleStep.modifications) {
|
||||||
|
modification.execute(moduleTestDir, moduleSourceDir) { deletedFiles.add(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val dependencies = moduleStep.dependencies.map { resolveModuleArtifact(it, buildDir) }
|
||||||
|
val outputKlibFile = resolveModuleArtifact(module, buildDir)
|
||||||
|
val configuration = createConfiguration(module)
|
||||||
|
buildArtifact(configuration, module, moduleSourceDir, dependencies, outputKlibFile)
|
||||||
|
|
||||||
|
return TestStepInfo(
|
||||||
|
module.safeModuleName,
|
||||||
|
outputKlibFile.canonicalPath,
|
||||||
|
resolveModuleCache(module, buildDir).canonicalPath,
|
||||||
|
moduleStep.directives,
|
||||||
|
moduleStep.dirtyFiles.map { File(moduleSourceDir, it).canonicalPath },
|
||||||
|
deletedFiles.map { it.canonicalPath }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyCacheUpdateStatus(stepId: Int, statuses: Map<String, CacheUpdateStatus>, testInfo: List<TestStepInfo>) {
|
||||||
|
val expectedInfo = testInfo.filter { StepDirectives.UNUSED_MODULE !in it.directives }
|
||||||
|
|
||||||
|
JUnit4Assertions.assertEquals(statuses.size, expectedInfo.size) {
|
||||||
|
"Mismatched updated modules count at step $stepId"
|
||||||
|
}
|
||||||
|
|
||||||
|
for (info in expectedInfo) {
|
||||||
|
JUnit4Assertions.assertTrue(info.modulePath in statuses) {
|
||||||
|
"Status is missed for ${info.modulePath} at step $stepId"
|
||||||
|
}
|
||||||
|
val updateStatus = statuses[info.modulePath]!!
|
||||||
|
if (StepDirectives.FAST_PATH_UPDATE in info.directives) {
|
||||||
|
JUnit4Assertions.assertEquals(CacheUpdateStatus.FastPath, updateStatus) {
|
||||||
|
"Cache has to be checked by fast path, instead it $updateStatus at step $stepId"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JUnit4Assertions.assertNotEquals(CacheUpdateStatus.FastPath, updateStatus) {
|
||||||
|
"Cache has not to be checked by fast path, but it is at step $stepId"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val dependencies = moduleStep.dependencies.map { resolveModuleArtifact(it, buildDir) }
|
val (updated, removed) = when (updateStatus) {
|
||||||
|
is CacheUpdateStatus.FastPath -> emptySet<String>() to emptySet()
|
||||||
|
is CacheUpdateStatus.NoDirtyFiles -> emptySet<String>() to updateStatus.removed
|
||||||
|
is CacheUpdateStatus.Dirty -> updateStatus.updated to updateStatus.removed
|
||||||
|
}
|
||||||
|
|
||||||
val outputKlibFile = resolveModuleArtifact(module, buildDir)
|
JUnit4Assertions.assertSameElements(info.dirtyFiles, updated.map { File(it).canonicalPath }) {
|
||||||
|
"Mismatched DIRTY files for module ${info.moduleName} at step $stepId"
|
||||||
|
}
|
||||||
|
|
||||||
val configuration = createConfiguration(module)
|
JUnit4Assertions.assertSameElements(info.deletedFiles, removed.map { File(it).canonicalPath }) {
|
||||||
|
"Mismatched DELETED files for module ${info.moduleName} at step $stepId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildArtifact(configuration, module, moduleSourceDir, dependencies, outputKlibFile)
|
private fun verifyJsExecutableProducerBuildModules(stepId: Int, gotRebuilt: Set<String>, expectedRebuilt: List<String>) {
|
||||||
|
val expected = expectedRebuilt.map { if (it == stdlibAlias) stdlibModuleName.safeModuleName else it.safeModuleName }
|
||||||
|
JUnit4Assertions.assertSameElements(expected, gotRebuilt) {
|
||||||
|
"Mismatched rebuilt modules at step $stepId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val dirtyFiles = moduleStep.dirtyFiles.map { File(moduleSourceDir, it) }
|
fun writeJsFile(name: String, text: String): String {
|
||||||
val icCaches = moduleStep.dependencies.map { resolveModuleCache(it, buildDir) }
|
val file = File(buildDir, "$name.js")
|
||||||
|
if (file.exists()) {
|
||||||
|
file.delete()
|
||||||
|
}
|
||||||
|
file.writeText(text)
|
||||||
|
return file.canonicalPath
|
||||||
|
}
|
||||||
|
|
||||||
val moduleCacheDir = resolveModuleCache(module, buildDir)
|
private fun verifyJsCode(stepId: Int, mainModuleName: String, jsOutput: CompilationOutputs) {
|
||||||
|
val files = jsOutput.dependencies.map { writeJsFile(it.first, it.second.jsCode) } + writeJsFile(mainModuleName, jsOutput.jsCode)
|
||||||
buildCachesAndCheck(
|
try {
|
||||||
moduleStep,
|
V8IrJsTestChecker.checkWithTestFunctionArgs(
|
||||||
configuration,
|
files = files,
|
||||||
outputKlibFile,
|
testModuleName = mainModuleName,
|
||||||
moduleCacheDir,
|
testPackageName = null,
|
||||||
dependencies,
|
testFunctionName = boxFunctionName,
|
||||||
icCaches,
|
testFunctionArgs = "$stepId",
|
||||||
dirtyFiles,
|
expectedResult = "OK",
|
||||||
deletedFiles
|
withModuleSystem = false
|
||||||
)
|
)
|
||||||
|
} catch (e: ComparisonFailure) {
|
||||||
|
throw ComparisonFailure("Mismatched box out at step $stepId", e.expected, e.actual)
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
throw IllegalStateException("Something goes wrong (bad JS code?) at step $stepId\n${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun executorWithBoxExport(
|
||||||
|
currentModule: IrModuleFragment,
|
||||||
|
dependencies: Collection<IrModuleFragment>,
|
||||||
|
deserializer: JsIrLinker,
|
||||||
|
configuration: CompilerConfiguration,
|
||||||
|
dirtyFiles: Collection<String>?,
|
||||||
|
artifactCache: ArtifactCache,
|
||||||
|
exportedDeclarations: Set<FqName>,
|
||||||
|
mainArguments: List<String>?
|
||||||
|
) {
|
||||||
|
buildCacheForModuleFiles(
|
||||||
|
currentModule = currentModule,
|
||||||
|
dependencies = dependencies,
|
||||||
|
deserializer = deserializer,
|
||||||
|
configuration = configuration,
|
||||||
|
dirtyFiles = dirtyFiles,
|
||||||
|
artifactCache = artifactCache,
|
||||||
|
exportedDeclarations = exportedDeclarations + FqName(boxFunctionName),
|
||||||
|
mainArguments = mainArguments,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun execute() {
|
||||||
|
val stdlibInfo = TestStepInfo(
|
||||||
|
moduleName = stdlibModuleName.safeModuleName,
|
||||||
|
modulePath = stdlibKlibPath,
|
||||||
|
icCacheDir = stdlibCacheDir!!.canonicalPath,
|
||||||
|
directives = setOf(StepDirectives.FAST_PATH_UPDATE)
|
||||||
|
)
|
||||||
|
for (projStep in projectInfo.steps) {
|
||||||
|
val testInfo = projStep.order.mapTo(mutableListOf(stdlibInfo)) { setupTestStep(projStep.id, it) }
|
||||||
|
|
||||||
|
val configuration = createConfiguration(projStep.order.last())
|
||||||
|
val cacheUpdater = CacheUpdater(
|
||||||
|
rootModule = testInfo.last().modulePath,
|
||||||
|
testInfo.map { it.modulePath },
|
||||||
|
configuration,
|
||||||
|
testInfo.map { it.icCacheDir },
|
||||||
|
{ IrFactoryImplForJsIC(WholeWorldStageController()) },
|
||||||
|
null,
|
||||||
|
::executorWithBoxExport
|
||||||
|
)
|
||||||
|
|
||||||
|
val updateStatuses = mutableMapOf<String, CacheUpdateStatus>()
|
||||||
|
var icCaches = cacheUpdater.actualizeCaches { updateStatus, updatedModule -> updateStatuses[updatedModule] = updateStatus }
|
||||||
|
verifyCacheUpdateStatus(projStep.id, updateStatuses, testInfo)
|
||||||
|
|
||||||
|
val mainModuleCacheDir = icCaches.last().artifactsDir!!
|
||||||
|
// tests use one stdlib artifact for all cases, patching stdlib cache path here:
|
||||||
|
// - enable using cached js (stdlib) file through all steps in a test case
|
||||||
|
// - disable using cached js (stdlib) file through test cases
|
||||||
|
icCaches = icCaches.map {
|
||||||
|
when (it.moduleSafeName) {
|
||||||
|
stdlibModuleName.safeModuleName -> {
|
||||||
|
val stdlibDir = File(mainModuleCacheDir, stdlibAlias).apply { mkdirs() }
|
||||||
|
ModuleArtifact(stdlibModuleName, it.fileArtifacts, stdlibDir, it.forceRebuildJs)
|
||||||
|
}
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jsExecutableProducer = JsExecutableProducer(
|
||||||
|
mainModuleName = testInfo.last().moduleName,
|
||||||
|
moduleKind = configuration[JSConfigurationKeys.MODULE_KIND]!!,
|
||||||
|
sourceMapsInfo = SourceMapsInfo.from(configuration),
|
||||||
|
caches = icCaches,
|
||||||
|
relativeRequirePath = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val rebuiltModules = mutableSetOf<String>()
|
||||||
|
val jsOutput = jsExecutableProducer.buildExecutable(true) { rebuiltModules += it }
|
||||||
|
verifyJsExecutableProducerBuildModules(projStep.id, rebuiltModules, projStep.dirtyJS)
|
||||||
|
verifyJsCode(projStep.id, testInfo.last().moduleName, jsOutput)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,83 +320,6 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
return listFiles { _, name -> name.endsWith(".kt") }!!.toList()
|
return listFiles { _, name -> name.endsWith(".kt") }!!.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildCachesAndCheck(
|
|
||||||
moduleStep: ModuleInfo.ModuleStep,
|
|
||||||
configuration: CompilerConfiguration,
|
|
||||||
moduleKlibFile: File,
|
|
||||||
moduleCacheDir: File,
|
|
||||||
dependencies: List<File>,
|
|
||||||
icCaches: List<File>,
|
|
||||||
expectedDirtyFiles: List<File>,
|
|
||||||
expectedDeletedFiles: List<File>
|
|
||||||
) {
|
|
||||||
val dependenciesPaths = mutableListOf<String>()
|
|
||||||
dependencies.mapTo(dependenciesPaths) { it.canonicalPath }
|
|
||||||
dependenciesPaths.add(moduleKlibFile.canonicalPath)
|
|
||||||
|
|
||||||
val updateStatus = actualizeCacheForModuleWithPrepare(
|
|
||||||
moduleKlibFile.canonicalPath,
|
|
||||||
moduleCacheDir.canonicalPath,
|
|
||||||
configuration,
|
|
||||||
dependenciesPaths,
|
|
||||||
icCaches.map { it.canonicalPath },// + moduleCacheDir.canonicalPath,
|
|
||||||
IrFactoryImpl,
|
|
||||||
null, // TODO: mainArguments
|
|
||||||
::emptyChecker
|
|
||||||
)
|
|
||||||
|
|
||||||
if (StepDirectives.FAST_PATH_UPDATE in moduleStep.directives) {
|
|
||||||
JUnit4Assertions.assertEquals(CacheUpdateStatus.FastPath, updateStatus) {
|
|
||||||
"Cache has to be checked by fast path, instead it $updateStatus"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val (updated, removed) = when (updateStatus) {
|
|
||||||
is CacheUpdateStatus.FastPath -> emptySet<String>() to emptySet<String>()
|
|
||||||
is CacheUpdateStatus.NoDirtyFiles -> emptySet<String>() to updateStatus.removed
|
|
||||||
is CacheUpdateStatus.Dirty -> updateStatus.updated to updateStatus.removed
|
|
||||||
}
|
|
||||||
|
|
||||||
val actualDirtyFiles = updated.map { File(it).canonicalPath }
|
|
||||||
val expectedDirtyFilesCanonical = expectedDirtyFiles.map { it.canonicalPath }
|
|
||||||
JUnit4Assertions.assertSameElements(expectedDirtyFilesCanonical, actualDirtyFiles) {
|
|
||||||
"Mismatched DIRTY files for module $moduleKlibFile at step ${moduleStep.id}"
|
|
||||||
}
|
|
||||||
|
|
||||||
val actualDeletedFiles = removed.map { File(it).canonicalPath }
|
|
||||||
val expectedDeletedFilesCanonical = expectedDeletedFiles.map { it.canonicalPath }
|
|
||||||
JUnit4Assertions.assertSameElements(expectedDeletedFilesCanonical, actualDeletedFiles) {
|
|
||||||
"Mismatched DELETED files for module $moduleKlibFile at step ${moduleStep.id}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun actualizeCacheForModuleWithPrepare(
|
|
||||||
moduleName: String,
|
|
||||||
cachePath: String,
|
|
||||||
compilerConfiguration: CompilerConfiguration,
|
|
||||||
dependencies: Collection<String>,
|
|
||||||
icCachePaths: Collection<String>,
|
|
||||||
irFactory: IrFactory,
|
|
||||||
mainArguments: List<String>?,
|
|
||||||
executor: CacheExecutor
|
|
||||||
): CacheUpdateStatus {
|
|
||||||
val modulePath = File(moduleName).canonicalPath
|
|
||||||
val statuses = mutableMapOf<String, CacheUpdateStatus>()
|
|
||||||
val cacheUpdater = CacheUpdater(
|
|
||||||
modulePath,
|
|
||||||
dependencies,
|
|
||||||
compilerConfiguration,
|
|
||||||
icCachePaths + cachePath,
|
|
||||||
{ irFactory },
|
|
||||||
mainArguments,
|
|
||||||
executor
|
|
||||||
)
|
|
||||||
cacheUpdater.actualizeCaches { updateStatus, updatedModule ->
|
|
||||||
statuses[updatedModule] = updateStatus
|
|
||||||
}
|
|
||||||
return statuses[modulePath] ?: error("Status is missed for $modulePath")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KotlinCoreEnvironment.createPsiFile(file: File): KtFile {
|
private fun KotlinCoreEnvironment.createPsiFile(file: File): KtFile {
|
||||||
val psiManager = PsiManager.getInstance(project)
|
val psiManager = PsiManager.getInstance(project)
|
||||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL) as CoreLocalFileSystem
|
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL) as CoreLocalFileSystem
|
||||||
@@ -317,9 +383,4 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() {
|
|||||||
|
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TEST_DATA_DIR_PATH = "js/js.translator/testData/"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationOptions
|
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationOptions
|
||||||
import org.jetbrains.kotlin.ir.backend.js.codegen.generateEsModules
|
import org.jetbrains.kotlin.ir.backend.js.codegen.generateEsModules
|
||||||
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ic.JsExecutableProducer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformerTmp
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformerTmp
|
||||||
@@ -98,11 +99,20 @@ class JsIrBackendFacade(
|
|||||||
} else {
|
} else {
|
||||||
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + ".js")
|
File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + ".js")
|
||||||
}
|
}
|
||||||
val moduleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
|
||||||
val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
val compiledModule = CompilerResult(
|
||||||
val sourceMapsInfo = SourceMapsInfo.from(configuration)
|
outputs = listOf(TranslationMode.FULL, TranslationMode.PER_MODULE).associateWith {
|
||||||
val translationModes = setOf(TranslationMode.FULL, TranslationMode.PER_MODULE)
|
val jsExecutableProducer = JsExecutableProducer(
|
||||||
val compiledModule = generateJsFromAst(moduleName, moduleKind, sourceMapsInfo, translationModes, testServices.jsIrIncrementalDataProvider.getCaches())
|
mainModuleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME),
|
||||||
|
moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN),
|
||||||
|
sourceMapsInfo = SourceMapsInfo.from(configuration),
|
||||||
|
caches = testServices.jsIrIncrementalDataProvider.getCaches(),
|
||||||
|
relativeRequirePath = false
|
||||||
|
)
|
||||||
|
jsExecutableProducer.buildExecutable(it.perModule)
|
||||||
|
},
|
||||||
|
tsDefinitions = null
|
||||||
|
)
|
||||||
return BinaryArtifacts.Js.JsIrArtifact(
|
return BinaryArtifacts.Js.JsIrArtifact(
|
||||||
outputFile, compiledModule, testServices.jsIrIncrementalDataProvider.getCacheForModule(module)
|
outputFile, compiledModule, testServices.jsIrIncrementalDataProvider.getCacheForModule(module)
|
||||||
).dump(module, firstTimeCompilation)
|
).dump(module, firstTimeCompilation)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.WholeWorldStageController
|
import org.jetbrains.kotlin.ir.backend.js.WholeWorldStageController
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.moduleName
|
import org.jetbrains.kotlin.ir.backend.js.moduleName
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
|
||||||
import org.jetbrains.kotlin.js.test.handlers.JsBoxRunner
|
import org.jetbrains.kotlin.js.test.handlers.JsBoxRunner
|
||||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||||
@@ -22,17 +23,31 @@ import org.jetbrains.kotlin.test.services.TestServices
|
|||||||
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
|
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
|
||||||
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
|
||||||
import org.jetbrains.kotlin.test.services.jsLibraryProvider
|
import org.jetbrains.kotlin.test.services.jsLibraryProvider
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
private class TestArtifactCache(var moduleName: String? = null) : ArtifactCache() {
|
private class TestArtifactCache(var moduleName: String? = null) : ArtifactCache() {
|
||||||
override fun fetchArtifacts() = KLibArtifact(
|
override fun fetchArtifacts(): ModuleArtifact {
|
||||||
moduleName = moduleName ?: error("Module name is not set"),
|
val deserializer = JsIrAstDeserializer()
|
||||||
fileArtifacts = binaryAsts.entries.map {
|
return ModuleArtifact(
|
||||||
SrcFileArtifact(it.key, "", it.value)
|
moduleName = moduleName ?: error("Module name is not set"),
|
||||||
}
|
fileArtifacts = binaryAsts.entries.map {
|
||||||
)
|
SrcFileArtifact(
|
||||||
|
srcFilePath = it.key,
|
||||||
|
// TODO: It will be better to use saved fragments (this.fragments), but it doesn't work
|
||||||
|
// Merger.merge() + JsNode.resolveTemporaryNames() modify fragments,
|
||||||
|
// therefore the sequential calls produce different results
|
||||||
|
fragment = deserializer.deserialize(ByteArrayInputStream(it.value))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invalidateForFile(srcPath: String) {
|
||||||
|
binaryAsts.remove(srcPath)
|
||||||
|
fragments.remove(srcPath)
|
||||||
|
}
|
||||||
|
|
||||||
fun invalidateForFile(srcPath: String) = binaryAsts.remove(srcPath)
|
|
||||||
fun getAst(srcPath: String) = binaryAsts[srcPath]
|
fun getAst(srcPath: String) = binaryAsts[srcPath]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ fun ScriptEngine.runTestFunction(
|
|||||||
testModuleName: String?,
|
testModuleName: String?,
|
||||||
testPackageName: String?,
|
testPackageName: String?,
|
||||||
testFunctionName: String,
|
testFunctionName: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean,
|
||||||
|
testFunctionArgs: String = "",
|
||||||
): String {
|
): String {
|
||||||
var script = when {
|
var script = when {
|
||||||
withModuleSystem -> "\$kotlin_test_internal\$.require('" + testModuleName!! + "')"
|
withModuleSystem -> "\$kotlin_test_internal\$.require('" + testModuleName!! + "')"
|
||||||
@@ -38,7 +39,7 @@ fun ScriptEngine.runTestFunction(
|
|||||||
script += ".$testPackageName"
|
script += ".$testPackageName"
|
||||||
}
|
}
|
||||||
|
|
||||||
script += ".$testFunctionName()"
|
script += ".$testFunctionName($testFunctionArgs)"
|
||||||
|
|
||||||
return eval(script)
|
return eval(script)
|
||||||
}
|
}
|
||||||
@@ -52,7 +53,20 @@ abstract class AbstractJsTestChecker {
|
|||||||
expectedResult: String,
|
expectedResult: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean
|
||||||
) {
|
) {
|
||||||
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem)
|
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, "", withModuleSystem)
|
||||||
|
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkWithTestFunctionArgs(
|
||||||
|
files: List<String>,
|
||||||
|
testModuleName: String?,
|
||||||
|
testPackageName: String?,
|
||||||
|
testFunctionName: String,
|
||||||
|
testFunctionArgs: String,
|
||||||
|
expectedResult: String,
|
||||||
|
withModuleSystem: Boolean
|
||||||
|
) {
|
||||||
|
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, testFunctionArgs, withModuleSystem)
|
||||||
Assert.assertEquals(expectedResult, actualResult.normalize())
|
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,9 +75,10 @@ abstract class AbstractJsTestChecker {
|
|||||||
testModuleName: String?,
|
testModuleName: String?,
|
||||||
testPackageName: String?,
|
testPackageName: String?,
|
||||||
testFunctionName: String,
|
testFunctionName: String,
|
||||||
|
testFunctionArgs: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean
|
||||||
) = run(files) {
|
) = run(files) {
|
||||||
runTestFunction(testModuleName, testPackageName, testFunctionName, withModuleSystem)
|
runTestFunction(testModuleName, testPackageName, testFunctionName, withModuleSystem, testFunctionArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
@@ -45,6 +45,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest {
|
|||||||
runTest("js/js.translator/testData/incremental/invalidation/constVals/");
|
runTest("js/js.translator/testData/incremental/invalidation/constVals/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossModuleReferences")
|
||||||
|
public void testCrossModuleReferences() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/incremental/invalidation/crossModuleReferences/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("fastPath1")
|
@TestMetadata("fastPath1")
|
||||||
public void testFastPath1() throws Exception {
|
public void testFastPath1() throws Exception {
|
||||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath1/");
|
runTest("js/js.translator/testData/incremental/invalidation/fastPath1/");
|
||||||
|
|||||||
@@ -1,2 +1,9 @@
|
|||||||
|
|
||||||
fun box() = Demo(100500) == Demo(15)
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0, 2 -> if (Demo(15) == Demo(15)) return "Fail"
|
||||||
|
1, 3 -> if (Demo(15) != Demo(15)) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 1:
|
STEP 1..3:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
libs: lib1, main
|
STEP 1..3:
|
||||||
STEP 2:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 3:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: stdlib, lib1
|
||||||
|
|||||||
+39
-1
@@ -1 +1,39 @@
|
|||||||
fun box() = Demo("test1").foo() + Demo("test2").foo_inline() + "${Demo("test3").field1}"
|
|
||||||
|
fun isEqual(l: Any?, r: Any?) = if (l == r) true else null
|
||||||
|
|
||||||
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> {
|
||||||
|
isEqual(Demo("test1").foo(), "foo test1") ?: return "Fail function"
|
||||||
|
isEqual(Demo("test2").foo_inline(), "inline foo test2") ?: return "Fail inline function"
|
||||||
|
isEqual(Demo("test3").field1, "field1") ?: return "Fail field"
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
isEqual(Demo("test1").foo(), "foo test1 update") ?: return "Fail function"
|
||||||
|
isEqual(Demo("test2").foo_inline(), "inline foo test2") ?: return "Fail inline function"
|
||||||
|
isEqual(Demo("test3").field1, "field1") ?: return "Fail field"
|
||||||
|
}
|
||||||
|
2, 3, 4 -> {
|
||||||
|
isEqual(Demo("test1").foo(), "foo test1 update") ?: return "Fail function"
|
||||||
|
isEqual(Demo("test2").foo_inline(), "inline foo test2 update") ?: return "Fail inline function"
|
||||||
|
isEqual(Demo("test3").field1, "field1") ?: return "Fail field"
|
||||||
|
}
|
||||||
|
5, 6, 7, 8, 9 -> {
|
||||||
|
isEqual(Demo("test1").foo(), "foo test1 update") ?: return "Fail function"
|
||||||
|
isEqual(Demo("test2").foo_inline(), "inline foo test2 update") ?: return "Fail inline function"
|
||||||
|
isEqual(Demo("test3").field1, "field1 update") ?: return "Fail field"
|
||||||
|
}
|
||||||
|
10 -> {
|
||||||
|
isEqual(Demo("test1").foo(), "foo test1 update") ?: return "Fail function"
|
||||||
|
isEqual(Demo("test2").foo_inline(), "inline foo test2 update") ?: return "Fail inline function"
|
||||||
|
isEqual(Demo("test3").field1, 77) ?: return "Fail field"
|
||||||
|
}
|
||||||
|
11 -> {
|
||||||
|
isEqual(Demo("test1").foo(), "foo test1 update") ?: return "Fail function"
|
||||||
|
isEqual(Demo("test2").foo_inline(), "inline foo test2 update") ?: return "Fail inline function"
|
||||||
|
isEqual(Demo("test3").field1, null) ?: return "Fail field"
|
||||||
|
}
|
||||||
|
else -> return "Unkown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+4
-20
@@ -3,27 +3,11 @@ STEP 0:
|
|||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
STEP 2:
|
STEP 2..3:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 3:
|
STEP 4..9:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
STEP 10..11:
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 5:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 6:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 7:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 8:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 9:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 10:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 11:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|||||||
+11
-14
@@ -2,25 +2,22 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: stdlib, lib1, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 2:
|
dirty js: lib1
|
||||||
|
STEP 2..3:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 3:
|
dirty js: lib1, main
|
||||||
libs: lib1, main
|
STEP 4..6:
|
||||||
STEP 4:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 5:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 6:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1
|
||||||
STEP 7:
|
STEP 7:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 8:
|
dirty js: stdlib, lib1
|
||||||
|
STEP 8..9:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 9:
|
dirty js: lib1
|
||||||
libs: lib1, main
|
STEP 10..11:
|
||||||
STEP 10:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 11:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: l2.kt
|
dirty: l2.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
|
|||||||
@@ -1,2 +1,15 @@
|
|||||||
|
|
||||||
fun box() = qux() == bar()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> {
|
||||||
|
if (qux() != "FOO") return "Fail qux"
|
||||||
|
if (bar() != "FOO") return "Fail bar"
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
if (qux() != "BAR") return "Fail qux"
|
||||||
|
if (bar() != "BAR") return "Fail bar"
|
||||||
|
}
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ MODULES: lib1, lib2, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, lib2, main
|
libs: lib1, lib2, main
|
||||||
|
dirty js: stdlib, lib1, lib2, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, lib2, main
|
libs: lib1, lib2, main
|
||||||
|
dirty js: lib1
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo() = 42
|
||||||
|
fun bar() = 24
|
||||||
|
|
||||||
|
fun baz(s: String) = s.length
|
||||||
|
fun baz(i: Int) = i + 2
|
||||||
|
fun baz(b: Boolean) = if (b) 10 else 1
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
STEP 0:
|
||||||
|
dependencies: stdlib
|
||||||
|
dirty: l1.kt
|
||||||
|
STEP 1..6:
|
||||||
|
dependencies: stdlib
|
||||||
|
flags: FP
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
fun qux() = foo() + 2
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
fun qux() = foo() + bar()
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
fun qux() = foo() - 2
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
fun qux() = baz(2) + baz("test") + baz(true)
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
fun qux() = baz("test") + baz(true)
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
fun qux() = baz("test") + 100
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
STEP 0:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
dirty: l2.kt
|
||||||
|
STEP 1:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
modifications:
|
||||||
|
U : l2.kt.1.txt -> l2.kt
|
||||||
|
dirty: l2.kt
|
||||||
|
STEP 2:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
modifications:
|
||||||
|
U : l2.kt.2.txt -> l2.kt
|
||||||
|
dirty: l2.kt
|
||||||
|
STEP 3:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
modifications:
|
||||||
|
U : l2.kt.3.txt -> l2.kt
|
||||||
|
dirty: l2.kt
|
||||||
|
STEP 4:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
modifications:
|
||||||
|
U : l2.kt.4.txt -> l2.kt
|
||||||
|
dirty: l2.kt
|
||||||
|
STEP 5:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
flags: FP
|
||||||
|
STEP 6:
|
||||||
|
dependencies: stdlib, lib1
|
||||||
|
modifications:
|
||||||
|
U : l2.kt.6.txt -> l2.kt
|
||||||
|
dirty: l2.kt
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (qux() != 44) return "Fail"
|
||||||
|
1 -> if (qux() != 66) return "Fail"
|
||||||
|
2 -> if (qux() != 40) return "Fail"
|
||||||
|
3 -> if (qux() != 18) return "Fail"
|
||||||
|
4 -> if (qux() != 14) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
5 -> if (qux() != 14) return "Fail"
|
||||||
|
6 -> if (qux() != 104) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
if (baz(77) != 79) return "Fail"
|
||||||
|
if (baz("test") != 4) return "Fail"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
STEP 0:
|
||||||
|
dependencies: stdlib, lib1, lib2
|
||||||
|
dirty: m.kt
|
||||||
|
STEP 1..4:
|
||||||
|
dependencies: stdlib, lib1, lib2
|
||||||
|
STEP 5:
|
||||||
|
dependencies: stdlib, lib1, lib2
|
||||||
|
modifications:
|
||||||
|
U : m.kt.5.txt -> m.kt
|
||||||
|
dirty: m.kt
|
||||||
|
STEP 6:
|
||||||
|
dependencies: stdlib, lib1, lib2
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
MODULES: lib1, lib2, main
|
||||||
|
|
||||||
|
STEP 0:
|
||||||
|
libs: lib1, lib2, main
|
||||||
|
dirty js: stdlib, lib1, lib2, main
|
||||||
|
STEP 1..4:
|
||||||
|
libs: lib1, lib2, main
|
||||||
|
dirty js: lib1, lib2
|
||||||
|
STEP 5:
|
||||||
|
libs: lib1, lib2, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
STEP 6:
|
||||||
|
libs: lib1, lib2, main
|
||||||
|
dirty js: lib1, lib2, main
|
||||||
@@ -3,5 +3,4 @@ STEP 0:
|
|||||||
dirty: l1.kt
|
dirty: l1.kt
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib
|
dependencies: stdlib
|
||||||
dirty:
|
|
||||||
flags: FP
|
flags: FP
|
||||||
|
|||||||
+1
-2
@@ -1,9 +1,8 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: l2.kt
|
dirty: l2.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
modifications:
|
modifications:
|
||||||
U : l2.kt.1 -> l2.kt
|
U : l2.kt.1 -> l2.kt
|
||||||
dirty: l2.kt
|
dirty: l2.kt
|
||||||
|
|||||||
@@ -1,2 +1,9 @@
|
|||||||
|
|
||||||
fun box() = qux()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (qux() != 42) return "Fail"
|
||||||
|
1 -> if (qux() != 44) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ MODULES: lib1, lib2, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, lib2, main
|
libs: lib1, lib2, main
|
||||||
|
dirty js: stdlib, lib1, lib2, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, lib2, main
|
libs: lib1, lib2, main
|
||||||
|
dirty js: lib2
|
||||||
|
|||||||
@@ -3,5 +3,4 @@ STEP 0:
|
|||||||
dirty: l1.kt
|
dirty: l1.kt
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib
|
dependencies: stdlib
|
||||||
dirty:
|
|
||||||
flags: FP
|
flags: FP
|
||||||
|
|||||||
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: l2.kt
|
dirty: l2.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
flags: FP
|
flags: FP
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
|
|
||||||
fun box() = qux()
|
fun box() = if (qux() == 42) "OK" else "Fail"
|
||||||
|
|||||||
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
flags: FP
|
flags: FP
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ MODULES: lib1, lib2, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, lib2, main
|
libs: lib1, lib2, main
|
||||||
|
dirty js: stdlib, lib1, lib2, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, lib2, main
|
libs: lib1, lib2, main
|
||||||
|
|||||||
+10
-1
@@ -1,2 +1,11 @@
|
|||||||
|
|
||||||
fun box() = foo()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (foo() != (42 + 77)) return "Fail"
|
||||||
|
1 -> if (foo() != (42 + 88)) return "Fail"
|
||||||
|
2 -> if (foo() != (42 + 88 + 11)) return "Fail"
|
||||||
|
3 -> if (foo() != (42 + 88 + 22)) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+4
@@ -2,9 +2,13 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: stdlib, lib1, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1
|
||||||
STEP 2:
|
STEP 2:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
STEP 3:
|
STEP 3:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1
|
||||||
|
|||||||
+22
-1
@@ -1,2 +1,23 @@
|
|||||||
|
|
||||||
fun box() = foo()
|
fun isEqual(l: Any?, r: Any?) = if (l == r) true else null
|
||||||
|
|
||||||
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0, 8, 15, 16 -> isEqual(foo(), 42) ?: return "Fail"
|
||||||
|
1 -> isEqual(foo(), false) ?: return "Fail"
|
||||||
|
2 -> isEqual(foo(), 3.14) ?: return "Fail"
|
||||||
|
3, 5, 6, 12 -> isEqual(foo(), "string") ?: return "Fail"
|
||||||
|
4 -> isEqual(foo(), null) ?: return "Fail"
|
||||||
|
7 -> {
|
||||||
|
foo() // Unit
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
9 -> isEqual(foo(), 42 + 77) ?: return "Fail"
|
||||||
|
10 -> isEqual(foo(), 42 + 98 + 1) ?: return "Fail"
|
||||||
|
11 -> isEqual(foo(), 42 + 91) ?: return "Fail"
|
||||||
|
13 -> isEqual(foo(), 99) ?: return "Fail"
|
||||||
|
14 -> isEqual(foo(), 1L) ?: return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+1
-49
@@ -1,51 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..16:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 5:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 6:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 7:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 8:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 9:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 10:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 11:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 12:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 13:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 14:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 15:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 16:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|||||||
+7
-29
@@ -2,35 +2,13 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
|
STEP 1..6:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 2:
|
dirty js: lib1, main
|
||||||
|
STEP 7..8:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 3:
|
dirty js: stdlib, lib1, main
|
||||||
libs: lib1, main
|
STEP 9..16:
|
||||||
STEP 4:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 5:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 6:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 7:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 8:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 9:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 10:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 11:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 12:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 13:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 14:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 15:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 16:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
|
|
||||||
fun box() = foo("demo")
|
fun box() = foo("OK")
|
||||||
|
|||||||
+1
-13
@@ -1,15 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..4:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|||||||
+3
-7
@@ -2,11 +2,7 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
libs: lib1, main
|
STEP 1..4:
|
||||||
STEP 2:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 3:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 4:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
|||||||
Vendored
+3
-57
@@ -3,25 +3,7 @@ STEP 0:
|
|||||||
modifications:
|
modifications:
|
||||||
U : proxy.kt.0.txt -> proxy.kt
|
U : proxy.kt.0.txt -> proxy.kt
|
||||||
dirty: proxy.kt
|
dirty: proxy.kt
|
||||||
STEP 1:
|
STEP 1..7:
|
||||||
dependencies: stdlib
|
|
||||||
flags: FP
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib
|
|
||||||
flags: FP
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib
|
|
||||||
flags: FP
|
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib
|
|
||||||
flags: FP
|
|
||||||
STEP 5:
|
|
||||||
dependencies: stdlib
|
|
||||||
flags: FP
|
|
||||||
STEP 6:
|
|
||||||
dependencies: stdlib
|
|
||||||
flags: FP
|
|
||||||
STEP 7:
|
|
||||||
dependencies: stdlib
|
dependencies: stdlib
|
||||||
flags: FP
|
flags: FP
|
||||||
STEP 8:
|
STEP 8:
|
||||||
@@ -29,25 +11,7 @@ STEP 8:
|
|||||||
modifications:
|
modifications:
|
||||||
U : proxy.kt.1.txt -> proxy.kt
|
U : proxy.kt.1.txt -> proxy.kt
|
||||||
dirty: proxy.kt
|
dirty: proxy.kt
|
||||||
STEP 9:
|
STEP 9..15:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 10:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 11:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 12:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 13:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 14:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 15:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: proxy.kt
|
dirty: proxy.kt
|
||||||
STEP 16:
|
STEP 16:
|
||||||
@@ -55,24 +19,6 @@ STEP 16:
|
|||||||
modifications:
|
modifications:
|
||||||
U : proxy.kt.2.txt -> proxy.kt
|
U : proxy.kt.2.txt -> proxy.kt
|
||||||
dirty: proxy.kt
|
dirty: proxy.kt
|
||||||
STEP 17:
|
STEP 17..23:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 18:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 19:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 20:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 21:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 22:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: proxy.kt
|
|
||||||
STEP 23:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: proxy.kt
|
dirty: proxy.kt
|
||||||
|
|||||||
+13
-1
@@ -1,2 +1,14 @@
|
|||||||
|
|
||||||
fun box() = foo("demo")
|
fun isEqual(l: Any?, r: Any?) = if (l == r) true else null
|
||||||
|
|
||||||
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
in 0..5 -> isEqual(foo("test"), 123) ?: return "Fail"
|
||||||
|
in 8..13 -> isEqual(foo("test"), 123) ?: return "Fail"
|
||||||
|
in 16..21 -> isEqual(foo("test"), 123) ?: return "Fail"
|
||||||
|
6, 14, 22 -> isEqual(foo("test"), 99) ?: return "Fail"
|
||||||
|
7, 15, 23 -> isEqual(foo("test"), "test") ?: return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+13
-1
@@ -1,2 +1,14 @@
|
|||||||
|
|
||||||
fun box() = foo_proxy("demo")
|
fun isEqual(l: Any?, r: Any?) = if (l == r) true else null
|
||||||
|
|
||||||
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
in 0..5 -> isEqual(foo_proxy("test"), 123) ?: return "Fail"
|
||||||
|
in 8..13 -> isEqual(foo_proxy("test"), 123) ?: return "Fail"
|
||||||
|
in 16..21 -> isEqual(foo_proxy("test"), 123) ?: return "Fail"
|
||||||
|
6, 14, 22 -> isEqual(foo_proxy("test"), 99) ?: return "Fail"
|
||||||
|
7, 15, 23 -> isEqual(foo_proxy("test"), "test") ?: return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+2
-65
@@ -1,25 +1,4 @@
|
|||||||
STEP 0:
|
STEP 0..7:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 5:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 6:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 7:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 8:
|
STEP 8:
|
||||||
@@ -27,48 +6,6 @@ STEP 8:
|
|||||||
modifications:
|
modifications:
|
||||||
U : m.proxy.kt.txt -> m.kt
|
U : m.proxy.kt.txt -> m.kt
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 9:
|
STEP 9..23:
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 10:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 11:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 12:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 13:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 14:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 15:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 16:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 17:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 18:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 19:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 20:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 21:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 22:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 23:
|
|
||||||
dependencies: stdlib, lib1, libProxy
|
dependencies: stdlib, lib1, libProxy
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|||||||
+13
-40
@@ -2,49 +2,22 @@ MODULES: lib1, main, libProxy
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
|
STEP 1..5:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 2:
|
dirty js: lib1, main
|
||||||
|
STEP 6..7:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 3:
|
dirty js: stdlib, lib1, main
|
||||||
libs: lib1, main
|
STEP 8..13:
|
||||||
STEP 4:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 5:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 6:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 7:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 8:
|
|
||||||
libs: lib1, libProxy, main
|
libs: lib1, libProxy, main
|
||||||
STEP 9:
|
dirty js: lib1, libProxy, main
|
||||||
|
STEP 14..16:
|
||||||
libs: lib1, libProxy, main
|
libs: lib1, libProxy, main
|
||||||
STEP 10:
|
dirty js: stdlib, lib1, libProxy, main
|
||||||
|
STEP 17..21:
|
||||||
libs: lib1, libProxy, main
|
libs: lib1, libProxy, main
|
||||||
STEP 11:
|
dirty js: lib1, libProxy, main
|
||||||
libs: lib1, libProxy, main
|
STEP 22..23:
|
||||||
STEP 12:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 13:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 14:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 15:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 16:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 17:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 18:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 19:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 20:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 21:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 22:
|
|
||||||
libs: lib1, libProxy, main
|
|
||||||
STEP 23:
|
|
||||||
libs: lib1, libProxy, main
|
libs: lib1, libProxy, main
|
||||||
|
dirty js: stdlib, lib1, libProxy, main
|
||||||
|
|||||||
+8
-1
@@ -1,2 +1,9 @@
|
|||||||
|
|
||||||
fun box() = foo()
|
fun box(stepId: Int): String {
|
||||||
|
when(stepId) {
|
||||||
|
0, 1 -> if (foo() != 42) return "Fail"
|
||||||
|
2 -> if (foo() != 77) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+1
-4
@@ -1,7 +1,4 @@
|
|||||||
STEP 0:
|
STEP 0..1:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 2:
|
STEP 2:
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
MODULES: lib1, main
|
MODULES: lib1, main
|
||||||
|
|
||||||
STEP 0:
|
STEP 0..1:
|
||||||
libs: lib1, main
|
|
||||||
STEP 1:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: stdlib, lib1, main
|
||||||
STEP 2:
|
STEP 2:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1
|
||||||
|
|||||||
+48
-1
@@ -1,6 +1,53 @@
|
|||||||
|
|
||||||
|
fun isEqual(l: Any?, r: Any?) = if (l == r) true else null
|
||||||
|
|
||||||
inline fun test1(x: () -> Any) = x()
|
inline fun test1(x: () -> Any) = x()
|
||||||
fun test2(x: () -> Any) = x()
|
fun test2(x: () -> Any) = x()
|
||||||
inline fun test3(x: () -> Any) = x()
|
inline fun test3(x: () -> Any) = x()
|
||||||
|
|
||||||
fun box() = test1(::foo1).toString() + test2(::foo2).toString() + test3 { foo3() }.toString()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> {
|
||||||
|
isEqual(test1(::foo1), "foo1") ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), "foo2") ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
isEqual(test1(::foo1), "foo1 update") ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), "foo2") ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
isEqual(test1(::foo1), "foo1 update") ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), "foo2 update") ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
3 -> {
|
||||||
|
isEqual(test1(::foo1), 77) ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), "foo2 update") ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
4 -> {
|
||||||
|
isEqual(test1(::foo1), 77) ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), 88) ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
5, 6 -> {
|
||||||
|
isEqual(test1(::foo1), 77) ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), 88) ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3 update") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
7, 8 -> {
|
||||||
|
isEqual(test1(::foo1), 99) ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), 88) ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3 update") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
9 -> {
|
||||||
|
isEqual(test1(::foo1), 88) ?: return "Fail foo1"
|
||||||
|
isEqual(test2(::foo2), 88) ?: return "Fail foo2"
|
||||||
|
isEqual(test3 { foo3() }, "foo3 update") ?: return "Fail foo3"
|
||||||
|
}
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+2
-22
@@ -1,28 +1,8 @@
|
|||||||
STEP 0:
|
STEP 0..1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 2:
|
STEP 2:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
STEP 3:
|
STEP 3..9:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 5:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 6:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 7:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 8:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 9:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|||||||
+5
-13
@@ -2,21 +2,13 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: stdlib, lib1, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
STEP 2:
|
STEP 2:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 3:
|
dirty js: lib1
|
||||||
libs: lib1, main
|
STEP 3..9:
|
||||||
STEP 4:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 5:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 6:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 7:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 8:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 9:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
|||||||
+8
-1
@@ -1,2 +1,9 @@
|
|||||||
|
|
||||||
fun box() = foo()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (foo() != (42 + 77)) return "Fail"
|
||||||
|
1, 2, 3 -> if (foo() != (42 + 88)) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+1
-10
@@ -1,12 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..3:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|||||||
Vendored
+3
-5
@@ -2,9 +2,7 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
libs: lib1, main
|
STEP 1..3:
|
||||||
STEP 2:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 3:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
inline fun foo() = js("40 + 2")
|
inline fun foo() = js("42 + 1")
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
inline fun foo() = js("'42'")
|
inline fun foo() = js("'44'")
|
||||||
|
|||||||
@@ -1,2 +1,11 @@
|
|||||||
|
|
||||||
fun box() = foo()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (foo() != 42) return "Fail"
|
||||||
|
1 -> if (foo() != 43) return "Fail"
|
||||||
|
2 -> if (foo() != "44") return "Fail"
|
||||||
|
3 -> if (foo() != "hello") return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+1
-11
@@ -1,13 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..3:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
libs: lib1, main
|
STEP 1..3:
|
||||||
STEP 2:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 3:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1, main
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
|
|
||||||
fun box() = foo() + gaz()
|
fun box(): String {
|
||||||
|
if (foo() != 77) return "Fail foo"
|
||||||
|
if (gaz() != 99) return "Fail gaz"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+2
-15
@@ -1,18 +1,5 @@
|
|||||||
STEP 0:
|
STEP 0..3:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 1:
|
STEP 4..6:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 3:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
dirty: m.kt
|
|
||||||
STEP 4:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 5:
|
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 6:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
|
|||||||
@@ -2,15 +2,10 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 1:
|
dirty js: stdlib, lib1, main
|
||||||
|
STEP 1..3:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
STEP 2:
|
dirty js: lib1, main
|
||||||
libs: lib1, main
|
STEP 4..6:
|
||||||
STEP 3:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 4:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 5:
|
|
||||||
libs: lib1, main
|
|
||||||
STEP 6:
|
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: lib1
|
||||||
|
|||||||
+4
-1
@@ -1,2 +1,5 @@
|
|||||||
|
|
||||||
fun box() = qux()
|
fun box(): String {
|
||||||
|
if (qux() != 42) return "Fail"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+4
-1
@@ -1,2 +1,5 @@
|
|||||||
|
|
||||||
fun box() = qux() + 88
|
fun box(): String {
|
||||||
|
if (qux() != 42) return "Fail qux"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
-1
@@ -1,7 +1,6 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt, m0.kt, m1.kt
|
dirty: m.kt, m0.kt, m1.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
modifications:
|
modifications:
|
||||||
|
|||||||
+2
-1
@@ -2,6 +2,7 @@ MODULES: lib1, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: stdlib, lib1, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, main
|
libs: lib1, main
|
||||||
|
dirty js: main
|
||||||
|
|||||||
Vendored
-2
@@ -5,8 +5,6 @@ STEP 1:
|
|||||||
dependencies: stdlib
|
dependencies: stdlib
|
||||||
modifications:
|
modifications:
|
||||||
D : l12.kt
|
D : l12.kt
|
||||||
dirty:
|
|
||||||
|
|
||||||
STEP 2:
|
STEP 2:
|
||||||
dependencies: stdlib
|
dependencies: stdlib
|
||||||
modifications:
|
modifications:
|
||||||
|
|||||||
Vendored
+1
-3
@@ -1,15 +1,13 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: l21.kt
|
dirty: l21.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
modifications:
|
modifications:
|
||||||
U : l22.kt.1 -> l22.kt
|
U : l22.kt.1 -> l22.kt
|
||||||
dirty: l21.kt, l22.kt
|
dirty: l21.kt, l22.kt
|
||||||
|
|
||||||
STEP 2:
|
STEP 2:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
modifications:
|
modifications:
|
||||||
D : l22.kt
|
D : l22.kt
|
||||||
dirty: l21.kt
|
dirty: l21.kt
|
||||||
|
|||||||
Vendored
+1
-9
@@ -1,11 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..2:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
dirty: l3.kt
|
dirty: l3.kt
|
||||||
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1, lib2
|
|
||||||
dirty: l3.kt
|
|
||||||
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1, lib2
|
|
||||||
dirty: l3.kt
|
|
||||||
+9
-1
@@ -1,2 +1,10 @@
|
|||||||
|
|
||||||
fun box() = dex(4, 2)
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (dex(4, 2) != 11) return "Fail"
|
||||||
|
1 -> if (dex(4, 2) != 10) return "Fail"
|
||||||
|
2 -> if (dex(4, 2) != 9) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+1
-9
@@ -1,11 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..2:
|
||||||
dependencies: stdlib, lib1, lib2, lib3
|
dependencies: stdlib, lib1, lib2, lib3
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1, lib2, lib3
|
|
||||||
dirty: m.kt
|
|
||||||
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1, lib2, lib3
|
|
||||||
dirty: m.kt
|
|
||||||
+3
-5
@@ -2,9 +2,7 @@ MODULES: lib1, lib2, lib3, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, lib2, lib3, main
|
libs: lib1, lib2, lib3, main
|
||||||
|
dirty js: stdlib, lib1, lib2, lib3, main
|
||||||
STEP 1:
|
STEP 1..2:
|
||||||
libs: lib1, lib2, lib3, main
|
libs: lib1, lib2, lib3, main
|
||||||
|
dirty js: lib1, lib2, lib3, main
|
||||||
STEP 2:
|
|
||||||
libs: lib1, lib2, lib3, main
|
|
||||||
|
|||||||
js/js.translator/testData/incremental/invalidation/moveInlineFunctionBetweenModules/lib2/module.info
Vendored
+1
-2
@@ -1,9 +1,8 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: l2.kt
|
dirty: l2.kt
|
||||||
|
|
||||||
STEP 1:
|
STEP 1:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
modifications:
|
modifications:
|
||||||
U : l22.kt.1 -> l22.kt
|
U : l22.kt.1 -> l22.kt
|
||||||
dirty: l2.kt, l22.kt
|
dirty: l2.kt, l22.kt
|
||||||
|
|||||||
js/js.translator/testData/incremental/invalidation/moveInlineFunctionBetweenModules/lib3/module.info
Vendored
+1
-5
@@ -1,7 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..1:
|
||||||
dependencies: stdlib, lib1, lib2
|
dependencies: stdlib, lib1, lib2
|
||||||
dirty: l3.kt
|
dirty: l3.kt
|
||||||
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1, lib2
|
|
||||||
dirty: l3.kt
|
|
||||||
Vendored
+8
-1
@@ -1,2 +1,9 @@
|
|||||||
|
|
||||||
fun box() = dex(4, 2)
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (dex(4, 2) != 11) return "Fail"
|
||||||
|
1 -> if (dex(4, 2) != 18) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
js/js.translator/testData/incremental/invalidation/moveInlineFunctionBetweenModules/main/module.info
Vendored
+1
-5
@@ -1,7 +1,3 @@
|
|||||||
STEP 0:
|
STEP 0..1:
|
||||||
dependencies: stdlib, lib1, lib2, lib3
|
dependencies: stdlib, lib1, lib2, lib3
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
|
|
||||||
STEP 1:
|
|
||||||
dependencies: stdlib, lib1, lib2, lib3
|
|
||||||
dirty: m.kt
|
|
||||||
Vendored
+3
-2
@@ -2,6 +2,7 @@ MODULES: lib1, lib2, lib3, main
|
|||||||
|
|
||||||
STEP 0:
|
STEP 0:
|
||||||
libs: lib1, lib2, lib3, main
|
libs: lib1, lib2, lib3, main
|
||||||
|
dirty js: stdlib, lib1, lib2, lib3, main
|
||||||
STEP 1:
|
STEP 1:
|
||||||
libs: lib1, lib2, lib3, main
|
libs: lib1, lib2, lib3, main
|
||||||
|
dirty js: lib1, lib2, lib3, main
|
||||||
|
|||||||
+9
-1
@@ -1,2 +1,10 @@
|
|||||||
|
|
||||||
fun box() = foo()
|
fun box(stepId: Int): String {
|
||||||
|
when (stepId) {
|
||||||
|
0 -> if (foo() != 42) return "Fail"
|
||||||
|
1 -> if (foo() != 33) return "Fail"
|
||||||
|
2 -> if (foo() != 77) return "Fail"
|
||||||
|
else -> return "Unknown"
|
||||||
|
}
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|||||||
+1
-3
@@ -1,7 +1,5 @@
|
|||||||
STEP 0:
|
STEP 0:
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
dirty: m.kt
|
dirty: m.kt
|
||||||
STEP 1:
|
STEP 1..2:
|
||||||
dependencies: stdlib, lib1
|
|
||||||
STEP 2:
|
|
||||||
dependencies: stdlib, lib1
|
dependencies: stdlib, lib1
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user