diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 64097ca3d60..9f25622a924 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -10778,6 +10778,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte public void testLambdasInTryCatch() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt"); } + + @TestMetadata("takingExtensibilityFromDeclarationOfAnonymousFunction.kt") + public void testTakingExtensibilityFromDeclarationOfAnonymousFunction() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt"); + } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt index 01566a569b6..7d48a50d562 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt @@ -92,18 +92,23 @@ class PostponedArgumentInputTypesResolver( } }?.toSet() - val annotations = functionalTypesFromConstraints?.run { - Annotations.create(map { it.type.annotations }.flatten()) - } - - val parameterTypesFromDeclarationOfRelatedLambdas = + // An extension function flag can only come from a declaration of anonymous function: `select({ this + it }, fun Int.(x: Int) = 10)` + val (parameterTypesFromDeclarationOfRelatedLambdas, isThereExtensionFunctionAmongRelatedLambdas) = getDeclaredParametersFromRelatedLambdas(argument, postponedArguments, variableDependencyProvider) + val annotationsFromConstraints = functionalTypesFromConstraints?.run { + Annotations.create(map { it.type.annotations }.flatten()) + } ?: Annotations.EMPTY + + val annotations = if (isThereExtensionFunctionAmongRelatedLambdas) { + annotationsFromConstraints.withExtensionFunctionAnnotation(expectedType.builtIns) + } else annotationsFromConstraints + return ParameterTypesInfo( parameterTypesFromDeclaration, parameterTypesFromDeclarationOfRelatedLambdas, parameterTypesFromConstraints, - annotations ?: Annotations.EMPTY, + annotations, isSuspend = !functionalTypesFromConstraints.isNullOrEmpty() && functionalTypesFromConstraints.any { it.type.isSuspendFunctionTypeOrSubtype }, isNullable = !functionalTypesFromConstraints.isNullOrEmpty() && functionalTypesFromConstraints.all { it.type.isMarkedNullable } ) @@ -113,24 +118,26 @@ class PostponedArgumentInputTypesResolver( argument: PostponedAtomWithRevisableExpectedType, postponedArguments: List, dependencyProvider: TypeVariableDependencyInformationProvider - ): Set>? { - fun PostponedAtomWithRevisableExpectedType.getExpectedTypeConstructor() = expectedType?.typeConstructor() - + ): Pair>?, Boolean> { val parameterTypesFromDeclarationOfRelatedLambdas = postponedArguments .filterIsInstance() .filter { it.parameterTypesFromDeclaration != null && it != argument } .mapNotNull { anotherArgument -> - val argumentExpectedTypeConstructor = argument.getExpectedTypeConstructor() ?: return@mapNotNull null - val anotherArgumentExpectedTypeConstructor = anotherArgument.getExpectedTypeConstructor() ?: return@mapNotNull null + val argumentExpectedTypeConstructor = argument.expectedType?.typeConstructor() ?: return@mapNotNull null + val anotherArgumentExpectedTypeConstructor = anotherArgument.expectedType.typeConstructor() val areTypeVariablesRelated = dependencyProvider.areVariablesDependentShallowly( - argumentExpectedTypeConstructor, - anotherArgumentExpectedTypeConstructor + argumentExpectedTypeConstructor, anotherArgumentExpectedTypeConstructor ) + val anotherAtom = anotherArgument.atom + val isAnonymousExtensionFunction = anotherAtom is FunctionExpression && anotherAtom.receiverType != null + val parameterTypesFromDeclarationOfRelatedLambda = anotherArgument.parameterTypesFromDeclaration - if (areTypeVariablesRelated) anotherArgument.parameterTypesFromDeclaration else null + if (areTypeVariablesRelated && parameterTypesFromDeclarationOfRelatedLambda != null) { + parameterTypesFromDeclarationOfRelatedLambda to isAnonymousExtensionFunction + } else null } - return parameterTypesFromDeclarationOfRelatedLambdas.toSet().takeIf { it.isNotEmpty() } + return parameterTypesFromDeclarationOfRelatedLambdas.run { map { it.first }.toSet() to any { it.second } } } private fun Context.createTypeVariableForReturnType(argument: PostponedAtomWithRevisableExpectedType): NewTypeVariable { diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt index 8a948df4410..653dfdc3756 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt @@ -62,8 +62,7 @@ class A5: Function2 { override fun invoke(p1: K, p2: Q): Float = 5f } - -fun test1() { +fun main() { // Inferring lambda parameter types by other lambda explicit parameters; expected type is type variable select(id1 { x -> x.inv() }, id2 { x: Int -> }) select(id1 { it.inv() }, id2 { x: Int -> }) @@ -220,4 +219,17 @@ fun test1() { ")!>select(id { x: Int -> null }, id { x: String -> "" }) ")!>select(id { x: Int -> 10 }, id { x: Int, y: Number -> TODO() }) val x68: String.(String) -> String = select(id { x: String, y: String -> "10" }, id { x: String, y: String -> "TODO()" }) + + // Anonymous functions + val x69: (C) -> Unit = selectB({ it }, { }, id(fun (x) { x })) + select(id1(fun(it) { it.inv() }), id1 { x: Number -> TODO() }, id1(id2(::takeInt))) + select(id(fun (it) { it }), id(id<(Int) -> Unit> { x: Number -> Unit })) + select(id(fun (it) { it.inv() }), id<(Int) -> Unit> { }) + val x70: (Int) -> Unit = selectNumber(id(fun (it) { }), id {}, id {}) + val x71: String.() -> Unit = select( kotlin.Unit")!>id(fun String.() { }), kotlin.Unit")!>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 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 }) + java.io.Serializable")!>select(A3(), fun (x) = "", { a -> a }) } diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt index 3766c363583..467d8af8faa 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.txt @@ -3,6 +3,7 @@ package public fun id(/*0*/ x: K): K public fun id1(/*0*/ x: K): K public fun id2(/*0*/ x: L): L +public fun main(): kotlin.Unit public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T public fun kotlin.Unit> selectA(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T public fun kotlin.Unit> selectB(/*0*/ arg1: T, /*1*/ arg2: T, /*2*/ arg3: T): T @@ -17,7 +18,6 @@ public fun takeLambdas(/*0*/ vararg x: (T) -> kotlin.Unit /*kotlin.Arr public fun takeLambdasWithDirectlyDependentTypeParameters(/*0*/ x: (T) -> kotlin.Unit, /*1*/ y: (R) -> kotlin.Unit, /*2*/ z: (L) -> kotlin.Unit): (T) -> kotlin.Unit public fun takeLambdasWithInverselyDependentTypeParameters(/*0*/ x: (T) -> kotlin.Unit, /*1*/ y: (R) -> kotlin.Unit, /*2*/ z: (L) -> kotlin.Unit): (T) -> kotlin.Unit public fun takeNumber(/*0*/ i: kotlin.Number): kotlin.Unit -public fun test1(): kotlin.Unit public fun withOverload(/*0*/ i: kotlin.Int): kotlin.Unit public fun withOverload(/*0*/ s: kotlin.String): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt new file mode 100644 index 00000000000..af01f35acc1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.fir.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER + +fun id(x: T) = x +fun select(vararg x: T) = x[0] + +val x1 = select(id { this }, fun Int.() = this) +val x2 = select(id { this + it.inv() }, fun Int.(x: Int) = this) +val x3 = select(id { this.length + it.inv() }, fun String.(x: Int) = length) diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt new file mode 100644 index 00000000000..3fa8df88796 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER + +fun id(x: T) = x +fun select(vararg x: T) = x[0] + +val x1 = select(id { this }, fun Int.() = this) +val x2 = select(id { this + it.inv() }, fun Int.(x: Int) = this) +val x3 = select(id { this.length + it.inv() }, fun String.(x: Int) = length) diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.txt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.txt new file mode 100644 index 00000000000..30b17204fed --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.txt @@ -0,0 +1,7 @@ +package + +public val x1: kotlin.Int.() -> kotlin.Int +public val x2: kotlin.Int.(kotlin.Int) -> kotlin.Int +public val x3: kotlin.String.(kotlin.Int) -> kotlin.Int +public fun id(/*0*/ x: T): T +public fun select(/*0*/ vararg x: T /*kotlin.Array*/): T diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 6b1392955de..3fa5e2df98b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10785,6 +10785,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali public void testLambdasInTryCatch() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt"); } + + @TestMetadata("takingExtensibilityFromDeclarationOfAnonymousFunction.kt") + public void testTakingExtensibilityFromDeclarationOfAnonymousFunction() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt"); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index b12bda8f987..1b7864a8909 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10780,6 +10780,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing public void testLambdasInTryCatch() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/lambdasInTryCatch.kt"); } + + @TestMetadata("takingExtensibilityFromDeclarationOfAnonymousFunction.kt") + public void testTakingExtensibilityFromDeclarationOfAnonymousFunction() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt"); + } } }