JVM_IR: "fix" reified type parameter scope check

where "fix" means "work around a bug that is much harder to fix". When
lambdas are extracted into the nearest class, captured type parameters
are not transformed into type parameters of the new method; because of
this, to check whether a reified type parameter is captured by a method
we need to check the outermost named function, not the current function.
This commit is contained in:
pyos
2019-09-20 10:58:55 +02:00
committed by max-kammerer
parent c70b2e3e4b
commit 301e3d27fd
4 changed files with 28 additions and 10 deletions
@@ -100,7 +100,7 @@ class ExpressionCodegen(
override val frameMap: IrFrameMap,
val mv: InstructionAdapter,
val classCodegen: ClassCodegen,
val isInlineLambda: Boolean = false
val inlinedInto: ExpressionCodegen?
) : IrElementVisitor<PromisedValue, BlockInfo>, BaseExpressionCodegen {
var finallyDepth = 0
@@ -202,7 +202,7 @@ class ExpressionCodegen(
if (state.isParamAssertionsDisabled)
return
val notCallableFromJava = isInlineLambda ||
val notCallableFromJava = inlinedInto != null ||
Visibilities.isPrivate(irFunction.visibility) ||
irFunction.origin.isSynthetic ||
// TODO: refine this condition to not generate nullability assertions on parameters
@@ -314,7 +314,7 @@ class ExpressionCodegen(
visitStatementContainer(expression, data).coerce(expression.type)
override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue {
return visitFunctionAccess(expression.createSuspendFunctionCallViewIfNeeded(context, irFunction, isInlineLambda), data)
return visitFunctionAccess(expression.createSuspendFunctionCallViewIfNeeded(context, irFunction, inlinedInto != null), data)
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: BlockInfo): PromisedValue {
@@ -1012,7 +1012,26 @@ class ExpressionCodegen(
override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) {
require(typeParameter is IrTypeParameterSymbol)
if (typeParameter.owner.parent != irFunction) {
// This is a hack to work around the problem in LocalDeclarationsLowering. Specifically, suppose an inline
// lambda uses a reified type parameter declared by a function:
//
// object {
// inline fun <reified T : Any> f() = run { T::class.java.getName() }
// }
//
// LocalDeclarationsLowering would extract that lambda into a method of the enclosing type, but will not create
// a reified type parameter in it (in fact, the lambda method isn't even marked as inline):
//
// object {
// /* static */ private fun `f$lambda-0`() = T::class.java.getName()
// inline fun <reified T : Any> f() = run(::`f$lambda-0`)
// }
//
// The parent of the type parameter then is not `irFunction` (i.e. the lambda itself), but the function
// it is inlined into.
//
// TODO make LocalDeclarationsLowering handle captured type parameters and only compare with `irFunction`.
if (generateSequence(this) { it.inlinedInto }.none { it.irFunction == typeParameter.owner.parent }) {
classCodegen.reifiedTypeParametersUsages.addUsedReifiedParameter(typeParameter.owner.name.asString())
}
}
@@ -1039,7 +1058,7 @@ class ExpressionCodegen(
}
fun isFinallyMarkerRequired(): Boolean {
return irFunction.isInline || isInlineLambda
return irFunction.isInline || inlinedInto != null
}
private val IrType.isReifiedTypeParameter: Boolean
@@ -30,7 +30,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
open class FunctionCodegen(
private val irFunction: IrFunction,
private val classCodegen: ClassCodegen,
private val isInlineLambda: Boolean = false
private val inlinedInto: ExpressionCodegen? = null
) {
val context = classCodegen.context
val state = classCodegen.state
@@ -95,7 +95,7 @@ open class FunctionCodegen(
)
else -> methodVisitor
}
ExpressionCodegen(functionView, signature, frameMap, InstructionAdapter(methodVisitor), classCodegen, isInlineLambda).generate()
ExpressionCodegen(functionView, signature, frameMap, InstructionAdapter(methodVisitor), classCodegen, inlinedInto).generate()
methodVisitor.visitMaxs(-1, -1)
continuationClassBuilder?.done()
}
@@ -74,7 +74,7 @@ class IrSourceCompilerForInline(
private fun makeInlineNode(function: IrFunction, classCodegen: ClassCodegen, isLambda: Boolean): SMAPAndMethodNode {
var node: MethodNode? = null
val functionCodegen = object : FunctionCodegen(function, classCodegen, isLambda) {
val functionCodegen = object : FunctionCodegen(function, classCodegen, codegen.takeIf { isLambda }) {
override fun createMethod(flags: Int, signature: JvmMethodGenericSignature): MethodVisitor {
val asmMethod = signature.asmMethod
node = MethodNode(Opcodes.API_VERSION, flags, asmMethod.name, asmMethod.descriptor, signature.genericsSignature, null)
@@ -134,7 +134,7 @@ class IrSourceCompilerForInline(
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
ExpressionCodegen(
codegen.irFunction, codegen.signature, codegen.frameMap, InstructionAdapter(finallyNode), codegen.classCodegen,
codegen.isInlineLambda
codegen.inlinedInto
).also {
it.finallyDepth = curFinallyDepth
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME