NI: do type checking for anonymous functions not inside a call

^KT-38890 Fixed
^KT-38439 Fixed
This commit is contained in:
Victor Petukhov
2020-05-19 11:31:15 +03:00
parent 425ce8c3ab
commit eff5f3a242
18 changed files with 174 additions and 25 deletions
@@ -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");
@@ -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<Int, Unit>`
*/
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
@@ -9,7 +9,7 @@ fun testReturnType(foo: String) {
val bas: () -> String = fun () = foo
val bag: () -> Int = <!OI;TYPE_MISMATCH!>fun () = foo<!>
val bag: () -> Int = <!TYPE_MISMATCH!>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 = <!OI;TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>param: String<!>) {}<!>
val bag: (Int) -> Unit = <!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>param: String<!>) {}<!>
}
fun testReceiverType() {
@@ -28,5 +28,5 @@ fun testReceiverType() {
val bas: String.() -> Unit = fun String.() {}
val bag: Int.() -> Unit = <!OI;TYPE_MISMATCH!>fun String.() {}<!>
val bag: Int.() -> Unit = <!TYPE_MISMATCH!>fun String.() {}<!>
}
@@ -17,4 +17,4 @@ fun test2(a: () -> List<Int>) {
val a: (Int) -> Unit = fun(x) { checkSubtype<Int>(x) }
val b: (Int) -> Unit = <!OI;TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>
val b: (Int) -> Unit = <!TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>
@@ -6,22 +6,22 @@ val a = fun (<!CANNOT_INFER_PARAMETER_TYPE!>x<!>) = <!DEBUG_INFO_ELEMENT_WITH_ER
val b: (Int) -> Int = fun (x) = x + 3
val c: (Int, String) -> Int = <!OI;TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
val c: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
val d: (Int, String) -> Int = <!OI;TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
val d: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(x)<!> = 3<!>
val e: (Int, String) -> Int = <!OI;TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> = 3<!>
val e: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> = 3<!>
val f: (Int) -> Int = <!OI;TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) = 3<!>
val f: (Int) -> Int = <!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) = 3<!>
fun test1(a: (Int) -> Unit) {
test1(fun (x) { checkSubtype<Int>(x)})
}
fun test2(a: (Int) -> Unit) {
test2(<!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>)
test2(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>)
}
fun test3(a: (Int, String) -> Unit) {
test3(<!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> {}<!>)
test3(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> {}<!>)
}
@@ -1,3 +1,3 @@
// !WITH_NEW_INFERENCE
fun foo(<!UNUSED_PARAMETER!>f<!>: String.() -> Int) {}
val test = foo(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun <!NI;EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = <!UNRESOLVED_REFERENCE!>length<!><!>)
val test = foo(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun <!NI;EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = <!UNRESOLVED_REFERENCE!>length<!><!>)
@@ -16,6 +16,6 @@ fun test(s: Sub) {
t: Trait -> s
}
foo(<!TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>t: Sub<!>) = s<!>)
foo(<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>t: Sub<!>) = s<!>)
foo(<!TYPE_MISMATCH!>fun(t): Super = s<!>)
}
@@ -0,0 +1,40 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST
// Issues: KT-38890, KT-38439
fun foo(x: () -> Int) {}
fun <T>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"
<!INAPPLICABLE_CANDIDATE!>foo<!>(fun(): String = "1")
<!INAPPLICABLE_CANDIDATE!>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() = {}
}
@@ -0,0 +1,40 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNCHECKED_CAST
// Issues: KT-38890, KT-38439
fun foo(x: () -> Int) {}
fun <T>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 = { <!TYPE_MISMATCH!>""<!> }
val a0: () -> Int = <!TYPE_MISMATCH!>fun(): String = "1"<!>
val a1: () -> Int = (<!TYPE_MISMATCH!>fun() = "1"<!>)
val a2: () -> Unit = (<!TYPE_MISMATCH!>fun() = "1"<!>)
val a3: Unit = (<!TYPE_MISMATCH!>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 = <!TYPE_MISMATCH!>fun(): String = "1"<!>
val a9: () -> () -> () -> Int = <!TYPE_MISMATCH!>fun(): () -> () -> String = fun(): () -> String = fun(): String = "1"<!>
foo(<!TYPE_MISMATCH!>fun(): String = "1"<!>)
foo(((<!TYPE_MISMATCH!>fun(): String = "1"<!>)))
val a10: Int.(String) -> Int = <!TYPE_MISMATCH!>fun (x: String) = 10<!>
val a11: () -> () -> () -> Int = <!TYPE_MISMATCH!>fun() = fun() = fun(): String = "1"<!>
val a12: Int = <!TYPE_MISMATCH!>fun(): String = "1"<!>
val a13: Int = <!TYPE_MISMATCH!>fun() = fun(): String = "1"<!>
val a14: Int = <!TYPE_MISMATCH!>fun() = fun() = "1"<!>
val a15: Int = <!TYPE_MISMATCH!>fun() = fun() = {}<!>
val a16: Int = <!TYPE_MISMATCH!>fun() = fun() {}<!>
val a17: () -> Unit = fun() {}
val a18: () -> Int = <!TYPE_MISMATCH!>fun() {}<!>
val a19: () -> () -> Int = <!TYPE_MISMATCH!>fun() = fun() {}<!>
val a20: () -> () -> () -> Unit = fun() = fun() = {}
val a21: () -> () -> () -> Int = <!TYPE_MISMATCH!>fun() = fun() = {}<!>
}
@@ -0,0 +1,5 @@
package
public fun foo(/*0*/ x: () -> kotlin.Int): kotlin.Unit
public fun </*0*/ T> id(/*0*/ x: T): T
public fun main(): kotlin.Unit
@@ -0,0 +1,24 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun take(fn: () -> List<String>) {}
fun <L> inferFromLambda(fn: () -> L): L = TODO()
fun <L> inferFromLambda2(fn: (Int) -> L): L = TODO()
fun <T> materialize(): T = TODO()
fun <I> id(arg: I) = arg
fun testFunctions() {
take { materialize() }
take(fun() = materialize())
take(fun(): List<String> = materialize())
take(fun(): List<String> {
return materialize()
})
}
fun testNestedCalls() {
id<String>(inferFromLambda { materialize() })
id<String>(inferFromLambda(fun() = materialize()))
id<String>(inferFromLambda2(fun() = materialize()))
}
@@ -1,9 +1,9 @@
// FIR_IDENTICAL
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun take(fn: () -> List<String>) {}
fun <L> inferFromLambda(fn: () -> L): L = TODO()
fun <L> inferFromLambda2(fn: (Int) -> L): L = TODO()
fun <T> materialize(): T = TODO()
fun <I> id(arg: I) = arg
@@ -20,4 +20,5 @@ fun testFunctions() {
fun testNestedCalls() {
id<String>(inferFromLambda { materialize() })
id<String>(inferFromLambda(fun() = materialize()))
id<String>(inferFromLambda2(<!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>fun<!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>()<!> = materialize()<!>))
}
@@ -2,6 +2,7 @@ package
public fun </*0*/ I> id(/*0*/ arg: I): I
public fun </*0*/ L> inferFromLambda(/*0*/ fn: () -> L): L
public fun </*0*/ L> inferFromLambda2(/*0*/ fn: (kotlin.Int) -> L): L
public fun </*0*/ T> materialize(): T
public fun take(/*0*/ fn: () -> kotlin.collections.List<kotlin.String>): kotlin.Unit
public fun testFunctions(): kotlin.Unit
@@ -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) { }), <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>x, <!CANNOT_INFER_PARAMETER_TYPE!>y<!><!> -> x }<!>)
select(id(id(fun(x: String, y: String) { }), <!TOO_MANY_ARGUMENTS!>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 = <!TYPE_MISMATCH!>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(<!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> = 10<!>)
select(id<Int.(String) -> Unit> {}, { x: Int, y: String -> x })
+1 -1
View File
@@ -15,7 +15,7 @@ class A() {
//more tests
val g : () -> Unit = { <!UNUSED_EXPRESSION!>42<!> }
val gFunction : () -> Unit = <!OI;TYPE_MISMATCH!>fun(): Int = 1<!>
val gFunction : () -> Unit = <!TYPE_MISMATCH!>fun(): Int = 1<!>
val h : () -> Unit = { doSmth() }
@@ -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");
@@ -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");
@@ -428,9 +428,11 @@ public class TypeUtils {
SmartSet<KotlinType> 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) {