diff --git a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArgumentsCopyGenerated.kt b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArgumentsCopyGenerated.kt index 19b883b6d08..fb839ca4f3a 100644 --- a/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArgumentsCopyGenerated.kt +++ b/compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArgumentsCopyGenerated.kt @@ -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 diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt index 107b38aabf9..9aa0704c348 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt @@ -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, diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index 679393062b7..31bd01d5cb2 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -208,6 +208,7 @@ class K2JsIrCompiler : CLICompiler() { 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 { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index 3780cda7208..659e1dadd96 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 0a5727ea108..209b6a42873 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -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( + { 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 diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt index 086c45900b2..aa8532909bd 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt @@ -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 diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt index 525b05e4b75..d09fbf61943 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/JsDefaultArgumentStubGenerator.kt @@ -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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt index 0c02a925ddb..918fbd689bb 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/MainFunctionCallWrapperLowering.kt @@ -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 { - 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 + } } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrivateMembersLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrivateMembersLowering.kt index 73d2453f4a8..a4d9f103f46 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrivateMembersLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrivateMembersLowering.kt @@ -60,6 +60,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTrans visibility = newVisibility }.also { it.parent = function.parent + it.annotations = function.annotations } staticFunction.typeParameters = diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PurifyObjectInstanceGettersLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PurifyObjectInstanceGettersLowering.kt index 1379789861d..f5fbd6487d3 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PurifyObjectInstanceGettersLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PurifyObjectInstanceGettersLowering.kt @@ -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 { it.isEs6PrimaryConstructorReplacement } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/AbstractSuspendFunctionsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/AbstractSuspendFunctionsLowering.kt index 5f8cc105484..a246a6c7e1e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/AbstractSuspendFunctionsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/AbstractSuspendFunctionsLowering.kt @@ -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(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(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(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")) } + diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionWithGeneratorsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionWithGeneratorsLowering.kt new file mode 100644 index 00000000000..aaf8329afc8 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionWithGeneratorsLowering.kt @@ -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? { + if (declaration is IrSimpleFunction && declaration.isSuspend) { + return transformSuspendFunction(declaration) + } + return null + } + + private fun transformSuspendFunction(function: IrSimpleFunction): List? { + 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 { + val generatorFunction = context.irFactory.createSimpleFunction( + function.startOffset, + function.endOffset, + SUSPEND_FUNCTION_AS_GENERATOR, + Name.special(""), + 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() + 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))) + } + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionsLowering.kt index 5f8294bc935..047fceb6ccc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/JsSuspendFunctionsLowering.kt @@ -32,8 +32,7 @@ import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.addToStdlib.assertedCast class JsSuspendFunctionsLowering(ctx: JsCommonBackendContext) : AbstractSuspendFunctionsLowering(ctx) { - - val coroutineSymbols = ctx.coroutineSymbols + private val coroutineSymbols = ctx.coroutineSymbols private val coroutineImplExceptionPropertyGetter = coroutineSymbols.coroutineImplExceptionPropertyGetter private val coroutineImplExceptionPropertySetter = coroutineSymbols.coroutineImplExceptionPropertySetter diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/ReplaceSuspendIntrinsicLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/ReplaceSuspendIntrinsicLowering.kt new file mode 100644 index 00000000000..04b91b368fc --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/ReplaceSuspendIntrinsicLowering.kt @@ -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.groupPerValueParamSize(): Map { + 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 + + 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) + } + }) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt index ebd3c734947..983c50063a2 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt @@ -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 diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt index de3dd3fed0d..2bcbc5330a6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt @@ -143,7 +143,9 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer 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) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt index 8edcc3cf597..d8ee4eb3e96 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt @@ -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().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 -} +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt index 394b5448a82..e5f66635c12 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt @@ -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") diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt index c6bf77649f6..2884e8697e8 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt @@ -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 } -} \ No newline at end of file +} + +val IrClass.primaryConstructorReplacement: IrSimpleFunction? + get() = findDeclaration { it.isEs6PrimaryConstructorReplacement } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt index 65d87c62ac0..6f0cec4f467 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt @@ -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!! \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/Constants.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/Constants.kt index 358792f8f6e..cbb5db50444 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/Constants.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/Constants.kt @@ -70,4 +70,5 @@ object ExpressionIds { const val NEW = 21 const val CLASS = 22 const val SUPER_REF = 23 + const val YIELD = 24 } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt index 9108028ae00..003bb3d3425 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt @@ -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") } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt index 40b4bdd4a44..a854ab2197c 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt @@ -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) { diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index 9573e0c4f18..2220b889b4f 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -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 diff --git a/compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt b/compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt index d9d34f04146..cc8c32e5423 100644 --- a/compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt +++ b/compiler/testData/codegen/box/coroutines/intrinsicSemantics/intercepted.kt @@ -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.* diff --git a/compiler/testData/codegen/box/coroutines/intrinsicSemantics/releaseIntercepted.kt b/compiler/testData/codegen/box/coroutines/intrinsicSemantics/releaseIntercepted.kt index 8049e9f10f2..ef9b9a3d88c 100644 --- a/compiler/testData/codegen/box/coroutines/intrinsicSemantics/releaseIntercepted.kt +++ b/compiler/testData/codegen/box/coroutines/intrinsicSemantics/releaseIntercepted.kt @@ -1,5 +1,5 @@ // WITH_STDLIB -// IGNORE_BACKEND: JS_IR, JS_IR_ES6 +// IGNORE_BACKEND: JS_IR import kotlin.coroutines.* import kotlin.coroutines.intrinsics.* diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt index 6802ca50251..dce1eba33a9 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt @@ -139,6 +139,7 @@ fun createCompilerConfiguration(module: TestModule, configurators: List getModifiers() { if (modifiers == null) { diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNew.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNew.java index 88909709c6c..6696826ded8 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNew.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNew.java @@ -22,6 +22,10 @@ public final class JsNew extends JsExpression.JsExpressionHasArguments { this.constructorExpression = constructorExpression; } + public JsNew(JsExpression constructorExpression, JsExpression... arguments) { + this(constructorExpression, new SmartList(arguments)); + } + public JsExpression getConstructorExpression() { return constructorExpression; } diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt index 7ab6c26b536..22df5b2392c 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt @@ -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) diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java index 5af94dbc92b..bdaebad6060 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java @@ -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; } diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsYield.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsYield.kt new file mode 100644 index 00000000000..55f8af5e7ec --- /dev/null +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsYield.kt @@ -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) + } +} \ No newline at end of file diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt index 94573ab6616..02ec58e845b 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt @@ -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) /** diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java index abb5236cce8..c8c3cdfd788 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java @@ -87,6 +87,9 @@ public class JSConfigurationKeys { public static final CompilerConfigurationKey GENERATE_DTS = CompilerConfigurationKey.create("generate TypeScript definition file"); + public static final CompilerConfigurationKey COMPILE_SUSPEND_AS_JS_GENERATOR = + CompilerConfigurationKey.create("force suspend functions compilation int JS generator functions"); + public static final CompilerConfigurationKey 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"); diff --git a/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java b/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java index 45a31ae83a1..3858985628a 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java +++ b/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java @@ -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); diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java index 1ab1de0aff1..7627a00ba45 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java @@ -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); } /** diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java index 0c1d707ccc6..b2206ebca4b 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java @@ -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); diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java index f653c6dc9cc..1c0f93f2a35 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java @@ -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); diff --git a/js/js.serializer/src/js-ast.proto b/js/js.serializer/src/js-ast.proto index 5124cd1d151..b175c00b95f 100644 --- a/js/js.serializer/src/js-ast.proto +++ b/js/js.serializer/src/js-ast.proto @@ -122,6 +122,7 @@ message Function { STATIC = 1; GET = 2; SET = 3; + GENERATOR = 4; } } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt index 32c60c20670..e5dd3a8b727 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt @@ -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) { diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java index dd3c24b2c68..8e99246cef3 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java @@ -8934,6 +8934,10 @@ public final class JsAstProtoBuf { * SET = 3; */ SET(2, 3), + /** + * GENERATOR = 4; + */ + GENERATOR(3, 4), ; /** @@ -8948,6 +8952,10 @@ public final class JsAstProtoBuf { * SET = 3; */ public static final int SET_VALUE = 3; + /** + * GENERATOR = 4; + */ + 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; } } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt index 099df3205d0..c5a3e5cb336 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt @@ -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) { diff --git a/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt b/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt index af6ccbcb64c..00ac5c10baa 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt @@ -93,6 +93,14 @@ fun main(args: Array) { model("incremental/invalidation/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR, recursive = false) } + testClass { + model("incremental/invalidation/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR_ES6, recursive = false) + } + + testClass { + model("incremental/invalidation/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR_ES6, recursive = false) + } + testClass { model("incremental/invalidationWithPL/", pattern = "^([^_](.+))$", targetBackend = TargetBackend.JS_IR, recursive = false) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt index c2a12bbcfe3..d3135277e2a 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -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 { diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt index 5a1d9e0b978..7105529900c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt @@ -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, diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerFileTestGenerated.java new file mode 100644 index 00000000000..0b86f05d979 --- /dev/null +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerFileTestGenerated.java @@ -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/"); + } +} diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerModuleTestGenerated.java new file mode 100644 index 00000000000..35732ea4b7e --- /dev/null +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirES6InvalidationPerModuleTestGenerated.java @@ -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/"); + } +} diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java index 42b82c967ed..c26f3cde88e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerFileTestGenerated.java @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java index 25b91073c9f..455aa2f8983 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsFirInvalidationPerModuleTestGenerated.java @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java index db8efb2c6ac..952cc4b10a6 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerFileTestGenerated.java @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java index 3ee49578fd4..45b6a763725 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrES6InvalidationPerModuleTestGenerated.java @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java index c1da3032df6..112e3183c13 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerFileTestGenerated.java @@ -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 { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java index 60a9db0bb78..340aaab249c 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/JsIrInvalidationPerModuleTestGenerated.java @@ -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 { diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib1/generator.0.kt b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib1/generator.0.kt new file mode 100644 index 00000000000..e0d29e2e9e4 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib1/generator.0.kt @@ -0,0 +1,57 @@ +import kotlin.coroutines.* + +abstract class Generator { + private var generatorContinuation: Continuation? = null + private var callerContinuation: Continuation? = null + + fun resetGenerator() { + this::initGenerator.startCoroutine(object: Continuation { + override val context = EmptyCoroutineContext + override fun resumeWith(result: Result) { + 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() { + override suspend fun generatorBody() { + for (i in IntProgression.fromClosedRange(rangeStart, rangeEnd, step)) { + yieldValue(i) + } + } +} diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib1/module.info b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib1/module.info new file mode 100644 index 00000000000..d7206fbaf9a --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib1/module.info @@ -0,0 +1,5 @@ +STEP 0: + modifications: + U : generator.0.kt -> generator.kt + added file: generator.kt +STEP 1: diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/module.info b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/module.info new file mode 100644 index 00000000000..25d9661fdd2 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/module.info @@ -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 diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/test.0.kt b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/test.0.kt new file mode 100644 index 00000000000..959fae9975a --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/test.0.kt @@ -0,0 +1,22 @@ +import kotlin.coroutines.* + +private fun runCoroutine(c: suspend () -> Unit) { + c.startCoroutine(object: Continuation { + override val context = EmptyCoroutineContext + override fun resumeWith(result: Result) { + 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 +} diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/test.1.kt b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/test.1.kt new file mode 100644 index 00000000000..f48fa9b39af --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/lib2/test.1.kt @@ -0,0 +1,22 @@ +import kotlin.coroutines.* + +private fun runCoroutine(c: suspend () -> Unit) { + c.startCoroutine(object: Continuation { + override val context = EmptyCoroutineContext + override fun resumeWith(result: Result) { + 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 +} diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/main/m.kt b/js/js.translator/testData/incremental/invalidation/suspendGenerator/main/m.kt new file mode 100644 index 00000000000..0cedc592f54 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/main/m.kt @@ -0,0 +1,7 @@ +fun box(stepId: Int): String { + val got = test() + if (got != stepId) { + return "Fail: $got != $stepId" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/main/module.info b/js/js.translator/testData/incremental/invalidation/suspendGenerator/main/module.info new file mode 100644 index 00000000000..406ec8bd244 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/main/module.info @@ -0,0 +1,5 @@ +STEP 0: + dependencies: lib1, lib2 + added file: m.kt +STEP 1: + dependencies: lib1, lib2 diff --git a/js/js.translator/testData/incremental/invalidation/suspendGenerator/project.info b/js/js.translator/testData/incremental/invalidation/suspendGenerator/project.info new file mode 100644 index 00000000000..44bcf43137e --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/suspendGenerator/project.info @@ -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 diff --git a/js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/main/m.kt b/js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/main/m.kt index 9a943517202..81237316fda 100644 --- a/js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/main/m.kt +++ b/js/js.translator/testData/incremental/invalidation/suspendInterfaceWithDefaultParams/main/m.kt @@ -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 { + override val context = EmptyCoroutineContext + override fun resumeWith(r: Result) { + result = r.getOrThrow() + } + }) + return result +} + +fun box(stepId: Int) = runCoroutine { suspendBox(stepId) } \ No newline at end of file diff --git a/libraries/stdlib/js/runtime/jsIntrinsics.kt b/libraries/stdlib/js/runtime/jsIntrinsics.kt index 547fea7461e..0331cf8a0b7 100644 --- a/libraries/stdlib/js/runtime/jsIntrinsics.kt +++ b/libraries/stdlib/js/runtime/jsIntrinsics.kt @@ -227,3 +227,6 @@ internal fun jsContextfulRef(context: dynamic, fn: dynamic): dynamic @JsIntrinsic internal fun jsIsEs6(): Boolean + +@JsIntrinsic +internal fun jsYield(suspendFunction: () -> T): T diff --git a/libraries/stdlib/js/runtime/kotlinJsHacks.kt b/libraries/stdlib/js/runtime/kotlinJsHacks.kt index b9b02b76050..c87d298dc78 100644 --- a/libraries/stdlib/js/runtime/kotlinJsHacks.kt +++ b/libraries/stdlib/js/runtime/kotlinJsHacks.kt @@ -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 diff --git a/libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt b/libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt index 3ae9e6f3a72..066f610820e 100644 --- a/libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt +++ b/libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt @@ -9,7 +9,9 @@ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED @SinceKotlin("1.3") @JsName("CoroutineImpl") -internal abstract class CoroutineImpl(private val resultContinuation: Continuation?) : Continuation { +internal abstract class CoroutineImpl( + private val resultContinuation: Continuation? +) : InterceptedCoroutine(), Continuation { 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? = null - - public fun intercepted(): Continuation = - intercepted_ - ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this) - .also { intercepted_ = it } - override fun resumeWith(result: Result) { 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 { diff --git a/libraries/stdlib/js/src/kotlin/coroutines/GeneratorCoroutineImpl.kt b/libraries/stdlib/js/src/kotlin/coroutines/GeneratorCoroutineImpl.kt new file mode 100644 index 00000000000..ce55348c36f --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/coroutines/GeneratorCoroutineImpl.kt @@ -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 { + val done: Boolean + val value: T +} + +internal external interface JsIterator { + fun next(value: Any? = definedExternally): JsIterationStep + + @JsName("throw") + fun throws(exception: Throwable = definedExternally): JsIterationStep +} + +internal class GeneratorCoroutineImpl(val resultContinuation: Continuation?) : InterceptedCoroutine(), Continuation { + private val jsIterators = arrayOf>() + private val _context = resultContinuation?.context + + var isRunning: Boolean = false + private val unknown: Result = Result(js("Symbol()")) + private var savedResult: Result = unknown + + public override val context: CoroutineContext get() = _context!! + + @InlineOnly + public inline fun dropLastIterator() { + jsIterators.asDynamic().pop() + } + + @InlineOnly + public inline fun addNewIterator(iterator: JsIterator) { + jsIterators.asDynamic().push(iterator) + } + + @InlineOnly + private inline val isCompleted: Boolean get() = jsIterators.size == 0 + + @InlineOnly + private inline fun getLastIterator(): JsIterator = jsIterators[jsIterators.size - 1] + + @InlineOnly + public inline fun shouldResumeImmediately(): Boolean = unknown.value !== savedResult.value + + override fun resumeWith(result: Result) { + 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) + } + } + } + } +} \ No newline at end of file diff --git a/libraries/stdlib/js/src/kotlin/coroutines/InterceptedCoroutine.kt b/libraries/stdlib/js/src/kotlin/coroutines/InterceptedCoroutine.kt new file mode 100644 index 00000000000..ec922deb310 --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/coroutines/InterceptedCoroutine.kt @@ -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 { + private var _intercepted: Continuation? = null + + public fun intercepted(): Continuation = + _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 + } +} \ No newline at end of file diff --git a/libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt b/libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt index 893e2b8e1a3..4d7146cbc62 100644 --- a/libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt +++ b/libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt @@ -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 (suspend R.() -> T).createCoroutineUnintercepted( */ @SinceKotlin("1.3") public actual fun Continuation.intercepted(): Continuation = - (this as? CoroutineImpl)?.intercepted() ?: this - + (this as? InterceptedCoroutine)?.intercepted() ?: this private inline fun createCoroutineFromSuspendFunction( completion: Continuation, @@ -183,3 +180,107 @@ private inline fun createCoroutineFromSuspendFunction( } } } + +@InlineOnly +internal inline fun createCoroutineFromGeneratorFunction( + completion: Continuation, + crossinline generatorFunction: (Continuation) -> dynamic, +): Continuation { + val continuation = GeneratorCoroutineImpl(completion.unsafeCast>()) + continuation.addNewIterator(dummyGenerator(COROUTINE_SUSPENDED) { generatorFunction(continuation) }) + return continuation +} + +@InlineOnly +internal inline fun startCoroutineFromGeneratorFunction( + completion: Continuation, + crossinline generatorFunction: (Continuation) -> dynamic, +): Any? { + val continuation = GeneratorCoroutineImpl(completion.unsafeCast>()) + continuation.isRunning = true + val result = generatorFunction(continuation) + continuation.isRunning = false + if (continuation.shouldResumeImmediately()) continuation.resume(result) + return result +} + +internal fun (suspend () -> T).startCoroutineUninterceptedOrReturnGeneratorVersion( + completion: Continuation +): Any? = startCoroutineFromGeneratorFunction(completion) { + val a = asDynamic() + if (jsTypeOf(a) === "function") a(it) + else invokeSuspendSuperType(it) +} + +internal fun (suspend R.() -> T).startCoroutineUninterceptedOrReturnGeneratorVersion( + receiver: R, + completion: Continuation +): Any? = startCoroutineFromGeneratorFunction(completion) { + val a = asDynamic() + if (jsTypeOf(a) === "function") a(receiver, it) + else invokeSuspendSuperTypeWithReceiver(receiver, it) +} + +internal fun (suspend R.(P) -> T).startCoroutineUninterceptedOrReturnGeneratorVersion( + receiver: R, + param: P, + completion: Continuation +): Any? = startCoroutineFromGeneratorFunction(completion) { + val a = asDynamic() + if (jsTypeOf(a) === "function") a(receiver, param, it) + else invokeSuspendSuperTypeWithReceiverAndParam(receiver, param, it) +} + +internal fun (suspend () -> T).createCoroutineUninterceptedGeneratorVersion( + completion: Continuation +): Continuation = + createCoroutineFromGeneratorFunction(completion) { + val a = asDynamic() + if (jsTypeOf(a) === "function") a(it) + else invokeSuspendSuperType(it) + } + +internal fun (suspend R.() -> T).createCoroutineUninterceptedGeneratorVersion( + receiver: R, + completion: Continuation +): Continuation = + createCoroutineFromGeneratorFunction(completion) { + val a = asDynamic() + if (jsTypeOf(a) === "function") a(receiver, it) + else invokeSuspendSuperTypeWithReceiver(receiver, it) + } + + +internal fun (suspend R.(P) -> T).createCoroutineUninterceptedGeneratorVersion( + receiver: R, + param: P, + completion: Continuation +): Continuation = + 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? { + if (!isGeneratorSuspendStep(value)) return value + + val iterator = value.unsafeCast>() + + if (continuation.asDynamic().constructor !== GeneratorCoroutineImpl::class.js) { + return iterator.next().value + } + + val generatorCoroutineImpl = continuation.unsafeCast() + + generatorCoroutineImpl.addNewIterator(iterator) + try { + val iteratorStep = iterator.next() + if (iteratorStep.done) generatorCoroutineImpl.dropLastIterator() + return iteratorStep.value + } catch (e: Throwable) { + generatorCoroutineImpl.dropLastIterator() + throw e + } +} \ No newline at end of file