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 7b46cd11983..085d7462dbf 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 @@ -8195,6 +8195,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/functionLiterals/lambdaInLambda2.kt"); } + @TestMetadata("missedTypeMismatch.kt") + public void testMissedTypeMismatch() throws Exception { + runTest("compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt"); + } + @TestMetadata("prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt") public void testPrematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument() throws Exception { runTest("compiler/testData/diagnostics/tests/functionLiterals/prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index e0311c1497b..323faf5f2e3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor import org.jetbrains.kotlin.resolve.checkers.TrailingCommaChecker -import org.jetbrains.kotlin.resolve.checkers.TrailingCommaDeclarationChecker import org.jetbrains.kotlin.resolve.checkers.UnderscoreChecker import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope @@ -116,17 +115,35 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre return if (isDeclaration) { createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context) } else { - val expectedType = context.expectedType - - val functionalTypeExpected = expectedType.isBuiltinFunctionalType() + val newInferenceEnabled = components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) // We forbid anonymous function expressions to suspend type coercion for now, until `suspend fun` syntax is supported - val resultType = functionDescriptor.createFunctionType(components.builtIns, suspendFunction = false) + val resultType = functionDescriptor.createFunctionType( + components.builtIns, + suspendFunction = false + ) - if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) && functionalTypeExpected && !expectedType.isSuspendFunctionType) + if (newInferenceEnabled) { + // We should avoid type checking for types containing `NO_EXPECTED_TYPE`, the error will be report later if needed + if (!context.expectedType.contains { it === NO_EXPECTED_TYPE }) { + /* + * We do type checking without converted vararg type as the new inference create expected type with raw vararg type (see KotlinResolutionCallbacksImpl.kt) + * Example: + * fun foo(x: Any?) {} + * val x = foo(fun(vararg p: Int) {}) + * In NI, context.expectedType = `Function1` + */ + val typeToTypeCheck = functionDescriptor.createFunctionType( + components.builtIns, + suspendFunction = false, + shouldUseVarargType = true + ) + components.dataFlowAnalyzer.checkType(typeToTypeCheck, function, context) + } createTypeInfo(resultType, context) - else + } else { components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, function) + } } } @@ -370,12 +387,16 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre } } -fun SimpleFunctionDescriptor.createFunctionType(builtIns: KotlinBuiltIns, suspendFunction: Boolean = false): KotlinType? { +fun SimpleFunctionDescriptor.createFunctionType( + builtIns: KotlinBuiltIns, + suspendFunction: Boolean = false, + shouldUseVarargType: Boolean = false +): KotlinType? { return createFunctionType( builtIns, Annotations.EMPTY, extensionReceiverParameter?.type, - valueParameters.map { it.type }, + if (shouldUseVarargType) valueParameters.map { it.varargElementType ?: it.type } else valueParameters.map { it.type }, null, returnType ?: return null, suspendFunction = suspendFunction diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/FunctionType.kt b/compiler/testData/diagnostics/tests/functionAsExpression/FunctionType.kt index 024f02028d2..fe07efb7534 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/FunctionType.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/FunctionType.kt @@ -9,7 +9,7 @@ fun testReturnType(foo: String) { val bas: () -> String = fun () = foo - val bag: () -> Int = fun () = foo + val bag: () -> Int = fun () = foo } fun testParamType() { @@ -18,7 +18,7 @@ fun testParamType() { bar.checkType { _<(String) -> Unit>() } val bas: (String) -> Unit = fun (param: String) {} - val bag: (Int) -> Unit = fun (param: String) {} + val bag: (Int) -> Unit = fun (param: String) {} } fun testReceiverType() { @@ -28,5 +28,5 @@ fun testReceiverType() { val bas: String.() -> Unit = fun String.() {} - val bag: Int.() -> Unit = fun String.() {} + val bag: Int.() -> Unit = fun String.() {} } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt b/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt index b458f865a91..0fce1feccb1 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt @@ -17,4 +17,4 @@ fun test2(a: () -> List) { val a: (Int) -> Unit = fun(x) { checkSubtype(x) } -val b: (Int) -> Unit = fun(x: String) {} \ No newline at end of file +val b: (Int) -> Unit = fun(x: String) {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt b/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt index 442c7f3c2a2..2a4e5fbf600 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt @@ -6,22 +6,22 @@ val a = fun (x) = Int = fun (x) = x + 3 -val c: (Int, String) -> Int = fun (x) = 3 +val c: (Int, String) -> Int = fun (x) = 3 -val d: (Int, String) -> Int = fun (x) = 3 +val d: (Int, String) -> Int = fun (x) = 3 -val e: (Int, String) -> Int = fun (x: String) = 3 +val e: (Int, String) -> Int = fun (x: String) = 3 -val f: (Int) -> Int = fun (x: String) = 3 +val f: (Int) -> Int = fun (x: String) = 3 fun test1(a: (Int) -> Unit) { test1(fun (x) { checkSubtype(x)}) } fun test2(a: (Int) -> Unit) { - test2(fun (x: String) {}) + test2(fun (x: String) {}) } fun test3(a: (Int, String) -> Unit) { - test3(fun (x: String) {}) + test3(fun (x: String) {}) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt b/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt index 14ddcad79dc..f517152c8f1 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/ReceiverByExpectedType.kt @@ -1,3 +1,3 @@ // !WITH_NEW_INFERENCE fun foo(f: String.() -> Int) {} -val test = foo(fun () = length) \ No newline at end of file +val test = foo(fun () = length) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt index 36d113e6f6f..2bf2645eee8 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt @@ -16,6 +16,6 @@ fun test(s: Sub) { t: Trait -> s } - foo(fun(t: Sub) = s) + foo(fun(t: Sub) = s) foo(fun(t): Super = s) } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.fir.kt new file mode 100644 index 00000000000..21c7540c3c1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.fir.kt @@ -0,0 +1,40 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST +// Issues: KT-38890, KT-38439 + +fun foo(x: () -> Int) {} + +fun id(x: T) = x + +// Before the fix, there wasn't any type mismatch error in NI due to result type not being a subtype of expected type +fun main() { + val x: () -> Int = { "" } + + val a0: () -> Int = fun(): String = "1" + val a1: () -> Int = (fun() = "1") + val a2: () -> Unit = (fun() = "1") + val a3: Unit = (fun() = "1") + val a4 = (fun() = "1") + val a5 = (fun(): String = "1") + val a6: () -> Int = (fun() = 1) + val a7: () -> Int = (fun(): String = "1") as () -> Int + val a8: () -> Int = fun(): String = "1" + val a9: () -> () -> () -> Int = fun(): () -> () -> String = fun(): () -> String = fun(): String = "1" + + foo(fun(): String = "1") + foo(((fun(): String = "1"))) + + val a10: Int.(String) -> Int = fun (x: String) = 10 + val a11: () -> () -> () -> Int = fun() = fun() = fun(): String = "1" + + val a12: Int = fun(): String = "1" + val a13: Int = fun() = fun(): String = "1" + val a14: Int = fun() = fun() = "1" + val a15: Int = fun() = fun() = {} + val a16: Int = fun() = fun() {} + + val a17: () -> Unit = fun() {} + val a18: () -> Int = fun() {} + val a19: () -> () -> Int = fun() = fun() {} + val a20: () -> () -> () -> Unit = fun() = fun() = {} + val a21: () -> () -> () -> Int = fun() = fun() = {} +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt b/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt new file mode 100644 index 00000000000..167a38b890b --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt @@ -0,0 +1,40 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST +// Issues: KT-38890, KT-38439 + +fun foo(x: () -> Int) {} + +fun id(x: T) = x + +// Before the fix, there wasn't any type mismatch error in NI due to result type not being a subtype of expected type +fun main() { + val x: () -> Int = { "" } + + val a0: () -> Int = fun(): String = "1" + val a1: () -> Int = (fun() = "1") + val a2: () -> Unit = (fun() = "1") + val a3: Unit = (fun() = "1") + val a4 = (fun() = "1") + val a5 = (fun(): String = "1") + val a6: () -> Int = (fun() = 1) + val a7: () -> Int = (fun(): String = "1") as () -> Int + val a8: () -> Int = fun(): String = "1" + val a9: () -> () -> () -> Int = fun(): () -> () -> String = fun(): () -> String = fun(): String = "1" + + foo(fun(): String = "1") + foo(((fun(): String = "1"))) + + val a10: Int.(String) -> Int = fun (x: String) = 10 + val a11: () -> () -> () -> Int = fun() = fun() = fun(): String = "1" + + val a12: Int = fun(): String = "1" + val a13: Int = fun() = fun(): String = "1" + val a14: Int = fun() = fun() = "1" + val a15: Int = fun() = fun() = {} + val a16: Int = fun() = fun() {} + + val a17: () -> Unit = fun() {} + val a18: () -> Int = fun() {} + val a19: () -> () -> Int = fun() = fun() {} + val a20: () -> () -> () -> Unit = fun() = fun() = {} + val a21: () -> () -> () -> Int = fun() = fun() = {} +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.txt b/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.txt new file mode 100644 index 00000000000..8da0a5859d3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.txt @@ -0,0 +1,5 @@ +package + +public fun foo(/*0*/ x: () -> kotlin.Int): kotlin.Unit +public fun id(/*0*/ x: T): T +public fun main(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt new file mode 100644 index 00000000000..dc35cde2de0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.fir.kt @@ -0,0 +1,24 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun take(fn: () -> List) {} +fun inferFromLambda(fn: () -> L): L = TODO() +fun inferFromLambda2(fn: (Int) -> L): L = TODO() + +fun materialize(): T = TODO() +fun id(arg: I) = arg + +fun testFunctions() { + take { materialize() } + take(fun() = materialize()) + take(fun(): List = materialize()) + take(fun(): List { + return materialize() + }) +} + +fun testNestedCalls() { + id(inferFromLambda { materialize() }) + id(inferFromLambda(fun() = materialize())) + id(inferFromLambda2(fun() = materialize())) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt index 5fc14bebbe2..75473e3d5a3 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt @@ -1,9 +1,9 @@ -// FIR_IDENTICAL // !LANGUAGE: +NewInference // !DIAGNOSTICS: -UNUSED_PARAMETER fun take(fn: () -> List) {} fun inferFromLambda(fn: () -> L): L = TODO() +fun inferFromLambda2(fn: (Int) -> L): L = TODO() fun materialize(): T = TODO() fun id(arg: I) = arg @@ -20,4 +20,5 @@ fun testFunctions() { fun testNestedCalls() { id(inferFromLambda { materialize() }) id(inferFromLambda(fun() = materialize())) + id(inferFromLambda2(fun() = materialize())) } diff --git a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.txt b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.txt index ba09cc8ce83..31673e675d0 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.txt +++ b/compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.txt @@ -2,6 +2,7 @@ package public fun id(/*0*/ arg: I): I public fun inferFromLambda(/*0*/ fn: () -> L): L +public fun inferFromLambda2(/*0*/ fn: (kotlin.Int) -> L): L public fun materialize(): T public fun take(/*0*/ fn: () -> kotlin.collections.List): kotlin.Unit public fun testFunctions(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt index f9af745674a..376b81c8f35 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.kt @@ -153,7 +153,7 @@ fun main() { // Convert to extension lambda is impossible because the lambda parameter types aren't specified explicitly select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), { x, y -> x }) select(id(id(fun(x: String, y: String) { }), fun String.(x: String) {}), { x, y -> x }) - val x26: Int.(String) -> Int = fun (x: String) = 10 // it must be error, see KT-38439 + val x26: Int.(String) -> Int = fun (x: String) = 10 // it must be error, see KT-38439 // Receiver must be specified in anonymous function declaration val x27: Int.(String) -> Int = id(fun (x: String) = 10) select(id Unit> {}, { x: Int, y: String -> x }) diff --git a/compiler/testData/diagnostics/tests/regressions/kt352.kt b/compiler/testData/diagnostics/tests/regressions/kt352.kt index 89d65292cba..5bd249c75ea 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt352.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt352.kt @@ -15,7 +15,7 @@ class A() { //more tests val g : () -> Unit = { 42 } -val gFunction : () -> Unit = fun(): Int = 1 +val gFunction : () -> Unit = fun(): Int = 1 val h : () -> Unit = { doSmth() } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 8ccb0ce7052..2dc09770362 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -8202,6 +8202,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/functionLiterals/lambdaInLambda2.kt"); } + @TestMetadata("missedTypeMismatch.kt") + public void testMissedTypeMismatch() throws Exception { + runTest("compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt"); + } + @TestMetadata("prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt") public void testPrematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument() throws Exception { runTest("compiler/testData/diagnostics/tests/functionLiterals/prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index b262053f52f..de9f0a087ef 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -8197,6 +8197,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/functionLiterals/lambdaInLambda2.kt"); } + @TestMetadata("missedTypeMismatch.kt") + public void testMissedTypeMismatch() throws Exception { + runTest("compiler/testData/diagnostics/tests/functionLiterals/missedTypeMismatch.kt"); + } + @TestMetadata("prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt") public void testPrematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument() throws Exception { runTest("compiler/testData/diagnostics/tests/functionLiterals/prematurelyAnalyzingLambdaWhileFixingTypeVariableForAnotherArgument.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java index 78d3c424297..174d1e06723 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java @@ -428,9 +428,11 @@ public class TypeUtils { SmartSet visited ) { if (type == null) return false; - if (visited != null && visited.contains(type)) return false; UnwrappedType unwrappedType = type.unwrap(); + + if (noExpectedType(type)) return isSpecialType.invoke(unwrappedType); + if (visited != null && visited.contains(type)) return false; if (isSpecialType.invoke(unwrappedType)) return true; if (visited == null) {