From 84222afe2f9bc77b5ccaf96f2f9d72dc8c26ce03 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 17 Dec 2018 12:33:03 +0300 Subject: [PATCH] Fix exception when expected type is subtype of a function type #KT-28984 Fixed #EA-132850 Fixed --- .../resolve/calls/GenericCandidateResolver.kt | 11 +++++++++-- .../calls/components/CallableReferenceResolution.kt | 7 +------ .../expectedTypeAsSubtypeOfFunctionType.kt | 12 ++++++++++++ .../expectedTypeAsSubtypeOfFunctionType.txt | 13 +++++++++++++ .../kotlin/checkers/DiagnosticsTestGenerated.java | 5 +++++ .../javac/DiagnosticsUsingJavacTestGenerated.java | 5 +++++ .../jetbrains/kotlin/builtins/ReflectionTypes.kt | 5 +++++ 7 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index a49e8a7a300..7134af0a971 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -434,7 +434,7 @@ class GenericCandidateResolver( expectedType?.isSuspendFunctionType == true ) } - if (expectedType == null || !expectedType.isBuiltinFunctionalTypeOrSubtype || hasUnknownFunctionParameter(expectedType)) { + if (expectedType == null || !expectedType.isBuiltinFunctionalType || hasUnknownFunctionParameter(expectedType)) { return } val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments @@ -491,7 +491,7 @@ class GenericCandidateResolver( val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context) val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType) ?: return - if (!ReflectionTypes.isCallableType(expectedType)) return + if (!expectedType.isApplicableExpectedTypeForCallableReference()) return val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) constraintSystem.addSubtypeConstraint( @@ -555,3 +555,10 @@ fun makeConstantSubstitutor(typeParameterDescriptors: Collection extractInputOutputTypesFromFunctionType(expectedType) - expectedType.isBaseTypeForNumberedReferenceTypes() -> + ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) -> InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap()) ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(expectedType) -> { @@ -367,11 +367,6 @@ fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: Unwra } } -private fun UnwrappedType.isBaseTypeForNumberedReferenceTypes(): Boolean = - ReflectionTypes.hasKPropertyTypeFqName(this) || - ReflectionTypes.hasKMutablePropertyTypeFqName(this) || - ReflectionTypes.hasKCallableTypeFqName(this) - private fun extractInputOutputTypesFromFunctionType(functionType: UnwrappedType): InputOutputTypes { val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap() val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() } diff --git a/compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.kt b/compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.kt new file mode 100644 index 00000000000..121bba05a6d --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +abstract class SubFunction : kotlin.Function0 + +fun takeIt(x: T, f: SubFunction) {} + +fun cr() {} + +fun test() { + takeIt(42, ::cr) + takeIt(42, { }) +} diff --git a/compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.txt b/compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.txt new file mode 100644 index 00000000000..5bd592a648d --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.txt @@ -0,0 +1,13 @@ +package + +public fun cr(): kotlin.Unit +public fun takeIt(/*0*/ x: T, /*1*/ f: SubFunction): kotlin.Unit +public fun test(): kotlin.Unit + +public abstract class SubFunction : () -> kotlin.Unit { + public constructor SubFunction() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun invoke(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 9f8a8471d3e..0c84b5c7200 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -1651,6 +1651,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/callableReference/emptyLhs.kt"); } + @TestMetadata("expectedTypeAsSubtypeOfFunctionType.kt") + public void testExpectedTypeAsSubtypeOfFunctionType() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.kt"); + } + @TestMetadata("kt15439_completeCall.kt") public void testKt15439_completeCall() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/kt15439_completeCall.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 44024ff3e1d..265ff9e8c1b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -1651,6 +1651,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/callableReference/emptyLhs.kt"); } + @TestMetadata("expectedTypeAsSubtypeOfFunctionType.kt") + public void testExpectedTypeAsSubtypeOfFunctionType() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/expectedTypeAsSubtypeOfFunctionType.kt"); + } + @TestMetadata("kt15439_completeCall.kt") public void testKt15439_completeCall() throws Exception { runTest("compiler/testData/diagnostics/tests/callableReference/kt15439_completeCall.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt index 239ab4a3059..07589fc778d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt @@ -97,6 +97,11 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not fun isCallableType(type: KotlinType): Boolean = type.isFunctionTypeOrSubtype || type.isSuspendFunctionTypeOrSubtype || isKCallableType(type) + fun isBaseTypeForNumberedReferenceTypes(type: KotlinType): Boolean = + ReflectionTypes.hasKPropertyTypeFqName(type) || + ReflectionTypes.hasKMutablePropertyTypeFqName(type) || + ReflectionTypes.hasKCallableTypeFqName(type) + @JvmStatic fun isNumberedKPropertyOrKMutablePropertyType(type: KotlinType): Boolean = isNumberedKPropertyType(type) || isNumberedKMutablePropertyType(type)