From 4cf8203ce726d71a7a427d786ca057e8516eace2 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 9 Jan 2020 13:47:56 +0300 Subject: [PATCH] PSI2IR: Unify behavior for lambda return values with old back-end See KT-35849. 1. When expected lambda return type is a type parameter, don't generate introduce implicit casts (even if the corresponding type parameter has an upper bound that would otherwise require such cast). 2. Do not generate implicit null check for lambda return value of @EnhancedNullability type. --- .../kotlin/fir/Fir2IrTextTestGenerated.java | 5 ++ .../transformations/InsertImplicitCasts.kt | 49 +++++++++--- .../inLambdaReturnWithExpectedType.kt | 64 ++++++++++++++++ .../nullCheckOnGenericLambdaReturn.fir.txt | 69 +++++++++++++++++ .../nullCheckOnGenericLambdaReturn.kt | 27 +++++++ .../nullCheckOnGenericLambdaReturn.txt | 75 +++++++++++++++++++ .../nullCheckOnLambdaReturn.fir.txt | 30 +++++++- .../expressions/nullCheckOnLambdaReturn.kt | 14 +++- .../expressions/nullCheckOnLambdaReturn.txt | 32 +++++++- .../codegen/BlackBoxCodegenTestGenerated.java | 5 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../ir/FirBlackBoxCodegenTestGenerated.java | 5 ++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 ++ .../kotlin/ir/IrTextTestCaseGenerated.java | 5 ++ 14 files changed, 368 insertions(+), 22 deletions(-) create mode 100644 compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt create mode 100644 compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.fir.txt create mode 100644 compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.kt create mode 100644 compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.txt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java index a0b1c22a31f..ea3634063c4 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java @@ -1087,6 +1087,11 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { runTest("compiler/testData/ir/irText/expressions/multipleThisReferences.kt"); } + @TestMetadata("nullCheckOnGenericLambdaReturn.kt") + public void testNullCheckOnGenericLambdaReturn() throws Exception { + runTest("compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.kt"); + } + @TestMetadata("nullCheckOnLambdaReturn.kt") public void testNullCheckOnLambdaReturn() throws Exception { runTest("compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.kt"); diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt index 3050f3620e4..ee133925703 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass @@ -94,7 +95,9 @@ internal class InsertImplicitCasts( private fun IrMemberAccessExpression.transformReceiverArguments(substitutedDescriptor: CallableDescriptor) { dispatchReceiver = dispatchReceiver?.cast(getEffectiveDispatchReceiverType(substitutedDescriptor)) - extensionReceiver = extensionReceiver?.cast(substitutedDescriptor.extensionReceiverParameter?.type) + val extensionReceiverType = substitutedDescriptor.extensionReceiverParameter?.type + val originalExtensionReceiverType = substitutedDescriptor.original.extensionReceiverParameter?.type + extensionReceiver = extensionReceiver?.cast(extensionReceiverType, originalExtensionReceiverType) } private fun getEffectiveDispatchReceiverType(descriptor: CallableDescriptor): KotlinType? = @@ -121,6 +124,7 @@ internal class InsertImplicitCasts( for (index in substitutedDescriptor.valueParameters.indices) { val argument = getValueArgument(index) ?: continue val parameterType = substitutedDescriptor.valueParameters[index].type + val originalParameterType = substitutedDescriptor.original.valueParameters[index].type // Hack to support SAM conversions on out-projected types. // See SamType#createByValueParameter and genericSamProjectedOut.kt for more details. @@ -130,7 +134,7 @@ internal class InsertImplicitCasts( else parameterType - putValueArgument(index, argument.cast(expectedType)) + putValueArgument(index, argument.cast(expectedType, originalExpectedType = originalParameterType)) } } } @@ -168,8 +172,12 @@ internal class InsertImplicitCasts( value = if (expression.returnTargetSymbol is IrConstructorSymbol) { value.coerceToUnit() } else { - returnExpressionsToBePostprocessed.add(expression) - value.cast(expression.returnTarget.returnType) + val returnTargetDescriptor = expression.returnTarget + val isLambdaReturnValue = returnTargetDescriptor is AnonymousFunctionDescriptor + if (isLambdaReturnValue) { + returnExpressionsToBePostprocessed.add(expression) + } + value.cast(returnTargetDescriptor.returnType, isLambdaReturnValue = isLambdaReturnValue) } } @@ -292,15 +300,16 @@ internal class InsertImplicitCasts( else null - private fun IrExpression.cast(expectedType: KotlinType?): IrExpression { + private fun IrExpression.cast( + expectedType: KotlinType?, + originalExpectedType: KotlinType? = expectedType, + isLambdaReturnValue: Boolean = false + ): IrExpression { if (expectedType == null) return this if (expectedType.isError) return this - if (this is IrFunctionExpression) { - val expectedFunctionReturnType = expectedType.getFunctionReturnTypeOrNull() - if (expectedFunctionReturnType != null) { - expectedFunctionExpressionReturnType[function.descriptor] = expectedFunctionReturnType.toIrType() - } + if (this is IrFunctionExpression && originalExpectedType != null) { + recordExpectedLambdaReturnTypeIfAppropriate(expectedType, originalExpectedType) } // TODO here we can have non-denotable KotlinTypes (both in 'this@cast.type' and 'expectedType'). @@ -319,8 +328,10 @@ internal class InsertImplicitCasts( else implicitCast(expectedType, IrTypeOperator.IMPLICIT_DYNAMIC_CAST) - (valueType.isNullabilityFlexible() && valueType.containsNull() || valueType.hasEnhancedNullability()) && - !expectedType.containsNull() -> + (valueType.isNullabilityFlexible() && valueType.containsNull()) && !expectedType.containsNull() -> + implicitNonNull(valueType, expectedType) + + (valueType.hasEnhancedNullability() && !isLambdaReturnValue) && !expectedType.containsNull() -> implicitNonNull(valueType, expectedType) KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType.makeNullable()) -> @@ -336,6 +347,20 @@ internal class InsertImplicitCasts( } } + private fun IrFunctionExpression.recordExpectedLambdaReturnTypeIfAppropriate( + expectedType: KotlinType, + originalExpectedType: KotlinType + ) { + // TODO see KT-35849 + + val returnTypeFromExpected = expectedType.getFunctionReturnTypeOrNull() ?: return + val returnTypeFromOriginalExpected = originalExpectedType.getFunctionReturnTypeOrNull() + + if (returnTypeFromOriginalExpected?.isTypeParameter() != true) { + expectedFunctionExpressionReturnType[function.descriptor] = returnTypeFromExpected.toIrType() + } + } + private fun KotlinType.hasEnhancedNullability() = generatorExtensions.enhancedNullability.hasEnhancedNullability(this) diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt new file mode 100644 index 00000000000..1961949d271 --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt @@ -0,0 +1,64 @@ +// !LANGUAGE: +StrictJavaNullabilityAssertions +// TARGET_BACKEND: JVM + +// FILE: inLambdaReturnWithExpectedType.kt +fun check(fn: () -> Any) { fn() } + +fun checkT(fn: () -> T) { fn() } + +fun checkTAny(fn: () -> T) { fn() } + +fun box(): String { + // TODO language design; see KT-35849 + + try { + check { J().nullString() } + throw AssertionError("Fail: 'check { J().nullString() }' should throw") + } catch (e: Throwable) { + } + + try { + check { J().notNullString() } + throw AssertionError("Fail: 'check { J().notNullString() }' should throw") + } catch (e: Throwable) { + } + + try { + checkT { J().nullString() } + } catch (e: Throwable) { + throw AssertionError("Fail: 'checkT { J().nullString() }' should not throw") + } + + try { + checkT { J().notNullString() } + } catch (e: Throwable) { + throw AssertionError("Fail: 'checkT { J().notNullString() }' should not throw") + } + + try { + checkTAny { J().nullString() } + } catch (e: Throwable) { + throw AssertionError("Fail: 'checkTAny { J().nullString() }' should not throw") + } + + try { + checkTAny { J().notNullString() } + } catch (e: Throwable) { + throw AssertionError("Fail: 'checkTAny { J().notNullString() }' should not throw") + } + + return "OK" +} + +// FILE: J.java +import org.jetbrains.annotations.NotNull; + +public class J { + public String nullString() { + return null; + } + + public @NotNull String notNullString() { + return null; + } +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.fir.txt b/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.fir.txt new file mode 100644 index 00000000000..291568f5eaa --- /dev/null +++ b/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.fir.txt @@ -0,0 +1,69 @@ +FILE fqName: fileName:/nullCheckOnGenericLambdaReturn.kt + FUN name:checkAny visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkAny (fn: kotlin.Function0): kotlin.Any declared in ' + CALL 'public abstract fun invoke (): kotlin.Any [operator] declared in kotlin.Function0' type=kotlin.Any origin=null + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAny' type=kotlin.Function0 origin=null + FUN name:checkAnyN visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any? + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' + CALL 'public abstract fun invoke (): kotlin.Any? [operator] declared in kotlin.Function0' type=kotlin.Any? origin=null + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAnyN' type=kotlin.Function0 origin=null + FUN name:checkT visibility:public modality:FINAL (fn:kotlin.Function0.checkT>) returnType:T of .checkT + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0.checkT> + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkT (fn: kotlin.Function0.checkT>): T of .checkT declared in ' + CALL 'public abstract fun invoke (): T of .checkT [operator] declared in kotlin.Function0' type=T of .checkT origin=null + $this: GET_VAR 'fn: kotlin.Function0.checkT> declared in .checkT' type=kotlin.Function0.checkT> origin=null + FUN name:checkTAny visibility:public modality:FINAL (fn:kotlin.Function0.checkTAny>) returnType:T of .checkTAny + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any] + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0.checkTAny> + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkTAny (fn: kotlin.Function0.checkTAny>): T of .checkTAny declared in ' + CALL 'public abstract fun invoke (): T of .checkTAny [operator] declared in kotlin.Function0' type=T of .checkTAny origin=null + $this: GET_VAR 'fn: kotlin.Function0.checkTAny> declared in .checkTAny' type=kotlin.Function0.checkTAny> origin=null + FUN name:id visibility:public modality:FINAL (x:T of .id) returnType:T of .id + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] + VALUE_PARAMETER name:x index:0 type:T of .id + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun id (x: T of .id): T of .id declared in ' + GET_VAR 'x: T of .id declared in .id' type=T of .id origin=null + FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test1 (): kotlin.String? declared in ' + CALL 'public final fun checkT (fn: kotlin.Function0.checkT>): T of .checkT declared in ' type=kotlin.String? origin=null + : kotlin.String? + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + CALL 'public open fun foo (): kotlin.String? [operator] declared in .J' type=kotlin.String? origin=null + FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test2 (): kotlin.String declared in ' + CALL 'public final fun checkT (fn: kotlin.Function0.checkT>): T of .checkT declared in ' type=kotlin.String origin=null + : kotlin.String + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + CALL 'public open fun nnFoo (): kotlin.String [operator] declared in .J' type=kotlin.String origin=null + FUN name:test3 visibility:public modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test3 (): kotlin.String? declared in ' + CALL 'public final fun checkTAny (fn: kotlin.Function0.checkTAny>): T of .checkTAny declared in ' type=kotlin.String? origin=null + : kotlin.String? + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + CALL 'public open fun foo (): kotlin.String? [operator] declared in .J' type=kotlin.String? origin=null + FUN name:test4 visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test4 (): kotlin.String declared in ' + CALL 'public final fun checkTAny (fn: kotlin.Function0.checkTAny>): T of .checkTAny declared in ' type=kotlin.String origin=null + : kotlin.String + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + CALL 'public open fun nnFoo (): kotlin.String [operator] declared in .J' type=kotlin.String origin=null diff --git a/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.kt b/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.kt new file mode 100644 index 00000000000..0db77324671 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.kt @@ -0,0 +1,27 @@ +// FILE: nullCheckOnGenericLambdaReturn.kt +fun checkAny(fn: () -> Any) = fn() + +fun checkAnyN(fn: () -> Any?) = fn() + +fun checkT(fn: () -> T) = fn() + +fun checkTAny(fn: () -> T) = fn() + +fun id(x: T) = x + +fun test1() = checkT { J.foo() } + +fun test2() = checkT { J.nnFoo() } + +fun test3() = checkTAny { J.foo() } + +fun test4() = checkTAny { J.nnFoo() } + +// FILE: J.java +import org.jetbrains.annotations.*; + +public class J { + public static String foo() { return null; } + + public static @NotNull String nnFoo() { return null; } +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.txt b/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.txt new file mode 100644 index 00000000000..423dc3101e1 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.txt @@ -0,0 +1,75 @@ +FILE fqName: fileName:/nullCheckOnGenericLambdaReturn.kt + FUN name:checkAny visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkAny (fn: kotlin.Function0): kotlin.Any declared in ' + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Any origin=INVOKE + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAny' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION + FUN name:checkAnyN visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any? + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Any? origin=INVOKE + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAnyN' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION + FUN name:checkT visibility:public modality:FINAL (fn:kotlin.Function0.checkT>) returnType:T of .checkT + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0.checkT> + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkT (fn: kotlin.Function0.checkT>): T of .checkT declared in ' + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of .checkT origin=INVOKE + $this: GET_VAR 'fn: kotlin.Function0.checkT> declared in .checkT' type=kotlin.Function0.checkT> origin=VARIABLE_AS_FUNCTION + FUN name:checkTAny visibility:public modality:FINAL (fn:kotlin.Function0.checkTAny>) returnType:T of .checkTAny + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any] + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0.checkTAny> + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkTAny (fn: kotlin.Function0.checkTAny>): T of .checkTAny declared in ' + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of .checkTAny origin=INVOKE + $this: GET_VAR 'fn: kotlin.Function0.checkTAny> declared in .checkTAny' type=kotlin.Function0.checkTAny> origin=VARIABLE_AS_FUNCTION + FUN name:id visibility:public modality:FINAL (x:T of .id) returnType:T of .id + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] + VALUE_PARAMETER name:x index:0 type:T of .id + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun id (x: T of .id): T of .id declared in ' + GET_VAR 'x: T of .id declared in .id' type=T of .id origin=null + FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test1 (): kotlin.String? declared in ' + CALL 'public final fun checkT (fn: kotlin.Function0.checkT>): T of .checkT declared in ' type=kotlin.String? origin=null + : kotlin.String? + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.String? declared in .test1' + CALL 'public open fun foo (): kotlin.String? declared in .J' type=kotlin.String? origin=null + FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test2 (): kotlin.String declared in ' + TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String + CALL 'public final fun checkT (fn: kotlin.Function0.checkT>): T of .checkT declared in ' type=kotlin.String origin=null + : kotlin.String + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.String declared in .test2' + CALL 'public open fun nnFoo (): kotlin.String declared in .J' type=kotlin.String origin=null + FUN name:test3 visibility:public modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test3 (): kotlin.String? declared in ' + CALL 'public final fun checkTAny (fn: kotlin.Function0.checkTAny>): T of .checkTAny declared in ' type=kotlin.String? origin=null + : kotlin.String? + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.String? declared in .test3' + CALL 'public open fun foo (): kotlin.String? declared in .J' type=kotlin.String? origin=null + FUN name:test4 visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test4 (): kotlin.String declared in ' + TYPE_OP type=kotlin.String origin=IMPLICIT_NOTNULL typeOperand=kotlin.String + CALL 'public final fun checkTAny (fn: kotlin.Function0.checkTAny>): T of .checkTAny declared in ' type=kotlin.String origin=null + : kotlin.String + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.String declared in .test4' + CALL 'public open fun nnFoo (): kotlin.String declared in .J' type=kotlin.String origin=null diff --git a/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.fir.txt b/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.fir.txt index 47ef579b674..3ca8cbc972e 100644 --- a/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.fir.txt +++ b/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.fir.txt @@ -1,10 +1,16 @@ FILE fqName: fileName:/nullCheckOnLambdaReturn.kt - FUN name:check visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any + FUN name:checkAny visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun check (fn: kotlin.Function0): kotlin.Any declared in ' + RETURN type=kotlin.Nothing from='public final fun checkAny (fn: kotlin.Function0): kotlin.Any declared in ' CALL 'public abstract fun invoke (): kotlin.Any [operator] declared in kotlin.Function0' type=kotlin.Any origin=null - $this: GET_VAR 'fn: kotlin.Function0 declared in .check' type=kotlin.Function0 origin=null + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAny' type=kotlin.Function0 origin=null + FUN name:checkAnyN visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any? + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' + CALL 'public abstract fun invoke (): kotlin.Any? [operator] declared in kotlin.Function0' type=kotlin.Any? origin=null + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAnyN' type=kotlin.Function0 origin=null FUN name:id visibility:public modality:FINAL (x:T of .id) returnType:T of .id TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] VALUE_PARAMETER name:x index:0 type:T of .id @@ -14,7 +20,7 @@ FILE fqName: fileName:/nullCheckOnLambdaReturn.kt FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Any BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun test1 (): kotlin.Any declared in ' - CALL 'public final fun check (fn: kotlin.Function0): kotlin.Any declared in ' type=kotlin.Any origin=null + CALL 'public final fun checkAny (fn: kotlin.Function0): kotlin.Any declared in ' type=kotlin.Any origin=null fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Any BLOCK_BODY @@ -58,3 +64,19 @@ FILE fqName: fileName:/nullCheckOnLambdaReturn.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun (): kotlin.Function0 declared in ' GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test4 type:kotlin.Function0 visibility:private [final,static]' type=kotlin.Function0 origin=null + FUN name:test5 visibility:public modality:FINAL <> () returnType:kotlin.Any? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test5 (): kotlin.Any? declared in ' + CALL 'public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' type=kotlin.Any? origin=null + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Any? + BLOCK_BODY + CALL 'public open fun foo (): kotlin.String? [operator] declared in .J' type=kotlin.String? origin=null + FUN name:test6 visibility:public modality:FINAL <> () returnType:kotlin.Any? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test6 (): kotlin.Any? declared in ' + CALL 'public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' type=kotlin.Any? origin=null + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Any? + BLOCK_BODY + CALL 'public open fun nnFoo (): kotlin.String [operator] declared in .J' type=kotlin.String origin=null diff --git a/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.kt b/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.kt index fc72c8bde2a..7ce4e63da85 100644 --- a/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.kt +++ b/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.kt @@ -1,9 +1,11 @@ // FILE: nullCheckOnLambdaReturn.kt -fun check(fn: () -> Any) = fn() +fun checkAny(fn: () -> Any) = fn() + +fun checkAnyN(fn: () -> Any?) = fn() fun id(x: T) = x -fun test1() = check { J.foo() } +fun test1() = checkAny { J.foo() } val test2: () -> Any = { J.foo() } @@ -11,7 +13,15 @@ val test3: () -> Any = { J.foo() } as () -> Any val test4: () -> Any = id { J.foo() } +fun test5() = checkAnyN { J.foo() } + +fun test6() = checkAnyN { J.nnFoo() } + // FILE: J.java +import org.jetbrains.annotations.*; + public class J { public static String foo() { return null; } + + public static @NotNull String nnFoo() { return null; } } \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.txt b/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.txt index 67076913820..7186077e147 100644 --- a/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.txt +++ b/compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.txt @@ -1,10 +1,16 @@ FILE fqName: fileName:/nullCheckOnLambdaReturn.kt - FUN name:check visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any + FUN name:checkAny visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun check (fn: kotlin.Function0): kotlin.Any declared in ' + RETURN type=kotlin.Nothing from='public final fun checkAny (fn: kotlin.Function0): kotlin.Any declared in ' CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Any origin=INVOKE - $this: GET_VAR 'fn: kotlin.Function0 declared in .check' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAny' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION + FUN name:checkAnyN visibility:public modality:FINAL <> (fn:kotlin.Function0) returnType:kotlin.Any? + VALUE_PARAMETER name:fn index:0 type:kotlin.Function0 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Any? origin=INVOKE + $this: GET_VAR 'fn: kotlin.Function0 declared in .checkAnyN' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION FUN name:id visibility:public modality:FINAL (x:T of .id) returnType:T of .id TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] VALUE_PARAMETER name:x index:0 type:T of .id @@ -14,7 +20,7 @@ FILE fqName: fileName:/nullCheckOnLambdaReturn.kt FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Any BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun test1 (): kotlin.Any declared in ' - CALL 'public final fun check (fn: kotlin.Function0): kotlin.Any declared in ' type=kotlin.Any origin=null + CALL 'public final fun checkAny (fn: kotlin.Function0): kotlin.Any declared in ' type=kotlin.Any origin=null fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String? BLOCK_BODY @@ -64,3 +70,21 @@ FILE fqName: fileName:/nullCheckOnLambdaReturn.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun (): kotlin.Function0 declared in ' GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test4 type:kotlin.Function0 visibility:private [final,static]' type=kotlin.Function0 origin=null + FUN name:test5 visibility:public modality:FINAL <> () returnType:kotlin.Any? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test5 (): kotlin.Any? declared in ' + CALL 'public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' type=kotlin.Any? origin=null + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.String? declared in .test5' + CALL 'public open fun foo (): kotlin.String? declared in .J' type=kotlin.String? origin=null + FUN name:test6 visibility:public modality:FINAL <> () returnType:kotlin.Any? + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test6 (): kotlin.Any? declared in ' + CALL 'public final fun checkAnyN (fn: kotlin.Function0): kotlin.Any? declared in ' type=kotlin.Any? origin=null + fn: FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.String declared in .test6' + CALL 'public open fun nnFoo (): kotlin.String declared in .J' type=kotlin.String origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index b8f48ce24b4..fb870140b31 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -14644,6 +14644,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inFunctionWithExpressionBodyWithJavaGeneric.kt"); } + @TestMetadata("inLambdaReturnWithExpectedType.kt") + public void testInLambdaReturnWithExpectedType() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt"); + } + @TestMetadata("inLocalFunctionWithExpressionBody.kt") public void testInLocalFunctionWithExpressionBody() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLocalFunctionWithExpressionBody.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 8d76f9d39d9..f8380ab05bf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -14644,6 +14644,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inFunctionWithExpressionBodyWithJavaGeneric.kt"); } + @TestMetadata("inLambdaReturnWithExpectedType.kt") + public void testInLambdaReturnWithExpectedType() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt"); + } + @TestMetadata("inLocalFunctionWithExpressionBody.kt") public void testInLocalFunctionWithExpressionBody() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLocalFunctionWithExpressionBody.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index a2569abb42f..aee297818f6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -13494,6 +13494,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inFunctionWithExpressionBodyWithJavaGeneric.kt"); } + @TestMetadata("inLambdaReturnWithExpectedType.kt") + public void testInLambdaReturnWithExpectedType() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt"); + } + @TestMetadata("inLocalFunctionWithExpressionBody.kt") public void testInLocalFunctionWithExpressionBody() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLocalFunctionWithExpressionBody.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 891c051249e..ea39d6f1f17 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13494,6 +13494,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inFunctionWithExpressionBodyWithJavaGeneric.kt"); } + @TestMetadata("inLambdaReturnWithExpectedType.kt") + public void testInLambdaReturnWithExpectedType() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLambdaReturnWithExpectedType.kt"); + } + @TestMetadata("inLocalFunctionWithExpressionBody.kt") public void testInLocalFunctionWithExpressionBody() throws Exception { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability/inLocalFunctionWithExpressionBody.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index ffeddee9c3d..3344ae32ce7 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -1086,6 +1086,11 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { runTest("compiler/testData/ir/irText/expressions/multipleThisReferences.kt"); } + @TestMetadata("nullCheckOnGenericLambdaReturn.kt") + public void testNullCheckOnGenericLambdaReturn() throws Exception { + runTest("compiler/testData/ir/irText/expressions/nullCheckOnGenericLambdaReturn.kt"); + } + @TestMetadata("nullCheckOnLambdaReturn.kt") public void testNullCheckOnLambdaReturn() throws Exception { runTest("compiler/testData/ir/irText/expressions/nullCheckOnLambdaReturn.kt");