JS IR: support kotlin.test
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.backend.common.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
|
||||
val IrDeclaration.isExpect get() = descriptor.let { it is MemberDescriptor && it.isExpect }
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceKey
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ConstructorPair
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
@@ -81,6 +82,17 @@ class JsIrBackendContext(
|
||||
}
|
||||
}
|
||||
|
||||
private var testContainerField: IrSimpleFunction? = null
|
||||
|
||||
val hasTests get() = testContainerField != null
|
||||
|
||||
val testContainer
|
||||
get() = testContainerField ?: JsIrBuilder.buildFunction("test fun", irBuiltIns.unitType, implicitDeclarationFile).apply {
|
||||
body = JsIrBuilder.buildBlockBody(emptyList())
|
||||
testContainerField = this
|
||||
implicitDeclarationFile.declarations += this
|
||||
}
|
||||
|
||||
override val sharedVariablesManager = JsSharedVariablesManager(irBuiltIns, implicitDeclarationFile)
|
||||
override val declarationFactory = JsDeclarationFactory()
|
||||
|
||||
@@ -224,6 +236,9 @@ class JsIrBackendContext(
|
||||
|
||||
val throwISEymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single())
|
||||
|
||||
val suiteFun = getFunctions(FqName("kotlin.test.suite")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) }
|
||||
val testFun = getFunctions(FqName("kotlin.test.test")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) }
|
||||
|
||||
val coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
|
||||
val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
|
||||
val coroutineImplResultSymbolGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner }
|
||||
|
||||
@@ -333,10 +333,17 @@ private val callsLoweringPhase = makeJsModulePhase(
|
||||
description = "Handle intrinsics"
|
||||
)
|
||||
|
||||
private val testGenerationPhase = makeJsModulePhase(
|
||||
::TestGenerator,
|
||||
name = "TestGenerationLowering",
|
||||
description = "Generate invocations to kotlin.test suite and test functions"
|
||||
)
|
||||
|
||||
val jsPhases = namedIrModulePhase(
|
||||
name = "IrModuleLowering",
|
||||
description = "IR module lowering",
|
||||
lower = expectDeclarationsRemovingPhase then
|
||||
lower = testGenerationPhase then
|
||||
expectDeclarationsRemovingPhase then
|
||||
functionInliningPhase then
|
||||
lateinitLoweringPhase then
|
||||
tailrecLoweringPhase then
|
||||
|
||||
@@ -5,27 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -149,6 +140,9 @@ object JsIrBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
fun buildAnonymousInitializer() =
|
||||
IrAnonymousInitializerImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor()))
|
||||
|
||||
fun buildGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
|
||||
IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, classSymbol)
|
||||
|
||||
@@ -257,6 +251,7 @@ object JsIrBuilder {
|
||||
fun buildBoolean(type: IrType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||
fun buildInt(type: IrType, v: Int) = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
|
||||
fun buildString(type: IrType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
|
||||
fun buildTry(type: IrType) = IrTryImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
|
||||
fun buildCatch(ex: IrVariable, block: IrBlockImpl) = IrCatchImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ex, block)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.isExpect
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.fqNameSafe
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class TestGenerator(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.declarations.forEach {
|
||||
if (it is IrClass) {
|
||||
generateTestCalls(it) { suiteForPackage(irFile.fqName).body }
|
||||
}
|
||||
|
||||
// TODO top-level functions
|
||||
}
|
||||
}
|
||||
|
||||
private val packageSuites = mutableMapOf<FqName, FunctionWithBody>()
|
||||
|
||||
private fun suiteForPackage(fqName: FqName) = packageSuites.getOrPut(fqName) {
|
||||
context.suiteFun!!.createInvocation(fqName.asString(), context.testContainer.body as IrBlockBody)
|
||||
}
|
||||
|
||||
private data class FunctionWithBody(val function: IrSimpleFunction, val body: IrBlockBody)
|
||||
|
||||
private fun IrSimpleFunctionSymbol.createInvocation(
|
||||
name: String,
|
||||
parentBody: IrBlockBody,
|
||||
ignored: Boolean = false
|
||||
): FunctionWithBody {
|
||||
val body = JsIrBuilder.buildBlockBody(emptyList())
|
||||
|
||||
val function = JsIrBuilder.buildFunction(
|
||||
"$name test fun",
|
||||
context.irBuiltIns.unitType,
|
||||
context.implicitDeclarationFile
|
||||
).also {
|
||||
it.body = body
|
||||
context.implicitDeclarationFile.declarations += it
|
||||
}
|
||||
|
||||
parentBody.statements += JsIrBuilder.buildCall(this).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildString(context.irBuiltIns.stringType, name))
|
||||
putValueArgument(1, JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, ignored))
|
||||
|
||||
val refType = IrSimpleTypeImpl(context.functionN(0), false, emptyList(), emptyList())
|
||||
putValueArgument(2, JsIrBuilder.buildFunctionReference(refType, function.symbol))
|
||||
}
|
||||
|
||||
return FunctionWithBody(function, body)
|
||||
}
|
||||
|
||||
private fun generateTestCalls(irClass: IrClass, parentBody: () -> IrBlockBody) {
|
||||
if (irClass.modality == Modality.ABSTRACT || irClass.isEffectivelyExternal() || irClass.isExpect) return
|
||||
|
||||
val suiteFunBody by lazy { context.suiteFun!!.createInvocation(irClass.name.asString(), parentBody(), irClass.isIgnored) }
|
||||
|
||||
val beforeFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isBefore }
|
||||
val afterFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>().filter { it.isAfter }
|
||||
|
||||
irClass.declarations.forEach {
|
||||
when {
|
||||
it is IrClass ->
|
||||
generateTestCalls(it) { suiteFunBody.body }
|
||||
|
||||
it is IrSimpleFunction && it.isTest ->
|
||||
generateCodeForTestMethod(it, beforeFunctions, afterFunctions, irClass, suiteFunBody.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateCodeForTestMethod(
|
||||
testFun: IrSimpleFunction,
|
||||
beforeFuns: List<IrSimpleFunction>,
|
||||
afterFuns: List<IrSimpleFunction>,
|
||||
irClass: IrClass,
|
||||
parentBody: IrBlockBody
|
||||
) {
|
||||
val (fn, body) = context.testFun!!.createInvocation(testFun.name.asString(), parentBody, testFun.isIgnored)
|
||||
|
||||
val classVal = JsIrBuilder.buildVar(irClass.defaultType, fn, initializer = irClass.instance())
|
||||
|
||||
body.statements += classVal
|
||||
|
||||
body.statements += beforeFuns.map {
|
||||
JsIrBuilder.buildCall(it.symbol).apply {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(classVal.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
val returnStatement = JsIrBuilder.buildReturn(
|
||||
fn.symbol,
|
||||
JsIrBuilder.buildCall(testFun.symbol).apply {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(classVal.symbol)
|
||||
},
|
||||
context.irBuiltIns.unitType
|
||||
)
|
||||
|
||||
if (afterFuns.isEmpty()) {
|
||||
body.statements += returnStatement
|
||||
} else {
|
||||
body.statements += JsIrBuilder.buildTry(context.irBuiltIns.unitType).apply {
|
||||
tryResult = returnStatement
|
||||
finallyExpression = JsIrBuilder.buildComposite(context.irBuiltIns.unitType).apply {
|
||||
statements += afterFuns.map {
|
||||
JsIrBuilder.buildCall(it.symbol).apply {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(classVal.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.instance(): IrExpression {
|
||||
return if (kind == ClassKind.OBJECT) {
|
||||
JsIrBuilder.buildGetObjectValue(defaultType, symbol)
|
||||
} else {
|
||||
declarations.asSequence().filterIsInstance<IrConstructor>().single { it.isPrimary }.let { constructor ->
|
||||
JsIrBuilder.buildCall(constructor.symbol).also {
|
||||
if (isInner) {
|
||||
it.dispatchReceiver = (parent as IrClass).instance()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IrAnnotationContainer.isTest
|
||||
get() = hasAnnotation("kotlin.test.Test")
|
||||
|
||||
private val IrAnnotationContainer.isIgnored
|
||||
get() = hasAnnotation("kotlin.test.Ignore")
|
||||
|
||||
private val IrAnnotationContainer.isBefore
|
||||
get() = hasAnnotation("kotlin.test.BeforeTest")
|
||||
|
||||
private val IrAnnotationContainer.isAfter
|
||||
get() = hasAnnotation("kotlin.test.AfterTest")
|
||||
|
||||
private fun IrAnnotationContainer.hasAnnotation(fqName: String) =
|
||||
annotations.any { it.symbol.owner.parent.fqNameSafe == FqName(fqName) }
|
||||
}
|
||||
+1
-4
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsDeclarationScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsEmpty
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsVars
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||
|
||||
|
||||
+4
@@ -49,6 +49,10 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
||||
statements += postDeclarationBlock
|
||||
statements += context.staticContext.initializerBlock
|
||||
|
||||
if (backendContext.hasTests) {
|
||||
statements += JsInvocation(context.getNameForSymbol(backendContext.testContainer.symbol).makeRef()).makeStmt()
|
||||
}
|
||||
|
||||
return statements
|
||||
}
|
||||
|
||||
|
||||
@@ -21,25 +21,214 @@ sourceSets {
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
val generateIrRuntimeKlib by task<NoDebugJavaExec> {
|
||||
val inDirs = arrayOf(fileFrom(rootDir, "core", "builtins", "src"),
|
||||
fileFrom(rootDir, "core", "builtins", "native"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "common", "src"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "src", "kotlin"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "js", "src", "generated"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "js", "irRuntime"),
|
||||
fileFrom(rootDir, "libraries", "stdlib", "unsigned"),
|
||||
fileFrom(rootDir, "js", "js.translator", "testData", "_commonFiles"))
|
||||
inDirs.forEach { inputs.dir(it) }
|
||||
val unimplementedNativeBuiltIns =
|
||||
(file("$rootDir/core/builtins/native/kotlin/").list().toSet() - file("$rootDir/libraries/stdlib/js/irRuntime/builtins/").list())
|
||||
.map { "core/builtins/native/kotlin/$it" }
|
||||
|
||||
val outDir = "$rootDir/js/js.translator/testData/out/klibs/"
|
||||
outputs.dir(outDir)
|
||||
// Required to compile native builtins with the rest of runtime
|
||||
val builtInsHeader = """@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
"""
|
||||
|
||||
val fullRuntimeSources by task<Copy> {
|
||||
val sources = listOf(
|
||||
"core/builtins/src/kotlin/",
|
||||
"libraries/stdlib/common/src/",
|
||||
"libraries/stdlib/src/kotlin/",
|
||||
"libraries/stdlib/js/src/kotlin/",
|
||||
"libraries/stdlib/js/src/generated/",
|
||||
"libraries/stdlib/js/irRuntime/",
|
||||
"libraries/stdlib/js/runtime/",
|
||||
"libraries/stdlib/unsigned/",
|
||||
|
||||
// TODO get rid - move to test module
|
||||
"js/js.translator/testData/_commonFiles/"
|
||||
) + unimplementedNativeBuiltIns
|
||||
|
||||
val excluded = listOf(
|
||||
"libraries/stdlib/common/src/kotlin/JvmAnnotationsH.kt",
|
||||
"libraries/stdlib/src/kotlin/annotations/Multiplatform.kt",
|
||||
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt",
|
||||
|
||||
// TODO: Support Int.pow
|
||||
"libraries/stdlib/js/src/kotlin/random/PlatformRandom.kt",
|
||||
|
||||
// Fails with: EXPERIMENTAL_IS_NOT_ENABLED
|
||||
"libraries/stdlib/common/src/kotlin/annotations/Annotations.kt",
|
||||
|
||||
// Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt
|
||||
"libraries/stdlib/js/runtime/hacks.kt",
|
||||
|
||||
// TODO: Reuse in IR BE
|
||||
"libraries/stdlib/js/runtime/Enum.kt",
|
||||
|
||||
// JS-specific optimized version of emptyArray() already defined
|
||||
"core/builtins/src/kotlin/ArrayIntrinsics.kt",
|
||||
|
||||
// Unnecessary for now
|
||||
"libraries/stdlib/js/src/kotlin/dom/**",
|
||||
"libraries/stdlib/js/src/kotlin/browser/**",
|
||||
|
||||
// TODO: fix compilation issues in arrayPlusCollection
|
||||
// Replaced with irRuntime/kotlinHacks.kt
|
||||
"libraries/stdlib/js/src/kotlin/kotlin.kt",
|
||||
|
||||
"libraries/stdlib/js/src/kotlin/currentBeMisc.kt",
|
||||
|
||||
// IR BE has its own generated sources
|
||||
"libraries/stdlib/js/src/generated/**",
|
||||
"libraries/stdlib/js/src/kotlin/collectionsExternal.kt",
|
||||
|
||||
// Full version is defined in stdlib
|
||||
// This file is useful for smaller subset of runtime sources
|
||||
"libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt",
|
||||
|
||||
// Mostly array-specific stuff
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt",
|
||||
|
||||
// coroutines
|
||||
// TODO: merge coroutines_13 with JS BE coroutines
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt",
|
||||
|
||||
// Inlining of js fun doesn't update the variables inside
|
||||
"libraries/stdlib/js/src/kotlin/jsTypeOf.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/utils.kt",
|
||||
|
||||
// TODO: Remove stub
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt",
|
||||
|
||||
// Expect declarations get thrown away and libraries/kotlin.test/common/src/main/kotlin/kotlin/test/Assertions.kt doesn't compile
|
||||
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt"
|
||||
)
|
||||
|
||||
sources.forEach { path ->
|
||||
from("$rootDir/$path") {
|
||||
into(path.dropLastWhile { it != '/' })
|
||||
excluded.filter { it.startsWith(path) }.forEach {
|
||||
exclude(it.substring(path.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
into("$buildDir/fullRuntime/src")
|
||||
|
||||
doLast {
|
||||
unimplementedNativeBuiltIns.forEach { path ->
|
||||
val file = File("$buildDir/fullRuntime/src/$path")
|
||||
val sourceCode = builtInsHeader + file.readText()
|
||||
file.writeText(sourceCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val reducedRuntimeSources by task<Copy> {
|
||||
dependsOn(fullRuntimeSources)
|
||||
|
||||
from(fullRuntimeSources.outputs.files.singleFile) {
|
||||
exclude(
|
||||
listOf(
|
||||
"libraries/stdlib/unsigned/**",
|
||||
"libraries/stdlib/common/src/generated/_Arrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_Collections.kt",
|
||||
"libraries/stdlib/common/src/generated/_Comparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_Maps.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sequences.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sets.kt",
|
||||
"libraries/stdlib/common/src/generated/_Strings.kt",
|
||||
"libraries/stdlib/common/src/generated/_UArrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_URanges.kt",
|
||||
"libraries/stdlib/common/src/generated/_UCollections.kt",
|
||||
"libraries/stdlib/common/src/generated/_UComparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_USequences.kt",
|
||||
"libraries/stdlib/common/src/kotlin/SequencesH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/TextH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/UMath.kt",
|
||||
"libraries/stdlib/common/src/kotlin/collections/**",
|
||||
"libraries/stdlib/common/src/kotlin/ioH.kt",
|
||||
"libraries/stdlib/js/irRuntime/collectionsHacks.kt",
|
||||
"libraries/stdlib/js/irRuntime/generated/**",
|
||||
"libraries/stdlib/js/src/kotlin/char.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/**",
|
||||
"libraries/stdlib/js/src/kotlin/console.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coreDeprecated.kt",
|
||||
"libraries/stdlib/js/src/kotlin/date.kt",
|
||||
"libraries/stdlib/js/src/kotlin/debug.kt",
|
||||
"libraries/stdlib/js/src/kotlin/grouping.kt",
|
||||
"libraries/stdlib/js/src/kotlin/json.kt",
|
||||
"libraries/stdlib/js/src/kotlin/numberConversions.kt",
|
||||
"libraries/stdlib/js/src/kotlin/promise.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regex.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regexp.kt",
|
||||
"libraries/stdlib/js/src/kotlin/sequence.kt",
|
||||
"libraries/stdlib/js/src/kotlin/string.kt",
|
||||
"libraries/stdlib/js/src/kotlin/stringsCode.kt",
|
||||
"libraries/stdlib/js/src/kotlin/text.kt",
|
||||
"libraries/stdlib/src/kotlin/collections/**",
|
||||
"libraries/stdlib/src/kotlin/experimental/bitwiseOperations.kt",
|
||||
"libraries/stdlib/src/kotlin/properties/Delegates.kt",
|
||||
"libraries/stdlib/src/kotlin/random/URandom.kt",
|
||||
"libraries/stdlib/src/kotlin/text/**",
|
||||
"libraries/stdlib/src/kotlin/util/KotlinVersion.kt",
|
||||
"libraries/stdlib/src/kotlin/util/Tuples.kt"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from("$rootDir/libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt") {
|
||||
into("libraries/stdlib/js/irRuntime/")
|
||||
}
|
||||
|
||||
into("$buildDir/reducedRuntime/src")
|
||||
}
|
||||
|
||||
|
||||
fun JavaExec.buildKLib(sources: List<String>, dependencies: List<String>, outPath: String) {
|
||||
inputs.files(sources)
|
||||
outputs.dir(file(outPath).parent)
|
||||
|
||||
classpath = sourceSets.test.get().runtimeClasspath
|
||||
main = "org.jetbrains.kotlin.ir.backend.js.GenerateIrRuntimeKt"
|
||||
workingDir = rootDir
|
||||
args = sources.toList() + listOf("-o", outPath) + dependencies.flatMap { listOf("-d", it) }
|
||||
|
||||
passClasspathInJar()
|
||||
}
|
||||
|
||||
val generateFullRuntimeKLib by task<NoDebugJavaExec> {
|
||||
dependsOn(fullRuntimeSources)
|
||||
|
||||
buildKLib(sources = listOf(fullRuntimeSources.outputs.files.singleFile.path),
|
||||
dependencies = emptyList(),
|
||||
outPath = "$buildDir/fullRuntime/klib/JS_IR_RUNTIME.klm")
|
||||
}
|
||||
|
||||
val generateReducedRuntimeKLib by task<NoDebugJavaExec> {
|
||||
dependsOn(reducedRuntimeSources)
|
||||
|
||||
buildKLib(sources = listOf(reducedRuntimeSources.outputs.files.singleFile.path),
|
||||
dependencies = emptyList(),
|
||||
outPath = "$buildDir/reducedRuntime/klib/JS_IR_RUNTIME.klm")
|
||||
}
|
||||
|
||||
val generateKotlinTestKLib by task<NoDebugJavaExec> {
|
||||
dependsOn(generateFullRuntimeKLib)
|
||||
|
||||
buildKLib(
|
||||
sources = listOf(
|
||||
"$rootDir/libraries/kotlin.test/annotations-common/src/main",
|
||||
"$rootDir/libraries/kotlin.test/common/src/main",
|
||||
"$rootDir/libraries/kotlin.test/js/src/main"
|
||||
),
|
||||
dependencies = listOf("${generateFullRuntimeKLib.outputs.files.singleFile.path}/JS_IR_RUNTIME.klm"),
|
||||
outPath = "$buildDir/kotlin.test/klib/kotlin.test.klm"
|
||||
)
|
||||
}
|
||||
|
||||
testsJar {}
|
||||
@@ -5,21 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import java.io.File
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
|
||||
fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguration {
|
||||
fun buildConfiguration(environment: KotlinCoreEnvironment, moduleName: String): CompilerConfiguration {
|
||||
val runtimeConfiguration = environment.configuration.copy()
|
||||
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, "JS_IR_RUNTIME")
|
||||
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||
runtimeConfiguration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
|
||||
runtimeConfiguration.languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
@@ -37,34 +37,69 @@ fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguratio
|
||||
return runtimeConfiguration
|
||||
}
|
||||
|
||||
private val fullRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeFull/"
|
||||
private val defaultRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeDefault/"
|
||||
val environment = KotlinCoreEnvironment.createForTests(Disposable { }, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
|
||||
fun main() {
|
||||
fun createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(environment.project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val environment = KotlinCoreEnvironment.createForTests(Disposable { }, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
fun createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(environment.project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
|
||||
fun buildKlib(sources: List<String>, outputPath: String) {
|
||||
generateKLib(
|
||||
project = environment.project,
|
||||
files = sources.map(::createPsiFile),
|
||||
configuration = buildConfiguration(environment),
|
||||
immediateDependencies = emptyList(),
|
||||
allDependencies = emptyList(),
|
||||
outputKlibPath = outputPath
|
||||
)
|
||||
}
|
||||
|
||||
buildKlib(JsIrTestRuntime.FULL.sources, fullRuntimeKlibPath)
|
||||
buildKlib(JsIrTestRuntime.DEFAULT.sources, defaultRuntimeKlibPath)
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
|
||||
fun buildKLib(moduleName: String, sources: List<String>, outputPath: String, dependencies: List<KlibModuleRef>): KlibModuleRef {
|
||||
return generateKLib(
|
||||
project = environment.project,
|
||||
files = sources.map(::createPsiFile),
|
||||
configuration = buildConfiguration(environment, moduleName),
|
||||
immediateDependencies = dependencies,
|
||||
allDependencies = dependencies,
|
||||
outputKlibPath = outputPath
|
||||
)
|
||||
}
|
||||
|
||||
private fun listOfKtFilesFrom(paths: List<String>): List<String> {
|
||||
val currentDir = File("")
|
||||
return paths.flatMap { path ->
|
||||
File(path)
|
||||
.walkTopDown()
|
||||
.filter { it.extension == "kt" }
|
||||
.map { it.relativeToOrSelf(currentDir).path }
|
||||
.asIterable()
|
||||
}.distinct()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val inputFiles = mutableListOf<String>()
|
||||
var outputPath: String? = null
|
||||
val dependencies = mutableListOf<String>()
|
||||
|
||||
var index = 0
|
||||
while (index < args.size) {
|
||||
val arg = args[index++]
|
||||
|
||||
when (arg) {
|
||||
"-o" -> outputPath = args[index++]
|
||||
"-d" -> dependencies += args[index++]
|
||||
else -> inputFiles += arg
|
||||
}
|
||||
}
|
||||
|
||||
if (outputPath == null) {
|
||||
error("Please set path to .klm file: `-o some/dir/module-name.klm`")
|
||||
}
|
||||
|
||||
val name = outputPath.takeLastWhile { it != '/' }
|
||||
|
||||
if (!name.endsWith(".klm")) error("invalid output file name")
|
||||
|
||||
val dependencyKLibs = dependencies.map {
|
||||
val file = File(it)
|
||||
KlibModuleRef(file.name.dropLast(4), file.parent)
|
||||
}
|
||||
|
||||
buildKLib(name.dropLast(4), listOfKtFilesFrom(inputFiles), File(outputPath).parent, dependencyKLibs)
|
||||
}
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
private const val runtimeDir = "js/js.translator/testData/out/irBox"
|
||||
|
||||
enum class JsIrTestRuntime(
|
||||
val sources: List<String>,
|
||||
val path: String
|
||||
) {
|
||||
// Includes all built-ins and reduced subset of stdlib
|
||||
DEFAULT(
|
||||
sources = reducedRuntimeSources,
|
||||
path = "$runtimeDir/testRuntime.js"
|
||||
),
|
||||
|
||||
// Includes almost full stdlib
|
||||
FULL(
|
||||
sources = fullRuntimeSources,
|
||||
path = "$runtimeDir/testRuntimeFull.js"
|
||||
)
|
||||
}
|
||||
|
||||
// Required to compile native builtins with the rest of runtime
|
||||
private const val builtInsHeader = """@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
"""
|
||||
|
||||
// Native builtins that were not implemented in JS IR runtime
|
||||
private val unimplementedNativeBuiltInsDir = KotlinTestUtils.tmpDir("unimplementedBuiltins").also { tmpDir ->
|
||||
val allBuiltins = listOfKtFilesFrom("core/builtins/native/kotlin").map { File(it).name }
|
||||
val implementedBuiltIns = listOfKtFilesFrom("libraries/stdlib/js/irRuntime/builtins/").map { File(it).name }
|
||||
val unimplementedBuiltIns = allBuiltins - implementedBuiltIns
|
||||
for (filename in unimplementedBuiltIns) {
|
||||
val originalFile = File("core/builtins/native/kotlin", filename)
|
||||
val newFile = File(tmpDir, filename)
|
||||
val sourceCode = builtInsHeader + originalFile.readText()
|
||||
newFile.writeText(sourceCode)
|
||||
}
|
||||
}
|
||||
|
||||
private val fullRuntimeSources = listOfKtFilesFrom(
|
||||
"core/builtins/src/kotlin",
|
||||
"libraries/stdlib/common/src",
|
||||
"libraries/stdlib/src/kotlin/",
|
||||
"libraries/stdlib/js/src/kotlin",
|
||||
"libraries/stdlib/js/src/generated",
|
||||
"libraries/stdlib/js/irRuntime",
|
||||
"libraries/stdlib/js/runtime",
|
||||
"libraries/stdlib/unsigned",
|
||||
|
||||
"core/builtins/src/kotlin/Unit.kt",
|
||||
unimplementedNativeBuiltInsDir.path,
|
||||
"js/js.translator/testData/_commonFiles"
|
||||
) - listOfKtFilesFrom(
|
||||
"libraries/stdlib/common/src/kotlin/JvmAnnotationsH.kt",
|
||||
"libraries/stdlib/src/kotlin/annotations/Multiplatform.kt",
|
||||
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt",
|
||||
|
||||
// TODO: Support Int.pow
|
||||
"libraries/stdlib/js/src/kotlin/random/PlatformRandom.kt",
|
||||
|
||||
// Fails with: EXPERIMENTAL_IS_NOT_ENABLED
|
||||
"libraries/stdlib/common/src/kotlin/annotations/Annotations.kt",
|
||||
|
||||
// Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt
|
||||
"libraries/stdlib/js/runtime/hacks.kt",
|
||||
|
||||
// TODO: Reuse in IR BE
|
||||
"libraries/stdlib/js/runtime/Enum.kt",
|
||||
|
||||
// JS-specific optimized version of emptyArray() already defined
|
||||
"core/builtins/src/kotlin/ArrayIntrinsics.kt",
|
||||
|
||||
// Unnecessary for now
|
||||
"libraries/stdlib/js/src/kotlin/dom",
|
||||
"libraries/stdlib/js/src/kotlin/browser",
|
||||
|
||||
// TODO: fix compilation issues in arrayPlusCollection
|
||||
// Replaced with irRuntime/kotlinHacks.kt
|
||||
"libraries/stdlib/js/src/kotlin/kotlin.kt",
|
||||
|
||||
"libraries/stdlib/js/src/kotlin/currentBeMisc.kt",
|
||||
|
||||
// IR BE has its own generated sources
|
||||
"libraries/stdlib/js/src/generated",
|
||||
"libraries/stdlib/js/src/kotlin/collectionsExternal.kt",
|
||||
|
||||
// Full version is defined in stdlib
|
||||
// This file is useful for smaller subset of runtime sources
|
||||
"libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt",
|
||||
|
||||
// Mostly array-specific stuff
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt",
|
||||
|
||||
// coroutines
|
||||
// TODO: merge coroutines_13 with JS BE coroutines
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt",
|
||||
|
||||
// Inlining of js fun doesn't update the variables inside
|
||||
"libraries/stdlib/js/src/kotlin/jsTypeOf.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/utils.kt",
|
||||
|
||||
// TODO: Remove stub
|
||||
"libraries/stdlib/js/src/kotlin/builtins.kt"
|
||||
)
|
||||
|
||||
private val reducedRuntimeSources = fullRuntimeSources - listOfKtFilesFrom(
|
||||
"libraries/stdlib/unsigned",
|
||||
"libraries/stdlib/common/src/generated/_Arrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_Collections.kt",
|
||||
"libraries/stdlib/common/src/generated/_Comparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_Maps.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sequences.kt",
|
||||
"libraries/stdlib/common/src/generated/_Sets.kt",
|
||||
"libraries/stdlib/common/src/generated/_Strings.kt",
|
||||
"libraries/stdlib/common/src/generated/_UArrays.kt",
|
||||
"libraries/stdlib/common/src/generated/_URanges.kt",
|
||||
"libraries/stdlib/common/src/generated/_UCollections.kt",
|
||||
"libraries/stdlib/common/src/generated/_UComparisons.kt",
|
||||
"libraries/stdlib/common/src/generated/_USequences.kt",
|
||||
"libraries/stdlib/common/src/kotlin/SequencesH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/TextH.kt",
|
||||
"libraries/stdlib/common/src/kotlin/UMath.kt",
|
||||
"libraries/stdlib/common/src/kotlin/collections/",
|
||||
"libraries/stdlib/common/src/kotlin/ioH.kt",
|
||||
"libraries/stdlib/js/irRuntime/collectionsHacks.kt",
|
||||
"libraries/stdlib/js/irRuntime/generated/",
|
||||
"libraries/stdlib/js/src/kotlin/char.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections.kt",
|
||||
"libraries/stdlib/js/src/kotlin/collections/",
|
||||
"libraries/stdlib/js/src/kotlin/console.kt",
|
||||
"libraries/stdlib/js/src/kotlin/coreDeprecated.kt",
|
||||
"libraries/stdlib/js/src/kotlin/date.kt",
|
||||
"libraries/stdlib/js/src/kotlin/debug.kt",
|
||||
"libraries/stdlib/js/src/kotlin/grouping.kt",
|
||||
"libraries/stdlib/js/src/kotlin/json.kt",
|
||||
"libraries/stdlib/js/src/kotlin/numberConversions.kt",
|
||||
"libraries/stdlib/js/src/kotlin/promise.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regex.kt",
|
||||
"libraries/stdlib/js/src/kotlin/regexp.kt",
|
||||
"libraries/stdlib/js/src/kotlin/sequence.kt",
|
||||
"libraries/stdlib/js/src/kotlin/string.kt",
|
||||
"libraries/stdlib/js/src/kotlin/stringsCode.kt",
|
||||
"libraries/stdlib/js/src/kotlin/text.kt",
|
||||
"libraries/stdlib/src/kotlin/collections/",
|
||||
"libraries/stdlib/src/kotlin/experimental/bitwiseOperations.kt",
|
||||
"libraries/stdlib/src/kotlin/properties/Delegates.kt",
|
||||
"libraries/stdlib/src/kotlin/random/URandom.kt",
|
||||
"libraries/stdlib/src/kotlin/text/",
|
||||
"libraries/stdlib/src/kotlin/util/KotlinVersion.kt",
|
||||
"libraries/stdlib/src/kotlin/util/Tuples.kt"
|
||||
) + listOfKtFilesFrom(
|
||||
"libraries/stdlib/js/irRuntime/smallRuntimeMissingDeclarations.kt"
|
||||
)
|
||||
|
||||
private fun listOfKtFilesFrom(vararg paths: String): List<String> {
|
||||
val currentDir = File("")
|
||||
return paths.flatMap { path ->
|
||||
File(path)
|
||||
.walkTopDown()
|
||||
.filter { it.extension == "kt" }
|
||||
.map { it.relativeToOrSelf(currentDir).path }
|
||||
.asIterable()
|
||||
}.distinct()
|
||||
}
|
||||
@@ -76,7 +76,8 @@ class CodeConformanceTest : TestCase() {
|
||||
"libraries/tools/kotlin-gradle-plugin-integration-tests/build",
|
||||
"libraries/tools/kotlin-test-nodejs-runner/node_modules",
|
||||
"libraries/tools/kotlin-test-nodejs-runner/.gradle",
|
||||
"buildSrc/prepare-deps/build"
|
||||
"buildSrc/prepare-deps/build",
|
||||
"compiler/ir/serialization.js/build"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,11 @@ sourceSets {
|
||||
fun Test.setUpBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean) {
|
||||
dependsOn(":dist")
|
||||
if (jsEnabled) dependsOn(testJsRuntime)
|
||||
if (jsIrEnabled) dependsOn(":compiler:ir.serialization.js:generateIrRuntimeKlib")
|
||||
if (jsIrEnabled) {
|
||||
dependsOn(":compiler:ir.serialization.js:generateFullRuntimeKLib")
|
||||
dependsOn(":compiler:ir.serialization.js:generateReducedRuntimeKLib")
|
||||
dependsOn(":compiler:ir.serialization.js:generateKotlinTestKLib")
|
||||
}
|
||||
|
||||
if (jsEnabled && !jsIrEnabled) exclude("org/jetbrains/kotlin/js/test/ir/semantics/*")
|
||||
if (!jsEnabled && jsIrEnabled) include("org/jetbrains/kotlin/js/test/ir/semantics/*")
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
|
||||
import org.jetbrains.kotlin.incremental.js.TranslationResultValue
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrTestRuntime
|
||||
import org.jetbrains.kotlin.js.JavaScript
|
||||
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
@@ -110,11 +109,7 @@ abstract class BasicBoxTest(
|
||||
fileContent = fileContent.replace("COROUTINES_PACKAGE", coroutinesPackage)
|
||||
}
|
||||
|
||||
val runtimeType =
|
||||
if (KJS_WITH_FULL_RUNTIME.matcher(fileContent).find())
|
||||
JsIrTestRuntime.FULL
|
||||
else
|
||||
JsIrTestRuntime.DEFAULT
|
||||
val needsFullIrRuntime = KJS_WITH_FULL_RUNTIME.matcher(fileContent).find()
|
||||
|
||||
val actualMainCallParameters = if (CALL_MAIN_PATTERN.matcher(fileContent).find()) MainCallParameters.mainWithArguments(listOf("testArg")) else mainCallParameters
|
||||
|
||||
@@ -150,7 +145,7 @@ abstract class BasicBoxTest(
|
||||
file.parent, module, outputFileName, dependencies, allDependencies, friends, modules.size > 1,
|
||||
!SKIP_SOURCEMAP_REMAPPING.matcher(fileContent).find(),
|
||||
outputPrefixFile, outputPostfixFile, actualMainCallParameters, testPackage, testFunction,
|
||||
runtimeType, isMainModule
|
||||
needsFullIrRuntime, isMainModule
|
||||
)
|
||||
|
||||
when {
|
||||
@@ -333,7 +328,7 @@ abstract class BasicBoxTest(
|
||||
mainCallParameters: MainCallParameters,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime,
|
||||
needsFullIrRuntime: Boolean,
|
||||
isMainModule: Boolean
|
||||
) {
|
||||
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
|
||||
@@ -356,13 +351,13 @@ abstract class BasicBoxTest(
|
||||
val incrementalData = IncrementalData()
|
||||
translateFiles(
|
||||
psiFiles.map(TranslationUnit::SourceFile), outputFile, config, outputPrefixFile, outputPostfixFile,
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime, isMainModule
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, isMainModule
|
||||
)
|
||||
|
||||
if (incrementalCompilationChecksEnabled && module.hasFilesToRecompile) {
|
||||
checkIncrementalCompilation(
|
||||
sourceDirs, module, kotlinFiles, dependencies, allDependencies, friends, multiModule, remap,
|
||||
outputFile, outputPrefixFile, outputPostfixFile, mainCallParameters, incrementalData, testPackage, testFunction, runtime
|
||||
outputFile, outputPrefixFile, outputPostfixFile, mainCallParameters, incrementalData, testPackage, testFunction, needsFullIrRuntime
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -383,7 +378,7 @@ abstract class BasicBoxTest(
|
||||
incrementalData: IncrementalData,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime
|
||||
needsFullIrRuntime: Boolean
|
||||
) {
|
||||
val sourceToTranslationUnit = hashMapOf<File, TranslationUnit>()
|
||||
for (testFile in kotlinFiles) {
|
||||
@@ -405,7 +400,7 @@ abstract class BasicBoxTest(
|
||||
|
||||
translateFiles(
|
||||
translationUnits, recompiledOutputFile, recompiledConfig, outputPrefixFile, outputPostfixFile,
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime, false
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, false
|
||||
)
|
||||
|
||||
val originalOutput = FileUtil.loadFile(outputFile)
|
||||
@@ -470,7 +465,7 @@ abstract class BasicBoxTest(
|
||||
remap: Boolean,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime,
|
||||
needsFullIrRuntime: Boolean,
|
||||
isMainModule: Boolean
|
||||
) {
|
||||
val translator = K2JSTranslator(config, false)
|
||||
|
||||
@@ -7,7 +7,10 @@ package org.jetbrains.kotlin.js.test
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.KlibModuleRef
|
||||
import org.jetbrains.kotlin.ir.backend.js.compile
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateKLib
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsPhases
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||
@@ -15,13 +18,9 @@ import org.jetbrains.kotlin.js.facade.TranslationUnit
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import java.io.File
|
||||
|
||||
private val fullRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeFull/"
|
||||
private val defaultRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeDefault/"
|
||||
|
||||
private val JS_IR_RUNTIME_MODULE_NAME = "JS_IR_RUNTIME"
|
||||
|
||||
private val fullRuntimeKlib = KlibModuleRef(JS_IR_RUNTIME_MODULE_NAME, fullRuntimeKlibPath)
|
||||
private val defaultRuntimeKlib = KlibModuleRef(JS_IR_RUNTIME_MODULE_NAME, defaultRuntimeKlibPath)
|
||||
private val fullRuntimeKlib = KlibModuleRef("JS_IR_RUNTIME", "compiler/ir/serialization.js/build/fullRuntime/klib")
|
||||
private val defaultRuntimeKlib = KlibModuleRef("JS_IR_RUNTIME", "compiler/ir/serialization.js/build/reducedRuntime/klib")
|
||||
private val kotlinTestKLib = KlibModuleRef("kotlin.test", "compiler/ir/serialization.js/build/kotlin.test/klib")
|
||||
|
||||
abstract class BasicIrBoxTest(
|
||||
pathToTestDir: String,
|
||||
@@ -53,10 +52,6 @@ abstract class BasicIrBoxTest(
|
||||
|
||||
override val testChecker get() = if (runTestInNashorn) NashornIrJsTestChecker() else V8IrJsTestChecker
|
||||
|
||||
private val runtimes = mapOf(
|
||||
JsIrTestRuntime.DEFAULT to defaultRuntimeKlib,
|
||||
JsIrTestRuntime.FULL to fullRuntimeKlib)
|
||||
|
||||
override fun translateFiles(
|
||||
units: List<TranslationUnit>,
|
||||
outputFile: File,
|
||||
@@ -68,7 +63,7 @@ abstract class BasicIrBoxTest(
|
||||
remap: Boolean,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime,
|
||||
needsFullIrRuntime: Boolean,
|
||||
isMainModule: Boolean
|
||||
) {
|
||||
val filesToCompile = units
|
||||
@@ -76,35 +71,20 @@ abstract class BasicIrBoxTest(
|
||||
// TODO: split input files to some parts (global common, local common, test)
|
||||
.filterNot { it.virtualFilePath.contains(BasicBoxTest.COMMON_FILES_DIR_PATH) }
|
||||
|
||||
// config.configuration.put(CommonConfigurationKeys.EXCLUDED_ELEMENTS_FROM_DUMPING, setOf("<JS_IR_RUNTIME>"))
|
||||
// config.configuration.put(
|
||||
// CommonConfigurationKeys.PHASES_TO_VALIDATE_AFTER,
|
||||
// setOf(
|
||||
// "RemoveInlineFunctionsWithReifiedTypeParametersLowering",
|
||||
// "InnerClassConstructorCallsLowering",
|
||||
// "InlineClassLowering", "ConstLowering"
|
||||
// )
|
||||
// )
|
||||
|
||||
val runtimeKlib = runtimes[runtime]!!
|
||||
val runtimeKlibs = if (needsFullIrRuntime) listOf(fullRuntimeKlib, kotlinTestKLib) else listOf(defaultRuntimeKlib)
|
||||
|
||||
val libraries = config.configuration[JSConfigurationKeys.LIBRARIES]!!.map { File(it).name }
|
||||
val transitiveLibraries = config.configuration[JSConfigurationKeys.TRANSITIVE_LIBRARIES]!!.map { File(it).name }
|
||||
|
||||
// TODO: Add proper depencencies
|
||||
val dependencies = listOf(runtimeKlib) + libraries.map {
|
||||
val dependencies = runtimeKlibs + libraries.map {
|
||||
compilationCache[it] ?: error("Can't find compiled module for dependency $it")
|
||||
}
|
||||
|
||||
val allDependencies = listOf(runtimeKlib) + transitiveLibraries.map {
|
||||
val allDependencies = runtimeKlibs + transitiveLibraries.map {
|
||||
compilationCache[it] ?: error("Can't find compiled module for dependency $it")
|
||||
}
|
||||
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE, setOf("UnitMaterializationLowering"))
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_BEFORE, setOf("ReturnableBlockLowering"))
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_AFTER, setOf("MultipleCatchesLowering"))
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_VALIDATE, setOf("ALL"))
|
||||
|
||||
val actualOutputFile = outputFile.absolutePath.let {
|
||||
if (!isMainModule) it.replace("_v5.js", "/") else it
|
||||
}
|
||||
|
||||
+90
-23
@@ -1,44 +1,107 @@
|
||||
package common
|
||||
|
||||
import kotlin.test.FrameworkAdapter
|
||||
import kotlin.collections.*
|
||||
|
||||
private val context = TestContext()
|
||||
private var sortingContext = SortingContext()
|
||||
|
||||
fun call(name: String) = context.call(name)
|
||||
private var bodyContext: TestBodyContext? = null
|
||||
|
||||
fun call(name: String) = bodyContext!!.call(name)
|
||||
|
||||
fun raise(name: String): Nothing {
|
||||
context.raised(name)
|
||||
bodyContext!!.raised(name)
|
||||
throw Exception(name)
|
||||
}
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
val underscore = kotlin.test.setAdapter(object : FrameworkAdapter {
|
||||
private val underscore = kotlin.test.setAdapter(object : FrameworkAdapter {
|
||||
override fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
|
||||
context.suite(name, ignored) { suiteFn() }
|
||||
sortingContext.suite(name, ignored) { suiteFn() }
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, testFn: () -> dynamic) {
|
||||
context.test(name, ignored) { returned(testFn()) }
|
||||
sortingContext.test(name, ignored) { returned(testFn()) }
|
||||
}
|
||||
})
|
||||
|
||||
class TestContext {
|
||||
interface SuiteContext {
|
||||
fun suite(name: String, ignored: Boolean = false, body: SuiteContext.() -> Unit)
|
||||
|
||||
fun test(name: String, ignored: Boolean = false, body: TestBodyContext.() -> Unit = {})
|
||||
}
|
||||
|
||||
|
||||
interface TestBodyContext {
|
||||
fun call(name: String)
|
||||
|
||||
fun raised(msg: String)
|
||||
|
||||
fun caught(msg: String)
|
||||
|
||||
fun returned(msg: dynamic)
|
||||
}
|
||||
|
||||
private sealed class Entity(val name: String,
|
||||
val ignored: Boolean)
|
||||
|
||||
private class Suite(name: String, ignored: Boolean, val body: SuiteContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
private class Test(name: String, ignored: Boolean, val body: TestBodyContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
|
||||
private class SortingContext: SuiteContext {
|
||||
|
||||
val structure = mutableListOf<Entity>()
|
||||
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) {
|
||||
structure += Suite(name, ignored, body)
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) {
|
||||
structure += Test(name, ignored, body)
|
||||
}
|
||||
|
||||
fun <T: SuiteContext> replayInto(context: T): T {
|
||||
structure.sortedBy { it.name }.forEach {
|
||||
when (it) {
|
||||
is Suite -> context.suite(it.name, it.ignored) {
|
||||
val oldSorter = sortingContext
|
||||
|
||||
sortingContext = SortingContext()
|
||||
it.body(sortingContext)
|
||||
sortingContext.replayInto(this)
|
||||
|
||||
sortingContext = oldSorter
|
||||
}
|
||||
is Test -> context.test(it.name, it.ignored) {
|
||||
bodyContext = this
|
||||
it.body(this)
|
||||
bodyContext = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
private class LoggingContext : SuiteContext, TestBodyContext{
|
||||
val log: String
|
||||
get() = logHead + (lastRecord ?: "")
|
||||
|
||||
var indentation = ""
|
||||
private var indentation = ""
|
||||
|
||||
fun suite(name: String, ignored: Boolean = false, body: TestContext.() -> Unit) = indent {
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) = indent {
|
||||
record("suite(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
body.runSafely()
|
||||
runSafely { this.body() }
|
||||
record("}")
|
||||
}
|
||||
|
||||
|
||||
fun test(name: String, ignored: Boolean = false, body: TestContext.() -> Unit = {}) = indent {
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) = indent {
|
||||
val num = record("test(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
|
||||
body.runSafely()
|
||||
runSafely { this.body() }
|
||||
|
||||
if (!writtenSince(num)) {
|
||||
record("test(\"$name\"${optionalIgnore(ignored)})", replaceLast = true)
|
||||
@@ -48,25 +111,25 @@ class TestContext {
|
||||
}
|
||||
}
|
||||
|
||||
fun call(name: String) = indent {
|
||||
override fun call(name: String) = indent {
|
||||
record("call(\"$name\")")
|
||||
}
|
||||
|
||||
fun raised(msg: String) = indent {
|
||||
override fun raised(msg: String) = indent {
|
||||
record("raised(\"$msg\")")
|
||||
}
|
||||
|
||||
fun caught(msg: String) = indent {
|
||||
override fun caught(msg: String) = indent {
|
||||
record("caught(\"$msg\")")
|
||||
}
|
||||
|
||||
fun returned(msg: dynamic) = indent {
|
||||
override fun returned(msg: dynamic) = indent {
|
||||
if (msg is String) record("returned(\"$msg\")")
|
||||
}
|
||||
|
||||
private fun (TestContext.() -> Unit).runSafely() {
|
||||
private fun runSafely(body: () -> Unit) {
|
||||
try {
|
||||
this()
|
||||
body()
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
caught(t.message ?: "")
|
||||
@@ -100,8 +163,8 @@ class TestContext {
|
||||
private fun optionalIgnore(ignored: Boolean) = if (ignored) ", true" else ""
|
||||
}
|
||||
|
||||
fun checkLog(wrapInEmptySuite: Boolean = true, body: TestContext.() -> Unit): String {
|
||||
val expectedContext = TestContext()
|
||||
fun checkLog(wrapInEmptySuite: Boolean = true, body: SuiteContext.() -> Unit): String {
|
||||
val expectedContext = SortingContext()
|
||||
if (wrapInEmptySuite) {
|
||||
expectedContext.suite("") {
|
||||
body()
|
||||
@@ -109,8 +172,12 @@ fun checkLog(wrapInEmptySuite: Boolean = true, body: TestContext.() -> Unit): St
|
||||
} else {
|
||||
expectedContext.body()
|
||||
}
|
||||
if (context.log != expectedContext.log) {
|
||||
return "Failed test structure check. Expected: ${expectedContext.log}; actual: ${context.log}."
|
||||
|
||||
val expectedLog = expectedContext.replayInto(LoggingContext()).log
|
||||
val actualLog = sortingContext.replayInto(LoggingContext()).log
|
||||
|
||||
if (actualLog != expectedLog) {
|
||||
return "Failed test structure check. Expected: ${expectedLog}; actual: ${actualLog}."
|
||||
}
|
||||
else {
|
||||
return "OK"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1339
|
||||
// EXPECTED_REACHABLE_NODES: 1706
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1340
|
||||
// EXPECTED_REACHABLE_NODES: 1709
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.Ignore
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1330
|
||||
// EXPECTED_REACHABLE_NODES: 1829
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
// FILE: a.kt
|
||||
package a
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1351
|
||||
// EXPECTED_REACHABLE_NODES: 1719
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1697
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// EXPECTED_REACHABLE_NODES: 1328
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
// FILE: lib.kt
|
||||
import kotlin.test.Test
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1367
|
||||
// EXPECTED_REACHABLE_NODES: 1735
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1297
|
||||
// EXPECTED_REACHABLE_NODES: 1737
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1330
|
||||
// EXPECTED_REACHABLE_NODES: 1698
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.native.concurrent
|
||||
|
||||
// Current serialization removes expect declarations, so some dummy annotations are needed
|
||||
// Expect declarations: libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@OptionalExpectation
|
||||
public annotation class ThreadLocal()
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@OptionalExpectation
|
||||
public annotation class SharedImmutable()
|
||||
Reference in New Issue
Block a user