Implement script instance capturing in script lowering

for regular classes only. Reimplementing the main behavior of the
old BE and implementing few cases on top of it.
#KT-19423 fixed
This commit is contained in:
Ilya Chernikov
2021-11-24 15:51:02 +01:00
committed by TeamCityServer
parent 87952d63a3
commit cb5e451e05
22 changed files with 659 additions and 94 deletions
@@ -177,7 +177,12 @@ class ClosureAnnotator(irElement: IrElement, declaration: IrDeclaration) {
closureBuilder.declareVariable(this.thisReceiver)
if (this.isInner) {
closureBuilder.declareVariable((this.parent as IrClass).thisReceiver)
val receiver = when (val parent = this.parent) {
is IrClass -> parent.thisReceiver
is IrScript -> parent.thisReceiver
else -> error("unexpected parent $parent")
}
closureBuilder.declareVariable(receiver)
includeInParent(closureBuilder)
}
@@ -6,9 +6,11 @@
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.ClosureAnnotator
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeCustomPhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmInnerClassesSupport
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
@@ -19,18 +21,17 @@ import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.interpreter.toIrConst
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
@@ -42,12 +43,12 @@ internal val scriptsToClassesPhase = makeCustomPhase<JvmBackendContext, IrModule
name = "ScriptsToClasses",
description = "Put script declarations into classes",
op = { context, input ->
ScriptsToClassesLowering(context).lower(input)
ScriptsToClassesLowering(context, context.innerClassesSupport).lower(input)
}
)
private class ScriptsToClassesLowering(val context: JvmBackendContext) {
private class ScriptsToClassesLowering(val context: JvmBackendContext, val innerClassesSupport: JvmInnerClassesSupport) {
fun lower(module: IrModuleFragment) {
val scriptsToClasses = mutableMapOf<IrScript, IrClass>()
@@ -89,15 +90,35 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
}
}
private fun collectCapturingClasses(irScript: IrScript): Set<IrClassImpl> {
val annotator = ClosureAnnotator(irScript, irScript)
val capturingClasses = mutableSetOf<IrClassImpl>()
for (clazz in irScript.statements) {
if (clazz is IrClassImpl && !clazz.isInner ) {
val closure = annotator.getClassClosure(clazz)
if (closure.capturedValues.singleOrNull()?.owner?.type == irScript.thisReceiver.type) {
if (clazz.isClass) {
capturingClasses.add(clazz)
}
}
}
}
return capturingClasses
}
private fun finalizeScriptClass(irScriptClass: IrClass, irScript: IrScript, symbolRemapper: ScriptsToClassesSymbolRemapper) {
val typeRemapper = SimpleTypeRemapper(symbolRemapper)
val scriptTransformer = ScriptToClassTransformer(irScript, irScriptClass, symbolRemapper, typeRemapper, context)
val capturingClasses = collectCapturingClasses(irScript)
val scriptTransformer = ScriptToClassTransformer(irScript, irScriptClass, symbolRemapper, typeRemapper, context, capturingClasses, innerClassesSupport)
val lambdaPatcher = ScriptFixLambdasTransformer(irScript, irScriptClass, context)
fun <E: IrElement> E.patchForClass(): IrElement =
transform(scriptTransformer, null).transform(lambdaPatcher, ScriptToClassTransformerContext())
irScriptClass.thisReceiver = scriptTransformer.scriptClassReceiver
irScriptClass.thisReceiver = irScript.thisReceiver.transform(scriptTransformer, null)
val defaultContext = ScriptToClassTransformerContext(irScriptClass.thisReceiver?.symbol, null, null)
fun <E: IrElement> E.patchForClass(): IrElement {
return transform(scriptTransformer, defaultContext)
.transform(lambdaPatcher, ScriptFixLambdasTransformerContext())
}
irScript.constructor?.patchForClass()?.safeAs<IrConstructor>()!!.also { constructor ->
val explicitParamsStartIndex = if (irScript.earlierScriptsParameter == null) 0 else 1
@@ -266,6 +287,12 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
}
data class ScriptToClassTransformerContext(
val valueParameterForScriptThis: IrValueParameterSymbol?,
val fieldForScriptThis: IrFieldSymbol?,
val valueParameterForFieldReceiver: IrValueParameterSymbol?
)
data class ScriptFixLambdasTransformerContext(
val insideTopLevelDestructuringDeclaration: Boolean = false,
val valueParameterToReplaceWithScript: IrValueParameter? = null
)
@@ -275,36 +302,54 @@ private class ScriptToClassTransformer(
val irScriptClass: IrClass,
val symbolRemapper: SymbolRemapper,
val typeRemapper: TypeRemapper,
val context: JvmBackendContext
) : IrElementTransformerVoid() {
val context: JvmBackendContext,
val capturingClasses: Set<IrClassImpl>,
val innerClassesSupport: JvmInnerClassesSupport
) : IrElementTransformer<ScriptToClassTransformerContext> {
private fun IrType.remapType() = typeRemapper.remapType(this)
val capturingClassesConstructors = mutableMapOf<IrConstructor, IrClassImpl>().apply {
capturingClasses.forEach { c ->
c.declarations.forEach { d ->
if (d is IrConstructor) {
put(d, c)
}
}
}
}
val scriptClassReceiver =
irScript.thisReceiver.transform(this, ScriptToClassTransformerContext(null, null, null))
private fun IrDeclaration.transformParent() {
if (parent == irScript) {
parent = irScriptClass
}
}
private fun IrMutableAnnotationContainer.transformAnnotations() {
annotations = annotations.transform()
private fun IrMutableAnnotationContainer.transformAnnotations(data: ScriptToClassTransformerContext) {
annotations = annotations.transform(data)
}
private inline fun <reified T : IrElement> T.transform() =
transform(this@ScriptToClassTransformer, null) as T
private inline fun <reified T : IrElement> T.transform(data: ScriptToClassTransformerContext) =
transform(this@ScriptToClassTransformer, data) as T
private inline fun <reified T : IrElement> List<T>.transform() =
map { it.transform() }
private inline fun <reified T : IrElement> List<T>.transform(data: ScriptToClassTransformerContext) =
map { it.transform(data) }
private fun <T : IrFunction> T.transformFunctionChildren(): T =
private fun <T : IrFunction> T.transformFunctionChildren(data: ScriptToClassTransformerContext): T =
apply {
transformAnnotations()
transformAnnotations(data)
typeRemapper.withinScope(this) {
dispatchReceiverParameter = dispatchReceiverParameter?.transform()
extensionReceiverParameter = extensionReceiverParameter?.transform()
dispatchReceiverParameter = dispatchReceiverParameter?.transform(data)
val dataForChildren =
if (dispatchReceiverParameter?.type != scriptClassReceiver.type) data
else ScriptToClassTransformerContext(dispatchReceiverParameter!!.symbol, null, null)
extensionReceiverParameter = extensionReceiverParameter?.transform(dataForChildren)
returnType = returnType.remapType()
valueParameters = valueParameters.transform()
body = body?.transform()
valueParameters = valueParameters.transform(dataForChildren)
body = body?.transform(dataForChildren)
}
}
@@ -315,89 +360,163 @@ private class ScriptToClassTransformer(
private fun unexpectedElement(element: IrElement): Nothing =
throw IllegalArgumentException("Unsupported element type: $element")
override fun visitElement(element: IrElement): IrElement = unexpectedElement(element)
override fun visitElement(element: IrElement, data: ScriptToClassTransformerContext): IrElement = unexpectedElement(element)
override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment = unexpectedElement(declaration)
override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment) = unexpectedElement(declaration)
override fun visitFile(declaration: IrFile): IrFile = unexpectedElement(declaration)
override fun visitScript(declaration: IrScript): IrStatement = unexpectedElement(declaration)
override fun visitModuleFragment(declaration: IrModuleFragment, data: ScriptToClassTransformerContext): IrModuleFragment = unexpectedElement(declaration)
override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment, data: ScriptToClassTransformerContext) = unexpectedElement(declaration)
override fun visitFile(declaration: IrFile, data: ScriptToClassTransformerContext): IrFile = unexpectedElement(declaration)
override fun visitScript(declaration: IrScript, data: ScriptToClassTransformerContext): IrStatement = unexpectedElement(declaration)
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement = declaration.apply {
override fun visitDeclaration(declaration: IrDeclarationBase, data: ScriptToClassTransformerContext): IrStatement = declaration.apply {
transformParent()
transformAnnotations()
transformChildren(this@ScriptToClassTransformer, null)
transformAnnotations(data)
transformChildren(this@ScriptToClassTransformer, data)
}
override fun visitClass(declaration: IrClass): IrClass = declaration.apply {
override fun visitClass(declaration: IrClass, data: ScriptToClassTransformerContext): IrClass = declaration.apply {
superTypes = superTypes.map {
it.remapType()
}
visitDeclaration(declaration)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrSimpleFunction = declaration.apply {
transformParent()
transformFunctionChildren()
var dataForChildren = data
(declaration as? IrClassImpl)?.let {
if (it in capturingClasses) {
it.isInner = true
dataForChildren =
ScriptToClassTransformerContext(
null, innerClassesSupport.getOuterThisField(it).symbol, it.thisReceiver?.symbol
)
}
}
transformAnnotations(dataForChildren)
transformChildren(this@ScriptToClassTransformer, dataForChildren)
}
override fun visitConstructor(declaration: IrConstructor): IrConstructor = declaration.apply {
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: ScriptToClassTransformerContext): IrSimpleFunction =
declaration.apply {
transformParent()
val dataForChildren =
if (data.valueParameterForFieldReceiver?.owner?.type.let { it != null && it == this.dispatchReceiverParameter?.type })
ScriptToClassTransformerContext(
data.valueParameterForScriptThis, data.fieldForScriptThis, this.dispatchReceiverParameter?.symbol
)
else data
transformFunctionChildren(dataForChildren)
}
override fun visitConstructor(declaration: IrConstructor, data: ScriptToClassTransformerContext): IrConstructor = declaration.apply {
if (declaration in capturingClassesConstructors) {
declaration.dispatchReceiverParameter =
IrValueParameterBuilder().run<IrValueParameterBuilder, IrValueParameter> {
name = SpecialNames.THIS
type = scriptClassReceiver.type
declaration.factory.createValueParameter(
startOffset, endOffset, IrDeclarationOrigin.INSTANCE_RECEIVER,
IrValueParameterSymbolImpl(),
name, index, type, varargElementType, isCrossInline, isNoinline, isHidden, isAssignable
).also {
it.parent = declaration
}
}
}
transformParent()
transformFunctionChildren()
transformFunctionChildren(data)
}
override fun visitVariable(declaration: IrVariable): IrVariable = declaration.apply {
override fun visitVariable(declaration: IrVariable, data: ScriptToClassTransformerContext): IrVariable = declaration.apply {
type = type.remapType()
visitDeclaration(declaration)
visitDeclaration(declaration, data)
}
override fun visitTypeParameter(declaration: IrTypeParameter): IrTypeParameter = declaration.apply {
remapSuperTypes()
visitDeclaration(declaration)
}
override fun visitTypeParameter(declaration: IrTypeParameter, data: ScriptToClassTransformerContext): IrTypeParameter =
declaration.apply {
remapSuperTypes()
visitDeclaration(declaration, data)
}
override fun visitValueParameter(declaration: IrValueParameter): IrValueParameter = declaration.apply {
type = type.remapType()
varargElementType = varargElementType?.remapType()
visitDeclaration(declaration)
}
override fun visitValueParameter(declaration: IrValueParameter, data: ScriptToClassTransformerContext): IrValueParameter =
declaration.apply {
type = type.remapType()
varargElementType = varargElementType?.remapType()
visitDeclaration(declaration, data)
}
override fun visitTypeAlias(declaration: IrTypeAlias): IrTypeAlias = declaration.apply {
override fun visitTypeAlias(declaration: IrTypeAlias, data: ScriptToClassTransformerContext): IrTypeAlias = declaration.apply {
expandedType = expandedType.remapType()
visitDeclaration(declaration)
visitDeclaration(declaration, data)
}
override fun visitVararg(expression: IrVararg): IrVararg = expression.apply {
override fun visitVararg(expression: IrVararg, data: ScriptToClassTransformerContext): IrVararg = expression.apply {
type = type.remapType()
varargElementType = varargElementType.remapType()
transformChildren(this@ScriptToClassTransformer, null)
transformChildren(this@ScriptToClassTransformer, data)
}
override fun visitSpreadElement(spread: IrSpreadElement): IrSpreadElement = spread.apply {
transformChildren(this@ScriptToClassTransformer, null)
override fun visitSpreadElement(spread: IrSpreadElement, data: ScriptToClassTransformerContext): IrSpreadElement = spread.apply {
transformChildren(this@ScriptToClassTransformer, data)
}
override fun visitExpression(expression: IrExpression): IrExpression = expression.apply {
override fun visitExpression(expression: IrExpression, data: ScriptToClassTransformerContext): IrExpression = expression.apply {
type = type.remapType()
transformChildren(this@ScriptToClassTransformer, null)
transformChildren(this@ScriptToClassTransformer, data)
}
override fun visitClassReference(expression: IrClassReference): IrClassReference = expression.apply {
type = type.remapType()
classType = classType.remapType()
transformChildren(this@ScriptToClassTransformer, null)
}
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall = expression.apply {
type = type.remapType()
typeOperand = typeOperand.remapType()
transformChildren(this@ScriptToClassTransformer, null)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression = expression.apply {
for (i in 0 until typeArgumentsCount) {
putTypeArgument(i, getTypeArgument(i)?.remapType())
override fun visitClassReference(expression: IrClassReference, data: ScriptToClassTransformerContext): IrClassReference =
expression.apply {
type = type.remapType()
classType = classType.remapType()
transformChildren(this@ScriptToClassTransformer, data)
}
visitExpression(expression)
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: ScriptToClassTransformerContext): IrTypeOperatorCall =
expression.apply {
type = type.remapType()
typeOperand = typeOperand.remapType()
transformChildren(this@ScriptToClassTransformer, data)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>, data: ScriptToClassTransformerContext): IrExpression =
expression.apply {
for (i in 0 until typeArgumentsCount) {
putTypeArgument(i, getTypeArgument(i)?.remapType())
}
visitExpression(expression, data)
}
override fun visitConstructorCall(expression: IrConstructorCall, data: ScriptToClassTransformerContext): IrExpression {
capturingClassesConstructors.keys.find { it.symbol == expression.symbol }?.let {
expression.dispatchReceiver =
getAccessCallForScriptInstance(data, expression.startOffset, expression.endOffset, expression.origin)
}
return super.visitConstructorCall(expression, data) as IrExpression
}
private fun getAccessCallForScriptInstance(
data: ScriptToClassTransformerContext, startOffset: Int, endOffset: Int, origin: IrStatementOrigin?
) = when {
data.fieldForScriptThis != null ->
IrGetFieldImpl(
startOffset, endOffset,
data.fieldForScriptThis,
scriptClassReceiver.type,
origin
).apply {
receiver =
IrGetValueImpl(
startOffset, endOffset,
data.valueParameterForFieldReceiver!!.owner.type,
data.valueParameterForFieldReceiver,
origin
)
}
data.valueParameterForScriptThis != null ->
IrGetValueImpl(
startOffset, endOffset,
scriptClassReceiver.type,
data.valueParameterForScriptThis,
origin
)
else -> error("Unexpected script transformation state: $data")
}
private fun getAccessCallForEarlierScript(expression: IrDeclarationReference, maybeScriptType: IrType): IrExpression? {
@@ -432,7 +551,7 @@ private class ScriptToClassTransformer(
return null
}
override fun visitGetField(expression: IrGetField): IrExpression {
override fun visitGetField(expression: IrGetField, data: ScriptToClassTransformerContext): IrExpression {
if (irScript.earlierScripts != null) {
val receiver = expression.receiver
if (receiver is IrGetValue && receiver.symbol.owner.name == SpecialNames.THIS) {
@@ -440,14 +559,14 @@ private class ScriptToClassTransformer(
if (newReceiver != null) {
val newGetField =
IrGetFieldImpl(expression.startOffset, expression.endOffset, expression.symbol, expression.type, newReceiver)
return super.visitGetField(newGetField)
return super.visitGetField(newGetField, data)
}
}
}
return super.visitGetField(expression)
return super.visitGetField(expression, data)
}
override fun visitCall(expression: IrCall): IrExpression {
override fun visitCall(expression: IrCall, data: ScriptToClassTransformerContext): IrExpression {
if (irScript.earlierScripts != null) {
val target = expression.symbol.owner
val receiver: IrValueParameter? = target.dispatchReceiverParameter
@@ -458,34 +577,36 @@ private class ScriptToClassTransformer(
}
}
}
return super.visitCall(expression)
return super.visitCall(expression, data) as IrExpression
}
}
private class ScriptFixLambdasTransformer(
val irScript: IrScript,
val irScriptClass: IrClass,
val context: JvmBackendContext
) : IrElementTransformer<ScriptToClassTransformerContext> {
) : IrElementTransformer<ScriptFixLambdasTransformerContext> {
private fun unexpectedElement(element: IrElement): Nothing =
throw IllegalArgumentException("Unsupported element type: $element")
override fun visitElement(element: IrElement, data: ScriptToClassTransformerContext): IrElement = unexpectedElement(element)
override fun visitElement(element: IrElement, data: ScriptFixLambdasTransformerContext): IrElement = unexpectedElement(element)
override fun visitModuleFragment(declaration: IrModuleFragment, data: ScriptToClassTransformerContext): IrModuleFragment =
override fun visitModuleFragment(declaration: IrModuleFragment, data: ScriptFixLambdasTransformerContext): IrModuleFragment =
unexpectedElement(declaration)
override fun visitExternalPackageFragment(
declaration: IrExternalPackageFragment,
data: ScriptToClassTransformerContext
data: ScriptFixLambdasTransformerContext
): IrExternalPackageFragment =
unexpectedElement(declaration)
override fun visitFile(declaration: IrFile, data: ScriptToClassTransformerContext): IrFile = unexpectedElement(declaration)
override fun visitScript(declaration: IrScript, data: ScriptToClassTransformerContext): IrScript = unexpectedElement(declaration)
override fun visitFile(declaration: IrFile, data: ScriptFixLambdasTransformerContext): IrFile = unexpectedElement(declaration)
override fun visitScript(declaration: IrScript, data: ScriptFixLambdasTransformerContext): IrScript = unexpectedElement(declaration)
override fun visitGetValue(expression: IrGetValue, data: ScriptToClassTransformerContext): IrExpression {
override fun visitGetValue(expression: IrGetValue, data: ScriptFixLambdasTransformerContext): IrExpression {
if (data.valueParameterToReplaceWithScript == expression.symbol.owner) {
val newGetValue = IrGetValueImpl(
expression.startOffset, expression.endOffset,
@@ -497,7 +618,7 @@ private class ScriptFixLambdasTransformer(
} else return super.visitGetValue(expression, data)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: ScriptToClassTransformerContext): IrSimpleFunction =
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: ScriptFixLambdasTransformerContext): IrSimpleFunction =
with(declaration) {
if (data.insideTopLevelDestructuringDeclaration && origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA) {
visibility = DescriptorVisibilities.LOCAL
@@ -513,7 +634,7 @@ private class ScriptFixLambdasTransformer(
}
} as IrSimpleFunction
override fun visitComposite(expression: IrComposite, data: ScriptToClassTransformerContext): IrComposite {
override fun visitComposite(expression: IrComposite, data: ScriptFixLambdasTransformerContext): IrComposite {
val dataForChildren =
if (expression.origin == IrStatementOrigin.DESTRUCTURING_DECLARATION &&
expression.statements.firstIsInstanceOrNull<IrDeclaration>()?.parent == irScriptClass
@@ -35,7 +35,7 @@ open class IrClassImpl(
override var visibility: DescriptorVisibility,
override var modality: Modality,
override val isCompanion: Boolean = false,
override val isInner: Boolean = false,
override var isInner: Boolean = false,
override val isData: Boolean = false,
override val isExternal: Boolean = false,
override val isInline: Boolean = false,
@@ -147,6 +147,7 @@ val IrDeclaration.isLocal: Boolean
}
if (current.isAnonymousObject) return true
if (current is IrScript || (current is IrClass && current.origin == IrDeclarationOrigin.SCRIPT_CLASS)) return true
current = current.parent
}
@@ -0,0 +1,17 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// expected: rv: 42
fun foo() = B.bar()
val life = 42
interface A {
fun bar(): Int
}
val B = object : A {
override fun bar() = life
}
val rv = foo()
@@ -0,0 +1,20 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM
// expected: rv: kotlin.Unit
fun foo() {
B()
}
val b = B()
class A
fun A.ext() = Unit
class B {
fun bar() {
A().ext()
}
}
val rv = foo()
@@ -0,0 +1,21 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM
// expected: rv: kotlin.Unit
class C {
fun foo() {
B()
}
}
class A
fun A.ext() = Unit
class B {
fun bar() {
A().ext()
}
}
val rv = C().foo()
@@ -0,0 +1,14 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// expected: rv: 42
val x = 6
val y = 7
fun foo() = x
class A {
fun bar() = foo() * y
}
val rv = A().bar()
@@ -0,0 +1,11 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// expected: rv: abc
// KT-19423
val used = "abc"
class User {
val property = used // error: Expression is inaccessible from a nested class
}
val rv = User().property
@@ -0,0 +1,18 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM
// expected: rv: 42
fun foo() = B().bar()
val life = 42
class A {
val x = "$life"
}
class B {
fun bar() = A().x
}
val rv = foo()
@@ -0,0 +1,18 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM
// expected: rv: 42
fun foo() = B().bar()
val life = 42
class A {
val x = life
}
class B {
fun bar() = A().x
}
val rv = foo()
@@ -0,0 +1,20 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM
// expected: rv: 42
class C {
fun foo() = B().bar()
}
val life = 42
class A {
val x = life
}
class B {
fun bar() = A().x
}
val rv = C().foo()
@@ -0,0 +1,15 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM, JVM_IR
// expected: rv: <nofield>
// KT-30616
val foo = "hello"
class Bar(val s: String) {
companion object {
fun t() {
Bar(foo)
}
}
}
@@ -0,0 +1,12 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM, JVM_IR
// expected: rv: <nofield>
// KT-30616
val foo = "hello"
enum class Bar(val s: String = foo) {
Eleven("0")
}
@@ -0,0 +1,11 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM, JVM_IR
// expected: rv: <nofield>
// KT-30616
val foo = "hello"
enum class Bar(val s: String) {
Eleven(s = foo)
}
@@ -0,0 +1,18 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM, JVM_IR
// expected: rv: 42
fun foo() = B().bar()
val life = 42
interface A {
val x get() = life
}
class B : A {
fun bar() = x
}
val rv = foo()
@@ -0,0 +1,14 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM, JVM_IR
// expected: rv: 42
fun foo() = B.bar()
val life = 42
object B {
fun bar() = life
}
val rv = foo()
@@ -0,0 +1,18 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM, JVM_IR
// expected: rv: 42
fun foo() = B.bar()
val life = 42
class A {
val x = life
}
object B {
fun bar() = A().x
}
val rv = foo()
@@ -0,0 +1,34 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM_IR
// expected: rv: <nofield>
// This example shows a bug in the old BE
// original issue - KT-49443, this is the reduced example of it.
// Here the old BE manages to compile the script, because it assumes incorrect constructor of the DefaultEachEntryConfiguration class
// on generating code for buildZip.
// The original example from the issue works supposedly because the constructor is not called on the runtime.
// In this example, uncommenting call to buildZip leads to the runtime exception, while uncommenting the call to copy or
// moving DefaultEachEntryConfiguration class definition before ZipHelper breaks codegeneration (somewhat expectedly).
// The JVM IR BE now generates correct error about invalid script instance capturing.
interface I {
fun rename()
}
object ZipHelper {
fun buildZip() {
DefaultEachEntryConfiguration(0).rename()
// 0.copy()
}
}
class DefaultEachEntryConfiguration(val entry: Int) : I {
override fun rename() {
entry.copy()
}
}
fun Int.copy() = Unit
//ZipHelper.buildZip()
@@ -107,7 +107,7 @@ fun generateJUnit3CompilerTests(args: Array<String>) {
}
testClass<AbstractScriptCodegenTest> {
model("codegen/script", extension = "kts")
model("codegen/script", extension = "kts", targetBackend = TargetBackend.JVM)
}
testClass<AbstractCustomScriptCodegenTest> {
@@ -9,6 +9,7 @@ import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
@@ -22,7 +23,7 @@ import java.util.regex.Pattern;
@RunWith(JUnit3RunnerWithInners.class)
public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@TestMetadata("adder.kts")
@@ -31,7 +32,7 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest {
}
public void testAllFilesPresentInScript() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/script"), Pattern.compile("^(.+)\\.kts$"), null, true);
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/script"), Pattern.compile("^(.+)\\.kts$"), null, TargetBackend.JVM, true);
}
@TestMetadata("classLiteralInsideFunction.kts")
@@ -183,4 +184,92 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest {
public void testTopLevelTypealias() throws Exception {
runTest("compiler/testData/codegen/script/topLevelTypealias.kts");
}
@TestMetadata("compiler/testData/codegen/script/scriptInstanceCapturing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ScriptInstanceCapturing extends AbstractScriptCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInScriptInstanceCapturing() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/script/scriptInstanceCapturing"), Pattern.compile("^(.+)\\.kts$"), null, TargetBackend.JVM, true);
}
@TestMetadata("anonymousObjectCapturesProperty.kts")
public void testAnonymousObjectCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/anonymousObjectCapturesProperty.kts");
}
@TestMetadata("classCapturesExtensionIndirect.kts")
public void testClassCapturesExtensionIndirect() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesExtensionIndirect.kts");
}
@TestMetadata("classCapturesExtensionIndirect2x.kts")
public void testClassCapturesExtensionIndirect2x() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesExtensionIndirect2x.kts");
}
@TestMetadata("classCapturesFunction.kts")
public void testClassCapturesFunction() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesFunction.kts");
}
@TestMetadata("classCapturesProperty.kts")
public void testClassCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesProperty.kts");
}
@TestMetadata("classCapturesPropertyInStringTemplate.kts")
public void testClassCapturesPropertyInStringTemplate() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesPropertyInStringTemplate.kts");
}
@TestMetadata("classCapturesPropertyIndirect.kts")
public void testClassCapturesPropertyIndirect() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesPropertyIndirect.kts");
}
@TestMetadata("classCapturesPropertyIndirect2x.kts")
public void testClassCapturesPropertyIndirect2x() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesPropertyIndirect2x.kts");
}
@TestMetadata("companionCapturesProperty.kts")
public void testCompanionCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/companionCapturesProperty.kts");
}
@TestMetadata("enumCapturesProperty.kts")
public void testEnumCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/enumCapturesProperty.kts");
}
@TestMetadata("enumEntryCapturesProperty.kts")
public void testEnumEntryCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/enumEntryCapturesProperty.kts");
}
@TestMetadata("interfaceCapturesProperty.kts")
public void testInterfaceCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/interfaceCapturesProperty.kts");
}
@TestMetadata("objectCapturesProperty.kts")
public void testObjectCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/objectCapturesProperty.kts");
}
@TestMetadata("objectCapturesPropertyIndirect.kts")
public void testObjectCapturesPropertyIndirect() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/objectCapturesPropertyIndirect.kts");
}
@TestMetadata("objectCapturesPropertyViaExtension.kts")
public void testObjectCapturesPropertyViaExtension() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/objectCapturesPropertyViaExtension.kts");
}
}
}
@@ -184,4 +184,92 @@ public class IrScriptCodegenTestGenerated extends AbstractIrScriptCodegenTest {
public void testTopLevelTypealias() throws Exception {
runTest("compiler/testData/codegen/script/topLevelTypealias.kts");
}
@TestMetadata("compiler/testData/codegen/script/scriptInstanceCapturing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ScriptInstanceCapturing extends AbstractIrScriptCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInScriptInstanceCapturing() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/script/scriptInstanceCapturing"), Pattern.compile("^(.+)\\.kts$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("anonymousObjectCapturesProperty.kts")
public void testAnonymousObjectCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/anonymousObjectCapturesProperty.kts");
}
@TestMetadata("classCapturesExtensionIndirect.kts")
public void testClassCapturesExtensionIndirect() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesExtensionIndirect.kts");
}
@TestMetadata("classCapturesExtensionIndirect2x.kts")
public void testClassCapturesExtensionIndirect2x() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesExtensionIndirect2x.kts");
}
@TestMetadata("classCapturesFunction.kts")
public void testClassCapturesFunction() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesFunction.kts");
}
@TestMetadata("classCapturesProperty.kts")
public void testClassCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesProperty.kts");
}
@TestMetadata("classCapturesPropertyInStringTemplate.kts")
public void testClassCapturesPropertyInStringTemplate() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesPropertyInStringTemplate.kts");
}
@TestMetadata("classCapturesPropertyIndirect.kts")
public void testClassCapturesPropertyIndirect() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesPropertyIndirect.kts");
}
@TestMetadata("classCapturesPropertyIndirect2x.kts")
public void testClassCapturesPropertyIndirect2x() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/classCapturesPropertyIndirect2x.kts");
}
@TestMetadata("companionCapturesProperty.kts")
public void testCompanionCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/companionCapturesProperty.kts");
}
@TestMetadata("enumCapturesProperty.kts")
public void testEnumCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/enumCapturesProperty.kts");
}
@TestMetadata("enumEntryCapturesProperty.kts")
public void testEnumEntryCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/enumEntryCapturesProperty.kts");
}
@TestMetadata("interfaceCapturesProperty.kts")
public void testInterfaceCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/interfaceCapturesProperty.kts");
}
@TestMetadata("objectCapturesProperty.kts")
public void testObjectCapturesProperty() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/objectCapturesProperty.kts");
}
@TestMetadata("objectCapturesPropertyIndirect.kts")
public void testObjectCapturesPropertyIndirect() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/objectCapturesPropertyIndirect.kts");
}
@TestMetadata("objectCapturesPropertyViaExtension.kts")
public void testObjectCapturesPropertyViaExtension() throws Exception {
runTest("compiler/testData/codegen/script/scriptInstanceCapturing/objectCapturesPropertyViaExtension.kts");
}
}
}