diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index 041922436d0..6840e6680c4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -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 performResolutionForCandidateCall( - context: CallCandidateResolutionContext, - task: ResolutionTask) { - + public fun performResolutionForCandidateCall(context: CallCandidateResolutionContext, + task: ResolutionTask): 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()) - 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() 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 checkExtensionReceiver(context: CallCandidateResolutionContext) { - 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 CallCandidateResolutionContext.mapArguments(task: ResolutionTask) = check { + if (task.checkArguments == CheckValueArgumentsMode.ENABLED) { + val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters( + call, tracing, candidateCall, Sets.newLinkedHashSet()) + 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 checkAbstractAndSuper(context: CallCandidateResolutionContext) { - 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 checkReceiverTypeError( - context: CallCandidateResolutionContext): 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 checkReceiverTypeError( - context: CallCandidateResolutionContext, + 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 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 CallCandidateResolutionContext.shouldContinue() = + candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.getStatus().possibleTransformToSuccess() + + private inline fun CallCandidateResolutionContext + .check(checker: CallCandidateResolutionContext.() -> Unit): Unit = if (shouldContinue()) checker() + + private inline fun CallCandidateResolutionContext. + checkAndReport(checker: CallCandidateResolutionContext.() -> ResolutionStatus) { + if (shouldContinue()) { + candidateCall.addStatus(checker()) + } + } + + private val CallCandidateResolutionContext<*>.candidateDescriptor: CallableDescriptor get() = candidateCall.getCandidateDescriptor() + }