[K/JS] Compile Kotlin coroutines as JS generator ^KT-63038 Fixed
This commit is contained in:
+1
@@ -67,6 +67,7 @@ fun copyK2JSCompilerArguments(from: K2JSCompilerArguments, to: K2JSCompilerArgum
|
||||
to.target = from.target
|
||||
to.typedArrays = from.typedArrays
|
||||
to.useEsClasses = from.useEsClasses
|
||||
to.useEsGenerators = from.useEsGenerators
|
||||
to.wasm = from.wasm
|
||||
to.wasmDebug = from.wasmDebug
|
||||
to.wasmEnableArrayRangeChecks = from.wasmEnableArrayRangeChecks
|
||||
|
||||
+10
@@ -504,6 +504,16 @@ In combination with '-meta-info', this generates both IR and pre-IR versions of
|
||||
field = value
|
||||
}
|
||||
|
||||
@Argument(
|
||||
value = "-Xes-generators",
|
||||
description = "Enable ES2015 generator functions usage inside the compiled code"
|
||||
)
|
||||
var useEsGenerators = false
|
||||
set(value) {
|
||||
checkFrozen()
|
||||
field = value
|
||||
}
|
||||
|
||||
@GradleOption(
|
||||
value = DefaultValue.BOOLEAN_TRUE_DEFAULT,
|
||||
gradleInputType = GradleInputTypes.INPUT,
|
||||
|
||||
@@ -208,6 +208,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
configurationJs.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, arguments.irPropertyLazyInitialization)
|
||||
configurationJs.put(JSConfigurationKeys.GENERATE_POLYFILLS, arguments.generatePolyfills)
|
||||
configurationJs.put(JSConfigurationKeys.GENERATE_DTS, arguments.generateDts)
|
||||
configurationJs.put(JSConfigurationKeys.COMPILE_SUSPEND_AS_JS_GENERATOR, arguments.useEsGenerators)
|
||||
configurationJs.put(JSConfigurationKeys.GENERATE_INLINE_ANONYMOUS_FUNCTIONS, arguments.irGenerateInlineAnonymousFunctions)
|
||||
|
||||
arguments.platformArgumentsProviderJsExpression?.let {
|
||||
|
||||
@@ -181,6 +181,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsCoroutineContext
|
||||
get() = context.ir.symbols.coroutineContextGetter
|
||||
|
||||
val jsYieldFunctionSymbol = getInternalFunction("jsYield")
|
||||
|
||||
val jsGetContinuation = getInternalFunction("getContinuation")
|
||||
val jsInvokeSuspendSuperType =
|
||||
getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendSuperType")
|
||||
@@ -189,6 +191,25 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsInvokeSuspendSuperTypeWithReceiverAndParam =
|
||||
getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendSuperTypeWithReceiverAndParam")
|
||||
|
||||
val createCoroutineUnintercepted =
|
||||
getManyInternalWithoutPackage("kotlin.coroutines.intrinsics.createCoroutineUnintercepted")
|
||||
val startCoroutineUninterceptedOrReturn =
|
||||
getManyInternalWithoutPackage("kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn")
|
||||
|
||||
val createCoroutineUninterceptedGeneratorVersion =
|
||||
getManyInternalWithoutPackage("kotlin.coroutines.intrinsics.createCoroutineUninterceptedGeneratorVersion")
|
||||
val startCoroutineUninterceptedOrReturnGeneratorVersion =
|
||||
getManyInternalWithoutPackage("kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturnGeneratorVersion")
|
||||
|
||||
val startCoroutineUninterceptedOrReturnGeneratorVersion1 by context.lazy2 {
|
||||
startCoroutineUninterceptedOrReturnGeneratorVersion.single { it.owner.valueParameters.size == 1 }
|
||||
}
|
||||
val startCoroutineUninterceptedOrReturnGeneratorVersion2 by context.lazy2 {
|
||||
startCoroutineUninterceptedOrReturnGeneratorVersion.single { it.owner.valueParameters.size == 2 }
|
||||
}
|
||||
|
||||
val suspendOrReturnFunctionSymbol = getInternalWithoutPackage("kotlin.coroutines.intrinsics.suspendOrReturn")
|
||||
|
||||
val jsNumberRangeToNumber = getInternalFunction("numberRangeToNumber")
|
||||
val jsNumberRangeToLong = getInternalFunction("numberRangeToLong")
|
||||
|
||||
@@ -328,6 +349,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("DoNotIntrinsify"))
|
||||
val jsFunAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsFun"))
|
||||
val jsNameAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsName"))
|
||||
val jsGeneratorAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsGenerator"))
|
||||
|
||||
val jsExportAnnotationSymbol by lazy(LazyThreadSafetyMode.NONE) {
|
||||
context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsExport"))
|
||||
@@ -392,6 +414,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
private fun getInternalWithoutPackage(name: String) =
|
||||
context.symbolTable.descriptorExtension.referenceSimpleFunction(context.getFunctions(FqName(name)).single())
|
||||
|
||||
private fun getManyInternalWithoutPackage(name: String) =
|
||||
context.getFunctions(FqName(name)).mapTo(mutableSetOf()) { context.symbolTable.descriptorExtension.referenceSimpleFunction(it) }
|
||||
|
||||
private fun getInternalWithoutPackageOrNull(name: String): IrSimpleFunctionSymbol? {
|
||||
val descriptor = context.getFunctions(FqName(name)).singleOrNull() ?: return null
|
||||
return context.symbolTable.descriptorExtension.referenceSimpleFunction(descriptor)
|
||||
|
||||
@@ -14,15 +14,12 @@ import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunc
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLambdasLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering
|
||||
import org.jetbrains.kotlin.backend.common.phaser.*
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.cleanup.CleanupLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.AddContinuationToFunctionCallsLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendArityStoreLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.inline.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.compileSuspendAsJsGenerator
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
|
||||
import org.jetbrains.kotlin.platform.js.JsPlatforms
|
||||
@@ -185,11 +182,18 @@ private val wrapInlineDeclarationsWithReifiedTypeParametersLowering = makeIrModu
|
||||
description = "Wrap inline declarations with reified type parameters"
|
||||
)
|
||||
|
||||
private val replaceSuspendIntrinsicLowering = makeIrModulePhase(
|
||||
::ReplaceSuspendIntrinsicLowering,
|
||||
name = "ReplaceSuspendIntrinsicLowering",
|
||||
description = "Replace suspend intrinsic for generator based coroutines"
|
||||
)
|
||||
|
||||
private val saveInlineFunctionsBeforeInlining = makeIrModulePhase(
|
||||
::SaveInlineFunctionsBeforeInlining,
|
||||
name = "SaveInlineFunctionsBeforeInlining",
|
||||
description = "Save inline function before inlining",
|
||||
prerequisite = setOf(
|
||||
replaceSuspendIntrinsicLowering,
|
||||
expectDeclarationsRemovingPhase, sharedVariablesLoweringPhase,
|
||||
localClassesInInlineLambdasPhase, localClassesExtractionFromInlineFunctionsPhase,
|
||||
syntheticAccessorLoweringPhase, wrapInlineDeclarationsWithReifiedTypeParametersLowering
|
||||
@@ -426,10 +430,16 @@ private val innerClassConstructorCallsLoweringPhase = makeIrModulePhase<JsIrBack
|
||||
description = "Replace inner class constructor invocation"
|
||||
)
|
||||
|
||||
private val suspendFunctionsLoweringPhase = makeIrModulePhase(
|
||||
::JsSuspendFunctionsLowering,
|
||||
private val suspendFunctionsLoweringPhase = makeIrModulePhase<JsIrBackendContext>(
|
||||
{ context ->
|
||||
if (context.compileSuspendAsJsGenerator) {
|
||||
JsSuspendFunctionWithGeneratorsLowering(context)
|
||||
} else {
|
||||
JsSuspendFunctionsLowering(context)
|
||||
}
|
||||
},
|
||||
name = "SuspendFunctionsLowering",
|
||||
description = "Transform suspend functions into CoroutineImpl instance and build state machine"
|
||||
description = "Transform suspend functions into CoroutineImpl instance and build state machine or into GeneratorCoroutineImpl and ES2015 generators"
|
||||
)
|
||||
|
||||
private val addContinuationToNonLocalSuspendFunctionsLoweringPhase = makeIrModulePhase(
|
||||
@@ -789,6 +799,7 @@ val loweringList = listOf<SimpleNamedCompilerPhase<JsIrBackendContext, IrModuleF
|
||||
localClassesExtractionFromInlineFunctionsPhase,
|
||||
syntheticAccessorLoweringPhase,
|
||||
wrapInlineDeclarationsWithReifiedTypeParametersLowering,
|
||||
replaceSuspendIntrinsicLowering,
|
||||
saveInlineFunctionsBeforeInlining,
|
||||
functionInliningPhase,
|
||||
constEvaluationPhase,
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ internal class JsUsefulDeclarationProcessor(
|
||||
) : UsefulDeclarationProcessor(printReachabilityInfo, removeUnusedAssociatedObjects) {
|
||||
private val equalsMethod = getMethodOfAny("equals")
|
||||
private val hashCodeMethod = getMethodOfAny("hashCode")
|
||||
private val isEsModules = context.configuration[JSConfigurationKeys.MODULE_KIND] == ModuleKind.ES
|
||||
|
||||
override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() {
|
||||
override fun visitCall(expression: IrCall, data: IrDeclaration) {
|
||||
|
||||
+1
@@ -163,6 +163,7 @@ internal class ICHasher {
|
||||
JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION,
|
||||
JSConfigurationKeys.GENERATE_INLINE_ANONYMOUS_FUNCTIONS,
|
||||
JSConfigurationKeys.GENERATE_STRICT_IMPLICIT_EXPORT,
|
||||
JSConfigurationKeys.COMPILE_SUSPEND_AS_JS_GENERATOR,
|
||||
JSConfigurationKeys.OPTIMIZE_GENERATED_JS,
|
||||
)
|
||||
hashCalculator.updateConfigKeys(config, booleanKeys) { value: Boolean ->
|
||||
|
||||
+6
-5
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
|
||||
import org.jetbrains.kotlin.backend.common.lower.LoweredStatementOrigins
|
||||
@@ -16,6 +15,8 @@ import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.compileSuspendAsJsGenerator
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -30,7 +31,7 @@ import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedMapIndexed
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedPlus
|
||||
|
||||
class CallableReferenceLowering(private val context: CommonBackendContext) : BodyLoweringPass {
|
||||
class CallableReferenceLowering(private val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile, withLocalDeclarations = true)
|
||||
@@ -115,9 +116,9 @@ class CallableReferenceLowering(private val context: CommonBackendContext) : Bod
|
||||
|
||||
private val isLambda: Boolean get() = reflectionTarget == null
|
||||
|
||||
private val isSuspendLambda = isLambda && function.isSuspend
|
||||
private val shouldBeCoroutineImpl = isLambda && function.isSuspend && !context.compileSuspendAsJsGenerator
|
||||
|
||||
private val superClass = if (isSuspendLambda) context.ir.symbols.coroutineImpl.owner.defaultType else context.irBuiltIns.anyType
|
||||
private val superClass = if (shouldBeCoroutineImpl) context.ir.symbols.coroutineImpl.owner.defaultType else context.irBuiltIns.anyType
|
||||
private var boundReceiverField: IrField? = null
|
||||
|
||||
private val referenceType = reference.type as IrSimpleType
|
||||
@@ -225,7 +226,7 @@ class CallableReferenceLowering(private val context: CommonBackendContext) : Bod
|
||||
|
||||
var continuation: IrValueParameter? = null
|
||||
|
||||
if (isSuspendLambda) {
|
||||
if (shouldBeCoroutineImpl) {
|
||||
val superContinuation = superConstructor.valueParameters.single()
|
||||
continuation = addValueParameter {
|
||||
name = superContinuation.name
|
||||
|
||||
+2
-2
@@ -117,7 +117,7 @@ class JsDefaultArgumentStubGenerator(context: JsIrBackendContext) :
|
||||
context.additionalExportedDeclarations.add(defaultFunStub)
|
||||
|
||||
if (!originalFun.hasAnnotation(JsAnnotations.jsNameFqn)) {
|
||||
annotations = annotations memoryOptimizedPlus originalFun.generateJsNameAnnotationCall()
|
||||
originalFun.annotations = originalFun.annotations memoryOptimizedPlus originalFun.generateJsNameAnnotationCall()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class JsDefaultArgumentStubGenerator(context: JsIrBackendContext) :
|
||||
}
|
||||
|
||||
originalFun.annotations = irrelevantAnnotations
|
||||
defaultFunStub.annotations = defaultFunStub.annotations memoryOptimizedPlus exportAnnotations
|
||||
defaultFunStub.annotations = exportAnnotations
|
||||
originalFun.origin = JsLoweredDeclarationOrigin.JS_SHADOWED_EXPORT
|
||||
|
||||
return listOf(originalFun, defaultFunStub)
|
||||
|
||||
+30
-8
@@ -10,11 +10,13 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.compileSuspendAsJsGenerator
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isLoweredSuspendFunction
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isStringArrayParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrRawFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.toIrConst
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -59,19 +61,35 @@ class MainFunctionCallWrapperLowering(private val context: JsIrBackendContext) :
|
||||
).also {
|
||||
it.parent = parent
|
||||
it.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
|
||||
statements.add(JsIrBuilder.buildCall(originalFunctionSymbol).apply {
|
||||
generateMainArguments().forEachIndexed(this::putValueArgument)
|
||||
})
|
||||
val shouldCallMainFunctionAsCoroutine = isLoweredSuspendFunction(context) && context.compileSuspendAsJsGenerator
|
||||
val functionSymbolToCall = when {
|
||||
!shouldCallMainFunctionAsCoroutine -> originalFunctionSymbol
|
||||
hasStringArrayParameter() -> context.intrinsics.startCoroutineUninterceptedOrReturnGeneratorVersion2
|
||||
else -> context.intrinsics.startCoroutineUninterceptedOrReturnGeneratorVersion1
|
||||
}
|
||||
|
||||
val mainFunctionCall = JsIrBuilder.buildCall(functionSymbolToCall).apply {
|
||||
if (shouldCallMainFunctionAsCoroutine) {
|
||||
extensionReceiver = IrRawFunctionReferenceImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
context.irBuiltIns.anyType,
|
||||
originalFunctionSymbol
|
||||
)
|
||||
}
|
||||
generateMainArguments().forEachIndexed { index, arg ->
|
||||
putValueArgument(index, arg)
|
||||
}
|
||||
}
|
||||
|
||||
statements.add(mainFunctionCall)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.generateMainArguments(): List<IrExpression> {
|
||||
val generateArgv = valueParameters.firstOrNull()?.isStringArrayParameter() ?: false
|
||||
val generateContinuation = isLoweredSuspendFunction(context)
|
||||
|
||||
return listOfNotNull(
|
||||
runIf(generateArgv) {
|
||||
runIf(hasStringArrayParameter()) {
|
||||
context.platformArgumentsProviderJsExpression?.let {
|
||||
JsIrBuilder.buildCall(context.intrinsics.jsCode).apply {
|
||||
putValueArgument(0, it.toIrConst(context.irBuiltIns.stringType))
|
||||
@@ -82,9 +100,13 @@ class MainFunctionCallWrapperLowering(private val context: JsIrBackendContext) :
|
||||
context.irBuiltIns.stringType
|
||||
)
|
||||
},
|
||||
runIf(generateContinuation) {
|
||||
runIf(isLoweredSuspendFunction(context)) {
|
||||
JsIrBuilder.buildCall(context.coroutineEmptyContinuation.owner.getter!!.symbol)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.hasStringArrayParameter(): Boolean {
|
||||
return valueParameters.firstOrNull()?.isStringArrayParameter() == true
|
||||
}
|
||||
}
|
||||
+1
@@ -60,6 +60,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTrans
|
||||
visibility = newVisibility
|
||||
}.also {
|
||||
it.parent = function.parent
|
||||
it.annotations = function.annotations
|
||||
}
|
||||
|
||||
staticFunction.typeParameters =
|
||||
|
||||
+1
-3
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isObjectInstanceField
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isObjectInstanceGetter
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.primaryConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
@@ -102,7 +103,4 @@ class PurifyObjectInstanceGettersLowering(val context: JsCommonBackendContext) :
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private val IrClass.primaryConstructorReplacement: IrSimpleFunction?
|
||||
get() = findDeclaration<IrSimpleFunction> { it.isEs6PrimaryConstructorReplacement }
|
||||
}
|
||||
|
||||
+80
-75
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -78,71 +77,10 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuspendFunctionKind(function: IrSimpleFunction, body: IrBody): SuspendFunctionKind {
|
||||
|
||||
fun IrSimpleFunction.isSuspendLambda() =
|
||||
name.asString() == "invoke" && parentClassOrNull?.let { it.origin === CallableReferenceLowering.Companion.LAMBDA_IMPL } == true
|
||||
|
||||
if (function.isSuspendLambda())
|
||||
return SuspendFunctionKind.NEEDS_STATE_MACHINE // Suspend lambdas always need coroutine implementation.
|
||||
|
||||
var numberOfSuspendCalls = 0
|
||||
body.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
expression.acceptChildrenVoid(this)
|
||||
if (expression.isSuspend)
|
||||
++numberOfSuspendCalls
|
||||
}
|
||||
})
|
||||
// It is important to optimize the case where there is only one suspend call and it is the last statement
|
||||
// because we don't need to build a fat coroutine class in that case.
|
||||
// This happens a lot in practice because of suspend functions with default arguments.
|
||||
// TODO: use TailRecursionCallsCollector.
|
||||
val lastCall = when (val lastStatement = (body as IrBlockBody).statements.lastOrNull()) {
|
||||
is IrCall ->
|
||||
// Delegation to call without return can only be performed to Unit-returning function call from Unit-returning function
|
||||
if (lastStatement.type == context.irBuiltIns.unitType && function.returnType == context.irBuiltIns.unitType)
|
||||
lastStatement
|
||||
else
|
||||
null
|
||||
is IrReturn -> {
|
||||
var value: IrElement = lastStatement
|
||||
/*
|
||||
* Check if matches this pattern:
|
||||
* block/return {
|
||||
* block/return {
|
||||
* .. suspendCall()
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
loop@ while (true) {
|
||||
value = when {
|
||||
value is IrBlock && value.statements.size == 1 -> value.statements.first()
|
||||
value is IrReturn -> value.value
|
||||
else -> break@loop
|
||||
}
|
||||
}
|
||||
value as? IrCall
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val suspendCallAtEnd = lastCall != null && lastCall.isSuspend // Suspend call.
|
||||
return when {
|
||||
numberOfSuspendCalls == 0 -> SuspendFunctionKind.NO_SUSPEND_CALLS
|
||||
numberOfSuspendCalls == 1
|
||||
&& suspendCallAtEnd -> SuspendFunctionKind.DELEGATING(lastCall!!)
|
||||
else -> SuspendFunctionKind.NEEDS_STATE_MACHINE
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformSuspendFunction(function: IrSimpleFunction, body: IrBody): IrClass? {
|
||||
assert(function.isSuspend)
|
||||
|
||||
return when (val functionKind = getSuspendFunctionKind(function, body)) {
|
||||
return when (val functionKind = getSuspendFunctionKind(context, function, body)) {
|
||||
is SuspendFunctionKind.NO_SUSPEND_CALLS -> {
|
||||
null // No suspend function calls - just an ordinary function.
|
||||
}
|
||||
@@ -480,24 +418,13 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress since it is used in native
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
protected fun IrCall.isReturnIfSuspendedCall() =
|
||||
symbol.owner.run { fqNameWhenAvailable == context.internalPackageFqn.child(Name.identifier("returnIfSuspended")) }
|
||||
|
||||
private sealed class SuspendFunctionKind {
|
||||
object NO_SUSPEND_CALLS : SuspendFunctionKind()
|
||||
class DELEGATING(val delegatingCall: IrCall) : SuspendFunctionKind()
|
||||
object NEEDS_STATE_MACHINE : SuspendFunctionKind()
|
||||
}
|
||||
|
||||
private val symbols = context.ir.symbols
|
||||
private val getContinuationSymbol = symbols.getContinuation
|
||||
private val continuationClassSymbol = getContinuationSymbol.owner.returnType.classifierOrFail as IrClassSymbol
|
||||
|
||||
private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) {
|
||||
val returnValue =
|
||||
if (delegatingCall.isReturnIfSuspendedCall())
|
||||
if (delegatingCall.isReturnIfSuspendedCall(context))
|
||||
delegatingCall.getValueArgument(0)!!
|
||||
else delegatingCall
|
||||
val body = irFunction.body as IrBlockBody
|
||||
@@ -575,3 +502,81 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class SuspendFunctionKind {
|
||||
object NO_SUSPEND_CALLS : SuspendFunctionKind()
|
||||
class DELEGATING(val delegatingCall: IrCall) : SuspendFunctionKind()
|
||||
object NEEDS_STATE_MACHINE : SuspendFunctionKind()
|
||||
}
|
||||
|
||||
fun getSuspendFunctionKind(
|
||||
context: CommonBackendContext,
|
||||
function: IrSimpleFunction,
|
||||
body: IrBody,
|
||||
includeSuspendLambda: Boolean = true
|
||||
): SuspendFunctionKind {
|
||||
|
||||
fun IrSimpleFunction.isSuspendLambda() =
|
||||
name.asString() == "invoke" && parentClassOrNull?.let { it.origin === CallableReferenceLowering.Companion.LAMBDA_IMPL } == true
|
||||
|
||||
if (function.isSuspendLambda() && includeSuspendLambda)
|
||||
return SuspendFunctionKind.NEEDS_STATE_MACHINE // Suspend lambdas always need coroutine implementation.
|
||||
|
||||
var numberOfSuspendCalls = 0
|
||||
body.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
expression.acceptChildrenVoid(this)
|
||||
if (expression.isSuspend)
|
||||
++numberOfSuspendCalls
|
||||
}
|
||||
})
|
||||
// It is important to optimize the case where there is only one suspend call and it is the last statement
|
||||
// because we don't need to build a fat coroutine class in that case.
|
||||
// This happens a lot in practice because of suspend functions with default arguments.
|
||||
// TODO: use TailRecursionCallsCollector.
|
||||
val lastCall = when (val lastStatement = (body as IrBlockBody).statements.lastOrNull()) {
|
||||
is IrCall ->
|
||||
// Delegation to call without return can only be performed to Unit-returning function call from Unit-returning function
|
||||
if (lastStatement.type == context.irBuiltIns.unitType && function.returnType == context.irBuiltIns.unitType)
|
||||
lastStatement
|
||||
else
|
||||
null
|
||||
is IrReturn -> {
|
||||
var value: IrElement = lastStatement
|
||||
/*
|
||||
* Check if matches this pattern:
|
||||
* block/return {
|
||||
* block/return {
|
||||
* .. suspendCall()
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
loop@ while (true) {
|
||||
value = when {
|
||||
value is IrBlock && value.statements.size == 1 -> value.statements.first()
|
||||
value is IrReturn -> value.value
|
||||
else -> break@loop
|
||||
}
|
||||
}
|
||||
value as? IrCall
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
val suspendCallAtEnd = lastCall != null && lastCall.isSuspend // Suspend call.
|
||||
return when {
|
||||
numberOfSuspendCalls == 0 -> SuspendFunctionKind.NO_SUSPEND_CALLS
|
||||
numberOfSuspendCalls == 1
|
||||
&& suspendCallAtEnd -> SuspendFunctionKind.DELEGATING(lastCall!!)
|
||||
else -> SuspendFunctionKind.NEEDS_STATE_MACHINE
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress since it is used in native
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
fun IrCall.isReturnIfSuspendedCall(context: CommonBackendContext) =
|
||||
symbol.owner.run { fqNameWhenAvailable == context.internalPackageFqn.child(Name.identifier("returnIfSuspended")) }
|
||||
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.lower.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.butIf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedPlus
|
||||
|
||||
private val SUSPEND_FUNCTION_AS_GENERATOR by IrDeclarationOriginImpl
|
||||
|
||||
class JsSuspendFunctionWithGeneratorsLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
private val getContinuationSymbol = context.ir.symbols.getContinuation
|
||||
private val jsYieldFunctionSymbol = context.intrinsics.jsYieldFunctionSymbol
|
||||
private val suspendOrReturnFunctionSymbol = context.intrinsics.suspendOrReturnFunctionSymbol
|
||||
private val coroutineSuspendedGetterSymbol = context.coroutineSymbols.coroutineSuspendedGetter
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrSimpleFunction && declaration.isSuspend) {
|
||||
return transformSuspendFunction(declaration)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun transformSuspendFunction(function: IrSimpleFunction): List<IrFunction>? {
|
||||
val originalReturnType = function.returnType.also { function.returnType = context.irBuiltIns.anyNType }
|
||||
val body = function.body ?: return null
|
||||
return when (val functionKind = getSuspendFunctionKind(context, function, body, includeSuspendLambda = false)) {
|
||||
is SuspendFunctionKind.NO_SUSPEND_CALLS -> null
|
||||
is SuspendFunctionKind.DELEGATING -> {
|
||||
removeReturnIfSuspendedCallAndSimplifyDelegatingCall(function, functionKind.delegatingCall)
|
||||
null
|
||||
}
|
||||
is SuspendFunctionKind.NEEDS_STATE_MACHINE -> {
|
||||
generateGeneratorAndItsWrapper(function, body, originalReturnType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.addJsGeneratorAnnotation() {
|
||||
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(
|
||||
context.intrinsics.jsGeneratorAnnotationSymbol.owner.primaryConstructor!!.symbol
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateGeneratorAndItsWrapper(
|
||||
function: IrSimpleFunction,
|
||||
functionBody: IrBody,
|
||||
originalReturnType: IrType
|
||||
): List<IrFunction> {
|
||||
val generatorFunction = context.irFactory.createSimpleFunction(
|
||||
function.startOffset,
|
||||
function.endOffset,
|
||||
SUSPEND_FUNCTION_AS_GENERATOR,
|
||||
Name.special("<generator-${function.name.asString()}>"),
|
||||
DescriptorVisibilities.PRIVATE,
|
||||
function.isInline,
|
||||
function.isExpect,
|
||||
originalReturnType,
|
||||
function.modality,
|
||||
IrSimpleFunctionSymbolImpl(),
|
||||
function.isTailrec,
|
||||
function.isSuspend,
|
||||
function.isOperator,
|
||||
function.isInfix,
|
||||
function.isExternal,
|
||||
).apply {
|
||||
copyParameterDeclarationsFrom(function)
|
||||
parent = function.parent
|
||||
annotations = function.annotations
|
||||
body = functionBody.apply {
|
||||
val valueSymbols = function.valueParameters.zip(valueParameters)
|
||||
.plus(function.dispatchReceiverParameter to dispatchReceiverParameter)
|
||||
.plus(function.extensionReceiverParameter to extensionReceiverParameter)
|
||||
.mapNotNull { (old, new) -> new?.let { old?.symbol?.to(it.symbol) } }
|
||||
.toMap<IrValueSymbol, IrValueSymbol>()
|
||||
transformChildrenVoid(object : ValueRemapper(valueSymbols) {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val call = super.visitCall(expression)
|
||||
return if (call !is IrCall || !call.symbol.owner.isSuspend) {
|
||||
call
|
||||
} else {
|
||||
context.createIrBuilder(call.symbol).run {
|
||||
irBlock(resultType = call.type) {
|
||||
val tmp = createTmpVariable(call, irType = context.irBuiltIns.anyNType)
|
||||
val coroutineSuspended = irCall(coroutineSuspendedGetterSymbol)
|
||||
val condition = irEqeqeq(irGet(tmp), coroutineSuspended)
|
||||
val yield = irCall(jsYieldFunctionSymbol).apply { putValueArgument(0, irGet(tmp)) }
|
||||
+irIfThen(context.irBuiltIns.unitType, condition, irSet(tmp, yield))
|
||||
+irImplicitCast(irGet(tmp), call.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
addJsGeneratorAnnotation()
|
||||
}
|
||||
|
||||
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(suspendOrReturnFunctionSymbol).also {
|
||||
it.putValueArgument(0, irCall(generatorFunction.symbol).apply {
|
||||
dispatchReceiver = function.dispatchReceiverParameter?.let(::irGet)
|
||||
extensionReceiver = function.extensionReceiverParameter?.let(::irGet)
|
||||
contextReceiversCount = function.contextReceiverParametersCount
|
||||
function.valueParameters.forEachIndexed { i, v -> putValueArgument(i, irGet(v)) }
|
||||
})
|
||||
it.putValueArgument(1, irCall(getContinuationSymbol))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return listOf(generatorFunction, function)
|
||||
}
|
||||
|
||||
private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) {
|
||||
val returnValue = runIf(delegatingCall.isReturnIfSuspendedCall(context)) {
|
||||
delegatingCall.getValueArgument(0)
|
||||
} ?: delegatingCall
|
||||
|
||||
val body = irFunction.body as IrBlockBody
|
||||
|
||||
context.createIrBuilder(
|
||||
irFunction.symbol,
|
||||
startOffset = body.endOffset.previousOffset,
|
||||
endOffset = body.endOffset.previousOffset
|
||||
).run {
|
||||
val statements = body.statements
|
||||
val lastStatement = statements.last()
|
||||
assert(lastStatement == delegatingCall || lastStatement is IrReturn) { "Unexpected statement $lastStatement" }
|
||||
|
||||
val tempVar = scope.createTemporaryVariable(returnValue, irType = context.irBuiltIns.anyType)
|
||||
statements[statements.lastIndex] = tempVar
|
||||
statements.add(irReturn(irGet(tempVar)))
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -32,8 +32,7 @@ import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
|
||||
class JsSuspendFunctionsLowering(ctx: JsCommonBackendContext) : AbstractSuspendFunctionsLowering<JsCommonBackendContext>(ctx) {
|
||||
|
||||
val coroutineSymbols = ctx.coroutineSymbols
|
||||
private val coroutineSymbols = ctx.coroutineSymbols
|
||||
|
||||
private val coroutineImplExceptionPropertyGetter = coroutineSymbols.coroutineImplExceptionPropertyGetter
|
||||
private val coroutineImplExceptionPropertySetter = coroutineSymbols.coroutineImplExceptionPropertySetter
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.lower.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.compileSuspendAsJsGenerator
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCallableReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class ReplaceSuspendIntrinsicLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val valueParamSizeToItsCreateCoroutineUnintercepted =
|
||||
context.intrinsics.createCoroutineUninterceptedGeneratorVersion.groupPerValueParamSize()
|
||||
private val valueParamSizeToItsStartCoroutineUninterceptedOrReturn =
|
||||
context.intrinsics.startCoroutineUninterceptedOrReturnGeneratorVersion.groupPerValueParamSize()
|
||||
|
||||
private fun Set<IrSimpleFunctionSymbol>.groupPerValueParamSize(): Map<Int, IrSimpleFunctionSymbol> {
|
||||
return associateBy { it.owner.valueParameters.size }
|
||||
}
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (!context.compileSuspendAsJsGenerator) return
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCallableReference(expression: IrCallableReference<*>): IrExpression {
|
||||
if (expression.symbol !is IrSimpleFunctionSymbol) return super.visitCallableReference(expression)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val reference = expression as IrCallableReference<IrSimpleFunctionSymbol>
|
||||
|
||||
when (val symbol = reference.symbol) {
|
||||
in context.intrinsics.createCoroutineUnintercepted ->
|
||||
reference.symbol = valueParamSizeToItsCreateCoroutineUnintercepted.getValue(symbol.owner.valueParameters.size)
|
||||
in context.intrinsics.startCoroutineUninterceptedOrReturn ->
|
||||
reference.symbol = valueParamSizeToItsStartCoroutineUninterceptedOrReturn.getValue(symbol.owner.valueParameters.size)
|
||||
}
|
||||
|
||||
return super.visitCallableReference(reference)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
when (val symbol = expression.symbol) {
|
||||
in context.intrinsics.createCoroutineUnintercepted ->
|
||||
expression.symbol = valueParamSizeToItsCreateCoroutineUnintercepted.getValue(symbol.owner.valueParameters.size)
|
||||
in context.intrinsics.startCoroutineUninterceptedOrReturn ->
|
||||
expression.symbol = valueParamSizeToItsStartCoroutineUninterceptedOrReturn.getValue(symbol.owner.valueParameters.size)
|
||||
}
|
||||
return super.visitCall(expression)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+2
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.DefaultInlineFunctionResolver
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lazy2
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.compileSuspendAsJsGenerator
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||
|
||||
+3
-1
@@ -143,7 +143,9 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
}
|
||||
}
|
||||
|
||||
return expression.value.maybeOptimizeIntoSwitch(context, lastStatementTransformer).withSource(expression, context)
|
||||
return expression.value
|
||||
.maybeOptimizeIntoSwitch(context, lastStatementTransformer)
|
||||
.withSource(expression, context)
|
||||
}
|
||||
|
||||
override fun visitThrow(expression: IrThrow, context: JsGenerationContext): JsStatement {
|
||||
|
||||
+4
@@ -88,6 +88,10 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
|
||||
add(intrinsics.jsIsEs6) { _, _ -> JsBooleanLiteral(backendContext.es6mode) }
|
||||
|
||||
add(intrinsics.jsYieldFunctionSymbol) { call, context ->
|
||||
JsYield(translateCallArguments(call, context).single())
|
||||
}
|
||||
|
||||
add(intrinsics.jsObjectCreateSymbol) { call, context ->
|
||||
val classToCreate = call.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||
val className = classToCreate.getClassRef(context.staticContext)
|
||||
|
||||
+18
-4
@@ -12,8 +12,7 @@ import org.jetbrains.kotlin.ir.IrFileEntry
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBoxParameter
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.sourceMapsInfo
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -24,6 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isGeneratorFunction
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.js.config.SourceMapNamesPolicy
|
||||
@@ -119,7 +119,13 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
|
||||
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
||||
|
||||
val function = JsFunction(emptyScope, body, "member function ${name ?: "annon"}")
|
||||
.apply { if (declaration.isEs6ConstructorReplacement) modifiers.add(JsFunction.Modifier.STATIC) }
|
||||
.apply {
|
||||
if (declaration.isEs6ConstructorReplacement) modifiers.add(JsFunction.Modifier.STATIC)
|
||||
if (declaration.shouldBeCompiledAsGenerator()) {
|
||||
name?.isGeneratorFunction = true
|
||||
modifiers.add(JsFunction.Modifier.GENERATOR)
|
||||
}
|
||||
}
|
||||
.withSource(declaration, context, useNameOf = declaration)
|
||||
|
||||
function.name = name
|
||||
@@ -135,6 +141,9 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
|
||||
return function
|
||||
}
|
||||
|
||||
private fun IrFunction.shouldBeCompiledAsGenerator(): Boolean =
|
||||
hasAnnotation(JsAnnotations.jsGeneratorFqn)
|
||||
|
||||
private fun isFunctionTypeInvoke(receiver: JsExpression?, call: IrCall): Boolean {
|
||||
if (receiver == null || receiver is JsThisRef) return false
|
||||
val simpleFunction = call.symbol.owner
|
||||
@@ -237,6 +246,11 @@ fun translateCall(
|
||||
else -> jsElementAccess(symbolName.ident, jsDispatchReceiver)
|
||||
}
|
||||
|
||||
if (symbolName.isGeneratorFunction) {
|
||||
(ref.commentsBeforeNode ?: mutableListOf<JsComment>().also { ref.commentsBeforeNode = it })
|
||||
.add(JsMultiLineComment("#__NOINLINE__"))
|
||||
}
|
||||
|
||||
return if (isExternalVararg) {
|
||||
// TODO: Don't use `Function.prototype.apply` when number of arguments is known at compile time (e.g. there are no spread operators)
|
||||
|
||||
@@ -667,4 +681,4 @@ private fun IrClass?.canUseSuperRef(context: JsGenerationContext, superClass: Ir
|
||||
context.staticContext.backendContext.es6mode &&
|
||||
!superClass.isInterface &&
|
||||
!isInner && !isLocal && !currentFunction.isEs6ConstructorReplacement && currentFunction.parentClassOrNull?.superClass?.symbol != context.staticContext.backendContext.coroutineSymbols.coroutineImpl
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ object JsAnnotations {
|
||||
val jsNativeInvoke = FqName("kotlin.js.nativeInvoke")
|
||||
val jsFunFqn = FqName("kotlin.js.JsFun")
|
||||
val JsPolyfillFqn = FqName("kotlin.js.JsPolyfill")
|
||||
val jsGeneratorFqn = FqName("kotlin.js.JsGenerator")
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
||||
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBoxParameter
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isSyntheticConstructorForExport
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isSyntheticPrimaryConstructor
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
@@ -135,4 +132,7 @@ fun JsIrBackendContext.findDefaultConstructorFor(irClass: IrClass): IrFunction?
|
||||
return mapping.classToItsDefaultConstructor[irClass]?.let {
|
||||
mapping.secondaryConstructorToFactory[it] ?: it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val IrClass.primaryConstructorReplacement: IrSimpleFunction?
|
||||
get() = findDeclaration<IrSimpleFunction> { it.isEs6PrimaryConstructorReplacement }
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isMethodOfAny
|
||||
import org.jetbrains.kotlin.ir.util.isTopLevel
|
||||
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
fun TODO(element: IrElement): Nothing = TODO(element::class.java.simpleName + " is not supported yet here")
|
||||
@@ -110,6 +111,9 @@ fun JsCommonBackendContext.findUnitGetInstanceFunction(): IrSimpleFunction =
|
||||
fun JsCommonBackendContext.findUnitInstanceField(): IrField =
|
||||
mapping.objectToInstanceField[irBuiltIns.unitClass.owner]!!
|
||||
|
||||
val JsCommonBackendContext.compileSuspendAsJsGenerator: Boolean
|
||||
get() = configuration[JSConfigurationKeys.COMPILE_SUSPEND_AS_JS_GENERATOR] == true
|
||||
|
||||
fun IrDeclaration.isImportedFromModuleOnly(): Boolean {
|
||||
return isTopLevel && isEffectivelyExternal() && (getJsModule() != null && !isJsNonModule() || (parent as? IrAnnotationContainer)?.getJsModule() != null)
|
||||
}
|
||||
@@ -118,4 +122,4 @@ fun invokeFunForLambda(call: IrCall) =
|
||||
call.extensionReceiver!!
|
||||
.type
|
||||
.getClass()!!
|
||||
.invokeFun!!
|
||||
.invokeFun!!
|
||||
+1
@@ -70,4 +70,5 @@ object ExpressionIds {
|
||||
const val NEW = 21
|
||||
const val CLASS = 22
|
||||
const val SUPER_REF = 23
|
||||
const val YIELD = 24
|
||||
}
|
||||
+3
@@ -390,6 +390,9 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
NEW -> {
|
||||
JsNew(readExpression(), readList { readExpression() })
|
||||
}
|
||||
YIELD -> {
|
||||
JsYield(ifTrue { readExpression() })
|
||||
}
|
||||
else -> error("Unknown expression id: $id")
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -537,6 +537,11 @@ private class JsIrAstSerializer {
|
||||
writeExpression(x.constructorExpression)
|
||||
writeCollection(x.arguments) { writeExpression(it) }
|
||||
}
|
||||
|
||||
override fun visitYield(x: JsYield) {
|
||||
writeByte(ExpressionIds.YIELD)
|
||||
ifNotNull(x.expression) { writeExpression(it) }
|
||||
}
|
||||
}
|
||||
|
||||
withComments(expression) {
|
||||
|
||||
+1
@@ -54,6 +54,7 @@ where advanced options include:
|
||||
-Xstrict-implicit-export-types Generate strict types for implicitly exported entities inside d.ts files. This is available in the IR backend only.
|
||||
-Xtyped-arrays Translate primitive arrays into JS typed arrays.
|
||||
-Xes-classes Let generated JavaScript code use ES2015 classes.
|
||||
-Xes-generators Enable ES2015 generator functions usage inside the compiled code
|
||||
-Xwasm Use the experimental WebAssembly compiler backend.
|
||||
-Xwasm-debug-info Add debug info to the compiled WebAssembly module.
|
||||
-Xwasm-enable-array-range-checks
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
|
||||
+1
@@ -139,6 +139,7 @@ fun createCompilerConfiguration(module: TestModule, configurators: List<Abstract
|
||||
|
||||
if (JsEnvironmentConfigurationDirectives.ES6_MODE in module.directives) {
|
||||
configuration.put(JSConfigurationKeys.USE_ES6_CLASSES, true)
|
||||
configuration.put(JSConfigurationKeys.COMPILE_SUSPEND_AS_JS_GENERATOR, true)
|
||||
}
|
||||
|
||||
if (module.frontendKind == FrontendKinds.FIR) {
|
||||
|
||||
@@ -80,6 +80,11 @@ class JsPrecedenceVisitor extends JsVisitor {
|
||||
answer = 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitYield(@NotNull JsYield yield) {
|
||||
answer = 2; // https://esdiscuss.org/topic/precedence-of-yield-operator
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNameRef(@NotNull JsNameRef nameRef) {
|
||||
if (nameRef.isLeaf()) {
|
||||
|
||||
@@ -27,6 +27,7 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
||||
private static final char[] CHARS_CLASS = "class".toCharArray();
|
||||
private static final char[] CHARS_CONSTRUCTOR = "constructor".toCharArray();
|
||||
private static final char[] CHARS_CONTINUE = "continue".toCharArray();
|
||||
private static final char[] CHARS_YIELD = "yield".toCharArray();
|
||||
private static final char[] CHARS_DEBUGGER = "debugger".toCharArray();
|
||||
private static final char[] CHARS_DEFAULT = "default".toCharArray();
|
||||
private static final char[] CHARS_DO = "do".toCharArray();
|
||||
@@ -46,6 +47,7 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
||||
private static final char[] CHARS_RETURN = "return".toCharArray();
|
||||
private static final char[] CHARS_SWITCH = "switch".toCharArray();
|
||||
private static final char[] CHARS_THIS = "this".toCharArray();
|
||||
private static final char CHARS_GENERATOR = '*';
|
||||
|
||||
private static final char[] CHARS_SUPER = "super".toCharArray();
|
||||
private static final char[] CHARS_THROW = "throw".toCharArray();
|
||||
@@ -337,6 +339,24 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
||||
popSourceInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitYield(@NotNull JsYield x) {
|
||||
pushSourceInfo(x.getSource());
|
||||
printCommentsBeforeNode(x);
|
||||
|
||||
p.print(CHARS_YIELD);
|
||||
|
||||
JsExpression expression = x.getExpression();
|
||||
|
||||
if (expression != null) {
|
||||
space();
|
||||
accept(x.getExpression());
|
||||
}
|
||||
|
||||
printCommentsAfterNode(x);
|
||||
popSourceInfo();
|
||||
}
|
||||
|
||||
private void continueOrBreakLabel(JsContinue x) {
|
||||
JsNameRef label = x.getLabel();
|
||||
if (label != null) {
|
||||
@@ -684,6 +704,10 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
||||
space();
|
||||
}
|
||||
|
||||
if (x.isGenerator()) {
|
||||
p.print(CHARS_GENERATOR);
|
||||
}
|
||||
|
||||
if (x.getName() != null) {
|
||||
nameOf(x);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
public final class JsFunction extends JsLiteral implements HasName {
|
||||
public enum Modifier { STATIC, GET, SET }
|
||||
public enum Modifier { STATIC, GET, SET, GENERATOR }
|
||||
|
||||
@NotNull
|
||||
private JsBlock body;
|
||||
@@ -81,6 +81,10 @@ public final class JsFunction extends JsLiteral implements HasName {
|
||||
return modifiers != null && modifiers.contains(Modifier.SET);
|
||||
}
|
||||
|
||||
public boolean isGenerator() {
|
||||
return modifiers != null && modifiers.contains(Modifier.GENERATOR);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<Modifier> getModifiers() {
|
||||
if (modifiers == null) {
|
||||
|
||||
@@ -22,6 +22,10 @@ public final class JsNew extends JsExpression.JsExpressionHasArguments {
|
||||
this.constructorExpression = constructorExpression;
|
||||
}
|
||||
|
||||
public JsNew(JsExpression constructorExpression, JsExpression... arguments) {
|
||||
this(constructorExpression, new SmartList<JsExpression>(arguments));
|
||||
}
|
||||
|
||||
public JsExpression getConstructorExpression() {
|
||||
return constructorExpression;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ abstract class JsVisitor {
|
||||
open fun visitContinue(x: JsContinue): Unit =
|
||||
visitElement(x)
|
||||
|
||||
open fun visitYield(x: JsYield): Unit =
|
||||
visitElement(x)
|
||||
|
||||
open fun visitDebugger(x: JsDebugger): Unit =
|
||||
visitElement(x)
|
||||
|
||||
|
||||
@@ -101,6 +101,9 @@ public abstract class JsVisitorWithContext {
|
||||
public void endVisit(@NotNull JsContinue x, @NotNull JsContext ctx) {
|
||||
}
|
||||
|
||||
public void endVisit(@NotNull JsYield x, @NotNull JsContext ctx) {
|
||||
}
|
||||
|
||||
public void endVisit(@NotNull JsDebugger x, @NotNull JsContext ctx) {
|
||||
}
|
||||
|
||||
@@ -274,6 +277,10 @@ public abstract class JsVisitorWithContext {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(@NotNull JsYield x, @NotNull JsContext ctx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(@NotNull JsDebugger x, @NotNull JsContext ctx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.js.backend.ast
|
||||
|
||||
import org.jetbrains.kotlin.js.util.AstUtil
|
||||
|
||||
class JsYield(var expression: JsExpression?) : JsExpression() {
|
||||
override fun accept(visitor: JsVisitor) {
|
||||
visitor.visitYield(this)
|
||||
}
|
||||
|
||||
override fun acceptChildren(visitor: JsVisitor) {
|
||||
visitor.accept(expression)
|
||||
}
|
||||
|
||||
override fun deepCopy(): JsExpression {
|
||||
return JsYield(AstUtil.deepCopy(expression)).withMetadataFrom(this)
|
||||
}
|
||||
|
||||
override fun traverse(visitor: JsVisitorWithContext, ctx: JsContext<*>) {
|
||||
if (visitor.visit(this, ctx)) {
|
||||
expression = visitor.accept(expression)
|
||||
}
|
||||
visitor.endVisit(this, ctx)
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,8 @@ var HasMetadata.synthetic: Boolean by MetadataProperty(default = false)
|
||||
var HasMetadata.isInlineClassBoxing: Boolean by MetadataProperty(default = false)
|
||||
var HasMetadata.isInlineClassUnboxing: Boolean by MetadataProperty(default = false)
|
||||
|
||||
var HasMetadata.isGeneratorFunction: Boolean by MetadataProperty(default = false)
|
||||
|
||||
var HasMetadata.sideEffects: SideEffectKind by MetadataProperty(default = SideEffectKind.AFFECTS_STATE)
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,6 +87,9 @@ public class JSConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<Boolean> GENERATE_DTS =
|
||||
CompilerConfigurationKey.create("generate TypeScript definition file");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> COMPILE_SUSPEND_AS_JS_GENERATOR =
|
||||
CompilerConfigurationKey.create("force suspend functions compilation int JS generator functions");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> GENERATE_REGION_COMMENTS =
|
||||
CompilerConfigurationKey.create("generate special comments at the start and the end of each file block, " +
|
||||
"it allows to fold them and navigate to them in the IDEA");
|
||||
|
||||
@@ -178,6 +178,7 @@ public class JsAstMapper {
|
||||
return mapSetElem(node);
|
||||
|
||||
case TokenStream.FUNCTION:
|
||||
case TokenStream.GENERATOR:
|
||||
return mapFunction(node);
|
||||
|
||||
case TokenStream.BLOCK:
|
||||
@@ -199,6 +200,9 @@ public class JsAstMapper {
|
||||
case TokenStream.CONTINUE:
|
||||
return mapContinue(node);
|
||||
|
||||
case TokenStream.YIELD:
|
||||
return mapYield(node);
|
||||
|
||||
case TokenStream.OBJLIT:
|
||||
return mapObjectLit(node);
|
||||
|
||||
@@ -387,6 +391,10 @@ public class JsAstMapper {
|
||||
return new JsContinue(getTargetLabel(contNode));
|
||||
}
|
||||
|
||||
private JsYield mapYield(Node yieldNode) {
|
||||
return new JsYield(mapExpression(yieldNode.getFirstChild()));
|
||||
}
|
||||
|
||||
private JsStatement mapDebuggerStatement(Node node) {
|
||||
// Calls an optional method to invoke the debugger.
|
||||
//
|
||||
@@ -570,7 +578,7 @@ public class JsAstMapper {
|
||||
|
||||
public JsFunction mapFunction(Node fnNode) throws JsParserException {
|
||||
int nodeType = fnNode.getType();
|
||||
assert nodeType == TokenStream.FUNCTION: "Expected function node, got: " + TokenStream.tokenToName(nodeType);
|
||||
assert nodeType == TokenStream.FUNCTION || nodeType == TokenStream.GENERATOR: "Expected function node, got: " + TokenStream.tokenToName(nodeType);
|
||||
Node fromFnNameNode = fnNode.getFirstChild();
|
||||
Node fromParamNode = fnNode.getFirstChild().getNext().getFirstChild();
|
||||
Node fromBodyNode = fnNode.getFirstChild().getNext().getNext();
|
||||
@@ -586,6 +594,10 @@ public class JsAstMapper {
|
||||
JsFunction toFn = scopeContext.enterFunction();
|
||||
toFn.setName(functionName);
|
||||
|
||||
if (nodeType == TokenStream.GENERATOR) {
|
||||
toFn.getModifiers().add(JsFunction.Modifier.GENERATOR);
|
||||
}
|
||||
|
||||
while (fromParamNode != null) {
|
||||
String fromParamName = fromParamNode.getString();
|
||||
JsName name = scopeContext.localNameFor(fromParamName);
|
||||
|
||||
@@ -180,6 +180,19 @@ public class IRFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Yield (possibly with expression)
|
||||
*/
|
||||
public Node createYield(Node expression, CodePosition location) {
|
||||
Node result = new Node(TokenStream.YIELD, location);
|
||||
if (expression == null) {
|
||||
return result;
|
||||
} else {
|
||||
result.addChildToBack(expression);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* debugger
|
||||
*/
|
||||
@@ -197,11 +210,11 @@ public class IRFactory {
|
||||
return new Node(TokenStream.BLOCK, location);
|
||||
}
|
||||
|
||||
public Node createFunction(Node name, Node args, Node statements, CodePosition location) {
|
||||
public Node createFunction(Node name, Node args, Node statements, boolean isGenerator, CodePosition location) {
|
||||
if (name == null) {
|
||||
name = createName("", location);
|
||||
}
|
||||
return new Node(TokenStream.FUNCTION, name, args, statements, location);
|
||||
return new Node(isGenerator ? TokenStream.GENERATOR : TokenStream.FUNCTION, name, args, statements, location);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,6 +186,10 @@ public class Parser {
|
||||
|
||||
Node nameNode;
|
||||
Node memberExprNode = null;
|
||||
|
||||
// For generators
|
||||
boolean isGenerator = ts.matchToken(TokenStream.MUL);
|
||||
|
||||
if (ts.matchToken(TokenStream.NAME)) {
|
||||
nameNode = nf.createName(ts.getString(), basePosition);
|
||||
if (!ts.matchToken(TokenStream.LP)) {
|
||||
@@ -248,7 +252,7 @@ public class Parser {
|
||||
functionNumber = savedFunctionNumber;
|
||||
}
|
||||
|
||||
Node pn = nf.createFunction(nameNode, args, body, basePosition);
|
||||
Node pn = nf.createFunction(nameNode, args, body, isGenerator, basePosition);
|
||||
if (memberExprNode != null) {
|
||||
pn = nf.createBinary(TokenStream.ASSIGN, TokenStream.NOP, memberExprNode, pn, basePosition);
|
||||
}
|
||||
@@ -897,6 +901,9 @@ public class Parser {
|
||||
CodePosition position = ts.tokenPosition;
|
||||
|
||||
switch (tt) {
|
||||
case TokenStream.YIELD:
|
||||
return nf.createUnary(TokenStream.YIELD, ts.getOp(), unaryExpr(ts), position);
|
||||
|
||||
case TokenStream.UNARYOP:
|
||||
return nf.createUnary(TokenStream.UNARYOP, ts.getOp(), unaryExpr(ts), position);
|
||||
|
||||
|
||||
@@ -254,6 +254,9 @@ public class TokenStream {
|
||||
LAST_TOKEN = 147,
|
||||
NUMBER_INT = 148,
|
||||
|
||||
GENERATOR = 149,
|
||||
YIELD = 150,
|
||||
|
||||
// This value is only used as a return value for getTokenHelper,
|
||||
// which is only called from getToken and exists to avoid an excessive
|
||||
// recursion problem if a number of lines in a row are comments.
|
||||
@@ -390,6 +393,7 @@ public class TokenStream {
|
||||
case FOR: return "for";
|
||||
case BREAK: return "break";
|
||||
case CONTINUE: return "continue";
|
||||
case YIELD: return "yield";
|
||||
case VAR: return "var";
|
||||
case WITH: return "with";
|
||||
case CATCH: return "catch";
|
||||
@@ -456,6 +460,7 @@ public class TokenStream {
|
||||
KEYWORDS.put("break", BREAK);
|
||||
KEYWORDS.put("case", CASE);
|
||||
KEYWORDS.put("continue", CONTINUE);
|
||||
KEYWORDS.put("yield", YIELD);
|
||||
KEYWORDS.put("default", DEFAULT);
|
||||
KEYWORDS.put("delete", DELPROP);
|
||||
KEYWORDS.put("do", DO);
|
||||
|
||||
@@ -122,6 +122,7 @@ message Function {
|
||||
STATIC = 1;
|
||||
GET = 2;
|
||||
SET = 3;
|
||||
GENERATOR = 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -426,6 +426,7 @@ abstract class JsAstDeserializerBase {
|
||||
JsAstProtoBuf.Function.Modifier.STATIC -> JsFunction.Modifier.STATIC
|
||||
JsAstProtoBuf.Function.Modifier.SET -> JsFunction.Modifier.SET
|
||||
JsAstProtoBuf.Function.Modifier.GET -> JsFunction.Modifier.GET
|
||||
JsAstProtoBuf.Function.Modifier.GENERATOR -> JsFunction.Modifier.GENERATOR
|
||||
}
|
||||
|
||||
protected fun map(op: JsAstProtoBuf.BinaryOperation.Type) = when (op) {
|
||||
|
||||
@@ -8934,6 +8934,10 @@ public final class JsAstProtoBuf {
|
||||
* <code>SET = 3;</code>
|
||||
*/
|
||||
SET(2, 3),
|
||||
/**
|
||||
* <code>GENERATOR = 4;</code>
|
||||
*/
|
||||
GENERATOR(3, 4),
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -8948,6 +8952,10 @@ public final class JsAstProtoBuf {
|
||||
* <code>SET = 3;</code>
|
||||
*/
|
||||
public static final int SET_VALUE = 3;
|
||||
/**
|
||||
* <code>GENERATOR = 4;</code>
|
||||
*/
|
||||
public static final int GENERATOR_VALUE = 4;
|
||||
|
||||
|
||||
public final int getNumber() { return value; }
|
||||
@@ -8957,6 +8965,7 @@ public final class JsAstProtoBuf {
|
||||
case 1: return STATIC;
|
||||
case 2: return GET;
|
||||
case 3: return SET;
|
||||
case 4: return GENERATOR;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,6 +442,7 @@ abstract class JsAstSerializerBase {
|
||||
JsFunction.Modifier.STATIC -> JsAstProtoBuf.Function.Modifier.STATIC
|
||||
JsFunction.Modifier.SET -> JsAstProtoBuf.Function.Modifier.SET
|
||||
JsFunction.Modifier.GET -> JsAstProtoBuf.Function.Modifier.GET
|
||||
JsFunction.Modifier.GENERATOR -> JsAstProtoBuf.Function.Modifier.GENERATOR
|
||||
}
|
||||
|
||||
protected fun map(op: JsBinaryOperator) = when (op) {
|
||||
|
||||
@@ -93,6 +93,14 @@ fun main(args: Array<String>) {
|
||||
model("incremental/invalidation/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR, recursive = false)
|
||||
}
|
||||
|
||||
testClass<AbstractJsFirES6InvalidationPerFileTest> {
|
||||
model("incremental/invalidation/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR_ES6, recursive = false)
|
||||
}
|
||||
|
||||
testClass<AbstractJsFirES6InvalidationPerModuleTest> {
|
||||
model("incremental/invalidation/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR_ES6, recursive = false)
|
||||
}
|
||||
|
||||
testClass<AbstractJsIrInvalidationPerFileWithPLTest> {
|
||||
model("incremental/invalidationWithPL/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR, recursive = false)
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ abstract class AbstractInvalidationTest(
|
||||
copy.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true)
|
||||
copy.put(JSConfigurationKeys.SOURCE_MAP, true)
|
||||
copy.put(JSConfigurationKeys.USE_ES6_CLASSES, targetBackend == TargetBackend.JS_IR_ES6)
|
||||
copy.put(JSConfigurationKeys.COMPILE_SUSPEND_AS_JS_GENERATOR, targetBackend == TargetBackend.JS_IR_ES6)
|
||||
|
||||
copy.languageVersionSettings = with(LanguageVersionSettingsBuilder()) {
|
||||
language.forEach {
|
||||
|
||||
@@ -26,6 +26,10 @@ abstract class AbstractJsFirInvalidationPerFileTest :
|
||||
FirAbstractInvalidationTest(TargetBackend.JS_IR, JsGenerationGranularity.PER_FILE, "incrementalOut/invalidationFir/perFile")
|
||||
abstract class AbstractJsFirInvalidationPerModuleTest :
|
||||
FirAbstractInvalidationTest(TargetBackend.JS_IR, JsGenerationGranularity.PER_MODULE, "incrementalOut/invalidationFir/perModule")
|
||||
abstract class AbstractJsFirES6InvalidationPerFileTest :
|
||||
FirAbstractInvalidationTest(TargetBackend.JS_IR_ES6, JsGenerationGranularity.PER_FILE, "incrementalOut/invalidationFirES6/perFile")
|
||||
abstract class AbstractJsFirES6InvalidationPerModuleTest :
|
||||
FirAbstractInvalidationTest(TargetBackend.JS_IR_ES6, JsGenerationGranularity.PER_MODULE, "incrementalOut/invalidationFirES6/perModule")
|
||||
|
||||
abstract class FirAbstractInvalidationTest(
|
||||
targetBackend: TargetBackend,
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerFileTestGenerated.java
Generated
+597
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.incremental;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateJsTestsKt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("js/js.translator/testData/incremental/invalidation")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class JsFirES6InvalidationPerFileTestGenerated extends AbstractJsFirES6InvalidationPerFileTest {
|
||||
@Test
|
||||
@TestMetadata("abstractClassWithJsExport")
|
||||
public void testAbstractClassWithJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/abstractClassWithJsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("addUpdateRemoveDependentFile")
|
||||
public void testAddUpdateRemoveDependentFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("addUpdateRemoveDependentModule")
|
||||
public void testAddUpdateRemoveDependentModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInInvalidation() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/incremental/invalidation"), Pattern.compile("^([^_](.+))$"), null, TargetBackend.JS_IR_ES6, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("circleExportsUpdate")
|
||||
public void testCircleExportsUpdate() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/circleExportsUpdate/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("circleInlineImportsUpdate")
|
||||
public void testCircleInlineImportsUpdate() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/circleInlineImportsUpdate/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("class")
|
||||
public void testClass() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/class/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classFunctionsAndFields")
|
||||
public void testClassFunctionsAndFields() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/classFunctionsAndFields/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classWithJsExport")
|
||||
public void testClassWithJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/classWithJsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionConstVal")
|
||||
public void testCompanionConstVal() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionConstVal/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionFunction")
|
||||
public void testCompanionFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionInlineFunction")
|
||||
public void testCompanionInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionProperties")
|
||||
public void testCompanionProperties() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionProperties/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionWithStdLibCall")
|
||||
public void testCompanionWithStdLibCall() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionWithStdLibCall/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constVals")
|
||||
public void testConstVals() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/constVals/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("crossModuleReferences")
|
||||
public void testCrossModuleReferences() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/crossModuleReferences/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("eagerInitialization")
|
||||
public void testEagerInitialization() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/eagerInitialization/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enum")
|
||||
public void testEnum() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/enum/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumsInInlineFunctions")
|
||||
public void testEnumsInInlineFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exceptionsFromInlineFunction")
|
||||
public void testExceptionsFromInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportsThroughInlineFunction")
|
||||
public void testExportsThroughInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/exportsThroughInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideClassFunctionQualifiers")
|
||||
public void testFakeOverrideClassFunctionQualifiers() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideClassFunctionQualifiers/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInheritance")
|
||||
public void testFakeOverrideInheritance() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInheritance/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInlineExtension")
|
||||
public void testFakeOverrideInlineExtension() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineExtension/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInlineFunction")
|
||||
public void testFakeOverrideInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInlineProperty")
|
||||
public void testFakeOverrideInlineProperty() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineProperty/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInterfaceFunctionQualifiers")
|
||||
public void testFakeOverrideInterfaceFunctionQualifiers() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInterfaceFunctionQualifiers/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fastPath1")
|
||||
public void testFastPath1() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath1/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fastPath2")
|
||||
public void testFastPath2() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fileNameClash")
|
||||
public void testFileNameClash() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("friendDependency")
|
||||
public void testFriendDependency() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/friendDependency/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionDefaultParams")
|
||||
public void testFunctionDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionSignature")
|
||||
public void testFunctionSignature() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionSignature/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionTypeInterface")
|
||||
public void testFunctionTypeInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterface/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionTypeInterfaceReflect")
|
||||
public void testFunctionTypeInterfaceReflect() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericFunctions")
|
||||
public void testGenericFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/genericFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericInlineFunctions")
|
||||
public void testGenericInlineFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/genericInlineFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("gettersAndSettersInlining")
|
||||
public void testGettersAndSettersInlining() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/gettersAndSettersInlining/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineBecomeNonInline")
|
||||
public void testInlineBecomeNonInline() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineBecomeNonInline/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionAnnotations")
|
||||
public void testInlineFunctionAnnotations() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAnnotations/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionAsFunctionReference")
|
||||
public void testInlineFunctionAsFunctionReference() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAsFunctionReference/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionAsParam")
|
||||
public void testInlineFunctionAsParam() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAsParam/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionCircleUsage")
|
||||
public void testInlineFunctionCircleUsage() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionCircleUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionDefaultParams")
|
||||
public void testInlineFunctionDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionWithObject")
|
||||
public void testInlineFunctionWithObject() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionWithObject/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceOpenMethods")
|
||||
public void testInterfaceOpenMethods() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceOpenMethods/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceOpenMethodsInOpenClass")
|
||||
public void testInterfaceOpenMethodsInOpenClass() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceOpenMethodsInOpenClass/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceSuperUsage")
|
||||
public void testInterfaceSuperUsage() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceSuperUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceWithDefaultParams")
|
||||
public void testInterfaceWithDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceWithDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceWithJsExport")
|
||||
public void testInterfaceWithJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceWithJsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsCode")
|
||||
public void testJsCode() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCode/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsCodeWithConstString")
|
||||
public void testJsCodeWithConstString() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCodeWithConstString/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsCodeWithConstStringFromOtherModule")
|
||||
public void testJsCodeWithConstStringFromOtherModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCodeWithConstStringFromOtherModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExport")
|
||||
public void testJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExportReexport")
|
||||
public void testJsExportReexport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExportReexport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExportWithMultipleFiles")
|
||||
public void testJsExportWithMultipleFiles() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExportWithMultipleFiles/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsModuleAnnotation")
|
||||
public void testJsModuleAnnotation() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotation/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsModuleAnnotationOnObjectWithUsage")
|
||||
public void testJsModuleAnnotationOnObjectWithUsage() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsName")
|
||||
public void testJsName() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsName/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/languageVersionSettings/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localInlineFunction")
|
||||
public void testLocalInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/localInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localObjectsLeakThroughInterface")
|
||||
public void testLocalObjectsLeakThroughInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mainFunction")
|
||||
public void testMainFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/mainFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mainModuleInvalidation")
|
||||
public void testMainModuleInvalidation() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/mainModuleInvalidation/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveAndModifyInlineFunction")
|
||||
public void testMoveAndModifyInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveAndModifyInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveExternalDeclarationsBetweenFiles")
|
||||
public void testMoveExternalDeclarationsBetweenFiles() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveExternalDeclarationsBetweenFiles/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveExternalDeclarationsBetweenJsModules")
|
||||
public void testMoveExternalDeclarationsBetweenJsModules() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveExternalDeclarationsBetweenJsModules/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveFilesBetweenModules")
|
||||
public void testMoveFilesBetweenModules() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveFilesBetweenModules/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveInlineFunctionBetweenModules")
|
||||
public void testMoveInlineFunctionBetweenModules() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveInlineFunctionBetweenModules/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multiPlatformClashFileNames")
|
||||
public void testMultiPlatformClashFileNames() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/multiPlatformClashFileNames/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multiPlatformSimple")
|
||||
public void testMultiPlatformSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/multiPlatformSimple/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClass")
|
||||
public void testNestedClass() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/nestedClass/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonInlineBecomeInline")
|
||||
public void testNonInlineBecomeInline() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/nonInlineBecomeInline/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("openClassWithInternalField")
|
||||
public void testOpenClassWithInternalField() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/openClassWithInternalField/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateDeclarationLeakThroughDefaultParam")
|
||||
public void testPrivateDeclarationLeakThroughDefaultParam() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/privateDeclarationLeakThroughDefaultParam/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateInlineFunction1")
|
||||
public void testPrivateInlineFunction1() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/privateInlineFunction1/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateObjectsLeakThroughSealedInterface")
|
||||
public void testPrivateObjectsLeakThroughSealedInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/privateObjectsLeakThroughSealedInterface/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("removeFile")
|
||||
public void testRemoveFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/removeFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("removeModule")
|
||||
public void testRemoveModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/removeModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("removeUnusedFile")
|
||||
public void testRemoveUnusedFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/removeUnusedFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("renameFile")
|
||||
public void testRenameFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/renameFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("renameModule")
|
||||
public void testRenameModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/renameModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/simple/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("splitJoinModule")
|
||||
public void testSplitJoinModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/splitJoinModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendFunctions")
|
||||
public void testSuspendFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("toplevelProperties")
|
||||
public void testToplevelProperties() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/toplevelProperties/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("transitiveInlineFunction")
|
||||
public void testTransitiveInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/transitiveInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeScriptExportsPerFile")
|
||||
public void testTypeScriptExportsPerFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/typeScriptExportsPerFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeScriptExportsPerModule")
|
||||
public void testTypeScriptExportsPerModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/typeScriptExportsPerModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unicodeSerializationAndDeserialization")
|
||||
public void testUnicodeSerializationAndDeserialization() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/unicodeSerializationAndDeserialization/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("updateExports")
|
||||
public void testUpdateExports() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/updateExports/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("updateExportsAndInlineImports")
|
||||
public void testUpdateExportsAndInlineImports() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/updateExportsAndInlineImports/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("variance")
|
||||
public void testVariance() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/variance/");
|
||||
}
|
||||
}
|
||||
+597
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.incremental;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateJsTestsKt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("js/js.translator/testData/incremental/invalidation")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class JsFirES6InvalidationPerModuleTestGenerated extends AbstractJsFirES6InvalidationPerModuleTest {
|
||||
@Test
|
||||
@TestMetadata("abstractClassWithJsExport")
|
||||
public void testAbstractClassWithJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/abstractClassWithJsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("addUpdateRemoveDependentFile")
|
||||
public void testAddUpdateRemoveDependentFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("addUpdateRemoveDependentModule")
|
||||
public void testAddUpdateRemoveDependentModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInInvalidation() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/incremental/invalidation"), Pattern.compile("^([^_](.+))$"), null, TargetBackend.JS_IR_ES6, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("circleExportsUpdate")
|
||||
public void testCircleExportsUpdate() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/circleExportsUpdate/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("circleInlineImportsUpdate")
|
||||
public void testCircleInlineImportsUpdate() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/circleInlineImportsUpdate/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("class")
|
||||
public void testClass() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/class/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classFunctionsAndFields")
|
||||
public void testClassFunctionsAndFields() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/classFunctionsAndFields/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classWithJsExport")
|
||||
public void testClassWithJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/classWithJsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionConstVal")
|
||||
public void testCompanionConstVal() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionConstVal/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionFunction")
|
||||
public void testCompanionFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionInlineFunction")
|
||||
public void testCompanionInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionProperties")
|
||||
public void testCompanionProperties() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionProperties/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("companionWithStdLibCall")
|
||||
public void testCompanionWithStdLibCall() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/companionWithStdLibCall/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constVals")
|
||||
public void testConstVals() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/constVals/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("crossModuleReferences")
|
||||
public void testCrossModuleReferences() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/crossModuleReferences/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("eagerInitialization")
|
||||
public void testEagerInitialization() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/eagerInitialization/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enum")
|
||||
public void testEnum() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/enum/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumsInInlineFunctions")
|
||||
public void testEnumsInInlineFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exceptionsFromInlineFunction")
|
||||
public void testExceptionsFromInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("exportsThroughInlineFunction")
|
||||
public void testExportsThroughInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/exportsThroughInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideClassFunctionQualifiers")
|
||||
public void testFakeOverrideClassFunctionQualifiers() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideClassFunctionQualifiers/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInheritance")
|
||||
public void testFakeOverrideInheritance() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInheritance/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInlineExtension")
|
||||
public void testFakeOverrideInlineExtension() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineExtension/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInlineFunction")
|
||||
public void testFakeOverrideInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInlineProperty")
|
||||
public void testFakeOverrideInlineProperty() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInlineProperty/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fakeOverrideInterfaceFunctionQualifiers")
|
||||
public void testFakeOverrideInterfaceFunctionQualifiers() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fakeOverrideInterfaceFunctionQualifiers/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fastPath1")
|
||||
public void testFastPath1() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath1/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fastPath2")
|
||||
public void testFastPath2() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fastPath2/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fileNameClash")
|
||||
public void testFileNameClash() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/fileNameClash/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("friendDependency")
|
||||
public void testFriendDependency() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/friendDependency/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionDefaultParams")
|
||||
public void testFunctionDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionSignature")
|
||||
public void testFunctionSignature() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionSignature/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionTypeInterface")
|
||||
public void testFunctionTypeInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterface/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("functionTypeInterfaceReflect")
|
||||
public void testFunctionTypeInterfaceReflect() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/functionTypeInterfaceReflect/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericFunctions")
|
||||
public void testGenericFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/genericFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("genericInlineFunctions")
|
||||
public void testGenericInlineFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/genericInlineFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("gettersAndSettersInlining")
|
||||
public void testGettersAndSettersInlining() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/gettersAndSettersInlining/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineBecomeNonInline")
|
||||
public void testInlineBecomeNonInline() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineBecomeNonInline/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionAnnotations")
|
||||
public void testInlineFunctionAnnotations() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAnnotations/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionAsFunctionReference")
|
||||
public void testInlineFunctionAsFunctionReference() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAsFunctionReference/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionAsParam")
|
||||
public void testInlineFunctionAsParam() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionAsParam/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionCircleUsage")
|
||||
public void testInlineFunctionCircleUsage() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionCircleUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionDefaultParams")
|
||||
public void testInlineFunctionDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineFunctionWithObject")
|
||||
public void testInlineFunctionWithObject() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/inlineFunctionWithObject/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceOpenMethods")
|
||||
public void testInterfaceOpenMethods() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceOpenMethods/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceOpenMethodsInOpenClass")
|
||||
public void testInterfaceOpenMethodsInOpenClass() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceOpenMethodsInOpenClass/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceSuperUsage")
|
||||
public void testInterfaceSuperUsage() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceSuperUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceWithDefaultParams")
|
||||
public void testInterfaceWithDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceWithDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("interfaceWithJsExport")
|
||||
public void testInterfaceWithJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/interfaceWithJsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsCode")
|
||||
public void testJsCode() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCode/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsCodeWithConstString")
|
||||
public void testJsCodeWithConstString() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCodeWithConstString/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsCodeWithConstStringFromOtherModule")
|
||||
public void testJsCodeWithConstStringFromOtherModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsCodeWithConstStringFromOtherModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExport")
|
||||
public void testJsExport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExportReexport")
|
||||
public void testJsExportReexport() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExportReexport/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExportWithMultipleFiles")
|
||||
public void testJsExportWithMultipleFiles() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsExportWithMultipleFiles/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsModuleAnnotation")
|
||||
public void testJsModuleAnnotation() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotation/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsModuleAnnotationOnObjectWithUsage")
|
||||
public void testJsModuleAnnotationOnObjectWithUsage() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsModuleAnnotationOnObjectWithUsage/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsName")
|
||||
public void testJsName() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/jsName/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinTest")
|
||||
public void testKotlinTest() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/kotlinTest/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("languageVersionSettings")
|
||||
public void testLanguageVersionSettings() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/languageVersionSettings/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localInlineFunction")
|
||||
public void testLocalInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/localInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localObjectsLeakThroughInterface")
|
||||
public void testLocalObjectsLeakThroughInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/localObjectsLeakThroughInterface/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mainFunction")
|
||||
public void testMainFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/mainFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mainModuleInvalidation")
|
||||
public void testMainModuleInvalidation() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/mainModuleInvalidation/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveAndModifyInlineFunction")
|
||||
public void testMoveAndModifyInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveAndModifyInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveExternalDeclarationsBetweenFiles")
|
||||
public void testMoveExternalDeclarationsBetweenFiles() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveExternalDeclarationsBetweenFiles/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveExternalDeclarationsBetweenJsModules")
|
||||
public void testMoveExternalDeclarationsBetweenJsModules() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveExternalDeclarationsBetweenJsModules/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveFilesBetweenModules")
|
||||
public void testMoveFilesBetweenModules() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveFilesBetweenModules/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("moveInlineFunctionBetweenModules")
|
||||
public void testMoveInlineFunctionBetweenModules() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/moveInlineFunctionBetweenModules/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multiPlatformClashFileNames")
|
||||
public void testMultiPlatformClashFileNames() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/multiPlatformClashFileNames/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multiPlatformSimple")
|
||||
public void testMultiPlatformSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/multiPlatformSimple/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClass")
|
||||
public void testNestedClass() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/nestedClass/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonInlineBecomeInline")
|
||||
public void testNonInlineBecomeInline() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/nonInlineBecomeInline/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("openClassWithInternalField")
|
||||
public void testOpenClassWithInternalField() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/openClassWithInternalField/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateDeclarationLeakThroughDefaultParam")
|
||||
public void testPrivateDeclarationLeakThroughDefaultParam() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/privateDeclarationLeakThroughDefaultParam/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateInlineFunction1")
|
||||
public void testPrivateInlineFunction1() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/privateInlineFunction1/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("privateObjectsLeakThroughSealedInterface")
|
||||
public void testPrivateObjectsLeakThroughSealedInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/privateObjectsLeakThroughSealedInterface/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("removeFile")
|
||||
public void testRemoveFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/removeFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("removeModule")
|
||||
public void testRemoveModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/removeModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("removeUnusedFile")
|
||||
public void testRemoveUnusedFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/removeUnusedFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("renameFile")
|
||||
public void testRenameFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/renameFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("renameModule")
|
||||
public void testRenameModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/renameModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/simple/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("splitJoinModule")
|
||||
public void testSplitJoinModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/splitJoinModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendFunctions")
|
||||
public void testSuspendFunctions() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("toplevelProperties")
|
||||
public void testToplevelProperties() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/toplevelProperties/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("transitiveInlineFunction")
|
||||
public void testTransitiveInlineFunction() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/transitiveInlineFunction/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeScriptExportsPerFile")
|
||||
public void testTypeScriptExportsPerFile() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/typeScriptExportsPerFile/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeScriptExportsPerModule")
|
||||
public void testTypeScriptExportsPerModule() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/typeScriptExportsPerModule/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unicodeSerializationAndDeserialization")
|
||||
public void testUnicodeSerializationAndDeserialization() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/unicodeSerializationAndDeserialization/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("updateExports")
|
||||
public void testUpdateExports() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/updateExports/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("updateExportsAndInlineImports")
|
||||
public void testUpdateExportsAndInlineImports() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/updateExportsAndInlineImports/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("variance")
|
||||
public void testVariance() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/variance/");
|
||||
}
|
||||
}
|
||||
Generated
+6
@@ -535,6 +535,12 @@ public class JsFirInvalidationPerFileTestGenerated extends AbstractJsFirInvalida
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
|
||||
Generated
+6
@@ -535,6 +535,12 @@ public class JsFirInvalidationPerModuleTestGenerated extends AbstractJsFirInvali
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
|
||||
Generated
+6
@@ -535,6 +535,12 @@ public class JsIrES6InvalidationPerFileTestGenerated extends AbstractJsIrES6Inva
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
|
||||
+6
@@ -535,6 +535,12 @@ public class JsIrES6InvalidationPerModuleTestGenerated extends AbstractJsIrES6In
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
|
||||
Generated
+6
@@ -535,6 +535,12 @@ public class JsIrInvalidationPerFileTestGenerated extends AbstractJsIrInvalidati
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
|
||||
Generated
+6
@@ -535,6 +535,12 @@ public class JsIrInvalidationPerModuleTestGenerated extends AbstractJsIrInvalida
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendGenerator")
|
||||
public void testSuspendGenerator() throws Exception {
|
||||
runTest("js/js.translator/testData/incremental/invalidation/suspendGenerator/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("suspendInterfaceWithDefaultParams")
|
||||
public void testSuspendInterfaceWithDefaultParams() throws Exception {
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import kotlin.coroutines.*
|
||||
|
||||
abstract class Generator<T> {
|
||||
private var generatorContinuation: Continuation<Unit>? = null
|
||||
private var callerContinuation: Continuation<T>? = null
|
||||
|
||||
fun resetGenerator() {
|
||||
this::initGenerator.startCoroutine(object: Continuation<Unit> {
|
||||
override val context = EmptyCoroutineContext
|
||||
override fun resumeWith(result: Result<Unit>) {
|
||||
result.getOrThrow()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
suspend fun yieldValue(x: T) {
|
||||
suspendCoroutine { continuation ->
|
||||
generatorContinuation = continuation
|
||||
callerContinuation?.resume(x)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun initGenerator() {
|
||||
suspendCoroutine { continuation ->
|
||||
generatorContinuation = continuation
|
||||
}
|
||||
|
||||
generatorBody()
|
||||
|
||||
generatorContinuation = null
|
||||
}
|
||||
|
||||
protected abstract suspend fun generatorBody()
|
||||
|
||||
fun hasNext(): Boolean {
|
||||
return generatorContinuation != null
|
||||
}
|
||||
|
||||
suspend fun nextValue(): T {
|
||||
return suspendCoroutine { continuation ->
|
||||
callerContinuation = continuation
|
||||
generatorContinuation?.resume(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ClosedRangeGenerator(
|
||||
private val rangeStart: Int,
|
||||
private val rangeEnd: Int,
|
||||
private val step: Int
|
||||
) : Generator<Int>() {
|
||||
override suspend fun generatorBody() {
|
||||
for (i in IntProgression.fromClosedRange(rangeStart, rangeEnd, step)) {
|
||||
yieldValue(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
STEP 0:
|
||||
modifications:
|
||||
U : generator.0.kt -> generator.kt
|
||||
added file: generator.kt
|
||||
STEP 1:
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
STEP 0:
|
||||
dependencies: lib1
|
||||
modifications:
|
||||
U : test.0.kt -> test.kt
|
||||
added file: test.kt
|
||||
STEP 1:
|
||||
dependencies: lib1
|
||||
modifications:
|
||||
U : test.1.kt -> test.kt
|
||||
modified ir: test.kt
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import kotlin.coroutines.*
|
||||
|
||||
private fun runCoroutine(c: suspend () -> Unit) {
|
||||
c.startCoroutine(object: Continuation<Unit> {
|
||||
override val context = EmptyCoroutineContext
|
||||
override fun resumeWith(result: Result<Unit>) {
|
||||
result.getOrThrow()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun test(): Int {
|
||||
val generator = ClosedRangeGenerator(0, 0, 1)
|
||||
generator.resetGenerator()
|
||||
var s = 0
|
||||
runCoroutine {
|
||||
while(generator.hasNext()) {
|
||||
s += generator.nextValue()
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import kotlin.coroutines.*
|
||||
|
||||
private fun runCoroutine(c: suspend () -> Unit) {
|
||||
c.startCoroutine(object: Continuation<Unit> {
|
||||
override val context = EmptyCoroutineContext
|
||||
override fun resumeWith(result: Result<Unit>) {
|
||||
result.getOrThrow()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun test(): Int {
|
||||
val generator = ClosedRangeGenerator(0, 1, 1)
|
||||
generator.resetGenerator()
|
||||
var s = 0
|
||||
runCoroutine {
|
||||
while(generator.hasNext()) {
|
||||
s += generator.nextValue()
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fun box(stepId: Int): String {
|
||||
val got = test()
|
||||
if (got != stepId) {
|
||||
return "Fail: $got != $stepId"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
STEP 0:
|
||||
dependencies: lib1, lib2
|
||||
added file: m.kt
|
||||
STEP 1:
|
||||
dependencies: lib1, lib2
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
MODULES: lib1, lib2, main
|
||||
|
||||
STEP 0:
|
||||
libs: lib1, lib2, main
|
||||
dirty js modules: lib1, lib2, main
|
||||
dirty js files: lib1/generator, lib2/test, main/m, main/m.export, main
|
||||
STEP 1:
|
||||
libs: lib1, lib2, main
|
||||
dirty js modules: lib2
|
||||
dirty js files: lib2/test
|
||||
Vendored
+16
-1
@@ -1,3 +1,5 @@
|
||||
import kotlin.coroutines.*
|
||||
|
||||
internal suspend fun testDefaltParam(stepId: Int): Int {
|
||||
return callFun(ClassA2())
|
||||
}
|
||||
@@ -8,9 +10,22 @@ private suspend fun callFun(a: InterfaceA): Int {
|
||||
return a.functionA(0, "", false)
|
||||
}
|
||||
|
||||
suspend fun box(stepId: Int): String {
|
||||
suspend fun suspendBox(stepId: Int): String {
|
||||
if (testDefaltParam(stepId) != stepId) {
|
||||
return "Fail"
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun runCoroutine(coroutine: suspend () -> String): String {
|
||||
var result: String = "Uninitialized"
|
||||
coroutine.startCoroutine(object : Continuation<String> {
|
||||
override val context = EmptyCoroutineContext
|
||||
override fun resumeWith(r: Result<String>) {
|
||||
result = r.getOrThrow()
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
fun box(stepId: Int) = runCoroutine { suspendBox(stepId) }
|
||||
@@ -227,3 +227,6 @@ internal fun jsContextfulRef(context: dynamic, fn: dynamic): dynamic
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsIsEs6(): Boolean
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun <T> jsYield(suspendFunction: () -> T): T
|
||||
|
||||
@@ -51,3 +51,9 @@ internal annotation class JsFun(val code: String)
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class JsImplicitExport
|
||||
|
||||
/**
|
||||
* The annotation is needed for annotating function declarations that should be compiled as ES6 generators
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
internal annotation class JsGenerator
|
||||
|
||||
@@ -9,7 +9,9 @@ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||
|
||||
@SinceKotlin("1.3")
|
||||
@JsName("CoroutineImpl")
|
||||
internal abstract class CoroutineImpl(private val resultContinuation: Continuation<Any?>?) : Continuation<Any?> {
|
||||
internal abstract class CoroutineImpl(
|
||||
private val resultContinuation: Continuation<Any?>?
|
||||
) : InterceptedCoroutine(), Continuation<Any?> {
|
||||
protected var state = 0
|
||||
protected var exceptionState = 0
|
||||
protected var result: dynamic = null
|
||||
@@ -20,13 +22,6 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati
|
||||
|
||||
public override val context: CoroutineContext get() = _context!!
|
||||
|
||||
private var intercepted_: Continuation<Any?>? = null
|
||||
|
||||
public fun intercepted(): Continuation<Any?> =
|
||||
intercepted_
|
||||
?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
|
||||
.also { intercepted_ = it }
|
||||
|
||||
override fun resumeWith(result: Result<Any?>) {
|
||||
var current = this
|
||||
var currentResult: Any? = result.getOrNull()
|
||||
@@ -73,14 +68,6 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati
|
||||
}
|
||||
}
|
||||
|
||||
private fun releaseIntercepted() {
|
||||
val intercepted = intercepted_
|
||||
if (intercepted != null && intercepted !== this) {
|
||||
context[ContinuationInterceptor]!!.releaseInterceptedContinuation(intercepted)
|
||||
}
|
||||
this.intercepted_ = CompletedContinuation // just in case
|
||||
}
|
||||
|
||||
protected abstract fun doResume(): Any?
|
||||
|
||||
public open fun create(completion: Continuation<*>): Continuation<Unit> {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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 kotlin.coroutines
|
||||
|
||||
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||
import kotlin.internal.InlineOnly
|
||||
|
||||
// It should be replaced with the regular function generator after the bootstrapping
|
||||
internal val dummyGenerator = js("""
|
||||
// TO PREVENT PREVIOUS VERSIONS OF THE COMPILER FAIL TO COMPILE THE CODE
|
||||
var generatorFactory = new Function("return function*(suspended, c) { var a = c(); if (a === suspended) a = yield a; return a }")
|
||||
generatorFactory()
|
||||
""")
|
||||
|
||||
internal val GeneratorFunction = dummyGenerator.constructor.prototype
|
||||
|
||||
internal fun isGeneratorSuspendStep(value: dynamic): Boolean {
|
||||
return value != null && value.constructor === GeneratorFunction
|
||||
}
|
||||
|
||||
internal external interface JsIterationStep<T> {
|
||||
val done: Boolean
|
||||
val value: T
|
||||
}
|
||||
|
||||
internal external interface JsIterator<T> {
|
||||
fun next(value: Any? = definedExternally): JsIterationStep<T>
|
||||
|
||||
@JsName("throw")
|
||||
fun throws(exception: Throwable = definedExternally): JsIterationStep<T>
|
||||
}
|
||||
|
||||
internal class GeneratorCoroutineImpl(val resultContinuation: Continuation<Any?>?) : InterceptedCoroutine(), Continuation<Any?> {
|
||||
private val jsIterators = arrayOf<JsIterator<Any?>>()
|
||||
private val _context = resultContinuation?.context
|
||||
|
||||
var isRunning: Boolean = false
|
||||
private val unknown: Result<Any?> = Result(js("Symbol()"))
|
||||
private var savedResult: Result<Any?> = unknown
|
||||
|
||||
public override val context: CoroutineContext get() = _context!!
|
||||
|
||||
@InlineOnly
|
||||
public inline fun dropLastIterator() {
|
||||
jsIterators.asDynamic().pop()
|
||||
}
|
||||
|
||||
@InlineOnly
|
||||
public inline fun addNewIterator(iterator: JsIterator<Any?>) {
|
||||
jsIterators.asDynamic().push(iterator)
|
||||
}
|
||||
|
||||
@InlineOnly
|
||||
private inline val isCompleted: Boolean get() = jsIterators.size == 0
|
||||
|
||||
@InlineOnly
|
||||
private inline fun getLastIterator(): JsIterator<Any?> = jsIterators[jsIterators.size - 1]
|
||||
|
||||
@InlineOnly
|
||||
public inline fun shouldResumeImmediately(): Boolean = unknown.value !== savedResult.value
|
||||
|
||||
override fun resumeWith(result: Result<Any?>) {
|
||||
if (unknown.value === savedResult.value) savedResult = result
|
||||
if (isRunning) return
|
||||
|
||||
var currentResult: Any? = savedResult.getOrNull()
|
||||
var currentException: Throwable? = savedResult.exceptionOrNull()
|
||||
|
||||
savedResult = unknown
|
||||
|
||||
var current = this
|
||||
|
||||
while (true) {
|
||||
while (!current.isCompleted) {
|
||||
val jsIterator = current.getLastIterator()
|
||||
val exception = currentException.also { currentException = null }
|
||||
|
||||
isRunning = true
|
||||
|
||||
try {
|
||||
val step = when (exception) {
|
||||
null -> jsIterator.next(currentResult)
|
||||
else -> jsIterator.throws(exception)
|
||||
}
|
||||
|
||||
currentResult = step.value
|
||||
currentException = null
|
||||
|
||||
if (step.done) current.dropLastIterator()
|
||||
if (unknown.value !== savedResult.value) {
|
||||
currentResult = savedResult.getOrNull()
|
||||
currentException = savedResult.exceptionOrNull()
|
||||
savedResult = unknown
|
||||
} else if (currentResult === COROUTINE_SUSPENDED) return
|
||||
} catch (e: Throwable) {
|
||||
currentException = e
|
||||
current.dropLastIterator()
|
||||
} finally {
|
||||
isRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
releaseIntercepted()
|
||||
|
||||
val completion = resultContinuation!!
|
||||
|
||||
if (completion is GeneratorCoroutineImpl) {
|
||||
current = completion
|
||||
} else {
|
||||
return if (currentException != null) {
|
||||
completion.resumeWithException(currentException!!)
|
||||
} else {
|
||||
completion.resume(currentResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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 kotlin.coroutines
|
||||
|
||||
internal abstract class InterceptedCoroutine : Continuation<Any?> {
|
||||
private var _intercepted: Continuation<Any?>? = null
|
||||
|
||||
public fun intercepted(): Continuation<Any?> =
|
||||
_intercepted
|
||||
?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
|
||||
.also { _intercepted = it }
|
||||
|
||||
protected fun releaseIntercepted() {
|
||||
val intercepted = _intercepted
|
||||
if (intercepted != null && intercepted !== this) {
|
||||
context[ContinuationInterceptor]!!.releaseInterceptedContinuation(intercepted)
|
||||
}
|
||||
this._intercepted = CompletedContinuation
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
package kotlin.coroutines.intrinsics
|
||||
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.ContinuationInterceptor
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.*
|
||||
import kotlin.coroutines.CoroutineImpl
|
||||
import kotlin.internal.InlineOnly
|
||||
|
||||
@@ -169,8 +167,7 @@ public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
public actual fun <T> Continuation<T>.intercepted(): Continuation<T> =
|
||||
(this as? CoroutineImpl)?.intercepted() ?: this
|
||||
|
||||
(this as? InterceptedCoroutine)?.intercepted() ?: this
|
||||
|
||||
private inline fun <T> createCoroutineFromSuspendFunction(
|
||||
completion: Continuation<T>,
|
||||
@@ -183,3 +180,107 @@ private inline fun <T> createCoroutineFromSuspendFunction(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@InlineOnly
|
||||
internal inline fun <T> createCoroutineFromGeneratorFunction(
|
||||
completion: Continuation<T>,
|
||||
crossinline generatorFunction: (Continuation<T>) -> dynamic,
|
||||
): Continuation<Any?> {
|
||||
val continuation = GeneratorCoroutineImpl(completion.unsafeCast<Continuation<Any?>>())
|
||||
continuation.addNewIterator(dummyGenerator(COROUTINE_SUSPENDED) { generatorFunction(continuation) })
|
||||
return continuation
|
||||
}
|
||||
|
||||
@InlineOnly
|
||||
internal inline fun <T> startCoroutineFromGeneratorFunction(
|
||||
completion: Continuation<T>,
|
||||
crossinline generatorFunction: (Continuation<T>) -> dynamic,
|
||||
): Any? {
|
||||
val continuation = GeneratorCoroutineImpl(completion.unsafeCast<Continuation<Any?>>())
|
||||
continuation.isRunning = true
|
||||
val result = generatorFunction(continuation)
|
||||
continuation.isRunning = false
|
||||
if (continuation.shouldResumeImmediately()) continuation.resume(result)
|
||||
return result
|
||||
}
|
||||
|
||||
internal fun <T> (suspend () -> T).startCoroutineUninterceptedOrReturnGeneratorVersion(
|
||||
completion: Continuation<T>
|
||||
): Any? = startCoroutineFromGeneratorFunction(completion) {
|
||||
val a = asDynamic()
|
||||
if (jsTypeOf(a) === "function") a(it)
|
||||
else invokeSuspendSuperType(it)
|
||||
}
|
||||
|
||||
internal fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedOrReturnGeneratorVersion(
|
||||
receiver: R,
|
||||
completion: Continuation<T>
|
||||
): Any? = startCoroutineFromGeneratorFunction(completion) {
|
||||
val a = asDynamic()
|
||||
if (jsTypeOf(a) === "function") a(receiver, it)
|
||||
else invokeSuspendSuperTypeWithReceiver(receiver, it)
|
||||
}
|
||||
|
||||
internal fun <R, P, T> (suspend R.(P) -> T).startCoroutineUninterceptedOrReturnGeneratorVersion(
|
||||
receiver: R,
|
||||
param: P,
|
||||
completion: Continuation<T>
|
||||
): Any? = startCoroutineFromGeneratorFunction(completion) {
|
||||
val a = asDynamic()
|
||||
if (jsTypeOf(a) === "function") a(receiver, param, it)
|
||||
else invokeSuspendSuperTypeWithReceiverAndParam(receiver, param, it)
|
||||
}
|
||||
|
||||
internal fun <T> (suspend () -> T).createCoroutineUninterceptedGeneratorVersion(
|
||||
completion: Continuation<T>
|
||||
): Continuation<Any?> =
|
||||
createCoroutineFromGeneratorFunction(completion) {
|
||||
val a = asDynamic()
|
||||
if (jsTypeOf(a) === "function") a(it)
|
||||
else invokeSuspendSuperType(it)
|
||||
}
|
||||
|
||||
internal fun <R, T> (suspend R.() -> T).createCoroutineUninterceptedGeneratorVersion(
|
||||
receiver: R,
|
||||
completion: Continuation<T>
|
||||
): Continuation<Unit> =
|
||||
createCoroutineFromGeneratorFunction(completion) {
|
||||
val a = asDynamic()
|
||||
if (jsTypeOf(a) === "function") a(receiver, it)
|
||||
else invokeSuspendSuperTypeWithReceiver(receiver, it)
|
||||
}
|
||||
|
||||
|
||||
internal fun <R, T, P> (suspend R.(P) -> T).createCoroutineUninterceptedGeneratorVersion(
|
||||
receiver: R,
|
||||
param: P,
|
||||
completion: Continuation<T>
|
||||
): Continuation<Unit> =
|
||||
createCoroutineFromGeneratorFunction(completion) {
|
||||
val a = asDynamic()
|
||||
if (jsTypeOf(a) === "function") a(receiver, param, it)
|
||||
else invokeSuspendSuperTypeWithReceiverAndParam(receiver, param, it)
|
||||
}
|
||||
|
||||
|
||||
internal fun suspendOrReturn(value: Any?, continuation: Continuation<Any?>): Any? {
|
||||
if (!isGeneratorSuspendStep(value)) return value
|
||||
|
||||
val iterator = value.unsafeCast<JsIterator<Any?>>()
|
||||
|
||||
if (continuation.asDynamic().constructor !== GeneratorCoroutineImpl::class.js) {
|
||||
return iterator.next().value
|
||||
}
|
||||
|
||||
val generatorCoroutineImpl = continuation.unsafeCast<GeneratorCoroutineImpl>()
|
||||
|
||||
generatorCoroutineImpl.addNewIterator(iterator)
|
||||
try {
|
||||
val iteratorStep = iterator.next()
|
||||
if (iteratorStep.done) generatorCoroutineImpl.dropLastIterator()
|
||||
return iteratorStep.value
|
||||
} catch (e: Throwable) {
|
||||
generatorCoroutineImpl.dropLastIterator()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user