Unbox inline class parameter of lambda if underlying type is Any or Any?

The inline class is boxed when we pass it as lambda argument, now we
unbox it. If the underlying type is not Any or Any?, bridge method does
the unboxing.

 #KT-32450 Fixed
 #KT-39923 Fixed
 #KT-32228 Fixed
 #KT-40282 Fixed
This commit is contained in:
Ilmir Usmanov
2020-10-20 19:38:06 +02:00
parent 752f6d8f72
commit a775fa195b
59 changed files with 4371 additions and 0 deletions
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
import org.jetbrains.kotlin.metadata.ProtoBuf;
import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
@@ -367,6 +368,11 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
value = StackValue.local(slot, type, bridgeParameterKotlinTypes.get(i));
slot += type.getSize();
}
if (InlineClassesCodegenUtilKt.isInlineClassWithUnderlyingTypeAnyOrAnyN(parameterType) &&
functionReferenceCall == null
) {
parameterType = InlineClassesUtilsKt.unsubstitutedUnderlyingParameter(parameterType).getType();
}
value.put(typeMapper.mapType(calleeParameter), parameterType, iv);
}
@@ -1995,6 +1995,21 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
StackValue localOrCaptured = findLocalOrCapturedValue(descriptor);
if (localOrCaptured != null) {
if (descriptor instanceof ValueParameterDescriptor) {
KotlinType inlineClassType = ((ValueParameterDescriptor) descriptor).getType();
if (InlineClassesCodegenUtilKt.isInlineClassWithUnderlyingTypeAnyOrAnyN(inlineClassType) &&
InlineClassesCodegenUtilKt.isGenericParameter((CallableDescriptor) descriptor) &&
// TODO: HACK around bridgeGenerationCrossinline
!(context instanceof InlineLambdaContext) &&
// Do not unbox parameters of suspend lambda, they are unboxed in `invoke` method
!CoroutineCodegenUtilKt.isInvokeSuspendOfLambda(context.getFunctionDescriptor())
) {
KotlinType underlyingType = InlineClassesUtilsKt.underlyingRepresentation(
(ClassDescriptor) inlineClassType.getConstructor().getDeclarationDescriptor()).getType();
return StackValue.underlyingValueOfInlineClass(
typeMapper.mapType(underlyingType), underlyingType, localOrCaptured);
}
}
return localOrCaptured;
}
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.underlyingRepresentation
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
fun KotlinType.isInlineClassWithUnderlyingTypeAnyOrAnyN(): Boolean {
if (!isInlineClassType()) return false
val classDescriptor = constructor.declarationDescriptor as? ClassDescriptor ?: return false
return classDescriptor.underlyingRepresentation()?.type?.isAnyOrNullableAny() == true
}
fun CallableDescriptor.isGenericParameter(): Boolean {
if (this !is ValueParameterDescriptor) return false
if (containingDeclaration is AnonymousFunctionDescriptor) return true
val index = containingDeclaration.valueParameters.indexOf(this)
return containingDeclaration.overriddenDescriptors.any { it.original.valueParameters[index].type.isTypeParameter() }
}