diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.kt new file mode 100644 index 00000000000..253d8cfa57c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.kt @@ -0,0 +1,9 @@ +public fun T.myAlso(block: (T) -> Unit): T = TODO() + +class B { + fun add(x: String): Boolean = true +} + +fun main(b: B) { + "".myAlso(b::add) +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.txt new file mode 100644 index 00000000000..f65780614ed --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.txt @@ -0,0 +1,17 @@ +FILE: coercionToUnit.kt + public final fun R|T|.myAlso(block: R|(T) -> kotlin/Unit|): R|T| { + ^myAlso R|kotlin/TODO|() + } + public final class B : R|kotlin/Any| { + public constructor(): R|B| { + super() + } + + public final fun add(x: R|kotlin/String|): R|kotlin/Boolean| { + ^add Boolean(true) + } + + } + public final fun main(b: R|B|): R|kotlin/Unit| { + String().R|/myAlso|(R|/b|::R|/B.add|) + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java index 2b624bbd943..ffea0fac13b 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithStdlibTestGenerated.java @@ -300,6 +300,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/beyoundCalls.kt"); } + @TestMetadata("coercionToUnit.kt") + public void testCoercionToUnit() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/coercionToUnit.kt"); + } + @TestMetadata("companions.kt") public void testCompanions() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/callableReferences/companions.kt"); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt index 69aa9765490..23092d3f426 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt @@ -11,11 +11,13 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier +import org.jetbrains.kotlin.fir.inferenceContext import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom import org.jetbrains.kotlin.fir.resolve.inference.csBuilder +import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -231,10 +233,11 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() { val returnTypeRef = candidate.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir) val resultingType: ConeKotlinType = when (fir) { - is FirFunction -> createKFunctionType( + is FirFunction -> callInfo.session.createKFunctionType( fir, resultingReceiverType, returnTypeRef, expectedParameterNumberWithReceiver = expectedType?.let { it.typeArguments.size - 1 }, - isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true + isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true, + expectedReturnType = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, callInfo.session)?.outputType ) is FirVariable<*> -> createKPropertyType(fir, resultingReceiverType, returnTypeRef) else -> ConeKotlinErrorType("Unknown callable kind: ${fir::class}") @@ -286,13 +289,15 @@ private fun createKPropertyType( ) } -private fun createKFunctionType( +private fun FirSession.createKFunctionType( function: FirFunction<*>, receiverType: ConeKotlinType?, returnTypeRef: FirResolvedTypeRef, expectedParameterNumberWithReceiver: Int?, - isSuspend: Boolean + isSuspend: Boolean, + expectedReturnType: ConeKotlinType? ): ConeKotlinType { + // The similar adaptations: defaults and coercion-to-unit happen at org.jetbrains.kotlin.resolve.calls.components.CallableReferencesCandidateFactory.getCallableReferenceAdaptation val parameterTypes = mutableListOf() val expectedParameterNumber = when { expectedParameterNumberWithReceiver == null -> null @@ -306,9 +311,15 @@ private fun createKFunctionType( } } + val returnType = + if (expectedReturnType != null && inferenceContext.run { expectedReturnType.isUnit() }) + expectedReturnType + else + returnTypeRef.coneTypeSafe() ?: ConeKotlinErrorType("No type for return type of $function") + return createFunctionalType( parameterTypes, receiverType = receiverType, - rawReturnType = returnTypeRef.coneTypeSafe() ?: ConeKotlinErrorType("No type for return type of $function"), + rawReturnType = returnType, isKFunctionType = true, isSuspend = isSuspend ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt index 3580d87d374..b61062b3713 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt @@ -99,9 +99,9 @@ class ResolvedCallableReferenceAtom( // -------------------------- Utils -------------------------- -private data class InputOutputTypes(val inputTypes: List, val outputType: ConeKotlinType) +internal data class InputOutputTypes(val inputTypes: List, val outputType: ConeKotlinType) -private fun extractInputOutputTypesFromCallableReferenceExpectedType( +internal fun extractInputOutputTypesFromCallableReferenceExpectedType( expectedType: ConeKotlinType?, session: FirSession ): InputOutputTypes? { @@ -150,4 +150,4 @@ private fun extractInputOutputTypesFromFunctionType( ) return InputOutputTypes(parameters, outputType) -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/callableReference/adaptedReferences/noAdaptedReferencesIfNoOptimizedReferencesEnabled.kt b/compiler/testData/codegen/box/callableReference/adaptedReferences/noAdaptedReferencesIfNoOptimizedReferencesEnabled.kt index cc0dd0863a5..231cd324f84 100644 --- a/compiler/testData/codegen/box/callableReference/adaptedReferences/noAdaptedReferencesIfNoOptimizedReferencesEnabled.kt +++ b/compiler/testData/codegen/box/callableReference/adaptedReferences/noAdaptedReferencesIfNoOptimizedReferencesEnabled.kt @@ -1,5 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR // WITH_RUNTIME // KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_OPTIMIZED_CALLABLE_REFERENCES diff --git a/compiler/testData/codegen/box/callableReference/adaptedReferences/noNameClashForReferencesToSameFunction.kt b/compiler/testData/codegen/box/callableReference/adaptedReferences/noNameClashForReferencesToSameFunction.kt index 2a0088ba780..130632b5260 100644 --- a/compiler/testData/codegen/box/callableReference/adaptedReferences/noNameClashForReferencesToSameFunction.kt +++ b/compiler/testData/codegen/box/callableReference/adaptedReferences/noNameClashForReferencesToSameFunction.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR - var result = "" class C(val token: String) { diff --git a/compiler/testData/codegen/box/callableReference/bound/coercionToUnit.kt b/compiler/testData/codegen/box/callableReference/bound/coercionToUnit.kt index 6ddbcf3037a..d05bbce7f2a 100644 --- a/compiler/testData/codegen/box/callableReference/bound/coercionToUnit.kt +++ b/compiler/testData/codegen/box/callableReference/bound/coercionToUnit.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // KJS_WITH_FULL_RUNTIME // !LANGUAGE: +NewInference // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/callableReference/function/coercionToUnit.kt b/compiler/testData/codegen/box/callableReference/function/coercionToUnit.kt index 203e0e7df2d..299413f7a2a 100644 --- a/compiler/testData/codegen/box/callableReference/function/coercionToUnit.kt +++ b/compiler/testData/codegen/box/callableReference/function/coercionToUnit.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +NewInference -// IGNORE_BACKEND_FIR: JVM_IR fun foo(s: String): Boolean { if (s != "kotlin") throw AssertionError(s) diff --git a/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt b/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt index ccddcecf6a6..cd1e4daa3b0 100644 --- a/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/function/ambiguityTopLevelVsTopLevel.fir.kt @@ -5,5 +5,5 @@ fun foo(x: Any, y: Int) = y fun main() { ::foo - val fooRef: (Int, Any) -> Unit = ::foo + val fooRef: (Int, Any) -> Unit = ::foo } diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt index b8f3daddd31..c2b725e8e42 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt @@ -17,5 +17,5 @@ fun test() { foo1(::bar1) foo1(::bar2) - foo1(::bar3) // Should be ambiguity + foo1(::bar3) // Should be ambiguity } diff --git a/compiler/testData/ir/irText/expressions/callableReferences/adaptedWithCoercionToUnit.fir.txt b/compiler/testData/ir/irText/expressions/callableReferences/adaptedWithCoercionToUnit.fir.txt index 2d371f203fe..b30b70682cc 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/adaptedWithCoercionToUnit.fir.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/adaptedWithCoercionToUnit.fir.txt @@ -19,16 +19,16 @@ FILE fqName: fileName:/adaptedWithCoercionToUnit.kt BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun fnv (vararg xs: kotlin.Int): kotlin.Int declared in ' CONST Int type=kotlin.Int value=1 - FUN name:test0 visibility:public modality:FINAL <> () returnType:IrErrorType + FUN name:test0 visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun test0 (): IrErrorType declared in ' - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - FUNCTION_REFERENCE 'public final fun fn0 (): kotlin.Int declared in ' type=kotlin.reflect.KFunction0 origin=null reflectionTarget= - FUN name:test1 visibility:public modality:FINAL <> () returnType:IrErrorType + RETURN type=kotlin.Nothing from='public final fun test0 (): kotlin.Unit declared in ' + CALL 'public final fun useUnit0 (fn: kotlin.Function0): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: FUNCTION_REFERENCE 'public final fun fn0 (): kotlin.Int declared in ' type=kotlin.reflect.KFunction0 origin=null reflectionTarget= + FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun test1 (): IrErrorType declared in ' - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - FUNCTION_REFERENCE 'public final fun fn1 (x: kotlin.Int): kotlin.Int declared in ' type=kotlin.reflect.KFunction1 origin=null reflectionTarget= + RETURN type=kotlin.Nothing from='public final fun test1 (): kotlin.Unit declared in ' + CALL 'public final fun useUnit1 (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: FUNCTION_REFERENCE 'public final fun fn1 (x: kotlin.Int): kotlin.Int declared in ' type=kotlin.reflect.KFunction1 origin=null reflectionTarget= FUN name:testV0 visibility:public modality:FINAL <> () returnType:IrErrorType BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun testV0 (): IrErrorType declared in ' diff --git a/compiler/testData/ir/irText/expressions/callableReferences/withAdaptedArguments.fir.txt b/compiler/testData/ir/irText/expressions/callableReferences/withAdaptedArguments.fir.txt index f420b8df813..6cf94d8293e 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/withAdaptedArguments.fir.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/withAdaptedArguments.fir.txt @@ -73,11 +73,11 @@ FILE fqName: fileName:/withAdaptedArguments.kt RETURN type=kotlin.Nothing from='public final fun testVararg (): IrErrorType declared in ' ERROR_CALL 'Unresolved reference: #' type=IrErrorType FUNCTION_REFERENCE 'public final fun fnWithVarargs (vararg xs: kotlin.Int): kotlin.String declared in ' type=kotlin.reflect.KFunction1 origin=null reflectionTarget= - FUN name:testCoercionToUnit visibility:public modality:FINAL <> () returnType:IrErrorType + FUN name:testCoercionToUnit visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun testCoercionToUnit (): IrErrorType declared in ' - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - FUNCTION_REFERENCE 'public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' type=kotlin.reflect.KFunction1 origin=null reflectionTarget= + RETURN type=kotlin.Nothing from='public final fun testCoercionToUnit (): kotlin.Unit declared in ' + CALL 'public final fun coerceToUnit (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: FUNCTION_REFERENCE 'public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' type=kotlin.reflect.KFunction1 origin=null reflectionTarget= FUN name:testImportedObjectMember visibility:public modality:FINAL <> () returnType:IrErrorType BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun testImportedObjectMember (): IrErrorType declared in '