Cleanup GenericCandidateResolver
This commit is contained in:
+29
-39
@@ -48,14 +48,12 @@ import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
|||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||||
|
|
||||||
|
|
||||||
class GenericCandidateResolver(
|
class GenericCandidateResolver(
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver
|
private val argumentTypeResolver: ArgumentTypeResolver
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
||||||
val candidateCall = context.candidateCall
|
val candidateCall = context.candidateCall
|
||||||
val candidate = candidateCall.getCandidateDescriptor()
|
val candidate = candidateCall.candidateDescriptor
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
val constraintSystem = ConstraintSystemImpl()
|
||||||
candidateCall.setConstraintSystem(constraintSystem)
|
candidateCall.setConstraintSystem(constraintSystem)
|
||||||
@@ -68,18 +66,16 @@ class GenericCandidateResolver(
|
|||||||
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
||||||
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
||||||
|
|
||||||
val conversionToOriginal = candidateWithFreshVariables.getTypeParameters().zip(candidate.getTypeParameters()).toMap()
|
val conversionToOriginal = candidateWithFreshVariables.typeParameters.zip(candidate.typeParameters).toMap()
|
||||||
constraintSystem.registerTypeVariables(candidateWithFreshVariables.getTypeParameters(), { Variance.INVARIANT }, { conversionToOriginal[it]!! })
|
constraintSystem.registerTypeVariables(candidateWithFreshVariables.typeParameters, { Variance.INVARIANT }, { conversionToOriginal[it]!! })
|
||||||
|
|
||||||
val substituteDontCare = makeConstantSubstitutor(candidate.getTypeParameters(), DONT_CARE)
|
val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE)
|
||||||
|
|
||||||
// Value parameters
|
// Value parameters
|
||||||
for (entry in candidateCall.getValueArguments().entrySet()) {
|
for ((candidateParameter, resolvedValueArgument) in candidateCall.valueArguments) {
|
||||||
val resolvedValueArgument = entry.getValue()
|
val valueParameterDescriptor = candidate.valueParameters[candidateParameter.index]
|
||||||
val valueParameterDescriptor = candidate.getValueParameters().get(entry.getKey().index)
|
|
||||||
|
|
||||||
|
for (valueArgument in resolvedValueArgument.arguments) {
|
||||||
for (valueArgument in resolvedValueArgument.getArguments()) {
|
|
||||||
// TODO : more attempts, with different expected types
|
// TODO : more attempts, with different expected types
|
||||||
|
|
||||||
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
||||||
@@ -92,19 +88,18 @@ class GenericCandidateResolver(
|
|||||||
|
|
||||||
// Receiver
|
// Receiver
|
||||||
// Error is already reported if something is missing
|
// Error is already reported if something is missing
|
||||||
val receiverArgument = candidateCall.getExtensionReceiver()
|
val receiverArgument = candidateCall.extensionReceiver
|
||||||
val receiverParameter = candidate.getExtensionReceiverParameter()
|
val receiverParameter = candidate.extensionReceiverParameter
|
||||||
if (receiverArgument.exists() && receiverParameter != null) {
|
if (receiverArgument.exists() && receiverParameter != null) {
|
||||||
assert(receiverArgument is ReceiverValue)
|
|
||||||
val receiverArgumentType = (receiverArgument as ReceiverValue).type
|
val receiverArgumentType = (receiverArgument as ReceiverValue).type
|
||||||
var receiverType: KotlinType? = if (context.candidateCall.isSafeCall())
|
var receiverType: KotlinType? = if (context.candidateCall.isSafeCall)
|
||||||
TypeUtils.makeNotNullable(receiverArgumentType)
|
TypeUtils.makeNotNullable(receiverArgumentType)
|
||||||
else
|
else
|
||||||
receiverArgumentType
|
receiverArgumentType
|
||||||
if (receiverArgument is ExpressionReceiver) {
|
if (receiverArgument is ExpressionReceiver) {
|
||||||
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
||||||
}
|
}
|
||||||
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), RECEIVER_POSITION.position())
|
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.type, RECEIVER_POSITION.position())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
@@ -128,11 +123,11 @@ class GenericCandidateResolver(
|
|||||||
val argumentExpression = valueArgument.getArgumentExpression()
|
val argumentExpression = valueArgument.getArgumentExpression()
|
||||||
|
|
||||||
val expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
val expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||||
val dataFlowInfoForArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(valueArgument)
|
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
|
||||||
val newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
val newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||||
|
|
||||||
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext, resolveFunctionArgumentBodies)
|
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext, resolveFunctionArgumentBodies)
|
||||||
context.candidateCall.getDataFlowInfoForArguments().updateInfo(valueArgument, typeInfoForCall.dataFlowInfo)
|
context.candidateCall.dataFlowInfoForArguments.updateInfo(valueArgument, typeInfoForCall.dataFlowInfo)
|
||||||
|
|
||||||
val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||||
|
|
||||||
@@ -150,15 +145,15 @@ class GenericCandidateResolver(
|
|||||||
effectiveExpectedType: KotlinType
|
effectiveExpectedType: KotlinType
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
|
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
|
||||||
if (resolutionResults == null || !resolutionResults.isSingleResult()) return false
|
if (resolutionResults == null || !resolutionResults.isSingleResult) return false
|
||||||
|
|
||||||
val resultingCall = resolutionResults.getResultingCall()
|
val resultingCall = resolutionResults.resultingCall
|
||||||
if (resultingCall.isCompleted()) return false
|
if (resultingCall.isCompleted) return false
|
||||||
|
|
||||||
val argumentConstraintSystem = resultingCall.getConstraintSystem() as ConstraintSystemImpl? ?: return false
|
val argumentConstraintSystem = resultingCall.constraintSystem as ConstraintSystemImpl? ?: return false
|
||||||
|
|
||||||
val candidateDescriptor = resultingCall.getCandidateDescriptor()
|
val candidateDescriptor = resultingCall.candidateDescriptor
|
||||||
val returnType = candidateDescriptor.getReturnType() ?: return false
|
val returnType = candidateDescriptor.returnType ?: return false
|
||||||
|
|
||||||
val nestedTypeVariables = with (argumentConstraintSystem) {
|
val nestedTypeVariables = with (argumentConstraintSystem) {
|
||||||
returnType.getNestedTypeVariables()
|
returnType.getNestedTypeVariables()
|
||||||
@@ -168,12 +163,12 @@ class GenericCandidateResolver(
|
|||||||
if (nestedTypeVariables.any { argumentConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false
|
if (nestedTypeVariables.any { argumentConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false
|
||||||
|
|
||||||
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor)
|
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor)
|
||||||
val conversion = candidateDescriptor.getTypeParameters().zip(candidateWithFreshVariables.getTypeParameters()).toMap()
|
val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap()
|
||||||
|
|
||||||
val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull()
|
val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull()
|
||||||
constraintSystem.registerTypeVariables(freshVariables, { Variance.INVARIANT }, { it }, external = true)
|
constraintSystem.registerTypeVariables(freshVariables, { Variance.INVARIANT }, { it }, external = true)
|
||||||
|
|
||||||
constraintSystem.addSubtypeConstraint(candidateWithFreshVariables.getReturnType(), effectiveExpectedType, constraintPosition)
|
constraintSystem.addSubtypeConstraint(candidateWithFreshVariables.returnType, effectiveExpectedType, constraintPosition)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,19 +189,14 @@ class GenericCandidateResolver(
|
|||||||
return TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, possibleTypes)
|
return TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, possibleTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(
|
fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext<D>) {
|
||||||
context: CallCandidateResolutionContext<D>
|
|
||||||
) {
|
|
||||||
val resolvedCall = context.candidateCall
|
val resolvedCall = context.candidateCall
|
||||||
val constraintSystem = resolvedCall.getConstraintSystem() ?: return
|
val constraintSystem = resolvedCall.constraintSystem ?: return
|
||||||
|
|
||||||
// constraints for function literals
|
// constraints for function literals
|
||||||
// Value parameters
|
// Value parameters
|
||||||
for (entry in resolvedCall.getValueArguments().entrySet()) {
|
for ((valueParameterDescriptor, resolvedValueArgument) in resolvedCall.valueArguments) {
|
||||||
val resolvedValueArgument = entry.getValue()
|
for (valueArgument in resolvedValueArgument.arguments) {
|
||||||
val valueParameterDescriptor = entry.getKey()
|
|
||||||
|
|
||||||
for (valueArgument in resolvedValueArgument.getArguments()) {
|
|
||||||
valueArgument.getArgumentExpression()?.let { argumentExpression ->
|
valueArgument.getArgumentExpression()?.let { argumentExpression ->
|
||||||
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, context)?.let { functionLiteral ->
|
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, context)?.let { functionLiteral ->
|
||||||
addConstraintForFunctionLiteral(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, context)
|
addConstraintForFunctionLiteral(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, context)
|
||||||
@@ -238,7 +228,7 @@ class GenericCandidateResolver(
|
|||||||
hasUnknownFunctionParameter(expectedType)) {
|
hasUnknownFunctionParameter(expectedType)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val dataFlowInfoForArguments = context.candidateCall.getDataFlowInfoForArguments()
|
val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments
|
||||||
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
|
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
|
||||||
|
|
||||||
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
|
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
|
||||||
@@ -248,7 +238,7 @@ class GenericCandidateResolver(
|
|||||||
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
|
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve function literal with expected return type", argumentExpression)
|
context, "trace to resolve function literal with expected return type", argumentExpression)
|
||||||
|
|
||||||
val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.getBodyExpression()) ?: return
|
val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return
|
||||||
val mismatch = BooleanArray(1)
|
val mismatch = BooleanArray(1)
|
||||||
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
||||||
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch)
|
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch)
|
||||||
@@ -309,7 +299,7 @@ class GenericCandidateResolver(
|
|||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
valueArgument: ValueArgument
|
valueArgument: ValueArgument
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val dataFlowInfoForArgument = context.candidateCall.getDataFlowInfoForArguments().getInfo(valueArgument)
|
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
|
||||||
val expectedTypeWithoutReturnType = if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
|
val expectedTypeWithoutReturnType = if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
|
||||||
val newContext = context
|
val newContext = context
|
||||||
.replaceExpectedType(expectedTypeWithoutReturnType)
|
.replaceExpectedType(expectedTypeWithoutReturnType)
|
||||||
@@ -324,7 +314,7 @@ class GenericCandidateResolver(
|
|||||||
|
|
||||||
fun getResolutionResultsCachedData(expression: KtExpression?, context: ResolutionContext<*>): ResolutionResultsCache.CachedData? {
|
fun getResolutionResultsCachedData(expression: KtExpression?, context: ResolutionContext<*>): ResolutionResultsCache.CachedData? {
|
||||||
if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null
|
if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null
|
||||||
val argumentCall = expression?.getCall(context.trace.getBindingContext()) ?: return null
|
val argumentCall = expression?.getCall(context.trace.bindingContext) ?: return null
|
||||||
|
|
||||||
return context.resolutionResultsCache[argumentCall]
|
return context.resolutionResultsCache[argumentCall]
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -17,12 +17,12 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.context
|
package org.jetbrains.kotlin.resolve.calls.context
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
|
||||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
|
||||||
import java.util.HashMap
|
|
||||||
import org.jetbrains.kotlin.psi.Call
|
import org.jetbrains.kotlin.psi.Call
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache.CachedData
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache.CachedData
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
public interface ResolutionResultsCache {
|
public interface ResolutionResultsCache {
|
||||||
public data class CachedData(
|
public data class CachedData(
|
||||||
@@ -40,7 +40,7 @@ public interface ResolutionResultsCache {
|
|||||||
resolutionTrace: DelegatingBindingTrace
|
resolutionTrace: DelegatingBindingTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
fun get(call: Call): CachedData?
|
operator fun get(call: Call): CachedData?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResolutionResultsCacheImpl : ResolutionResultsCache {
|
class ResolutionResultsCacheImpl : ResolutionResultsCache {
|
||||||
|
|||||||
Reference in New Issue
Block a user