From d5ace43614dda1fed09e55c0303d40b6eb9f097d Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 3 Apr 2020 16:31:00 +0300 Subject: [PATCH] KT-37986 Force boxing of inline class returned from function reference KT-37998 Provide KotlinType for safe call --- .../kotlin/codegen/ExpressionCodegen.java | 23 ++++++++++------- .../jetbrains/kotlin/codegen/StackValue.java | 4 +-- .../kotlin/codegen/state/KotlinTypeMapper.kt | 22 ++++++++++++---- .../ir/FirBlackBoxCodegenTestGenerated.java | 10 ++++++++ .../callableReferences/kt37986.kt | 25 +++++++++++++++++++ .../codegen/box/inlineClasses/kt37998.kt | 13 ++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 ++++++++ .../LightAnalysisModeTestGenerated.java | 10 ++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 ++++++++ .../IrJsCodegenBoxTestGenerated.java | 10 ++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 10 ++++++++ 11 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt create mode 100644 compiler/testData/codegen/box/inlineClasses/kt37998.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index be0eaa7b98c..dfda7cc7100 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1033,13 +1033,19 @@ public class ExpressionCodegen extends KtVisitor impleme ); ClosureCodegen coroutineCodegen = CoroutineCodegenForLambda.create(this, descriptor, declaration, cv); - ClosureContext closureContext = descriptor.isSuspend() ? this.context.intoCoroutineClosure( - CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(descriptor, state), - descriptor, this, state.getTypeMapper() - ) : this.context.intoClosure(descriptor, this, typeMapper); - ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen( - state, declaration, samType, closureContext, functionReferenceCall, strategy, parentCodegen, cv - ); + ClosureContext closureContext = + descriptor.isSuspend() + ? this.context.intoCoroutineClosure( + CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(descriptor, state), + descriptor, this, state.getTypeMapper() + ) + : this.context.intoClosure(descriptor, this, typeMapper); + ClosureCodegen closureCodegen = + coroutineCodegen != null + ? coroutineCodegen + : new ClosureCodegen( + state, declaration, samType, closureContext, functionReferenceCall, strategy, parentCodegen, cv + ); closureCodegen.generate(); @@ -3399,7 +3405,7 @@ public class ExpressionCodegen extends KtVisitor impleme StackValue result; if (!isPrimitive(expressionType(expression.getReceiverExpression()))) { - result = new StackValue.SafeFallback(type, ifnull, newReceiver); + result = new StackValue.SafeFallback(type, kotlinType, ifnull, newReceiver); } else { result = newReceiver; } @@ -4363,7 +4369,6 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.none(); } - @Override public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) { return initializeDestructuringDeclaration(multiDeclaration, false); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 890af120b29..601deaa2432 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -2308,8 +2308,8 @@ public abstract class StackValue { @Nullable private final Label ifNull; - public SafeFallback(@NotNull Type type, @Nullable Label ifNull, StackValue receiver) { - super(type, null, false, false, receiver, true); + public SafeFallback(@NotNull Type type, @Nullable KotlinType kotlinType, @Nullable Label ifNull, StackValue receiver) { + super(type, kotlinType, false, false, receiver, true); this.ifNull = ifNull; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index 3a59f0ca52e..b951ae1cff6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor @@ -41,10 +42,7 @@ import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider.IncrementalMultifileClassPackageFragment import org.jetbrains.kotlin.name.* -import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFunctionLiteral -import org.jetbrains.kotlin.psi.KtLambdaExpression +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getOutermostParenthesizerOrThis import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector import org.jetbrains.kotlin.resolve.* @@ -66,6 +64,7 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultAnnotation import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.types.* @@ -936,7 +935,20 @@ class KotlinTypeMapper @JvmOverloads constructor( private fun forceBoxedReturnType(descriptor: FunctionDescriptor): Boolean { if (isBoxMethodForInlineClass(descriptor)) return true - return isJvmPrimitiveOrInlineClass(descriptor.returnType!!) && + val returnType = descriptor.returnType!! + + // Crude hack to determine whether it is an AnonymousFunctionDescriptor created for callable reference. + // Ideally, we should force return type boxing for all anonymous functions returning an inline class value + // (so that the result is boxed properly, since technically it is a covariant override of a corresponding generic 'invoke'). + // But, unfortunately, we can't do so right now, because it'd break binary compatibility for lambdas returning 'Result'. + if (descriptor is AnonymousFunctionDescriptor) { + val source = descriptor.source + if (source is KotlinSourceElement && source.psi is KtCallableReferenceExpression && returnType.isInlineClassType()) { + return true + } + } + + return isJvmPrimitiveOrInlineClass(returnType) && getAllOverriddenDescriptors(descriptor).any { !isJvmPrimitiveOrInlineClass(it.returnType!!) } } diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 1eb5ee43f17..07e3cc51801 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -12534,6 +12534,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/inlineClasses/kt34268.kt"); } + @TestMetadata("kt37998.kt") + public void testKt37998() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); @@ -12898,6 +12903,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testInlineClassTypeTopLevelVar() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/inlineClassTypeTopLevelVar.kt"); } + + @TestMetadata("kt37986.kt") + public void testKt37986() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/contextsAndAccessors") diff --git a/compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt b/compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt new file mode 100644 index 00000000000..c71208658b1 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt @@ -0,0 +1,25 @@ +// IGNORE_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR + +inline class R(val x: Any) + +fun useR(r: R) { + if (r.x as String != "OK") throw AssertionError("$r") +} + +fun useR0(fn: () -> R) { + useR(fn()) +} + +fun useR1(r: R, fn: (R) -> R) { + useR(fn(r)) +} + +fun fnWithDefaultR(r: R = R("OK")) = r + +fun box(): String { + useR0(::fnWithDefaultR) + useR1(R("OK"), ::fnWithDefaultR) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/inlineClasses/kt37998.kt b/compiler/testData/codegen/box/inlineClasses/kt37998.kt new file mode 100644 index 00000000000..51d881322bb --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/kt37998.kt @@ -0,0 +1,13 @@ +inline class Z(val x: Int) + +class A { + fun foo() = Z(42) +} + +fun test(a: A?) = a?.foo()!! + +fun box(): String { + val t = test(A()) + if (t.x != 42) throw AssertionError("$t") + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 740d4762c7f..d5e74b2aee7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13724,6 +13724,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inlineClasses/kt34268.kt"); } + @TestMetadata("kt37998.kt") + public void testKt37998() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); @@ -14088,6 +14093,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testInlineClassTypeTopLevelVar() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/inlineClassTypeTopLevelVar.kt"); } + + @TestMetadata("kt37986.kt") + public void testKt37986() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/contextsAndAccessors") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 4b38d465199..cdafed18ae3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13729,6 +13729,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inlineClasses/kt34268.kt"); } + @TestMetadata("kt37998.kt") + public void testKt37998() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); @@ -14088,6 +14093,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testInlineClassTypeTopLevelVar() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/inlineClassTypeTopLevelVar.kt"); } + + @TestMetadata("kt37986.kt") + public void testKt37986() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/contextsAndAccessors") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 0d648544701..aff7f468463 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12534,6 +12534,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inlineClasses/kt34268.kt"); } + @TestMetadata("kt37998.kt") + public void testKt37998() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); @@ -12898,6 +12903,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testInlineClassTypeTopLevelVar() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/inlineClassTypeTopLevelVar.kt"); } + + @TestMetadata("kt37986.kt") + public void testKt37986() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/contextsAndAccessors") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index f36b4a43a84..b754f0edf1d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -10764,6 +10764,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inlineClasses/kt34268.kt"); } + @TestMetadata("kt37998.kt") + public void testKt37998() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); @@ -11113,6 +11118,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testInlineClassTypeTopLevelVar() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/inlineClassTypeTopLevelVar.kt"); } + + @TestMetadata("kt37986.kt") + public void testKt37986() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/contextsAndAccessors") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index d137c952224..6858b091074 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -10829,6 +10829,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inlineClasses/kt34268.kt"); } + @TestMetadata("kt37998.kt") + public void testKt37998() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); + } + @TestMetadata("mangledDefaultParameterFunction.kt") public void testMangledDefaultParameterFunction() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); @@ -11178,6 +11183,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testInlineClassTypeTopLevelVar() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/inlineClassTypeTopLevelVar.kt"); } + + @TestMetadata("kt37986.kt") + public void testKt37986() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/callableReferences/kt37986.kt"); + } } @TestMetadata("compiler/testData/codegen/box/inlineClasses/contextsAndAccessors")