[K/JS] Generate tests for K2 + ES-classes compilation

This commit is contained in:
Artem Kobzar
2023-08-01 09:16:20 +00:00
committed by Space Team
parent 19653df1c6
commit 08bd0d6ce1
43 changed files with 54150 additions and 72 deletions
@@ -35,6 +35,7 @@ object ES6_SYNTHETIC_EXPORT_CONSTRUCTOR: IrDeclarationOriginImpl("ES6_SYNTHETIC_
object ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT")
object ES6_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_INIT_FUNCTION")
object ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT : IrStatementOriginImpl("ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT")
object ES6_DELEGATING_CONSTRUCTOR_CALL_REPLACEMENT : IrDeclarationOriginImpl("ES6_DELEGATING_CONSTRUCTOR_CALL_REPLACEMENT")
val IrDeclaration.isEs6ConstructorReplacement: Boolean
get() = origin == ES6_CONSTRUCTOR_REPLACEMENT || origin == ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
@@ -54,6 +55,9 @@ val IrFunctionAccessExpression.isInitCall: Boolean
val IrDeclaration.isSyntheticConstructorForExport: Boolean
get() = origin == ES6_SYNTHETIC_EXPORT_CONSTRUCTOR
val IrDeclaration.isEs6DelegatingConstructorCallReplacement: Boolean
get() = origin == ES6_DELEGATING_CONSTRUCTOR_CALL_REPLACEMENT
class ES6ConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
private var IrConstructor.constructorFactory by context.mapping.secondaryConstructorToFactory
@@ -161,7 +165,7 @@ class ES6ConstructorLowering(val context: JsIrBackendContext) : DeclarationTrans
parent = this,
name = Namer.SYNTHETIC_RECEIVER_NAME,
initializer = initializer,
origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
origin = ES6_DELEGATING_CONSTRUCTOR_CALL_REPLACEMENT
)
}
@@ -339,10 +339,10 @@ class EnumEntryInstancesBodyLowering(val context: JsCommonBackendContext) : Body
if (enum.isInstantiableEnum) {
val entry = enum.declarations.findIsInstanceAnd<IrEnumEntry> { it.correspondingClass === entryClass }!!
//In ES6 using `this` before superCall is unavailable, so
//need to find superCall and put `instance = this` after it
// In ES6 using `this` before superCall is unavailable, so
// need to find superCall and put `instance = this` after it
val index = (irBody as IrBlockBody).statements
.indexOfFirst { it is IrTypeOperatorCall && it.argument is IrDelegatingConstructorCall } + 1
.indexOfFirst { it is IrDelegatingConstructorCall || it is IrTypeOperatorCall && it.argument is IrDelegatingConstructorCall } + 1
irBody.statements.add(index, context.createIrBuilder(container.symbol).run {
irSetField(null, entry.correspondingField!!, irGet(entryClass.thisReceiver!!))
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.getOrPut
import org.jetbrains.kotlin.backend.common.ir.isPure
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
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
@@ -24,21 +23,15 @@ class PurifyObjectInstanceGettersLowering(val context: JsCommonBackendContext) :
private var IrClass.instanceField by context.mapping.objectToInstanceField
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (
!declaration.isObjectInstanceGetter() &&
!declaration.isObjectInstanceField() &&
!declaration.isObjectConstructor()
) return null
return when (declaration) {
is IrSimpleFunction -> declaration.purifyObjectGetterIfPossible()
is IrField -> declaration.purifyObjectInstanceFieldIfPossible()
is IrConstructor -> declaration.removeInstanceFieldInitializationIfPossible()
else -> error("Unexpected IR type ${declaration::class.qualifiedName}")
return when {
(declaration is IrFunction && declaration.isObjectConstructor()) -> declaration.removeInstanceFieldInitializationIfPossible()
(declaration is IrSimpleFunction && declaration.isObjectInstanceGetter()) -> declaration.purifyObjectGetterIfPossible()
(declaration is IrField && declaration.isObjectInstanceField()) -> declaration.purifyObjectInstanceFieldIfPossible()
else -> null
}
}
private fun IrConstructor.removeInstanceFieldInitializationIfPossible(): List<IrDeclaration>? {
private fun IrFunction.removeInstanceFieldInitializationIfPossible(): List<IrDeclaration>? {
if (parentAsClass.isPureObject()) {
(body as? IrBlockBody)?.statements?.removeIf {
it is IrSetField && it.symbol.owner.isObjectInstanceField()
@@ -70,30 +63,36 @@ class PurifyObjectInstanceGettersLowering(val context: JsCommonBackendContext) :
val objectToCreate = type.classOrNull?.owner ?: return null
if (objectToCreate.isPureObject()) {
val objectConstructor = objectToCreate.primaryConstructor ?: error("Object should contain a primary constructor")
initializer = IrExpressionBodyImpl(JsIrBuilder.buildConstructorCall(objectConstructor.symbol))
initializer = IrExpressionBodyImpl(
objectToCreate.primaryConstructor?.let { JsIrBuilder.buildConstructorCall(it.symbol) }
?: objectToCreate.primaryConstructorReplacement?.let { JsIrBuilder.buildCall(it.symbol) }
?: error("Object should contain a primary constructor")
)
}
return null
}
private fun IrDeclaration.isObjectConstructor(): Boolean {
return this is IrConstructor && parentAsClass.isObject
return (this is IrConstructor || isEs6ConstructorReplacement) && parentAsClass.isObject
}
private fun IrClass.isPureObject(): Boolean {
return context.mapping.objectsWithPureInitialization.getOrPut(this) {
superClass == null && primaryConstructor?.body?.statements?.all { it.isPureStatementForObjectInitialization(this@isPureObject) } != false
val constructor = primaryConstructor ?: primaryConstructorReplacement
superClass == null && constructor?.body?.statements?.all { it.isPureStatementForObjectInitialization(this@isPureObject) } != false
}
}
private fun IrStatement.isPureStatementForObjectInitialization(owner: IrClass): Boolean {
return (
// Only objects which don't have a class parent
(this is IrDelegatingConstructorCall && symbol.owner.parent == context.irBuiltIns.anyClass.owner) ||
this is IrReturn ||
// Only objects which don't have a class parent
(this is IrDelegatingConstructorCall && symbol.owner.parent == context.irBuiltIns.anyClass.owner) ||
(this is IrExpression && isPure(anyVariable = true, checkFields = false, context = context)) ||
(this is IrContainerExpression && statements.all { it.isPureStatementForObjectInitialization(owner) }) ||
(this is IrVariable && initializer?.isPureStatementForObjectInitialization(owner) != false) ||
(this is IrVariable && (isEs6DelegatingConstructorCallReplacement || initializer?.isPureStatementForObjectInitialization(owner) != false)) ||
// Only fields of the objects are safe to not save an intermediate state of another class/object/global
(this is IrGetField && receiver?.isPureStatementForObjectInitialization(owner) == true) ||
(this is IrSetField && receiver?.isPureStatementForObjectInitialization(owner) == true && value.isPureStatementForObjectInitialization(owner)) ||
@@ -103,4 +102,7 @@ class PurifyObjectInstanceGettersLowering(val context: JsCommonBackendContext) :
)
}
private val IrClass.primaryConstructorReplacement: IrSimpleFunction?
get() = findDeclaration<IrSimpleFunction> { it.isEs6PrimaryConstructorReplacement }
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.util.inlineFunction
import org.jetbrains.kotlin.ir.util.innerInlinedBlockOrThis
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.lower.ES6_DELEGATING_CONSTRUCTOR_CALL_REPLACEMENT
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
import org.jetbrains.kotlin.ir.backend.js.utils.isTheLastReturnStatementIn
@@ -171,6 +172,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
is IrDeclarationOrigin.IR_TEMPORARY_VARIABLE -> true
is IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_PARAMETER -> true
is IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER -> true
is ES6_DELEGATING_CONSTRUCTOR_CALL_REPLACEMENT -> true
else -> false
}
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_K1: WASM
// IGNORE_BACKEND_K1: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_K1: JS_IR, WASM
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6, WASM
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
@@ -1,5 +1,5 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// WITH_REFLECT
// WITH_STDLIB
// FILE: J.java
@@ -1,6 +1,6 @@
// !LANGUAGE: +ContextReceivers
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// WITH_STDLIB
class A(val ok: String)
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_K1: JS_IR
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
//KT-3822 Compiler crashes when use invoke convention with `this` in class which extends Function0<T>
// IGNORE_BACKEND: JS
// JS backend does not allow to implement Function{N} interfaces
@@ -1,4 +1,4 @@
// IGNORE_BACKEND_K2: JS_IR, WASM
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6, WASM
// KT-40686
@@ -5,7 +5,7 @@
// IGNORE_BACKEND: NATIVE
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// FILE: lib.kt
@@ -1,6 +1,6 @@
// IGNORE_BACKEND_K1: ANY
// IGNORE_REASON: new rules for supertypes matching are implemented only in K2
// IGNORE_BACKEND_K2: JS_IR, WASM
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6, WASM
// IGNORE_REASON: `JsName` in js.translator/testData/_commonFiles/testUtils.kt is invisible for some reason
// LANGUAGE: +MultiPlatformProjects
// ISSUE: KT-59356
@@ -1,6 +1,6 @@
// IGNORE_BACKEND_K1: ANY
// IGNORE_REASON: KT-59355 is fixed only in K2
// IGNORE_BACKEND_K2: JS_IR, WASM
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6, WASM
// IGNORE_REASON: `JsName` in js.translator/testData/_commonFiles/testUtils.kt is invisible for some reason
// LANGUAGE: +MultiPlatformProjects
// ISSUE: KT-59355
@@ -7,7 +7,7 @@
// IGNORE_BACKEND_K1: ANY
// IllegalArgumentException: arg wrongly != this@Test5: arg=null, this@Test5=[object Object]
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// Wrong box result 'arg1 wrongly != this@Test5: arg1=Inner@1346131020, this@Test5=Test5@314569418'; Expected "OK"
// IGNORE_BACKEND_K2: WASM
+1 -2
View File
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_K1: WASM
// IGNORE_BACKEND_K1: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_K1: WASM
// IGNORE_BACKEND_K1: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
+1 -1
View File
@@ -5,7 +5,7 @@
// TARGET_BACKEND: JVM_IR
// TARGET_BACKEND: JS_IR
// K2 JS_IR MUTE_REASON: java.lang.NullPointerException at org.jetbrains.kotlin.fir.backend.Fir2IrClassifierStorage.getIrClassSymbol
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// Test that if we have two different files with the same name in the same package, KT-54028 doesn't reproduce.
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_K1: WASM
// IGNORE_BACKEND_K1: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
@@ -1,4 +1,4 @@
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// CHECK_CASES_COUNT: function=crash count=2 TARGET_BACKENDS=JS
// CHECK_CASES_COUNT: function=crash count=0 IGNORED_BACKENDS=JS
// CHECK_IF_COUNT: function=crash count=1 TARGET_BACKENDS=JS
@@ -1,4 +1,4 @@
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// CHECK_CASES_COUNT: function=doTheThing count=2 TARGET_BACKENDS=JS
// CHECK_CASES_COUNT: function=doTheThing count=0 IGNORED_BACKENDS=JS
// CHECK_IF_COUNT: function=doTheThing count=2 TARGET_BACKENDS=JS
@@ -1,6 +1,6 @@
// IGNORE_ERRORS
// ERROR_POLICY: SEMANTIC
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// MODULE: lib
// FILE: t.kt
@@ -1,6 +1,6 @@
// IGNORE_ERRORS
// ERROR_POLICY: SEMANTIC
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// MODULE: lib
// FILE: t.kt
@@ -1,6 +1,6 @@
// IGNORE_ERRORS
// ERROR_POLICY: SEMANTIC
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// MODULE: lib
// FILE: t.kt
@@ -1,6 +1,6 @@
// IGNORE_ERRORS
// ERROR_POLICY: SYNTAX
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// MODULE: lib
// FILE: t.kt
@@ -1,6 +1,6 @@
// IGNORE_ERRORS
// ERROR_POLICY: SYNTAX
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// MODULE: lib
// FILE: t.kt
+1 -1
View File
@@ -1,4 +1,4 @@
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// IGNORE_BACKEND_K2: WASM
// Partial copy of js/js.translator/testData/box/native/vararg.kt
+1 -1
View File
@@ -1,5 +1,5 @@
// WITH_STDLIB
// IGNORE_BACKEND_K2: JS_IR
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
// ^ the order of fake overrides is different on K2
interface X {