Ignore reified type parameters when regenerating objects from lambdas

All reified type parameters referenced by objects in non-default lambdas
are from outside the inline call, thus they cannot be substituted yet.
This means if the only reason for object regeneration is reification,
then regeneration isn't actually necessary.

E.g. in this code:

    inline fun <reified T> f(x: () -> Unit) = x()
    inline fun <reified V> g() = f<V> { { println(V::class.simpleName) }() }

we first inline the lambda into f(), then inline f()-with-lambda into g().
Because the object inside the lambda captures nothing from outside g(),
the original class can be used both times.

This brings the JVM_IR backend into complete compliance with KT-28064.
This commit is contained in:
pyos
2020-03-18 13:13:32 +01:00
committed by max-kammerer
parent 1fd3ac046a
commit 54e725668f
@@ -859,9 +859,20 @@ class MethodInliner(
needReification: Boolean,
capturesAnonymousObjectThatMustBeRegenerated: Boolean
): AnonymousObjectTransformationInfo {
// In objects inside non-default lambdas, all reified type parameters are free (not from the function
// we're inlining into) so there's nothing to reify:
//
// inline fun <reified T> f(x: () -> KClass<T> = { { T::class }() }) = x()
// fun a() = f<Int>()
// fun b() = f<Int> { { Int::class }() } // non-default lambda
// inline fun <reified V> c() = f<V> { { V::class }() }
//
// -- in a(), the default lambda captures T so a regeneration is needed; but in b() and c(), the non-default
// lambda cannot possibly reference it, while V is not yet bound so regenerating the object while inlining
// the lambda into f() is pointless.
val inNonDefaultLambda = inliningContext.isInliningLambda && inliningContext.lambdaInfo !is DefaultLambda
val info = AnonymousObjectTransformationInfo(
anonymousType, needReification, lambdaMapping,
anonymousType, needReification && !inNonDefaultLambda, lambdaMapping,
inliningContext.classRegeneration,
isAlreadyRegenerated(anonymousType),
desc,