[JS IR] Review remarks

- Use intrinsic on this
- Enqueue invoke for DCE
- Change transform
- Ignore instead of target backend

^KT-46204 fixed
This commit is contained in:
Ilya Goncharov
2021-08-09 12:49:06 +03:00
committed by Space
parent 2f0f88062a
commit 766857881a
10 changed files with 63 additions and 57 deletions
@@ -10205,6 +10205,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt"); runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt");
} }
@Test
@TestMetadata("suspendFunctionAsSupertypeIsCheckWithArity.kt")
public void testSuspendFunctionAsSupertypeIsCheckWithArity() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheckWithArity.kt");
}
@Test @Test
@TestMetadata("suspendFunctionIsAs.kt") @TestMetadata("suspendFunctionIsAs.kt")
public void testSuspendFunctionIsAs() throws Exception { public void testSuspendFunctionIsAs() throws Exception {
@@ -22,8 +22,8 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.* import java.util.*
@@ -458,6 +458,12 @@ fun usefulDeclarations(
val klass = arg.getClass() val klass = arg.getClass()
constructedClasses.addIfNotNull(klass) constructedClasses.addIfNotNull(klass)
} }
context.intrinsics.jsInvokeSuspendSuperType,
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
invokeFunForLambda(expression)
.enqueue("intrinsic: suspendSuperType")
}
} }
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.backend.js.export.isExported import org.jetbrains.kotlin.ir.backend.js.export.isExported
import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -162,19 +163,21 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
// interface II : I // interface II : I
// II.prototype.foo = I.prototype.foo // II.prototype.foo = I.prototype.foo
if (!irClass.isInterface) { if (!irClass.isInterface) {
declaration.realOverrideTarget.let { declaration.collectRealOverrides()
val implClassDeclaration = it.parent as IrClass .find { it.modality != Modality.ABSTRACT }
?.let {
val implClassDeclaration = it.parent as IrClass
if (implClassDeclaration.shouldCopyFrom() && !implClassDeclaration.defaultType.isFunctionType()) { if (implClassDeclaration.shouldCopyFrom()) {
val implMethodName = context.getNameForMemberFunction(it) val implMethodName = context.getNameForMemberFunction(it)
val implClassName = context.getNameForClass(implClassDeclaration) val implClassName = context.getNameForClass(implClassDeclaration)
val implClassPrototype = prototypeOf(implClassName.makeRef()) val implClassPrototype = prototypeOf(implClassName.makeRef())
val implMemberRef = JsNameRef(implMethodName, implClassPrototype) val implMemberRef = JsNameRef(implMethodName, implClassPrototype)
classModel.postDeclarationBlock.statements += jsAssignment(memberRef, implMemberRef).makeStmt() classModel.postDeclarationBlock.statements += jsAssignment(memberRef, implMemberRef).makeStmt()
}
} }
}
} }
return Pair(memberRef, null) return Pair(memberRef, null)
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
import org.jetbrains.kotlin.ir.backend.js.utils.getClassRef import org.jetbrains.kotlin.ir.backend.js.utils.getClassRef
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
@@ -232,45 +230,14 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
val suspendInvokeTransform: (IrCall, JsGenerationContext) -> JsExpression = { call, context: JsGenerationContext -> val suspendInvokeTransform: (IrCall, JsGenerationContext) -> JsExpression = { call, context: JsGenerationContext ->
// Because it is intrinsic, we know everything about this function // Because it is intrinsic, we know everything about this function
// There is callable reference as extension receiver // There is callable reference as extension receiver
val invokeFun = (call.extensionReceiver as IrCall) val invokeFun = invokeFunForLambda(call)
.getValueArgument(0)!!
.type
.getClass()!!
.declarations
.filterIsInstance<IrSimpleFunction>()
.single { it.name.asString() == "invoke" }
val jsInvokeFunName = context.getNameForMemberFunction(invokeFun) val jsInvokeFunName = context.getNameForMemberFunction(invokeFun)
val jsExtensionReceiver = call.extensionReceiver?.accept(IrElementToJsExpressionTransformer(), context)!! as JsInvocation val jsExtensionReceiver = call.extensionReceiver?.accept(IrElementToJsExpressionTransformer(), context)!!
val args = translateCallArguments(call, context) val args = translateCallArguments(call, context)
val jsArgsForClosureFun = args.mapIndexed { index, _ -> JsName("${"$"}p$index") }
// Function to make closure for invoke to avoid losing this JsInvocation(JsNameRef(jsInvokeFunName, jsExtensionReceiver), args)
jsExtensionReceiver.arguments[0] = JsInvocation(
JsNameRef(
Namer.BIND_FUNCTION,
JsFunction(
emptyScope,
JsBlock(
JsReturn(
JsInvocation(
JsNameRef(
jsInvokeFunName,
jsExtensionReceiver.arguments[0]
),
jsArgsForClosureFun.map { it.makeRef() }
)
)
),
"Function to make closure for invoke to avoid losing this"
).also { func ->
func.parameters.addAll(jsArgsForClosureFun.map { JsParameter(it) })
}
), JsThisRef()
)
JsInvocation(jsExtensionReceiver, args)
} }
add(intrinsics.jsInvokeSuspendSuperType, suspendInvokeTransform) add(intrinsics.jsInvokeSuspendSuperType, suspendInvokeTransform)
@@ -18,9 +18,8 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -119,3 +118,11 @@ fun IrBody.prependFunctionCall(
fun IrDeclaration.isImportedFromModuleOnly(): Boolean { fun IrDeclaration.isImportedFromModuleOnly(): Boolean {
return isTopLevel && isEffectivelyExternal() && (getJsModule() != null && !isJsNonModule() || (parent as? IrAnnotationContainer)?.getJsModule() != null) return isTopLevel && isEffectivelyExternal() && (getJsModule() != null && !isJsNonModule() || (parent as? IrAnnotationContainer)?.getJsModule() != null)
} }
fun invokeFunForLambda(call: IrCall) =
call.extensionReceiver!!
.type
.getClass()!!
.declarations
.filterIsInstance<IrSimpleFunction>()
.single { it.name.asString() == "invoke" }
@@ -1,6 +1,6 @@
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// TARGET_BACKEND: JS // IGNORE_BACKEND: JS, JVM, JVM_IR
// IGNORE_BACKEND: JS // IGNORE_BACKEND_FIR: JVM_IR
// !LANGUAGE: +SuspendFunctionAsSupertype // !LANGUAGE: +SuspendFunctionAsSupertype
import kotlin.coroutines.* import kotlin.coroutines.*
@@ -10109,6 +10109,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt"); runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt");
} }
@Test
@TestMetadata("suspendFunctionAsSupertypeIsCheckWithArity.kt")
public void testSuspendFunctionAsSupertypeIsCheckWithArity() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheckWithArity.kt");
}
@Test @Test
@TestMetadata("suspendFunctionIsAs.kt") @TestMetadata("suspendFunctionIsAs.kt")
public void testSuspendFunctionIsAs() throws Exception { public void testSuspendFunctionIsAs() throws Exception {
@@ -10205,6 +10205,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt"); runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt");
} }
@Test
@TestMetadata("suspendFunctionAsSupertypeIsCheckWithArity.kt")
public void testSuspendFunctionAsSupertypeIsCheckWithArity() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheckWithArity.kt");
}
@Test @Test
@TestMetadata("suspendFunctionIsAs.kt") @TestMetadata("suspendFunctionIsAs.kt")
public void testSuspendFunctionIsAs() throws Exception { public void testSuspendFunctionIsAs() throws Exception {
@@ -7883,6 +7883,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt"); runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheck.kt");
} }
@TestMetadata("suspendFunctionAsSupertypeIsCheckWithArity.kt")
public void ignoreSuspendFunctionAsSupertypeIsCheckWithArity() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionAsSupertypeIsCheckWithArity.kt");
}
private void runTest(String testDataFilePath) throws Exception { private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
} }
@@ -74,7 +74,7 @@ public actual inline fun <T> (suspend () -> T).startCoroutineUninterceptedOrRetu
): Any? { ): Any? {
val a = this.asDynamic() val a = this.asDynamic()
return if (jsTypeOf(a) == "function") a(completion) return if (jsTypeOf(a) == "function") a(completion)
else ::invoke.invokeSuspendSuperType(completion) else this.invokeSuspendSuperType(completion)
} }
/** /**
@@ -97,7 +97,7 @@ public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedO
): Any? { ): Any? {
val a = this.asDynamic() val a = this.asDynamic()
return if (jsTypeOf(a) == "function") a(receiver, completion) return if (jsTypeOf(a) == "function") a(receiver, completion)
else ::invoke.invokeSuspendSuperTypeWithReceiver(receiver, completion) else this.invokeSuspendSuperTypeWithReceiver(receiver, completion)
} }
@InlineOnly @InlineOnly
@@ -108,7 +108,7 @@ internal actual inline fun <R, P, T> (suspend R.(P) -> T).startCoroutineUninterc
): Any? { ): Any? {
val a = this.asDynamic() val a = this.asDynamic()
return if (jsTypeOf(a) == "function") a(receiver, param, completion) return if (jsTypeOf(a) == "function") a(receiver, param, completion)
else ::invoke.invokeSuspendSuperTypeWithReceiverAndParam(receiver, param, completion) else this.invokeSuspendSuperTypeWithReceiverAndParam(receiver, param, completion)
} }
/** /**
@@ -134,7 +134,7 @@ public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
createCoroutineFromSuspendFunction(completion) { createCoroutineFromSuspendFunction(completion) {
val a = this.asDynamic() val a = this.asDynamic()
if (jsTypeOf(a) == "function") a(completion) if (jsTypeOf(a) == "function") a(completion)
else ::invoke.invokeSuspendSuperType(completion) else this.invokeSuspendSuperType(completion)
} }
/** /**
@@ -161,7 +161,7 @@ public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
createCoroutineFromSuspendFunction(completion) { createCoroutineFromSuspendFunction(completion) {
val a = this.asDynamic() val a = this.asDynamic()
if (jsTypeOf(a) == "function") a(receiver, completion) if (jsTypeOf(a) == "function") a(receiver, completion)
else ::invoke.invokeSuspendSuperTypeWithReceiver(receiver, completion) else this.invokeSuspendSuperTypeWithReceiver(receiver, completion)
} }
/** /**