From 4e261cc35845d5c980c08e00acb259364c27f571 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 23 Dec 2020 17:19:02 +0300 Subject: [PATCH] JVM_IR KT-24258 fix NPE message for delegated properties --- .../ir/FirBlackBoxCodegenTestGenerated.java | 10 ++++ .../backend/jvm/lower/TypeOperatorLowering.kt | 7 ++- .../generators/DelegatedPropertyGenerator.kt | 51 +++++++++++-------- .../javaInterop/notNullAssertions/kt24258.kt | 28 ++++++++++ .../notNullAssertions/kt24258nn.kt | 30 +++++++++++ compiler/testData/ir/sourceRanges/kt24258.kt | 15 ++++++ compiler/testData/ir/sourceRanges/kt24258.txt | 22 ++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 ++++ .../LightAnalysisModeTestGenerated.java | 10 ++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 ++++ .../ir/IrSourceRangesTestCaseGenerated.java | 5 ++ 11 files changed, 175 insertions(+), 23 deletions(-) create mode 100644 compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt create mode 100644 compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt create mode 100644 compiler/testData/ir/sourceRanges/kt24258.kt create mode 100644 compiler/testData/ir/sourceRanges/kt24258.txt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 7b8e3e84cb6..ccecb20a7ec 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -16335,6 +16335,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt18911.kt"); } + @TestMetadata("kt24258.kt") + public void testKt24258() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt"); + } + + @TestMetadata("kt24258nn.kt") + public void testKt24258nn() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt"); + } + @TestMetadata("localEntities.kt") public void testLocalEntities() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/localEntities.kt"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt index e272e123bfa..e6400d94e35 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/TypeOperatorLowering.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol -import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.isInlined import org.jetbrains.kotlin.ir.util.render @@ -148,7 +147,7 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil IrTypeOperator.IMPLICIT_NOTNULL -> { val owner = scope.scopeOwnerSymbol.owner - val source = if (owner is IrFunction && owner.origin == IrDeclarationOrigin.DELEGATED_MEMBER) { + val source = if (owner is IrFunction && owner.isDelegated()) { "${owner.name.asString()}(...)" } else { val (startOffset, endOffset) = expression.extents() @@ -173,6 +172,10 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil } } + private fun IrFunction.isDelegated() = + origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR || + origin == IrDeclarationOrigin.DELEGATED_MEMBER + private fun IrElement.extents(): Pair { var startOffset = UNDEFINED_OFFSET var endOffset = UNDEFINED_OFFSET diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt index 6175f70a369..f9ee95beb29 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irReturn @@ -27,6 +28,7 @@ import org.jetbrains.kotlin.ir.descriptors.IrLocalDelegatedPropertyDelegateDescr import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol @@ -391,21 +393,17 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D irPropertyReference: IrCallableReference<*> ): IrBody = with(createBodyGenerator(irGetter.symbol)) { - val startOffset = ktDelegate.startOffsetSkippingComments - val endOffset = ktDelegate.endOffset + val ktDelegateExpression = ktDelegate.expression!! + val startOffset = ktDelegateExpression.startOffsetSkippingComments + val endOffset = ktDelegateExpression.endOffset irBlockBody(startOffset, endOffset) { val statementGenerator = createStatementGenerator() val conventionMethodResolvedCall = getOrFail(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor) val conventionMethodCall = statementGenerator.pregenerateCall(conventionMethodResolvedCall) conventionMethodCall.setExplicitReceiverValue(delegateReceiverValue) + updateNullThisRefValue(conventionMethodCall) conventionMethodCall.irValueArgumentsByIndex[1] = irPropertyReference - +irReturn( - CallGenerator(statementGenerator).generateCall( - startOffset, - endOffset, - conventionMethodCall - ) - ) + +irReturn(CallGenerator(statementGenerator).generateCall(startOffset, endOffset, conventionMethodCall)) } } @@ -415,18 +413,29 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D setterDescriptor: VariableAccessorDescriptor, delegateReceiverValue: IntermediateValue, irPropertyReference: IrCallableReference<*> - ): IrBody = with(createBodyGenerator(irSetter.symbol)) { - val startOffset = ktDelegate.startOffsetSkippingComments - val endOffset = ktDelegate.endOffset - irBlockBody(startOffset, endOffset) { - val statementGenerator = createStatementGenerator() - val conventionMethodResolvedCall = getOrFail(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor) - val conventionMethodCall = statementGenerator.pregenerateCall(conventionMethodResolvedCall) - conventionMethodCall.setExplicitReceiverValue(delegateReceiverValue) - conventionMethodCall.irValueArgumentsByIndex[1] = irPropertyReference - val irSetterParameter = irSetter.valueParameters[0] - conventionMethodCall.irValueArgumentsByIndex[2] = irGet(irSetterParameter.type, irSetterParameter.symbol) - +irReturn(CallGenerator(statementGenerator).generateCall(startOffset, endOffset, conventionMethodCall)) + ): IrBody = + with(createBodyGenerator(irSetter.symbol)) { + val ktDelegateExpression = ktDelegate.expression!! + val startOffset = ktDelegateExpression.startOffsetSkippingComments + val endOffset = ktDelegateExpression.endOffset + irBlockBody(startOffset, endOffset) { + val statementGenerator = createStatementGenerator() + val conventionMethodResolvedCall = getOrFail(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor) + val conventionMethodCall = statementGenerator.pregenerateCall(conventionMethodResolvedCall) + conventionMethodCall.setExplicitReceiverValue(delegateReceiverValue) + updateNullThisRefValue(conventionMethodCall) + conventionMethodCall.irValueArgumentsByIndex[1] = irPropertyReference + val irSetterParameter = irSetter.valueParameters[0] + conventionMethodCall.irValueArgumentsByIndex[2] = irGet(irSetterParameter) + +irReturn(CallGenerator(statementGenerator).generateCall(startOffset, endOffset, conventionMethodCall)) + } + } + + private fun updateNullThisRefValue(conventionMethodCall: CallBuilder) { + val arg0 = conventionMethodCall.irValueArgumentsByIndex[0] + if (arg0 is IrConstImpl<*> && arg0.kind == IrConstKind.Null) { + conventionMethodCall.irValueArgumentsByIndex[0] = + IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.nothingNType) } } } diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt new file mode 100644 index 00000000000..989964b04be --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt @@ -0,0 +1,28 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// WITH_RUNTIME +// FILE: kt24258.kt + +val lazyNullString: String by lazy { J.nullString() } + + +fun testLazyNullString() { + try { + val s: String = lazyNullString + throw Exception("'val s: String = lazyNullString' should throw NullPointerException") + } catch (e: NullPointerException) { + } +} + +fun box(): String { + testLazyNullString() + + return "OK" +} + +// FILE: J.java +public class J { + public static String nullString() { + return null; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt new file mode 100644 index 00000000000..cff3b9d8d14 --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt @@ -0,0 +1,30 @@ +// TARGET_BACKEND: JVM +// WITH_RUNTIME +// FILE: kt24258nn.kt + +val lazyNotNullString: String by lazy { J.nullNotNullString() } + + +fun testLazyNullNotNullString() { + try { + val s: String = lazyNotNullString + throw Exception("'val s: String = lazyNotNullString' should throw NullPointerException") + } catch (e: NullPointerException) { + } +} + +fun box(): String { + testLazyNullNotNullString() + + return "OK" +} + +// FILE: J.java +import org.jetbrains.annotations.NotNull; + +public class J { + @NotNull + public static String nullNotNullString() { + return null; + } +} \ No newline at end of file diff --git a/compiler/testData/ir/sourceRanges/kt24258.kt b/compiler/testData/ir/sourceRanges/kt24258.kt new file mode 100644 index 00000000000..ea2d708f522 --- /dev/null +++ b/compiler/testData/ir/sourceRanges/kt24258.kt @@ -0,0 +1,15 @@ +// WITH_RUNTIME +// FILE: kt24258.kt + +val lazyNullString: String by lazy { J.nullString() } + +fun testLazyNullString() { + val s: String = lazyNullString +} + +// FILE: J.java +public class J { + public static String nullString() { + return null; + } +} \ No newline at end of file diff --git a/compiler/testData/ir/sourceRanges/kt24258.txt b/compiler/testData/ir/sourceRanges/kt24258.txt new file mode 100644 index 00000000000..b168ecfeb0a --- /dev/null +++ b/compiler/testData/ir/sourceRanges/kt24258.txt @@ -0,0 +1,22 @@ +@0:0..9:0 FILE fqName: fileName:/kt24258.kt + @3:0..53 PROPERTY name:lazyNullString visibility:public modality:FINAL [delegated,val] + @3:27..53 FIELD PROPERTY_DELEGATE name:lazyNullString$delegate type:kotlin.Lazy<@[FlexibleNullability] kotlin.String?> visibility:private [final,static] + @3:30..53 EXPRESSION_BODY + @3:30..53 CALL 'public final fun lazy (initializer: kotlin.Function0): kotlin.Lazy declared in kotlin' type=kotlin.Lazy<@[FlexibleNullability] kotlin.String?> origin=null + @3:35..53 FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA + @3:35..53 FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? + @3:37..51 BLOCK_BODY + @3:39..51 RETURN type=kotlin.Nothing from='local final fun (): @[FlexibleNullability] kotlin.String? declared in .lazyNullString$delegate' + @3:39..51 CALL 'public open fun nullString (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + @3:27..53 FUN DELEGATED_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:kotlin.String + @3:30..53 BLOCK_BODY + @3:30..53 RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in ' + @3:30..53 TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String + @3:30..53 CALL 'public final fun getValue (thisRef: kotlin.Any?, property: kotlin.reflect.KProperty<*>): T of kotlin.getValue [inline,operator] declared in kotlin' type=@[FlexibleNullability] kotlin.String? origin=null + @3:27..53 GET_FIELD 'FIELD PROPERTY_DELEGATE name:lazyNullString$delegate type:kotlin.Lazy<@[FlexibleNullability] kotlin.String?> visibility:private [final,static]' type=kotlin.Lazy<@[FlexibleNullability] kotlin.String?> origin=null + @-1:-1..-1 CONST Null type=kotlin.Nothing? value=null + @3:27..53 PROPERTY_REFERENCE 'public final lazyNullString: kotlin.String [delegated,val]' field=null getter='public final fun (): kotlin.String declared in ' setter=null type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + @5:0..7:1 FUN name:testLazyNullString visibility:public modality:FINAL <> () returnType:kotlin.Unit + @5:25..7:1 BLOCK_BODY + @6:4..34 VAR name:s type:kotlin.String [val] + @6:20..34 CALL 'public final fun (): kotlin.String declared in ' type=kotlin.String origin=GET_PROPERTY diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 25b64e28e52..4cc861b6968 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -16335,6 +16335,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt18911.kt"); } + @TestMetadata("kt24258.kt") + public void testKt24258() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt"); + } + + @TestMetadata("kt24258nn.kt") + public void testKt24258nn() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt"); + } + @TestMetadata("localEntities.kt") public void testLocalEntities() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/localEntities.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8052a5fc3d5..bbf3508d3cc 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16287,6 +16287,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class NotNullAssertions extends AbstractLightAnalysisModeTest { + @TestMetadata("kt24258.kt") + public void ignoreKt24258() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -16335,6 +16340,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt18911.kt"); } + @TestMetadata("kt24258nn.kt") + public void testKt24258nn() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt"); + } + @TestMetadata("localEntities.kt") public void testLocalEntities() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/localEntities.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 97b19df353d..65d28ccab55 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -16335,6 +16335,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt18911.kt"); } + @TestMetadata("kt24258.kt") + public void testKt24258() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt"); + } + + @TestMetadata("kt24258nn.kt") + public void testKt24258nn() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258nn.kt"); + } + @TestMetadata("localEntities.kt") public void testLocalEntities() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/localEntities.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/ir/IrSourceRangesTestCaseGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/ir/IrSourceRangesTestCaseGenerated.java index 0aa0e7fed4d..fa93993bc8d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/ir/IrSourceRangesTestCaseGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/ir/IrSourceRangesTestCaseGenerated.java @@ -44,6 +44,11 @@ public class IrSourceRangesTestCaseGenerated extends AbstractIrSourceRangesTestC runTest("compiler/testData/ir/sourceRanges/kt17108.kt"); } + @TestMetadata("kt24258.kt") + public void testKt24258() throws Exception { + runTest("compiler/testData/ir/sourceRanges/kt24258.kt"); + } + @TestMetadata("compiler/testData/ir/sourceRanges/declarations") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)