Revert "[FE 1.0] Get rid of CandidateResolver"
This reverts commit 4ea08a59db.
This commit is contained in:
@@ -0,0 +1,734 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.google.common.collect.Lists
|
||||||
|
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||||
|
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors.EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors.SUPER_CANT_BE_EXTENSION_RECEIVER
|
||||||
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.resolve.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.SubstitutionFilteringInternalResolveAnnotations
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.error.ErrorUtils
|
||||||
|
import org.jetbrains.kotlin.types.error.ErrorTypeKind
|
||||||
|
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class CandidateResolver(
|
||||||
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
|
private val genericCandidateResolver: GenericCandidateResolver,
|
||||||
|
private val reflectionTypes: ReflectionTypes,
|
||||||
|
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
||||||
|
private val smartCastManager: SmartCastManager,
|
||||||
|
private val dataFlowValueFactory: DataFlowValueFactory,
|
||||||
|
private val upperBoundChecker: UpperBoundChecker
|
||||||
|
) {
|
||||||
|
fun <D : CallableDescriptor> performResolutionForCandidateCall(
|
||||||
|
context: CallCandidateResolutionContext<D>,
|
||||||
|
checkArguments: CheckArgumentTypesMode
|
||||||
|
): Unit = with(context) {
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
|
if (ErrorUtils.isError(candidateDescriptor)) {
|
||||||
|
candidateCall.addStatus(SUCCESS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkOuterClassMemberIsAccessible(this)) {
|
||||||
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context.isDebuggerContext) {
|
||||||
|
checkVisibilityWithoutReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
when (checkArguments) {
|
||||||
|
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
|
||||||
|
mapArguments()
|
||||||
|
CheckArgumentTypesMode.CHECK_CALLABLE_TYPE ->
|
||||||
|
checkExpectedCallableType()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkReceiverTypeError()
|
||||||
|
checkExtensionReceiver()
|
||||||
|
checkDispatchReceiver()
|
||||||
|
|
||||||
|
processTypeArguments()
|
||||||
|
checkValueArguments()
|
||||||
|
|
||||||
|
checkAbstractAndSuper()
|
||||||
|
checkConstructedExpandedType()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkValueArguments() = checkAndReport {
|
||||||
|
if (call.typeArguments.isEmpty()
|
||||||
|
&& !candidateDescriptor.typeParameters.isEmpty()
|
||||||
|
&& candidateCall.knownTypeParametersSubstitutor == null
|
||||||
|
) {
|
||||||
|
genericCandidateResolver.inferTypeArguments(this)
|
||||||
|
} else {
|
||||||
|
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.processTypeArguments() = check {
|
||||||
|
val ktTypeArguments = call.typeArguments
|
||||||
|
if (candidateCall.knownTypeParametersSubstitutor != null) {
|
||||||
|
candidateCall.setSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
|
||||||
|
} else if (ktTypeArguments.isNotEmpty()) {
|
||||||
|
// Explicit type arguments passed
|
||||||
|
|
||||||
|
val typeArguments = ArrayList<KotlinType>()
|
||||||
|
for (projection in ktTypeArguments) {
|
||||||
|
val type = projection.typeReference?.let { trace.bindingContext.get(BindingContext.TYPE, it) }
|
||||||
|
?: ErrorUtils.createErrorType(ErrorTypeKind.STAR_PROJECTION_IN_CALL)
|
||||||
|
typeArguments.add(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size
|
||||||
|
for (index in ktTypeArguments.size until expectedTypeArgumentCount) {
|
||||||
|
typeArguments.add(
|
||||||
|
ErrorUtils.createErrorType(
|
||||||
|
ErrorTypeKind.MISSED_TYPE_ARGUMENT_FOR_TYPE_PARAMETER,
|
||||||
|
candidateDescriptor.typeParameters[index].name.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments)
|
||||||
|
val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution))
|
||||||
|
|
||||||
|
if (expectedTypeArgumentCount != ktTypeArguments.size) {
|
||||||
|
candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR)
|
||||||
|
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor)
|
||||||
|
} else {
|
||||||
|
checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
candidateCall.setSubstitutor(substitutor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments() = check {
|
||||||
|
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||||
|
call, tracing, candidateCall, languageVersionSettings
|
||||||
|
)
|
||||||
|
if (!argumentMappingStatus.isSuccess) {
|
||||||
|
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType() = check {
|
||||||
|
if (!noExpectedType(expectedType)) {
|
||||||
|
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
|
||||||
|
candidateCall.candidateDescriptor,
|
||||||
|
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
|
||||||
|
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
|
||||||
|
},
|
||||||
|
reflectionTypes, scope.ownerDescriptor
|
||||||
|
)
|
||||||
|
if (candidateKCallableType == null ||
|
||||||
|
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
|
||||||
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canBeSubtype(subType: KotlinType, superType: KotlinType, candidateTypeParameters: List<TypeParameterDescriptor>): Boolean {
|
||||||
|
// Here we need to check that there exists a substitution from type parameters (used in types in candidate signature)
|
||||||
|
// to arguments such that substituted candidateKCallableType would be a subtype of expectedType.
|
||||||
|
// It looks like in general this can only be decided by constructing a constraint system and checking
|
||||||
|
// if it has a contradiction. Currently we use a heuristic that may not work ideally in all cases.
|
||||||
|
// TODO: use constraint system to check if candidateKCallableType can be a subtype of expectedType
|
||||||
|
val substituteDontCare = makeConstantSubstitutor(candidateTypeParameters, TypeUtils.DONT_CARE)
|
||||||
|
val subTypeSubstituted = substituteDontCare.substitute(subType, Variance.INVARIANT) ?: return true
|
||||||
|
return ErrorTypesAreEqualToAnything.isSubtypeOf(subTypeSubstituted, superType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkVisibilityWithoutReceiver() = checkAndReport {
|
||||||
|
checkVisibilityWithDispatchReceiver(DescriptorVisibilities.ALWAYS_SUITABLE_RECEIVER, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkVisibilityWithDispatchReceiver(
|
||||||
|
receiverArgument: ReceiverValue?,
|
||||||
|
smartCastType: KotlinType?
|
||||||
|
): ResolutionStatus {
|
||||||
|
val invisibleMember = DescriptorVisibilityUtils.findInvisibleMember(
|
||||||
|
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
|
||||||
|
candidateDescriptor,
|
||||||
|
scope.ownerDescriptor,
|
||||||
|
languageVersionSettings
|
||||||
|
)
|
||||||
|
return if (invisibleMember != null) {
|
||||||
|
tracing.invisibleMember(trace, invisibleMember)
|
||||||
|
INVISIBLE_MEMBER_ERROR
|
||||||
|
} else {
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.isCandidateVisibleOrExtensionReceiver(
|
||||||
|
receiverArgument: ReceiverValue?,
|
||||||
|
smartCastType: KotlinType?,
|
||||||
|
isDispatchReceiver: Boolean
|
||||||
|
) = !isDispatchReceiver || isCandidateVisible(receiverArgument, smartCastType)
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.isCandidateVisible(
|
||||||
|
receiverArgument: ReceiverValue?,
|
||||||
|
smartCastType: KotlinType?
|
||||||
|
) = DescriptorVisibilityUtils.findInvisibleMember(
|
||||||
|
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
|
||||||
|
candidateDescriptor, scope.ownerDescriptor,
|
||||||
|
languageVersionSettings
|
||||||
|
) == null
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport {
|
||||||
|
val receiverParameter = candidateCall.candidateDescriptor.extensionReceiverParameter
|
||||||
|
val receiverArgument = candidateCall.extensionReceiver
|
||||||
|
if (receiverParameter != null && receiverArgument == null) {
|
||||||
|
tracing.missingReceiver(candidateCall.trace, receiverParameter)
|
||||||
|
OTHER_ERROR
|
||||||
|
} else if (receiverParameter == null && receiverArgument != null) {
|
||||||
|
tracing.noReceiverAllowed(candidateCall.trace)
|
||||||
|
if (call.calleeExpression is KtSimpleNameExpression) {
|
||||||
|
RECEIVER_PRESENCE_ERROR
|
||||||
|
} else {
|
||||||
|
OTHER_ERROR
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkDispatchReceiver() = checkAndReport {
|
||||||
|
val candidateDescriptor = candidateDescriptor
|
||||||
|
val dispatchReceiver = candidateCall.dispatchReceiver
|
||||||
|
if (dispatchReceiver != null) {
|
||||||
|
var nestedClass: ClassDescriptor? = null
|
||||||
|
if (candidateDescriptor is ClassConstructorDescriptor
|
||||||
|
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration)
|
||||||
|
) {
|
||||||
|
nestedClass = candidateDescriptor.containingDeclaration
|
||||||
|
} else if (candidateDescriptor is FakeCallableDescriptorForObject) {
|
||||||
|
nestedClass = candidateDescriptor.getReferencedObject()
|
||||||
|
}
|
||||||
|
if (nestedClass != null) {
|
||||||
|
tracing.nestedClassAccessViaInstanceReference(trace, nestedClass, candidateCall.explicitReceiverKind)
|
||||||
|
return@checkAndReport OTHER_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((dispatchReceiver != null) == (candidateCall.resultingDescriptor.dispatchReceiverParameter != null)) {
|
||||||
|
"Shouldn't happen because of TaskPrioritizer: $candidateDescriptor"
|
||||||
|
}
|
||||||
|
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkOuterClassMemberIsAccessible(context: CallCandidateResolutionContext<*>): Boolean {
|
||||||
|
|
||||||
|
fun KtElement.insideScript() = (containingFile as? KtFile)?.isScript() ?: false
|
||||||
|
|
||||||
|
// context.scope doesn't contains outer class implicit receiver if we inside nested class
|
||||||
|
// Outer scope for some class in script file is scopeForInitializerResolution see: DeclarationScopeProviderImpl.getResolutionScopeForDeclaration
|
||||||
|
if (!context.call.callElement.insideScript()) return true
|
||||||
|
|
||||||
|
// In "this@Outer.foo()" the error will be reported on "this@Outer" instead
|
||||||
|
if (context.call.explicitReceiver != null || context.call.dispatchReceiver != null) return true
|
||||||
|
|
||||||
|
val candidateThis = getDeclaringClass(context.candidateCall.candidateDescriptor)
|
||||||
|
if (candidateThis == null || candidateThis.kind.isSingleton) return true
|
||||||
|
|
||||||
|
return DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, context.call.callElement, candidateThis)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkAbstractAndSuper() = check {
|
||||||
|
val descriptor = candidateDescriptor
|
||||||
|
val expression = candidateCall.call.calleeExpression
|
||||||
|
|
||||||
|
if (expression is KtSimpleNameExpression) {
|
||||||
|
// 'B' in 'class A: B()' is JetConstructorCalleeExpression
|
||||||
|
if (descriptor is ConstructorDescriptor) {
|
||||||
|
val modality = descriptor.constructedClass.modality
|
||||||
|
if (modality == Modality.ABSTRACT) {
|
||||||
|
tracing.instantiationOfAbstractClass(trace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val superDispatchReceiver = getReceiverSuper(candidateCall.dispatchReceiver)
|
||||||
|
if (superDispatchReceiver != null) {
|
||||||
|
if (descriptor is MemberDescriptor && descriptor.modality == Modality.ABSTRACT) {
|
||||||
|
tracing.abstractSuperCall(trace)
|
||||||
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this
|
||||||
|
// See TaskPrioritizer for more
|
||||||
|
val superExtensionReceiver = getReceiverSuper(candidateCall.extensionReceiver)
|
||||||
|
if (superExtensionReceiver != null) {
|
||||||
|
trace.report(SUPER_CANT_BE_EXTENSION_RECEIVER.on(superExtensionReceiver, superExtensionReceiver.text))
|
||||||
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkConstructedExpandedType() = check {
|
||||||
|
val descriptor = candidateDescriptor
|
||||||
|
|
||||||
|
if (descriptor is TypeAliasConstructorDescriptor) {
|
||||||
|
if (descriptor.returnType.containsTypeProjectionsInTopLevelArguments()) {
|
||||||
|
trace.report(EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED.on(call.callElement, descriptor.returnType))
|
||||||
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getReceiverSuper(receiver: Receiver?): KtSuperExpression? {
|
||||||
|
if (receiver is ExpressionReceiver) {
|
||||||
|
val expression = receiver.expression
|
||||||
|
if (expression is KtSuperExpression) {
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDeclaringClass(candidate: CallableDescriptor): ClassDescriptor? {
|
||||||
|
val expectedThis = candidate.dispatchReceiverParameter ?: return null
|
||||||
|
val descriptor = expectedThis.containingDeclaration
|
||||||
|
return if (descriptor is ClassDescriptor) descriptor else null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <D : CallableDescriptor> checkAllValueArguments(
|
||||||
|
context: CallCandidateResolutionContext<D>,
|
||||||
|
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||||
|
): ValueArgumentsCheckingResult {
|
||||||
|
val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies)
|
||||||
|
var resultStatus = checkingResult.status
|
||||||
|
resultStatus = resultStatus.combine(checkReceivers(context))
|
||||||
|
|
||||||
|
return ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : CallableDescriptor, C : CallResolutionContext<C>> checkValueArgumentTypes(
|
||||||
|
context: CallResolutionContext<C>,
|
||||||
|
candidateCall: MutableResolvedCall<D>,
|
||||||
|
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||||
|
): ValueArgumentsCheckingResult {
|
||||||
|
var resultStatus = SUCCESS
|
||||||
|
val argumentTypes = Lists.newArrayList<KotlinType>()
|
||||||
|
val infoForArguments = candidateCall.dataFlowInfoForArguments
|
||||||
|
for ((parameterDescriptor, resolvedArgument) in candidateCall.valueArguments) {
|
||||||
|
for (argument in resolvedArgument.arguments) {
|
||||||
|
val expression = argument.getArgumentExpression() ?: continue
|
||||||
|
|
||||||
|
val expectedType = getEffectiveExpectedType(parameterDescriptor, argument, context)
|
||||||
|
|
||||||
|
val newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument)).replaceExpectedType(expectedType)
|
||||||
|
val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(expression, newContext, resolveFunctionArgumentBodies, expectedType.isSuspendFunctionType)
|
||||||
|
val type = typeInfoForCall.type
|
||||||
|
infoForArguments.updateInfo(argument, typeInfoForCall.dataFlowInfo)
|
||||||
|
|
||||||
|
var matchStatus = ArgumentMatchStatus.SUCCESS
|
||||||
|
var resultingType: KotlinType? = type
|
||||||
|
if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
|
||||||
|
matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
|
||||||
|
} else if (!noExpectedType(expectedType)) {
|
||||||
|
if (!argumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
|
||||||
|
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
|
||||||
|
if (smartCast == null) {
|
||||||
|
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
|
||||||
|
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
|
||||||
|
} else {
|
||||||
|
resultingType = smartCast
|
||||||
|
}
|
||||||
|
} else if (ErrorUtils.containsUninferredTypeVariable(expectedType)) {
|
||||||
|
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
|
||||||
|
}
|
||||||
|
|
||||||
|
val spreadElement = argument.getSpreadElement()
|
||||||
|
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
||||||
|
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, type, context)
|
||||||
|
val smartCastResult = smartCastManager.checkAndRecordPossibleCast(
|
||||||
|
dataFlowValue, expectedType, expression, context,
|
||||||
|
call = null, recordExpressionType = false
|
||||||
|
)
|
||||||
|
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
||||||
|
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argumentTypes.add(resultingType)
|
||||||
|
candidateCall.recordArgumentMatchStatus(argument, matchStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ValueArgumentsCheckingResult(resultStatus, argumentTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun smartCastValueArgumentTypeIfPossible(
|
||||||
|
expression: KtExpression,
|
||||||
|
expectedType: KotlinType,
|
||||||
|
actualType: KotlinType,
|
||||||
|
context: ResolutionContext<*>
|
||||||
|
): KotlinType? {
|
||||||
|
val receiverToCast = ExpressionReceiver.create(KtPsiUtil.safeDeparenthesize(expression), actualType, context.trace.bindingContext)
|
||||||
|
val variants = smartCastManager.getSmartCastVariantsExcludingReceiver(context, receiverToCast)
|
||||||
|
return variants.firstOrNull { possibleType ->
|
||||||
|
KotlinTypeChecker.DEFAULT.isSubtypeOf(possibleType, expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryNotNullableArgument(argumentType: KotlinType, parameterType: KotlinType): ResolutionStatus? {
|
||||||
|
if (!argumentType.isMarkedNullable || parameterType.isMarkedNullable) return null
|
||||||
|
|
||||||
|
val notNullableArgumentType = argumentType.makeNotNullable()
|
||||||
|
val isApplicable = argumentTypeResolver.isSubtypeOfForArgumentType(notNullableArgumentType, parameterType)
|
||||||
|
return if (isApplicable) NULLABLE_ARGUMENT_TYPE_MISMATCH else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(): Unit = check {
|
||||||
|
val extensionReceiver = candidateDescriptor.extensionReceiverParameter
|
||||||
|
val dispatchReceiver = candidateDescriptor.dispatchReceiverParameter
|
||||||
|
|
||||||
|
// For the expressions like '42.(f)()' where f: String.() -> Unit we'd like to generate a type mismatch error on '1',
|
||||||
|
// not to throw away the candidate, so the following check is skipped.
|
||||||
|
if (!isInvokeCallOnExpressionWithBothReceivers(call)) {
|
||||||
|
checkReceiverTypeError(extensionReceiver, candidateCall.extensionReceiver)
|
||||||
|
}
|
||||||
|
checkReceiverTypeError(dispatchReceiver, candidateCall.dispatchReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(
|
||||||
|
receiverParameterDescriptor: ReceiverParameterDescriptor?,
|
||||||
|
receiverArgument: ReceiverValue?
|
||||||
|
) = checkAndReport {
|
||||||
|
if (receiverParameterDescriptor == null || receiverArgument == null) return@checkAndReport SUCCESS
|
||||||
|
|
||||||
|
val erasedReceiverType = getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor)
|
||||||
|
|
||||||
|
if (smartCastManager.getSmartCastReceiverResult(receiverArgument, erasedReceiverType, this) == null) {
|
||||||
|
RECEIVER_TYPE_ERROR
|
||||||
|
} else {
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : CallableDescriptor> checkReceivers(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
||||||
|
var resultStatus = SUCCESS
|
||||||
|
val candidateCall = context.candidateCall
|
||||||
|
|
||||||
|
// Comment about a very special case.
|
||||||
|
// Call 'b.foo(1)' where class 'Foo' has an extension member 'fun B.invoke(Int)' should be checked two times for safe call (in 'checkReceiver'), because
|
||||||
|
// both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
|
||||||
|
// Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
|
||||||
|
|
||||||
|
resultStatus = resultStatus.combine(
|
||||||
|
context.checkReceiver(
|
||||||
|
candidateCall,
|
||||||
|
candidateCall.resultingDescriptor.extensionReceiverParameter,
|
||||||
|
candidateCall.extensionReceiver,
|
||||||
|
candidateCall.explicitReceiverKind.isExtensionReceiver,
|
||||||
|
implicitInvokeCheck = false, isDispatchReceiver = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
resultStatus = resultStatus.combine(
|
||||||
|
context.checkReceiver(
|
||||||
|
candidateCall,
|
||||||
|
candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver,
|
||||||
|
candidateCall.explicitReceiverKind.isDispatchReceiver,
|
||||||
|
// for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
|
||||||
|
implicitInvokeCheck = context.call is CallForImplicitInvoke,
|
||||||
|
isDispatchReceiver = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!context.isDebuggerContext
|
||||||
|
&& candidateCall.dispatchReceiver != null
|
||||||
|
// Do not report error if it's already reported when checked without receiver
|
||||||
|
&& context.isCandidateVisible(receiverArgument = DescriptorVisibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
|
||||||
|
resultStatus = resultStatus.combine(
|
||||||
|
context.checkVisibilityWithDispatchReceiver(
|
||||||
|
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkReceiver(
|
||||||
|
candidateCall: MutableResolvedCall<D>,
|
||||||
|
receiverParameter: ReceiverParameterDescriptor?,
|
||||||
|
receiverArgument: ReceiverValue?,
|
||||||
|
isExplicitReceiver: Boolean,
|
||||||
|
implicitInvokeCheck: Boolean,
|
||||||
|
isDispatchReceiver: Boolean
|
||||||
|
): ResolutionStatus {
|
||||||
|
if (receiverParameter == null || receiverArgument == null) return SUCCESS
|
||||||
|
val candidateDescriptor = candidateCall.candidateDescriptor
|
||||||
|
if (TypeUtils.dependsOnTypeParameters(receiverParameter.type, candidateDescriptor.typeParameters)) return SUCCESS
|
||||||
|
|
||||||
|
// Here we know that receiver is OK ignoring nullability and check that nullability is OK too
|
||||||
|
// Doing it simply as full subtyping check (receiverValueType <: receiverParameterType)
|
||||||
|
val call = candidateCall.call
|
||||||
|
val safeAccess = isExplicitReceiver && !implicitInvokeCheck && call.isSemanticallyEquivalentToSafeCall
|
||||||
|
val expectedReceiverParameterType = if (safeAccess) TypeUtils.makeNullable(receiverParameter.type) else receiverParameter.type
|
||||||
|
|
||||||
|
val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
|
||||||
|
if (smartCastSubtypingResult == null) {
|
||||||
|
tracing.wrongReceiverType(
|
||||||
|
trace, receiverParameter, receiverArgument,
|
||||||
|
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))
|
||||||
|
)
|
||||||
|
return OTHER_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK
|
||||||
|
val smartCastNeeded =
|
||||||
|
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
|
||||||
|
var reportUnsafeCall = false
|
||||||
|
|
||||||
|
var nullableImplicitInvokeReceiver = false
|
||||||
|
var receiverArgumentType = receiverArgument.type
|
||||||
|
if (implicitInvokeCheck && call is CallForImplicitInvoke && call.isSafeCall()) {
|
||||||
|
val outerCallReceiver = call.outerCall.explicitReceiver
|
||||||
|
if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) {
|
||||||
|
val outerReceiverDataFlowValue = dataFlowValueFactory.createDataFlowValue(outerCallReceiver, this)
|
||||||
|
val outerReceiverNullability = dataFlowInfo.getStableNullability(outerReceiverDataFlowValue)
|
||||||
|
if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) {
|
||||||
|
nullableImplicitInvokeReceiver = true
|
||||||
|
receiverArgumentType = TypeUtils.makeNullable(receiverArgumentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverArgument, this)
|
||||||
|
val nullability = dataFlowInfo.getStableNullability(dataFlowValue)
|
||||||
|
val expression = (receiverArgument as? ExpressionReceiver)?.expression
|
||||||
|
if (nullability.canBeNull() && !nullability.canBeNonNull()) {
|
||||||
|
if (!TypeUtils.isNullableType(expectedReceiverParameterType)) {
|
||||||
|
reportUnsafeCall = true
|
||||||
|
}
|
||||||
|
if (dataFlowValue.immanentNullability.canBeNonNull()) {
|
||||||
|
expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) }
|
||||||
|
}
|
||||||
|
} else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
|
||||||
|
// Look if smart cast has some useful nullability info
|
||||||
|
|
||||||
|
val smartCastResult = smartCastManager.checkAndRecordPossibleCast(
|
||||||
|
dataFlowValue, expectedReceiverParameterType,
|
||||||
|
expression, this, candidateCall.call, recordExpressionType = true
|
||||||
|
) { possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) }
|
||||||
|
|
||||||
|
if (smartCastResult == null) {
|
||||||
|
if (notNullReceiverExpected) {
|
||||||
|
reportUnsafeCall = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isDispatchReceiver) {
|
||||||
|
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
||||||
|
} else {
|
||||||
|
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||||
|
}
|
||||||
|
if (!smartCastResult.isCorrect) {
|
||||||
|
// Error about unstable smart cast reported within checkAndRecordPossibleCast
|
||||||
|
return UNSTABLE_SMARTCAST_FOR_RECEIVER_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportUnsafeCall || nullableImplicitInvokeReceiver) {
|
||||||
|
tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck)
|
||||||
|
return UNSAFE_CALL_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalTypeCheckers.forEach { it.checkReceiver(receiverParameter, receiverArgument, safeAccess, this) }
|
||||||
|
|
||||||
|
return SUCCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ValueArgumentsCheckingResult(val status: ResolutionStatus, val argumentTypes: List<KotlinType>)
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInAFunctionCall(
|
||||||
|
ktTypeArguments: List<KtTypeProjection>,
|
||||||
|
typeArguments: List<KotlinType>,
|
||||||
|
functionDescriptor: CallableDescriptor,
|
||||||
|
substitutor: TypeSubstitutor,
|
||||||
|
trace: BindingTrace
|
||||||
|
) {
|
||||||
|
if (functionDescriptor is TypeAliasConstructorDescriptor) {
|
||||||
|
checkGenericBoundsInTypeAliasConstructorCall(ktTypeArguments, functionDescriptor, substitutor, trace)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeParameters = functionDescriptor.typeParameters
|
||||||
|
for (i in 0..min(typeParameters.size, ktTypeArguments.size) - 1) {
|
||||||
|
val typeParameterDescriptor = typeParameters[i]
|
||||||
|
val typeArgument = typeArguments[i]
|
||||||
|
val typeReference = ktTypeArguments[i].typeReference
|
||||||
|
if (typeReference != null) {
|
||||||
|
upperBoundChecker.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TypeAliasSingleStepExpansionReportStrategy(
|
||||||
|
private val callElement: KtElement,
|
||||||
|
typeAlias: TypeAliasDescriptor,
|
||||||
|
ktTypeArguments: List<KtTypeProjection>,
|
||||||
|
private val trace: BindingTrace,
|
||||||
|
private val upperBoundChecker: UpperBoundChecker
|
||||||
|
) : TypeAliasExpansionReportStrategy {
|
||||||
|
init {
|
||||||
|
assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val argumentsMapping = typeAlias.declaredTypeParameters.zip(ktTypeArguments).toMap()
|
||||||
|
|
||||||
|
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {
|
||||||
|
// can't happen in single-step expansion
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun conflictingProjection(
|
||||||
|
typeAlias: TypeAliasDescriptor,
|
||||||
|
typeParameter: TypeParameterDescriptor?,
|
||||||
|
substitutedArgument: KotlinType
|
||||||
|
) {
|
||||||
|
// can't happen in single-step expansion
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {
|
||||||
|
// can't happen in single-step expansion
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun repeatedAnnotation(annotation: AnnotationDescriptor) {
|
||||||
|
// can't happen in single-step expansion
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun boundsViolationInSubstitution(
|
||||||
|
substitutor: TypeSubstitutor,
|
||||||
|
unsubstitutedArgument: KotlinType,
|
||||||
|
argument: KotlinType,
|
||||||
|
typeParameter: TypeParameterDescriptor
|
||||||
|
) {
|
||||||
|
val descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor
|
||||||
|
val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument]
|
||||||
|
val argumentTypeReferenceElement = argumentElement?.typeReference
|
||||||
|
|
||||||
|
upperBoundChecker.checkBounds(argumentTypeReferenceElement, argument, typeParameter, substitutor, trace, callElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInTypeAliasConstructorCall(
|
||||||
|
ktTypeArguments: List<KtTypeProjection>,
|
||||||
|
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
|
||||||
|
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||||
|
trace: BindingTrace
|
||||||
|
) {
|
||||||
|
val substitutedType = typeAliasParametersSubstitutor.substitute(typeAliasConstructorDescriptor.returnType, Variance.INVARIANT)!!
|
||||||
|
val boundsSubstitutor = TypeSubstitutor.create(substitutedType)
|
||||||
|
|
||||||
|
val typeAliasDescriptor = typeAliasConstructorDescriptor.containingDeclaration
|
||||||
|
|
||||||
|
val unsubstitutedType = typeAliasDescriptor.expandedType
|
||||||
|
if (unsubstitutedType.isError) return
|
||||||
|
|
||||||
|
val reportStrategy =
|
||||||
|
TypeAliasSingleStepExpansionReportStrategy(call.callElement, typeAliasDescriptor, ktTypeArguments, trace, upperBoundChecker)
|
||||||
|
|
||||||
|
// TODO refactor TypeResolver
|
||||||
|
// - perform full type alias expansion
|
||||||
|
// - provide type alias expansion stack in diagnostics
|
||||||
|
|
||||||
|
checkTypeInTypeAliasSubstitutionRec(reportStrategy, unsubstitutedType, typeAliasParametersSubstitutor, boundsSubstitutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun checkTypeInTypeAliasSubstitutionRec(
|
||||||
|
reportStrategy: TypeAliasExpansionReportStrategy,
|
||||||
|
unsubstitutedType: KotlinType,
|
||||||
|
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||||
|
boundsSubstitutor: TypeSubstitutor
|
||||||
|
) {
|
||||||
|
// TODO refactor TypeResolver
|
||||||
|
val typeParameters = unsubstitutedType.constructor.parameters
|
||||||
|
|
||||||
|
// TODO do not perform substitution for type arguments multiple times
|
||||||
|
val substitutedTypeArguments = typeAliasParametersSubstitutor.safeSubstitute(unsubstitutedType, Variance.INVARIANT).arguments
|
||||||
|
|
||||||
|
for (i in 0..min(typeParameters.size, substitutedTypeArguments.size) - 1) {
|
||||||
|
val substitutedTypeProjection = substitutedTypeArguments[i]
|
||||||
|
if (substitutedTypeProjection.isStarProjection) continue
|
||||||
|
|
||||||
|
val typeParameter = typeParameters[i]
|
||||||
|
val substitutedTypeArgument = substitutedTypeProjection.type
|
||||||
|
val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].type
|
||||||
|
|
||||||
|
reportStrategy.boundsViolationInSubstitution(
|
||||||
|
boundsSubstitutor,
|
||||||
|
unsubstitutedTypeArgument,
|
||||||
|
substitutedTypeArgument,
|
||||||
|
typeParameter
|
||||||
|
)
|
||||||
|
|
||||||
|
checkTypeInTypeAliasSubstitutionRec(
|
||||||
|
reportStrategy,
|
||||||
|
unsubstitutedTypeArgument,
|
||||||
|
typeAliasParametersSubstitutor,
|
||||||
|
boundsSubstitutor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.shouldContinue() =
|
||||||
|
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
||||||
|
|
||||||
|
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.check(
|
||||||
|
crossinline checker: CallCandidateResolutionContext<D>.() -> Unit
|
||||||
|
) {
|
||||||
|
if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
|
||||||
|
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
||||||
|
) {
|
||||||
|
check {
|
||||||
|
candidateCall.addStatus(checker())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val CallCandidateResolutionContext<*>.candidateDescriptor: CallableDescriptor
|
||||||
|
get() = candidateCall.candidateDescriptor
|
||||||
|
}
|
||||||
+4
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace
|
|||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||||
@@ -57,6 +58,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.compactIfPossible
|
|||||||
import org.jetbrains.kotlin.utils.sure
|
import org.jetbrains.kotlin.utils.sure
|
||||||
|
|
||||||
class NewResolutionOldInference(
|
class NewResolutionOldInference(
|
||||||
|
private val candidateResolver: CandidateResolver,
|
||||||
private val towerResolver: TowerResolver,
|
private val towerResolver: TowerResolver,
|
||||||
private val resolutionResultsHandler: ResolutionResultsHandler,
|
private val resolutionResultsHandler: ResolutionResultsHandler,
|
||||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||||
@@ -229,6 +231,7 @@ class NewResolutionOldInference(
|
|||||||
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||||
)
|
)
|
||||||
|
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||||
|
|
||||||
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
|
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
|
||||||
MyCandidate(diagnostics, resolvedCall) {
|
MyCandidate(diagnostics, resolvedCall) {
|
||||||
@@ -475,6 +478,7 @@ class NewResolutionOldInference(
|
|||||||
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||||
)
|
)
|
||||||
|
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||||
|
|
||||||
val diagnostics = createDiagnosticsForCandidate(towerCandidate, candidateCall)
|
val diagnostics = createDiagnosticsForCandidate(towerCandidate, candidateCall)
|
||||||
return MyCandidate(diagnostics, candidateCall) {
|
return MyCandidate(diagnostics, candidateCall) {
|
||||||
|
|||||||
Reference in New Issue
Block a user