[NI] Fix input/output types for callable reference atom
Input and output types are crucial for type variable fixation order and analysis of postponed arguments (callable references, lambdas). Specifically, if there is non-fixed type variable inside input types of a callable reference, then we'll postpone resolution for such callable reference. Initial example with the expected type `KMutableProperty1<*, F>` caused problems because input types were computed incorrectly (while there aren't input types here) #KT-25431 Fixed
This commit is contained in:
+42
-14
@@ -5,9 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints
|
||||
@@ -28,6 +26,7 @@ import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -223,9 +222,9 @@ class CallableReferencesCandidateFactory(
|
||||
expectedType: UnwrappedType?,
|
||||
unboundReceiverCount: Int
|
||||
): Triple<Array<KotlinType>, CoercionStrategy, Int>? {
|
||||
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
|
||||
val inputOutputTypes = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType) ?: return null
|
||||
|
||||
val expectedArgumentCount = functionType.arguments.size - unboundReceiverCount - 1 // 1 -- return type
|
||||
val expectedArgumentCount = inputOutputTypes.inputTypes.size - unboundReceiverCount
|
||||
if (expectedArgumentCount < 0) return null
|
||||
|
||||
val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) }
|
||||
@@ -251,7 +250,7 @@ class CallableReferencesCandidateFactory(
|
||||
if (mappedArguments.any { it == null }) return null
|
||||
|
||||
// lower(Unit!) = Unit
|
||||
val returnExpectedType = functionType.getReturnTypeFromFunctionType().lowerIfFlexible()
|
||||
val returnExpectedType = inputOutputTypes.outputType
|
||||
|
||||
val coercion = if (returnExpectedType.isUnit()) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION
|
||||
|
||||
@@ -342,14 +341,43 @@ class CallableReferencesCandidateFactory(
|
||||
}
|
||||
}
|
||||
|
||||
fun getFunctionTypeFromCallableReferenceExpectedType(expectedType: UnwrappedType?): UnwrappedType? {
|
||||
data class InputOutputTypes(val inputTypes: List<UnwrappedType>, val outputType: UnwrappedType)
|
||||
|
||||
fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: UnwrappedType?): InputOutputTypes? {
|
||||
if (expectedType == null) return null
|
||||
|
||||
return if (expectedType.isFunctionType) {
|
||||
expectedType
|
||||
} else if (ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(expectedType)) {
|
||||
expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
|
||||
} else {
|
||||
null
|
||||
return when {
|
||||
expectedType.isFunctionType ->
|
||||
extractInputOutputTypesFromFunctionType(expectedType)
|
||||
|
||||
expectedType.isBaseTypeForNumberedReferenceTypes() ->
|
||||
InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap())
|
||||
|
||||
ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(expectedType) -> {
|
||||
val functionFromSupertype = expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
|
||||
extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
||||
}
|
||||
|
||||
ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(expectedType) -> {
|
||||
val functionFromSupertype = expectedType.supertypes().first { it.isFunctionType }.unwrap()
|
||||
extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() }
|
||||
|
||||
val inputTypes = listOfNotNull(receiver) + parameters
|
||||
val outputType = functionType.getReturnTypeFromFunctionType().unwrap()
|
||||
|
||||
return InputOutputTypes(inputTypes, outputType)
|
||||
}
|
||||
|
||||
+3
-16
@@ -5,14 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.model
|
||||
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
|
||||
import org.jetbrains.kotlin.resolve.calls.components.getFunctionTypeFromCallableReferenceExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
|
||||
@@ -132,18 +127,10 @@ class ResolvedCallableReferenceAtom(
|
||||
}
|
||||
|
||||
override val inputTypes: Collection<UnwrappedType>
|
||||
get() {
|
||||
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return listOfNotNull(expectedType)
|
||||
val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() }
|
||||
val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap()
|
||||
return receiver?.let { parameters + it } ?: parameters
|
||||
}
|
||||
get() = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.inputTypes ?: listOfNotNull(expectedType)
|
||||
|
||||
override val outputType: UnwrappedType?
|
||||
get() {
|
||||
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
|
||||
return functionType.getReturnTypeFromFunctionType().unwrap()
|
||||
}
|
||||
get() = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.outputType
|
||||
}
|
||||
|
||||
class ResolvedCollectionLiteralAtom(
|
||||
|
||||
Reference in New Issue
Block a user