JS: add metadata for generated continuation classes to properly implement RTTI
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// WITH_REFLECT
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
suspend fun runInstanceOf(x: Continuation<Boolean>) {
|
||||||
|
val y: Any = x
|
||||||
|
x.resume(x is Continuation<*>)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun runCast(x: Continuation<Boolean>) {
|
||||||
|
val y: Any = x
|
||||||
|
x.resume(Continuation::class.isInstance(y as Continuation<*>))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||||
|
c(Controller()).resume(Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = ""
|
||||||
|
|
||||||
|
builder {
|
||||||
|
result = runInstanceOf().toString() + "," + runCast().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != "true,true") return "fail: $result"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+6
@@ -4520,6 +4520,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("instanceOfContinuation.kt")
|
||||||
|
public void testInstanceOfContinuation() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("iterateOverArray.kt")
|
@TestMetadata("iterateOverArray.kt")
|
||||||
public void testIterateOverArray() throws Exception {
|
public void testIterateOverArray() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");
|
||||||
|
|||||||
@@ -4520,6 +4520,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("instanceOfContinuation.kt")
|
||||||
|
public void testInstanceOfContinuation() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("iterateOverArray.kt")
|
@TestMetadata("iterateOverArray.kt")
|
||||||
public void testIterateOverArray() throws Exception {
|
public void testIterateOverArray() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");
|
||||||
|
|||||||
+2
@@ -97,6 +97,8 @@ var JsNameRef.coroutineResult by MetadataProperty(default = false)
|
|||||||
*/
|
*/
|
||||||
var JsNameRef.coroutineController by MetadataProperty(default = false)
|
var JsNameRef.coroutineController by MetadataProperty(default = false)
|
||||||
|
|
||||||
|
var JsFunction.continuationInterfaceRef: JsExpression? by MetadataProperty(default = null)
|
||||||
|
|
||||||
enum class TypeCheck {
|
enum class TypeCheck {
|
||||||
TYPEOF,
|
TYPEOF,
|
||||||
INSTANCEOF,
|
INSTANCEOF,
|
||||||
|
|||||||
+17
-6
@@ -17,10 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.js.coroutine
|
package org.jetbrains.kotlin.js.coroutine
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
|
import com.google.dart.compiler.backend.js.ast.metadata.*
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.coroutineController
|
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.coroutineResult
|
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
||||||
@@ -70,7 +67,7 @@ class CoroutineFunctionTransformer(
|
|||||||
return additionalStatements
|
return additionalStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateContinuationConstructor(bodyTransformer: CoroutineBodyTransformer,statements: MutableList<JsStatement>) {
|
private fun generateContinuationConstructor(bodyTransformer: CoroutineBodyTransformer, statements: MutableList<JsStatement>) {
|
||||||
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
|
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
|
||||||
constructor.name = className
|
constructor.name = className
|
||||||
constructor.parameters += function.parameters.map { JsParameter(it.name) }
|
constructor.parameters += function.parameters.map { JsParameter(it.name) }
|
||||||
@@ -96,7 +93,21 @@ class CoroutineFunctionTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statements.add(0, constructor.makeStmt())
|
statements.addAll(0, listOf(constructor.makeStmt(), generateCoroutineMetadata(constructor.name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateCoroutineMetadata(constructorName: JsName): JsStatement {
|
||||||
|
val interfaceRef = function.continuationInterfaceRef!!.deepCopy()
|
||||||
|
|
||||||
|
val metadataObject = JsObjectLiteral(true)
|
||||||
|
metadataObject.propertyInitializers += JsPropertyInitializer(
|
||||||
|
JsNameRef("type"), JsNameRef("CLASS", JsNameRef("TYPE", Namer.KOTLIN_NAME)))
|
||||||
|
metadataObject.propertyInitializers += JsPropertyInitializer(
|
||||||
|
JsNameRef("classIndex"), JsInvocation(JsNameRef("newClassIndex", Namer.KOTLIN_NAME)))
|
||||||
|
metadataObject.propertyInitializers += JsPropertyInitializer(JsNameRef("simpleName"), JsLiteral.NULL)
|
||||||
|
metadataObject.propertyInitializers += JsPropertyInitializer(JsNameRef("baseClasses"), JsArrayLiteral(listOf(interfaceRef)))
|
||||||
|
|
||||||
|
return JsAstUtils.assignment(JsNameRef(Namer.METADATA, constructorName.makeRef()), metadataObject).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateContinuationMethods(doResumeName: JsName, statements: MutableList<JsStatement>) {
|
private fun generateContinuationMethods(doResumeName: JsName, statements: MutableList<JsStatement>) {
|
||||||
|
|||||||
+13
-1
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.js.translate.expression
|
|||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.*
|
import com.google.dart.compiler.backend.js.ast.metadata.*
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
|
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
|
||||||
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
|
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
|
||||||
@@ -28,14 +28,18 @@ import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor
|
|||||||
import org.jetbrains.kotlin.js.translate.context.hasCapturedExceptContaining
|
import org.jetbrains.kotlin.js.translate.context.hasCapturedExceptContaining
|
||||||
import org.jetbrains.kotlin.js.translate.context.isCaptured
|
import org.jetbrains.kotlin.js.translate.context.isCaptured
|
||||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||||
|
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor
|
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody
|
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||||
|
|
||||||
class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslator(context) {
|
class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslator(context) {
|
||||||
fun translate(
|
fun translate(
|
||||||
@@ -81,6 +85,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
lambda.name = null
|
lambda.name = null
|
||||||
}
|
}
|
||||||
lambdaCreator.name.staticRef = lambdaCreator
|
lambdaCreator.name.staticRef = lambdaCreator
|
||||||
|
lambdaCreator.continuationInterfaceRef = invokingContext.getContinuationInterfaceReference()
|
||||||
return lambdaCreator.withCapturedParameters(descriptor, descriptor.wrapContextForCoroutineIfNecessary(functionContext),
|
return lambdaCreator.withCapturedParameters(descriptor, descriptor.wrapContextForCoroutineIfNecessary(functionContext),
|
||||||
invokingContext)
|
invokingContext)
|
||||||
}
|
}
|
||||||
@@ -91,6 +96,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
|
|
||||||
invokingContext.addDeclarationStatement(lambda.makeStmt())
|
invokingContext.addDeclarationStatement(lambda.makeStmt())
|
||||||
lambda.name.staticRef = lambda
|
lambda.name.staticRef = lambda
|
||||||
|
lambda.continuationInterfaceRef = invokingContext.getContinuationInterfaceReference()
|
||||||
return getReferenceToLambda(invokingContext, descriptor, lambda.name)
|
return getReferenceToLambda(invokingContext, descriptor, lambda.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +110,12 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun TranslationContext.getContinuationInterfaceReference(): JsExpression {
|
||||||
|
val coroutineClassId = ClassId.topLevel(KotlinBuiltIns.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("Continuation")))
|
||||||
|
val classDescriptor = currentModule.findClassAcrossModuleDependencies(coroutineClassId)!!
|
||||||
|
return ReferenceTranslator.translateAsTypeReference(classDescriptor, this)
|
||||||
|
}
|
||||||
|
|
||||||
private fun CallableMemberDescriptor.wrapContextForCoroutineIfNecessary(context: TranslationContext): TranslationContext {
|
private fun CallableMemberDescriptor.wrapContextForCoroutineIfNecessary(context: TranslationContext): TranslationContext {
|
||||||
return if (isCoroutineLambda) context.innerContextWithDescriptorsAliased(mapOf(this to JsLiteral.THIS)) else context
|
return if (isCoroutineLambda) context.innerContextWithDescriptorsAliased(mapOf(this to JsLiteral.THIS)) else context
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user