Fix exception when expected type is subtype of a function type

#KT-28984 Fixed
 #EA-132850 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2018-12-17 12:33:03 +03:00
parent 68c65a5014
commit 84222afe2f
7 changed files with 50 additions and 8 deletions
@@ -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<TypeParameterDe
override fun isEmpty() = false
})
}
private fun KotlinType.isApplicableExpectedTypeForCallableReference(): Boolean {
return this.isFunctionType ||
ReflectionTypes.isBaseTypeForNumberedReferenceTypes(this) ||
ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(this) ||
ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(this)
}
@@ -350,7 +350,7 @@ fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: Unwra
expectedType.isFunctionType ->
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() }
@@ -0,0 +1,12 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
abstract class SubFunction : kotlin.Function0<Unit>
fun <T> takeIt(x: T, f: SubFunction) {}
fun cr() {}
fun test() {
<!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>takeIt<!>(42, <!TYPE_MISMATCH!>::cr<!>)
<!TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>takeIt<!>(42, <!TYPE_MISMATCH!>{ }<!>)
}
@@ -0,0 +1,13 @@
package
public fun cr(): kotlin.Unit
public fun </*0*/ T> 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
}
@@ -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");
@@ -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");
@@ -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)