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 2f89956c1d1..7ba52d05a65 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 @@ -17022,6 +17022,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @Test + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @Test @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index 6c82221fb0c..b1cebae3e80 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -508,7 +508,7 @@ fun FirExpression.isFunctional( session, scopeSession, classLikeExpectedFunctionType, shouldCalculateReturnTypesOfFakeOverrides = false ) ?: return false // Make sure the contributed `invoke` is indeed a wanted functional type by checking if types are compatible. - val expectedReturnType = classLikeExpectedFunctionType.returnType(session)!!.lowerBoundIfFlexible() + val expectedReturnType = classLikeExpectedFunctionType.returnType(session).lowerBoundIfFlexible() val returnTypeCompatible = expectedReturnType is ConeTypeParameterType || AbstractTypeChecker.isSubtypeOf( @@ -529,7 +529,7 @@ fun FirExpression.isFunctional( val parameterPairs = invokeSymbol.fir.valueParameters.zip(classLikeExpectedFunctionType.valueParameterTypesIncludingReceiver(session)) return parameterPairs.all { (invokeParameter, expectedParameter) -> - val expectedParameterType = expectedParameter!!.lowerBoundIfFlexible() + val expectedParameterType = expectedParameter.lowerBoundIfFlexible() expectedParameterType is ConeTypeParameterType || AbstractTypeChecker.isSubtypeOf( session.inferenceComponents.ctx.newBaseTypeCheckerContext( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt index 0e793eb30f3..51eac6a7ef4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt @@ -202,22 +202,28 @@ fun ConeKotlinType.isKClassType(): Boolean { } fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? { - if (isBuiltinFunctionalType(session) && isExtensionFunctionType(session)) { - return (this.fullyExpandedType(session).typeArguments.first() as ConeKotlinTypeProjection).type + if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null + return when (val projection = fullyExpandedType(session).typeArguments.first()) { + is ConeKotlinTypeProjection -> projection.type + is ConeStarProjection -> session.builtinTypes.nothingType.type } - return null } -fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType? { +fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType { require(this is ConeClassLikeType) - val projection = fullyExpandedType(session).typeArguments.last() - return (projection as? ConeKotlinTypeProjection)?.type + return when (val projection = fullyExpandedType(session).typeArguments.last()) { + is ConeKotlinTypeProjection -> projection.type + is ConeStarProjection -> session.builtinTypes.nullableAnyType.type + } } -fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List { +fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List { require(this is ConeClassLikeType) return fullyExpandedType(session).typeArguments.dropLast(1).map { - (it as? ConeKotlinTypeProjection)?.type + when (it) { + is ConeKotlinTypeProjection -> it.type + is ConeStarProjection -> session.builtinTypes.nothingType.type + } } } @@ -252,11 +258,22 @@ fun extractLambdaInfoFromFunctionalType( // Simply { }, i.e., function literals without body. Raw FIR added an implicit return with an implicit unit type ref. if (lastStatement?.source?.kind is FirFakeSourceElementKind.ImplicitReturn && (lastStatement as? FirReturnExpression)?.result?.source?.kind is FirFakeSourceElementKind.ImplicitUnit - ) { + ) session.builtinTypes.unitType.type - } else - argument.returnType ?: expectedType.returnType(session) ?: return null - val parameters = extractLambdaParameters(expectedType, argument, expectedType.isExtensionFunctionType(session), session) + else + argument.returnType ?: expectedType.returnType(session) + val expectedParameters = expectedType.valueParameterTypesIncludingReceiver(session).let { + if (expectedType.isExtensionFunctionType(session)) it.drop(1) else it + } + val parameters = if (argument.valueParameters.isEmpty()) { + expectedParameters + } else { + // TODO: `(A) -> B` is permitted as `A.() -> B` if it's an anonymous function, not a lambda; + // e.g. `fun (x: Any?) = x` can be used as `Any?.() -> Any?`, but `{ it -> it }` cannot. + argument.valueParameters.mapIndexed { index, parameter -> + parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: session.builtinTypes.nothingType.type + } + } return ResolvedLambdaAtom( argument, @@ -269,35 +286,3 @@ fun extractLambdaInfoFromFunctionalType( candidate ) } - -private fun extractLambdaParameters( - expectedType: ConeKotlinType, - argument: FirAnonymousFunction, - expectedTypeIsExtensionFunctionType: Boolean, - session: FirSession -): List { - val parameters = argument.valueParameters - val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType, session) - - val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type - if (parameters.isEmpty()) { - return expectedParameters.map { it?.type ?: nullableAnyType } - } - - return parameters.mapIndexed { index, parameter -> - parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: nullableAnyType - } -} - -private fun ConeKotlinType.extractParametersForFunctionalType( - isExtensionFunctionType: Boolean, - session: FirSession -): List { - return valueParameterTypesIncludingReceiver(session).let { - if (isExtensionFunctionType) { - it.drop(1) - } else { - it - } - } -} 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 cbe2be1adb5..2eed8d98f7f 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 @@ -164,7 +164,7 @@ internal fun extractInputOutputTypesFromCallableReferenceExpectedType( return when { expectedType.isBuiltinFunctionalType(session) -> - extractInputOutputTypesFromFunctionType(expectedType, session) + InputOutputTypes(expectedType.valueParameterTypesIncludingReceiver(session), expectedType.returnType(session)) // ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) -> // InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap()) @@ -187,22 +187,3 @@ internal fun extractInputOutputTypesFromCallableReferenceExpectedType( else -> null } } - -private fun extractInputOutputTypesFromFunctionType( - functionType: ConeKotlinType, - session: FirSession -): InputOutputTypes { - val parameters = functionType.valueParameterTypesIncludingReceiver(session).map { - it ?: ConeClassLikeTypeImpl( - ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(), - isNullable = false - ) - } - - val outputType = functionType.returnType(session) ?: ConeClassLikeTypeImpl( - ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(), - isNullable = true - ) - - return InputOutputTypes(parameters, outputType) -} diff --git a/compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt b/compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt new file mode 100644 index 00000000000..d0f7e1c0ee6 --- /dev/null +++ b/compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt @@ -0,0 +1,3 @@ +fun invoke(f: Function1) = f("OK") + +fun box() = invoke { it } as String diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt index 346a843d7ed..480bdc24d4b 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -228,7 +228,7 @@ fun main() { val x70: (Int) -> Unit = selectNumber(id(fun (it) { }), id {}, id {}) val x71: String.() -> Unit = select(")!>id(fun String.() { }), ")!>id(fun(x: String) {})) val x72: String.() -> Unit = select(fun String.() { }, fun(x: String) {}) // must be error - select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { x;y }) + select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { x;y }) select(id Unit>(fun (x, y) {}), { x: Int, y: String -> x }) // receiver of anonymous function must be specified explicitly select(id Unit>(fun Int.(y) {}), { x: Int, y: String -> x }) ")!>select(A3(), fun (x) = "", { a -> a }) 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 91402e97582..747150cb382 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 @@ -17004,6 +17004,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @Test + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @Test @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() 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 c3275dbfec2..1c006575301 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 @@ -17022,6 +17022,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @Test + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @Test @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() 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 8b23e2987ec..e5706dd5635 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -14086,6 +14086,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() throws Exception { runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index f9d02db8299..0dd027f1bd1 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -12370,6 +12370,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() throws Exception { runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 980e9c1f042..5b54c57e440 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -11791,6 +11791,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() throws Exception { runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index f51894a637a..f254c22f8b3 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -11856,6 +11856,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() throws Exception { runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 0abeb6377ec..e200bf51802 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -6256,6 +6256,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/inference/kt42130.kt"); } + @TestMetadata("lambdaWithStarReturn.kt") + public void testLambdaWithStarReturn() throws Exception { + runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt"); + } + @TestMetadata("lambdasWithExtensionFunctionType.kt") public void testLambdasWithExtensionFunctionType() throws Exception { runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt");