[FE 1.0] Get rid of GenericCandidateResolver
This commit is contained in:
committed by
teamcity
parent
4ea08a59db
commit
941a33a184
@@ -1,529 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getBinaryWithTypeParent
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.util.*
|
||||
import org.jetbrains.kotlin.resolve.calls.util.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
||||
import org.jetbrains.kotlin.resolve.calls.util.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ValidityConstraintForConstituentType
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.makeNullableTypeIfSafeReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.isFunctionForExpectTypeFromCastFeature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
||||
|
||||
class GenericCandidateResolver(
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val dataFlowValueFactory: DataFlowValueFactory
|
||||
) {
|
||||
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
||||
val candidateCall = context.candidateCall
|
||||
val candidate = candidateCall.candidateDescriptor
|
||||
|
||||
val builder = ConstraintSystemBuilderImpl()
|
||||
builder.registerTypeVariables(candidateCall.call.toHandle(), candidate.typeParameters)
|
||||
|
||||
val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE)
|
||||
|
||||
// Value parameters
|
||||
for ((candidateParameter, resolvedValueArgument) in candidateCall.valueArguments) {
|
||||
val valueParameterDescriptor = candidate.valueParameters[candidateParameter.index]
|
||||
|
||||
for (valueArgument in resolvedValueArgument.arguments) {
|
||||
// TODO : more attempts, with different expected types
|
||||
|
||||
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
||||
// and throw the results away
|
||||
// We'll type check the arguments later, with the inferred types expected
|
||||
addConstraintForValueArgument(
|
||||
valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate is TypeAliasConstructorDescriptor) {
|
||||
val substitutedReturnType = builder.compositeSubstitutor().safeSubstitute(candidate.returnType, Variance.INVARIANT)
|
||||
addValidityConstraintsForConstituentTypes(builder, substitutedReturnType)
|
||||
}
|
||||
|
||||
// Receiver
|
||||
// Error is already reported if something is missing
|
||||
val receiverArgument = candidateCall.extensionReceiver
|
||||
val receiverParameter = candidate.extensionReceiverParameter
|
||||
if (receiverArgument != null && receiverParameter != null) {
|
||||
val receiverArgumentType = receiverArgument.type
|
||||
var receiverType: KotlinType? = if (context.candidateCall.call.isSafeCall())
|
||||
TypeUtils.makeNotNullable(receiverArgumentType)
|
||||
else
|
||||
receiverArgumentType
|
||||
if (receiverArgument is ExpressionReceiver) {
|
||||
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
||||
}
|
||||
builder.addSubtypeConstraint(
|
||||
receiverType,
|
||||
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
|
||||
RECEIVER_POSITION.position()
|
||||
)
|
||||
}
|
||||
|
||||
val constraintSystem = builder.build()
|
||||
candidateCall.setConstraintSystem(constraintSystem)
|
||||
|
||||
// Solution
|
||||
val hasContradiction = constraintSystem.status.hasContradiction()
|
||||
if (!hasContradiction) {
|
||||
addExpectedTypeForExplicitCast(context, builder)
|
||||
return INCOMPLETE_TYPE_INFERENCE
|
||||
}
|
||||
return OTHER_ERROR
|
||||
}
|
||||
|
||||
private fun ConstraintSystem.Builder.typeInSystem(call: Call, type: KotlinType?): KotlinType? =
|
||||
type?.let {
|
||||
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
private fun addExpectedTypeForExplicitCast(
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
builder: ConstraintSystem.Builder
|
||||
) {
|
||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return
|
||||
|
||||
if (context.candidateCall is VariableAsFunctionResolvedCall) return
|
||||
|
||||
val candidateDescriptor = context.candidateCall.candidateDescriptor.safeAs<FunctionDescriptor>() ?: return
|
||||
|
||||
val binaryParent = context.call.calleeExpression?.getBinaryWithTypeParent() ?: return
|
||||
val operationType = binaryParent.operationReference.getReferencedNameElementType().takeIf {
|
||||
it == KtTokens.AS_KEYWORD || it == KtTokens.AS_SAFE
|
||||
} ?: return
|
||||
|
||||
val leftType = context.trace.get(BindingContext.TYPE, binaryParent.right ?: return) ?: return
|
||||
val expectedType = if (operationType == KtTokens.AS_SAFE) leftType.makeNullable() else leftType
|
||||
|
||||
if (context.candidateCall.call.typeArgumentList != null || !candidateDescriptor.isFunctionForExpectTypeFromCastFeature()) return
|
||||
|
||||
val typeInSystem = builder.typeInSystem(context.call, candidateDescriptor.returnType ?: return) ?: return
|
||||
|
||||
context.trace.record(BindingContext.CAST_TYPE_USED_AS_EXPECTED_TYPE, binaryParent)
|
||||
builder.addSubtypeConstraint(typeInSystem, expectedType, ConstraintPositionKind.SPECIAL.position())
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForConstituentTypes(builder: ConstraintSystem.Builder, type: KotlinType) {
|
||||
val typeConstructor = type.constructor
|
||||
if (typeConstructor.declarationDescriptor is TypeParameterDescriptor) return
|
||||
|
||||
val boundsSubstitutor = TypeSubstitutor.create(type)
|
||||
|
||||
type.arguments.forEachIndexed forEachArgument@ { i, typeProjection ->
|
||||
if (typeProjection.isStarProjection) return@forEachArgument // continue
|
||||
|
||||
val typeParameter = typeConstructor.parameters[i]
|
||||
addValidityConstraintsForTypeArgument(builder, typeProjection, typeParameter, boundsSubstitutor)
|
||||
|
||||
addValidityConstraintsForConstituentTypes(builder, typeProjection.type)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForTypeArgument(
|
||||
builder: ConstraintSystem.Builder,
|
||||
substitutedArgument: TypeProjection,
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
) {
|
||||
val substitutedType = substitutedArgument.type
|
||||
for (upperBound in typeParameter.upperBounds) {
|
||||
val substitutedUpperBound = boundsSubstitutor.safeSubstitute(upperBound, Variance.INVARIANT).upperIfFlexible()
|
||||
val constraintPosition = ValidityConstraintForConstituentType(substitutedType, typeParameter, substitutedUpperBound)
|
||||
|
||||
// Do not add extra constraints if upper bound is 'Any?';
|
||||
// otherwise it will be treated incorrectly in nested calls processing.
|
||||
if (KotlinBuiltIns.isNullableAny(substitutedUpperBound)) continue
|
||||
|
||||
builder.addSubtypeConstraint(substitutedType, substitutedUpperBound, constraintPosition)
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a substitutor which maps types to their representation in the constraint system.
|
||||
// In case when some type parameter descriptor is represented by more than one variable in the system, the behavior is undefined.
|
||||
private fun ConstraintSystem.Builder.compositeSubstitutor(): TypeSubstitutor {
|
||||
return TypeSubstitutor.create(object : TypeSubstitution() {
|
||||
override fun get(key: KotlinType): TypeProjection? {
|
||||
return typeVariableSubstitutors.values.reversed().asSequence().mapNotNull { it.substitution.get(key) }.firstOrNull()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun addConstraintForValueArgument(
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
builder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||
) {
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||
val argumentExpression = valueArgument.getArgumentExpression()
|
||||
|
||||
val expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
|
||||
val newContext = context.replaceExpectedType(expectedType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
|
||||
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(
|
||||
argumentExpression,
|
||||
newContext,
|
||||
resolveFunctionArgumentBodies,
|
||||
expectedType?.isSuspendFunctionType == true
|
||||
)
|
||||
context.candidateCall.dataFlowInfoForArguments.updateInfo(valueArgument, typeInfoForCall.dataFlowInfo)
|
||||
|
||||
val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||
|
||||
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return
|
||||
|
||||
val type =
|
||||
updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
|
||||
|
||||
if (argumentExpression is KtCallableReferenceExpression && type == null) return
|
||||
|
||||
builder.addSubtypeConstraint(
|
||||
type,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
constraintPosition
|
||||
)
|
||||
}
|
||||
|
||||
private fun addConstraintForNestedCall(
|
||||
argumentExpression: KtExpression?,
|
||||
constraintPosition: ConstraintPosition,
|
||||
builder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
effectiveExpectedType: KotlinType
|
||||
): Boolean {
|
||||
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
|
||||
if (resolutionResults == null || !resolutionResults.isSingleResult) return false
|
||||
|
||||
val nestedCall = resolutionResults.resultingCall
|
||||
if (nestedCall.isCompleted) return false
|
||||
|
||||
val nestedConstraintSystem = nestedCall.constraintSystem ?: return false
|
||||
|
||||
val candidateDescriptor = nestedCall.candidateDescriptor
|
||||
val returnType = candidateDescriptor.returnType ?: return false
|
||||
|
||||
val nestedTypeVariables = nestedConstraintSystem.getNestedTypeVariables(returnType)
|
||||
|
||||
// we add an additional type variable only if no information is inferred for it.
|
||||
// otherwise we add currently inferred return type as before
|
||||
if (nestedTypeVariables.any { nestedConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false
|
||||
|
||||
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor)
|
||||
val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap()
|
||||
|
||||
val freshVariables = returnType.getNestedTypeParameters().mapNotNull { conversion[it] }
|
||||
builder.registerTypeVariables(nestedCall.call.toHandle(), freshVariables, external = true)
|
||||
// Safe call result must be nullable if receiver is nullable
|
||||
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
|
||||
|
||||
builder.addSubtypeConstraint(
|
||||
argumentExpressionType,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
constraintPosition
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateResultTypeForSmartCasts(
|
||||
type: KotlinType?,
|
||||
argumentExpression: KtExpression?,
|
||||
context: ResolutionContext<*>
|
||||
): KotlinType? {
|
||||
val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
|
||||
if (deparenthesizedArgument == null || type == null) return type
|
||||
|
||||
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context)
|
||||
if (!dataFlowValue.isStable) return type
|
||||
|
||||
val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings)
|
||||
if (possibleTypes.isEmpty()) return type
|
||||
|
||||
return TypeIntersector.intersectTypes(possibleTypes + type)
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext<D>) {
|
||||
val resolvedCall = context.candidateCall
|
||||
val constraintSystem = resolvedCall.constraintSystem?.toBuilder() ?: return
|
||||
|
||||
// `resolvedCall` can contain wrapped call (e.g. CallForImplicitInvoke). Meanwhile, `context` contains simple call which leads
|
||||
// to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument`
|
||||
val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||
CallCandidateResolutionContext.create(
|
||||
resolvedCall, context, context.trace, context.tracing, resolvedCall.functionCall.call, context.candidateResolveMode
|
||||
)
|
||||
} else {
|
||||
context
|
||||
}
|
||||
|
||||
// constraints for function literals
|
||||
// Value parameters
|
||||
for ((valueParameterDescriptor, resolvedValueArgument) in resolvedCall.valueArguments) {
|
||||
for (valueArgument in resolvedValueArgument.arguments) {
|
||||
valueArgument.getArgumentExpression()?.let { argumentExpression ->
|
||||
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral ->
|
||||
addConstraintForFunctionLiteralArgument(
|
||||
functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
|
||||
resolvedCall.candidateDescriptor.returnType
|
||||
)
|
||||
}
|
||||
|
||||
// as inference for callable references depends on expected type,
|
||||
// we should postpone reporting errors on them until all types will be inferred
|
||||
|
||||
// We do not replace trace for special calls (e.g. if-expressions) because of their specific analysis
|
||||
// For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression)
|
||||
val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
|
||||
newContext
|
||||
} else {
|
||||
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
||||
newContext.trace, "Trace to complete argument for call that might be not resulting call"
|
||||
)
|
||||
newContext.replaceBindingTrace(temporaryBindingTrace)
|
||||
}
|
||||
|
||||
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference ->
|
||||
addConstraintForCallableReference(
|
||||
callableReference,
|
||||
valueArgument,
|
||||
valueParameterDescriptor,
|
||||
constraintSystem,
|
||||
temporaryContextForCall
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val resultingSystem = constraintSystem.build()
|
||||
resolvedCall.setConstraintSystem(resultingSystem)
|
||||
|
||||
val isNewInferenceEnabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|
||||
val resultingSubstitutor = if (isNewInferenceEnabled) {
|
||||
resultingSystem.resultingSubstitutor.replaceWithContravariantApproximatingSubstitution()
|
||||
} else resultingSystem.resultingSubstitutor
|
||||
|
||||
resolvedCall.setSubstitutor(resultingSubstitutor)
|
||||
}
|
||||
|
||||
// See KT-5385
|
||||
// When literal returns T, and it's an argument of a function that also returns T,
|
||||
// and we have some expected type Type, we can expected from literal to return Type
|
||||
// Otherwise we do not care about literal's exact return type
|
||||
private fun estimateLiteralReturnType(
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
literalExpectedType: KotlinType,
|
||||
ownerReturnType: KotlinType?
|
||||
) = if (!TypeUtils.noExpectedType(context.expectedType) &&
|
||||
ownerReturnType != null &&
|
||||
TypeUtils.isTypeParameter(ownerReturnType) &&
|
||||
literalExpectedType.isFunctionTypeOrSubtype &&
|
||||
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
|
||||
context.expectedType
|
||||
else DONT_CARE
|
||||
|
||||
private fun <D : CallableDescriptor> addConstraintForFunctionLiteralArgument(
|
||||
functionLiteral: KtFunction,
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
argumentOwnerReturnType: KotlinType?
|
||||
) {
|
||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||
|
||||
val currentSubstitutor = constraintSystem.build().currentSubstitutor
|
||||
val newSubstitution = object : DelegatedTypeSubstitution(currentSubstitutor.substitution) {
|
||||
override fun approximateContravariantCapturedTypes() = true
|
||||
}
|
||||
|
||||
var expectedType = newSubstitution.buildSubstitutor().substitute(effectiveExpectedType, Variance.IN_VARIANCE)
|
||||
|
||||
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
|
||||
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(
|
||||
functionLiteral,
|
||||
context.scope,
|
||||
context.trace,
|
||||
false,
|
||||
expectedType?.isSuspendFunctionType == true
|
||||
)
|
||||
}
|
||||
if (expectedType == null || !expectedType.isBuiltinFunctionalType || hasUnknownFunctionParameter(expectedType)) {
|
||||
return
|
||||
}
|
||||
val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments
|
||||
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
|
||||
|
||||
val effectiveExpectedTypeInSystem =
|
||||
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||
|
||||
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
|
||||
val hasExpectedReturnType = !hasUnknownReturnType(expectedType)
|
||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||
if (hasExpectedReturnType) {
|
||||
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve function literal with expected return type", argumentExpression
|
||||
)
|
||||
|
||||
val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return
|
||||
val mismatch = BooleanArray(1)
|
||||
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
||||
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch
|
||||
)
|
||||
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
|
||||
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS,
|
||||
expectedType.isSuspendFunctionType
|
||||
).type
|
||||
if (!mismatch[0]) {
|
||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
||||
temporaryToResolveFunctionLiteral.commit()
|
||||
return
|
||||
}
|
||||
}
|
||||
val estimatedReturnType = estimateLiteralReturnType(context, effectiveExpectedType, argumentOwnerReturnType)
|
||||
val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType)
|
||||
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
val type =
|
||||
argumentTypeResolver.getFunctionLiteralTypeInfo(
|
||||
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS,
|
||||
expectedType.isSuspendFunctionType
|
||||
).type
|
||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> addConstraintForCallableReference(
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>
|
||||
) {
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
|
||||
?: return
|
||||
if (!expectedType.isApplicableExpectedTypeForCallableReference()) return
|
||||
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return
|
||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||
constraintSystem.addSubtypeConstraint(
|
||||
resolvedType,
|
||||
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
effectiveExpectedType: KotlinType
|
||||
): KotlinType? {
|
||||
val substitutedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
|
||||
return substitutedType
|
||||
|
||||
val shapeType = argumentTypeResolver.getShapeTypeOfCallableReference(callableReference, context, false)
|
||||
if (shapeType != null && shapeType.isFunctionTypeOrSubtype && !hasUnknownFunctionParameter(shapeType))
|
||||
return shapeType
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> getResolvedTypeForCallableReference(
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
expectedType: KotlinType,
|
||||
valueArgument: ValueArgument
|
||||
): KotlinType? {
|
||||
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
|
||||
val expectedTypeWithoutReturnType =
|
||||
if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
|
||||
val newContext = context
|
||||
.replaceExpectedType(expectedTypeWithoutReturnType)
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
return argumentTypeResolver.getCallableReferenceTypeInfo(
|
||||
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
||||
).type
|
||||
}
|
||||
}
|
||||
|
||||
fun getResolutionResultsCachedData(expression: KtExpression?, context: ResolutionContext<*>): ResolutionResultsCache.CachedData? {
|
||||
if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null
|
||||
val argumentCall = expression?.getCall(context.trace.bindingContext) ?: return null
|
||||
|
||||
return context.resolutionResultsCache[argumentCall]
|
||||
}
|
||||
|
||||
fun makeConstantSubstitutor(typeParameterDescriptors: Collection<TypeParameterDescriptor>, type: KotlinType): TypeSubstitutor {
|
||||
val constructors = typeParameterDescriptors.map { it.typeConstructor }.toSet()
|
||||
val projection = TypeProjectionImpl(type)
|
||||
|
||||
return TypeSubstitutor.create(object : TypeConstructorSubstitution() {
|
||||
override operator fun get(key: TypeConstructor) =
|
||||
if (key in constructors) projection else null
|
||||
|
||||
override fun isEmpty() = false
|
||||
})
|
||||
}
|
||||
|
||||
private fun KotlinType.isApplicableExpectedTypeForCallableReference(): Boolean {
|
||||
return this.isFunctionType ||
|
||||
ReflectionTypes.isBaseTypeForNumberedReferenceTypes(this) ||
|
||||
ReflectionTypes.isNumberedKFunctionOrKSuspendFunction(this) ||
|
||||
ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(this)
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactoryList
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.components.stableType
|
||||
@@ -21,6 +20,7 @@ import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.psiExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.SPECIAL_FUNCTION_NAMES
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
|
||||
import org.jetbrains.kotlin.types.DeferredType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
-1
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactory
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.resolve.BindingContext.NEW_INFERENCE_CATCH_EXCEPTION
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES
|
||||
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
@@ -330,3 +331,5 @@ fun KotlinCall.extractCallableReferenceExpression(): KtCallableReferenceExpressi
|
||||
psiKotlinCall.psiCall.extractCallableReferenceExpression()
|
||||
|
||||
fun Call.extractCallableReferenceExpression(): KtCallableReferenceExpression? = callElement.asCallableReferenceExpression()
|
||||
|
||||
val SPECIAL_FUNCTION_NAMES = ControlStructureTypingUtils.ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
||||
|
||||
Reference in New Issue
Block a user