Support lazy perform for candidates
This commit is contained in:
@@ -19,121 +19,121 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
import com.google.common.collect.Lists
|
||||
import com.google.common.collect.Sets
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT
|
||||
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.callResolverUtil.*
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.*
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckValueArgumentsMode
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getErasedReceiverType
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnExpressionWithBothReceivers
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isExplicitSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils.canBeSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils.getSmartCastVariantsExcludingReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils.isSubTypeBySmartCastIgnoringNullability
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils.recordSmartCastIfNecessary
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTask
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isSynthesizedInvoke
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.expressions.JetTypeInfo
|
||||
|
||||
import javax.inject.Inject
|
||||
import java.util.ArrayList
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.SUPER_CANT_BE_EXTENSION_RECEIVER
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
|
||||
|
||||
public class CandidateResolver(
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val genericCandidateResolver: GenericCandidateResolver
|
||||
){
|
||||
|
||||
public fun <D : CallableDescriptor, F : D> performResolutionForCandidateCall(
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
task: ResolutionTask<D, F>) {
|
||||
|
||||
public fun <D : CallableDescriptor, F : D> performResolutionForCandidateCall(context: CallCandidateResolutionContext<D>,
|
||||
task: ResolutionTask<D, F>): Unit = with(context) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
val candidateCall = context.candidateCall
|
||||
val candidate = candidateCall.getCandidateDescriptor()
|
||||
|
||||
candidateCall.addStatus(checkReceiverTypeError(context))
|
||||
|
||||
if (ErrorUtils.isError(candidate)) {
|
||||
if (ErrorUtils.isError(candidateDescriptor)) {
|
||||
candidateCall.addStatus(SUCCESS)
|
||||
return
|
||||
}
|
||||
|
||||
if (!checkOuterClassMemberIsAccessible(context)) {
|
||||
if (!checkOuterClassMemberIsAccessible(this)) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
return
|
||||
}
|
||||
|
||||
checkVisibility()
|
||||
mapArguments(task)
|
||||
|
||||
val receiverValue = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidateCall.getDispatchReceiver(), context.trace.getBindingContext())
|
||||
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidate, context.scope.getContainingDeclaration())
|
||||
if (invisibleMember != null) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
context.tracing.invisibleMember(context.trace, invisibleMember)
|
||||
checkReceiverTypeError()
|
||||
checkExtensionReceiver()
|
||||
checkDispatchReceiver()
|
||||
|
||||
processTypeArguments()
|
||||
checkValueArguments()
|
||||
|
||||
checkAbstractAndSuper()
|
||||
checkNonExtensionCalledWithReceiver()
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkValueArguments() = checkAndReport {
|
||||
if (call.getTypeArguments().isEmpty()
|
||||
&& !candidateDescriptor.getTypeParameters().isEmpty()
|
||||
&& candidateCall.getKnownTypeParametersSubstitutor() == null
|
||||
) {
|
||||
genericCandidateResolver.inferTypeArguments(this)
|
||||
}
|
||||
|
||||
if (task.checkArguments == CheckValueArgumentsMode.ENABLED) {
|
||||
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||
context.call, context.tracing, candidateCall, Sets.newLinkedHashSet<ValueArgument>())
|
||||
if (!argumentMappingStatus.isSuccess()) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
else {
|
||||
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
|
||||
}
|
||||
}
|
||||
|
||||
checkExtensionReceiver(context)
|
||||
|
||||
if (!checkDispatchReceiver(context)) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
|
||||
val jetTypeArguments = context.call.getTypeArguments()
|
||||
private fun CallCandidateResolutionContext<*>.processTypeArguments() = check {
|
||||
val jetTypeArguments = call.getTypeArguments()
|
||||
if (!jetTypeArguments.isEmpty()) {
|
||||
// Explicit type arguments passed
|
||||
|
||||
val typeArguments = ArrayList<JetType>()
|
||||
for (projection in jetTypeArguments) {
|
||||
if (projection.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
|
||||
ModifiersChecker.checkIncompatibleVarianceModifiers(projection.getModifierList(), context.trace)
|
||||
trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
|
||||
ModifiersChecker.checkIncompatibleVarianceModifiers(projection.getModifierList(), trace)
|
||||
}
|
||||
val type = argumentTypeResolver.resolveTypeRefWithDefault(
|
||||
projection.getTypeReference(), context.scope, context.trace,
|
||||
projection.getTypeReference(), scope, trace,
|
||||
ErrorUtils.createErrorType("Star projection in a call"))!!
|
||||
ForceResolveUtil.forceResolveAllContents(type)
|
||||
typeArguments.add(type)
|
||||
}
|
||||
val expectedTypeArgumentCount = candidate.getTypeParameters().size()
|
||||
val expectedTypeArgumentCount = candidateDescriptor.getTypeParameters().size()
|
||||
for (index in jetTypeArguments.size()..expectedTypeArgumentCount - 1) {
|
||||
typeArguments.add(ErrorUtils.createErrorType(
|
||||
"Explicit type argument expected for " + candidate.getTypeParameters().get(index).getName()))
|
||||
"Explicit type argument expected for " + candidateDescriptor.getTypeParameters().get(index).getName()))
|
||||
}
|
||||
val substitutionContext = FunctionDescriptorUtil.createSubstitutionContext(candidate as FunctionDescriptor, typeArguments)
|
||||
val substitutionContext = FunctionDescriptorUtil.createSubstitutionContext(candidateDescriptor as FunctionDescriptor, typeArguments)
|
||||
val substitutor = TypeSubstitutor.create(substitutionContext)
|
||||
|
||||
if (expectedTypeArgumentCount != jetTypeArguments.size()) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
context.tracing.wrongNumberOfTypeArguments(context.trace, expectedTypeArgumentCount)
|
||||
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount)
|
||||
}
|
||||
else {
|
||||
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, substitutor, context.trace)
|
||||
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
|
||||
}
|
||||
|
||||
candidateCall.setResultingSubstitutor(substitutor)
|
||||
@@ -141,59 +141,75 @@ public class CandidateResolver(
|
||||
else if (candidateCall.getKnownTypeParametersSubstitutor() != null) {
|
||||
candidateCall.setResultingSubstitutor(candidateCall.getKnownTypeParametersSubstitutor()!!)
|
||||
}
|
||||
|
||||
if (jetTypeArguments.isEmpty() && !candidate.getTypeParameters().isEmpty() && candidateCall.getKnownTypeParametersSubstitutor() == null) {
|
||||
candidateCall.addStatus(genericCandidateResolver.inferTypeArguments(context))
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS).status)
|
||||
}
|
||||
|
||||
checkAbstractAndSuper(context)
|
||||
|
||||
checkNonExtensionCalledWithReceiver(context)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> checkExtensionReceiver(context: CallCandidateResolutionContext<D>) {
|
||||
val candidateCall = context.candidateCall
|
||||
val receiverParameter = candidateCall.getCandidateDescriptor().getExtensionReceiverParameter()
|
||||
val receiverArgument = candidateCall.getExtensionReceiver()
|
||||
if (receiverParameter != null && !receiverArgument.exists()) {
|
||||
context.tracing.missingReceiver(candidateCall.getTrace(), receiverParameter)
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
if (receiverParameter == null && receiverArgument.exists()) {
|
||||
context.tracing.noReceiverAllowed(candidateCall.getTrace())
|
||||
if (context.call.getCalleeExpression() is JetSimpleNameExpression) {
|
||||
candidateCall.addStatus(RECEIVER_PRESENCE_ERROR)
|
||||
}
|
||||
else {
|
||||
private fun <D : CallableDescriptor, F : D> CallCandidateResolutionContext<D>.mapArguments(task: ResolutionTask<D, F>) = check {
|
||||
if (task.checkArguments == CheckValueArgumentsMode.ENABLED) {
|
||||
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||
call, tracing, candidateCall, Sets.newLinkedHashSet<ValueArgument>())
|
||||
if (!argumentMappingStatus.isSuccess()) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDispatchReceiver(context: CallCandidateResolutionContext<*>): Boolean {
|
||||
val candidateCall = context.candidateCall
|
||||
val candidateDescriptor = candidateCall.getCandidateDescriptor()
|
||||
private fun CallCandidateResolutionContext<*>.checkVisibility() = checkAndReport {
|
||||
val receiverValue = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidateCall.getDispatchReceiver(),
|
||||
trace.getBindingContext())
|
||||
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, scope.getContainingDeclaration())
|
||||
if (invisibleMember != null) {
|
||||
tracing.invisibleMember(trace, invisibleMember)
|
||||
OTHER_ERROR
|
||||
} else {
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport {
|
||||
val receiverParameter = candidateCall.getCandidateDescriptor().getExtensionReceiverParameter()
|
||||
val receiverArgument = candidateCall.getExtensionReceiver()
|
||||
if (receiverParameter != null && !receiverArgument.exists()) {
|
||||
tracing.missingReceiver(candidateCall.getTrace(), receiverParameter)
|
||||
OTHER_ERROR
|
||||
}
|
||||
else if (receiverParameter == null && receiverArgument.exists()) {
|
||||
tracing.noReceiverAllowed(candidateCall.getTrace())
|
||||
if (call.getCalleeExpression() is JetSimpleNameExpression) {
|
||||
RECEIVER_PRESENCE_ERROR
|
||||
}
|
||||
else {
|
||||
OTHER_ERROR
|
||||
}
|
||||
}
|
||||
else {
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkDispatchReceiver() = checkAndReport {
|
||||
val candidateDescriptor = candidateDescriptor
|
||||
val dispatchReceiver = candidateCall.getDispatchReceiver()
|
||||
if (dispatchReceiver.exists()) {
|
||||
var nestedClass: ClassDescriptor? = null
|
||||
if (candidateDescriptor is ConstructorDescriptor && DescriptorUtils.isStaticNestedClass(candidateDescriptor.getContainingDeclaration())) {
|
||||
if (candidateDescriptor is ConstructorDescriptor
|
||||
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.getContainingDeclaration())
|
||||
) {
|
||||
nestedClass = candidateDescriptor.getContainingDeclaration()
|
||||
}
|
||||
else if (candidateDescriptor is FakeCallableDescriptorForObject) {
|
||||
nestedClass = candidateDescriptor.getReferencedDescriptor()
|
||||
}
|
||||
if (nestedClass != null) {
|
||||
context.tracing.nestedClassAccessViaInstanceReference(context.trace, nestedClass, candidateCall.getExplicitReceiverKind())
|
||||
return false
|
||||
tracing.nestedClassAccessViaInstanceReference(trace, nestedClass, candidateCall.getExplicitReceiverKind())
|
||||
return@checkAndReport OTHER_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
assert((dispatchReceiver.exists() == (candidateCall.getResultingDescriptor().getDispatchReceiverParameter() != null))) { "Shouldn't happen because of TaskPrioritizer: $candidateDescriptor" }
|
||||
assert((dispatchReceiver.exists() == (candidateCall.getResultingDescriptor().getDispatchReceiverParameter() != null))) {
|
||||
"Shouldn't happen because of TaskPrioritizer: $candidateDescriptor"
|
||||
}
|
||||
|
||||
return true
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
private fun checkOuterClassMemberIsAccessible(context: CallCandidateResolutionContext<*>): Boolean {
|
||||
@@ -206,17 +222,16 @@ public class CandidateResolver(
|
||||
return DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, context.call.getCallElement(), candidateThis)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> checkAbstractAndSuper(context: CallCandidateResolutionContext<D>) {
|
||||
val candidateCall = context.candidateCall
|
||||
val descriptor = candidateCall.getCandidateDescriptor()
|
||||
val expression = context.candidateCall.getCall().getCalleeExpression()
|
||||
private fun CallCandidateResolutionContext<*>.checkAbstractAndSuper() = check {
|
||||
val descriptor = candidateDescriptor
|
||||
val expression = candidateCall.getCall().getCalleeExpression()
|
||||
|
||||
if (expression is JetSimpleNameExpression) {
|
||||
// 'B' in 'class A: B()' is JetConstructorCalleeExpression
|
||||
if (descriptor is ConstructorDescriptor) {
|
||||
val modality = descriptor.getContainingDeclaration().getModality()
|
||||
if (modality == Modality.ABSTRACT) {
|
||||
context.tracing.instantiationOfAbstractClass(context.trace)
|
||||
tracing.instantiationOfAbstractClass(trace)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +239,7 @@ public class CandidateResolver(
|
||||
val superDispatchReceiver = getReceiverSuper(candidateCall.getDispatchReceiver())
|
||||
if (superDispatchReceiver != null) {
|
||||
if (descriptor is MemberDescriptor && descriptor.getModality() == Modality.ABSTRACT) {
|
||||
context.tracing.abstractSuperCall(context.trace)
|
||||
tracing.abstractSuperCall(trace)
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
}
|
||||
@@ -233,17 +248,19 @@ public class CandidateResolver(
|
||||
// See TaskPrioritizer for more
|
||||
val superExtensionReceiver = getReceiverSuper(candidateCall.getExtensionReceiver())
|
||||
if (superExtensionReceiver != null) {
|
||||
context.trace.report(SUPER_CANT_BE_EXTENSION_RECEIVER.on(superExtensionReceiver, superExtensionReceiver.getText()))
|
||||
trace.report(SUPER_CANT_BE_EXTENSION_RECEIVER.on(superExtensionReceiver, superExtensionReceiver.getText()))
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNonExtensionCalledWithReceiver(context: CallCandidateResolutionContext<*>) {
|
||||
val candidateCall = context.candidateCall
|
||||
|
||||
if (isSynthesizedInvoke(candidateCall.getCandidateDescriptor()) && !KotlinBuiltIns.isExtensionFunctionType(candidateCall.getDispatchReceiver().getType())) {
|
||||
context.tracing.freeFunctionCalledAsExtension(context.trace)
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
private fun CallCandidateResolutionContext<*>.checkNonExtensionCalledWithReceiver() = checkAndReport {
|
||||
if (isSynthesizedInvoke(candidateCall.getCandidateDescriptor())
|
||||
&& !KotlinBuiltIns.isExtensionFunctionType(candidateCall.getDispatchReceiver().getType())
|
||||
) {
|
||||
tracing.freeFunctionCalledAsExtension(trace)
|
||||
OTHER_ERROR
|
||||
} else {
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,8 +304,6 @@ public class CandidateResolver(
|
||||
var resultStatus = SUCCESS
|
||||
val candidateCall = context.candidateCall
|
||||
|
||||
resultStatus = resultStatus.combine(checkReceiverTypeError(context))
|
||||
|
||||
// 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'.
|
||||
@@ -365,7 +380,7 @@ public class CandidateResolver(
|
||||
actualType: JetType,
|
||||
context: ResolutionContext<*>): JetType? {
|
||||
val receiverToCast = ExpressionReceiver(JetPsiUtil.safeDeparenthesize(expression, false), actualType)
|
||||
val variants = SmartCastUtils.getSmartCastVariantsExcludingReceiver(context, receiverToCast)
|
||||
val variants = getSmartCastVariantsExcludingReceiver(context, receiverToCast)
|
||||
for (possibleType in variants) {
|
||||
if (JetTypeChecker.DEFAULT.isSubtypeOf(possibleType, expectedType)) {
|
||||
return possibleType
|
||||
@@ -374,39 +389,31 @@ public class CandidateResolver(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> checkReceiverTypeError(
|
||||
context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
||||
val candidateCall = context.candidateCall
|
||||
val candidateDescriptor = candidateCall.getCandidateDescriptor()
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(): Unit = check {
|
||||
val extensionReceiver = candidateDescriptor.getExtensionReceiverParameter()
|
||||
val dispatchReceiver = candidateDescriptor.getDispatchReceiverParameter()
|
||||
var status = SUCCESS
|
||||
|
||||
// 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(context.call)) {
|
||||
status = status.combine(checkReceiverTypeError(context, extensionReceiver, candidateCall.getExtensionReceiver()))
|
||||
if (!isInvokeCallOnExpressionWithBothReceivers(call)) {
|
||||
checkReceiverTypeError(extensionReceiver, candidateCall.getExtensionReceiver())
|
||||
}
|
||||
status = status.combine(checkReceiverTypeError(context, dispatchReceiver, candidateCall.getDispatchReceiver()))
|
||||
return status
|
||||
checkReceiverTypeError(dispatchReceiver, candidateCall.getDispatchReceiver())
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> checkReceiverTypeError(
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(
|
||||
receiverParameterDescriptor: ReceiverParameterDescriptor?,
|
||||
receiverArgument: ReceiverValue): ResolutionStatus {
|
||||
if (receiverParameterDescriptor == null || !receiverArgument.exists()) return SUCCESS
|
||||
|
||||
val candidateDescriptor = context.candidateCall.getCandidateDescriptor()
|
||||
receiverArgument: ReceiverValue
|
||||
) = checkAndReport {
|
||||
if (receiverParameterDescriptor == null || !receiverArgument.exists()) return@checkAndReport SUCCESS
|
||||
|
||||
val erasedReceiverType = getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor)
|
||||
|
||||
val isSubtypeBySmartCast = SmartCastUtils.isSubTypeBySmartCastIgnoringNullability(receiverArgument, erasedReceiverType, context)
|
||||
if (!isSubtypeBySmartCast) {
|
||||
return RECEIVER_TYPE_ERROR
|
||||
if (!isSubTypeBySmartCastIgnoringNullability(receiverArgument, erasedReceiverType, this)) {
|
||||
RECEIVER_TYPE_ERROR
|
||||
} else {
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> checkReceiver(
|
||||
@@ -422,13 +429,13 @@ public class CandidateResolver(
|
||||
if (TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) return SUCCESS
|
||||
|
||||
val safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.getCall().isExplicitSafeCall()
|
||||
val isSubtypeBySmartCast = SmartCastUtils.isSubTypeBySmartCastIgnoringNullability(
|
||||
val isSubtypeBySmartCast = isSubTypeBySmartCastIgnoringNullability(
|
||||
receiverArgument, receiverParameter.getType(), context)
|
||||
if (!isSubtypeBySmartCast) {
|
||||
context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument)
|
||||
return OTHER_ERROR
|
||||
}
|
||||
if (!SmartCastUtils.recordSmartCastIfNecessary(receiverArgument, receiverParameter.getType(), context, safeAccess)) {
|
||||
if (!recordSmartCastIfNecessary(receiverArgument, receiverParameter.getType(), context, safeAccess)) {
|
||||
return OTHER_ERROR
|
||||
}
|
||||
|
||||
@@ -436,7 +443,7 @@ public class CandidateResolver(
|
||||
|
||||
val bindingContext = trace.getBindingContext()
|
||||
if (!safeAccess && !receiverParameter.getType().isMarkedNullable() && receiverArgumentType.isMarkedNullable()) {
|
||||
if (!SmartCastUtils.canBeSmartCast(receiverParameter, receiverArgument, context)) {
|
||||
if (!canBeSmartCast(receiverParameter, receiverArgument, context)) {
|
||||
context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck)
|
||||
return UNSAFE_CALL_ERROR
|
||||
}
|
||||
@@ -469,4 +476,20 @@ public class CandidateResolver(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.shouldContinue() =
|
||||
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.getStatus().possibleTransformToSuccess()
|
||||
|
||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>
|
||||
.check(checker: CallCandidateResolutionContext<D>.() -> Unit): Unit = if (shouldContinue()) checker()
|
||||
|
||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.
|
||||
checkAndReport(checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus) {
|
||||
if (shouldContinue()) {
|
||||
candidateCall.addStatus(checker())
|
||||
}
|
||||
}
|
||||
|
||||
private val CallCandidateResolutionContext<*>.candidateDescriptor: CallableDescriptor get() = candidateCall.getCandidateDescriptor()
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user