From 0da23198e60feaf24ba4f9f2516bcd472f2c27d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Wed, 8 Dec 2021 11:17:58 +0100 Subject: [PATCH] JVM_IR: Add null-checks in SAM wrapper constructors (KT-50108) --- .../FirBlackBoxCodegenTestGenerated.java | 12 +++++++ .../backend/jvm/codegen/ExpressionCodegen.kt | 4 +-- compiler/testData/codegen/box/sam/kt50108.kt | 32 +++++++++++++++++++ .../testData/codegen/box/sam/kt50108_java.kt | 23 +++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 +++++++ .../IrBlackBoxCodegenTestGenerated.java | 12 +++++++ .../LightAnalysisModeTestGenerated.java | 10 ++++++ 7 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/box/sam/kt50108.kt create mode 100644 compiler/testData/codegen/box/sam/kt50108_java.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 878f2ac4279..ca6d8e329da 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -44609,6 +44609,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/sam/kt49226.kt"); } + @Test + @TestMetadata("kt50108.kt") + public void testKt50108() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108.kt"); + } + + @Test + @TestMetadata("kt50108_java.kt") + public void testKt50108_java() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108_java.kt"); + } + @Test @TestMetadata("kt50171.kt") public void testKt50171() throws Exception { diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 8dd17b3deed..74b139ec8ff 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -291,9 +291,7 @@ class ExpressionCodegen( irFunction.origin.isSynthetic || // TODO: refine this condition to not generate nullability assertions on parameters // corresponding to captured variables and anonymous object super constructor arguments - (irFunction is IrConstructor && - (irFunction.parentAsClass.isAnonymousObject || - irFunction.parentAsClass.origin == IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION)) || + (irFunction is IrConstructor && irFunction.parentAsClass.isAnonymousObject) || // TODO: Implement this as a lowering, so that we can more easily exclude generated methods. irFunction.origin == JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD || // Although these are accessible from Java, the functions they bridge to already have the assertions. diff --git a/compiler/testData/codegen/box/sam/kt50108.kt b/compiler/testData/codegen/box/sam/kt50108.kt new file mode 100644 index 00000000000..5f9782c995c --- /dev/null +++ b/compiler/testData/codegen/box/sam/kt50108.kt @@ -0,0 +1,32 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM + +fun interface IFoo { + fun foo(): String +} + +abstract class Base { + abstract val fn: () -> String + + init { + // This should throw a NPE, since the constructor of the IFoo + // SAM wrapper expects a non-nullable function type. + // + // In the JVM backend this expression evaluates to `null` instead, + // which isn't a valid result according to the type system. + IFoo(fn) + } +} + +class Derived : Base() { + override val fn: () -> String = { "OK" } +} + +fun box(): String { + try { + Derived() + } catch (e: java.lang.NullPointerException) { + return "OK" + } + return "Fail" +} diff --git a/compiler/testData/codegen/box/sam/kt50108_java.kt b/compiler/testData/codegen/box/sam/kt50108_java.kt new file mode 100644 index 00000000000..f110dcdbe37 --- /dev/null +++ b/compiler/testData/codegen/box/sam/kt50108_java.kt @@ -0,0 +1,23 @@ +// TARGET_BACKEND: JVM +// FILE: test.kt +fun interface IFoo { + fun foo(s: String) +} + +val foo = IFoo {} + +fun box(): String { + try { + J.callWithNull(foo) + return "J.callWithNull(foo) should throw NPE" + } catch (e: NullPointerException) { + return "OK" + } +} + +// FILE: J.java +public class J { + public static void callWithNull(IFoo iFoo) { + iFoo.foo(null); + } +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 909b44b8df1..5442e1c0659 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -44063,6 +44063,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/sam/kt49226.kt"); } + @Test + @TestMetadata("kt50108.kt") + public void testKt50108() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108.kt"); + } + + @Test + @TestMetadata("kt50108_java.kt") + public void testKt50108_java() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108_java.kt"); + } + @Test @TestMetadata("kt50171.kt") public void testKt50171() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 26618ee19b8..5ff0ca6abe0 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -44609,6 +44609,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/sam/kt49226.kt"); } + @Test + @TestMetadata("kt50108.kt") + public void testKt50108() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108.kt"); + } + + @Test + @TestMetadata("kt50108_java.kt") + public void testKt50108_java() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108_java.kt"); + } + @Test @TestMetadata("kt50171.kt") public void testKt50171() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c055720246e..39a65f3e489 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -35460,6 +35460,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class Sam extends AbstractLightAnalysisModeTest { + @TestMetadata("kt50108.kt") + public void ignoreKt50108() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -35593,6 +35598,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/sam/kt49226.kt"); } + @TestMetadata("kt50108_java.kt") + public void testKt50108_java() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50108_java.kt"); + } + @TestMetadata("kt50171.kt") public void testKt50171() throws Exception { runTest("compiler/testData/codegen/box/sam/kt50171.kt");