Cleanup GenericCandidateResolver

This commit is contained in:
Alexander Udalov
2015-11-10 16:20:03 +03:00
parent 99b411c8ca
commit 8cc484bc25
2 changed files with 34 additions and 44 deletions
@@ -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]
} }
@@ -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 {