[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.Errors
|
||||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactoryList
|
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactoryList
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.getParameterForArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.stableType
|
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.NewResolvedCallImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.psiExpression
|
import org.jetbrains.kotlin.resolve.calls.tower.psiExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall
|
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.resolve.scopes.LexicalScopeKind
|
||||||
import org.jetbrains.kotlin.types.DeferredType
|
import org.jetbrains.kotlin.types.DeferredType
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
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.KtNameReferenceExpression
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.getParameterForArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
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.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||||
import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver
|
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.InferenceSession
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
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.calls.tower.psiKotlinCall
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.types.*
|
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.asTypeProjection
|
||||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -330,3 +331,5 @@ fun KotlinCall.extractCallableReferenceExpression(): KtCallableReferenceExpressi
|
|||||||
psiKotlinCall.psiCall.extractCallableReferenceExpression()
|
psiKotlinCall.psiCall.extractCallableReferenceExpression()
|
||||||
|
|
||||||
fun Call.extractCallableReferenceExpression(): KtCallableReferenceExpression? = callElement.asCallableReferenceExpression()
|
fun Call.extractCallableReferenceExpression(): KtCallableReferenceExpression? = callElement.asCallableReferenceExpression()
|
||||||
|
|
||||||
|
val SPECIAL_FUNCTION_NAMES = ControlStructureTypingUtils.ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
||||||
|
|||||||
Reference in New Issue
Block a user