diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt index a966b099e77..65ed7b93eb9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt @@ -22,12 +22,12 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor -import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.diagnostics.Errors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtCallableReferenceExpression -import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression -import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext @@ -37,6 +37,8 @@ import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil import org.jetbrains.kotlin.resolve.calls.util.CallMaker +import org.jetbrains.kotlin.resolve.createFunctionType +import org.jetbrains.kotlin.resolve.createValueParametersForInvokeInFunctionType import org.jetbrains.kotlin.resolve.scopes.BaseLexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -159,7 +161,7 @@ fun resolvePossiblyAmbiguousCallableReference( return null } -private fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) { +internal fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) { val functionDescriptor = AnonymousFunctionDescriptor( context.scope.ownerDescriptor, Annotations.EMPTY, @@ -178,29 +180,20 @@ private fun bindFunctionReference(expression: KtCallableReferenceExpression, typ context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor) } -private fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) { +internal fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) { val localVariable = LocalVariableDescriptor(context.scope.ownerDescriptor, Annotations.EMPTY, Name.special(""), referenceType, /* mutable = */ false, false, expression.toSourceElement()) context.trace.record(BindingContext.VARIABLE, expression, localVariable) } -private fun createReflectionTypeForCallableDescriptor( +fun createReflectionTypeForCallableDescriptor( descriptor: CallableDescriptor, lhsType: KotlinType?, reflectionTypes: ReflectionTypes, - trace: BindingTrace?, - reportOn: KtExpression?, ignoreReceiver: Boolean, scopeOwnerDescriptor: DeclarationDescriptor ): KotlinType? { - if (descriptor is CallableMemberDescriptor && isMemberExtension(descriptor)) { - if (reportOn != null) { - trace?.report(EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED.on(reportOn, descriptor)) - } - return null - } - val extensionReceiver = descriptor.extensionReceiverParameter val dispatchReceiver = descriptor.dispatchReceiverParameter?.let { dispatchReceiver -> // See CallableDescriptor#getOwnerForEffectiveDispatchReceiverParameter @@ -228,52 +221,11 @@ private fun createReflectionTypeForCallableDescriptor( } reflectionTypes.getKPropertyType(Annotations.EMPTY, receiverType, descriptor.type, mutable) } - is VariableDescriptor -> { - if (reportOn != null) { - trace?.report(UNSUPPORTED.on(reportOn, "References to variables aren't supported yet")) - } - null - } - else -> - throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor") + is VariableDescriptor -> null + else -> throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor") } } -private fun isMemberExtension(descriptor: CallableMemberDescriptor): Boolean { - val original = (descriptor as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: descriptor - return original.extensionReceiverParameter != null && original.dispatchReceiverParameter != null -} - -fun getReflectionTypeForCandidateDescriptor( - descriptor: CallableDescriptor, - reflectionTypes: ReflectionTypes, - ignoreReceiver: Boolean, - scopeOwnerDescriptor: DeclarationDescriptor -): KotlinType? = - createReflectionTypeForCallableDescriptor(descriptor, null, reflectionTypes, null, null, ignoreReceiver, scopeOwnerDescriptor) - -fun createReflectionTypeForResolvedCallableReference( - reference: KtCallableReferenceExpression, - lhsType: KotlinType?, - ignoreReceiver: Boolean, - descriptor: CallableDescriptor, - context: ResolutionContext<*>, - reflectionTypes: ReflectionTypes -): KotlinType? { - val type = createReflectionTypeForCallableDescriptor( - descriptor, lhsType, reflectionTypes, context.trace, reference.callableReference, ignoreReceiver, context.scope.ownerDescriptor - ) ?: return null - when (descriptor) { - is FunctionDescriptor -> { - bindFunctionReference(reference, type, context) - } - is PropertyDescriptor -> { - bindPropertyReference(reference, type, context) - } - } - return type -} - fun getResolvedCallableReferenceShapeType( reference: KtCallableReferenceExpression, lhsType: KotlinType?, @@ -290,8 +242,7 @@ fun getResolvedCallableReferenceShapeType( overloadResolutionResults.isSingleResult -> OverloadResolutionResultsUtil.getResultingCall(overloadResolutionResults, context.contextDependency)?.let { call -> createReflectionTypeForCallableDescriptor( - call.resultingDescriptor, lhsType, reflectionTypes, context.trace, reference, reference.isEmptyLHS, - context.scope.ownerDescriptor + call.resultingDescriptor, lhsType, reflectionTypes, reference.isEmptyLHS, context.scope.ownerDescriptor ) } expectedTypeUnknown /* && overload resolution was ambiguous */ -> 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 60ebad81fe5..ec941675074 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.callableReferences.getReflectionTypeForCandidateDescriptor +import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForCallableDescriptor import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS @@ -158,18 +158,12 @@ class CandidateResolver( private fun CallCandidateResolutionContext.checkExpectedCallableType() = check { if (!noExpectedType(expectedType)) { - val candidate = candidateCall.candidateDescriptor - val candidateReflectionType = getReflectionTypeForCandidateDescriptor( - candidate, reflectionTypes, - call.callElement.parent.let { it is KtCallableReferenceExpression && it.isEmptyLHS }, - scope.ownerDescriptor + val callableReferenceExpression = call.callElement.parent as? KtCallableReferenceExpression + val candidateReflectionType = createReflectionTypeForCallableDescriptor( + candidateCall.candidateDescriptor, null, reflectionTypes, + callableReferenceExpression?.isEmptyLHS == true, scope.ownerDescriptor ) - if (candidateReflectionType != null) { - if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(candidateReflectionType, expectedType)) { - candidateCall.addStatus(OTHER_ERROR) - } - } - else { + if (candidateReflectionType == null || !KotlinTypeChecker.DEFAULT.isSubtypeOf(candidateReflectionType, expectedType)) { candidateCall.addStatus(OTHER_ERROR) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index b541428aa18..c1e911a945f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -20,17 +20,16 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeatureSettings -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForResolvedCallableReference +import org.jetbrains.kotlin.resolve.callableReferences.bindFunctionReference +import org.jetbrains.kotlin.resolve.callableReferences.bindPropertyReference +import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForCallableDescriptor import org.jetbrains.kotlin.resolve.callableReferences.resolvePossiblyAmbiguousCallableReference import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode @@ -272,32 +271,53 @@ class DoubleColonExpressionResolver( resolutionResults: OverloadResolutionResults<*>?, context: ExpressionTypingContext ): KotlinType? { - val reference = expression.callableReference - val descriptor = if (resolutionResults != null && !resolutionResults.isNothing) { - OverloadResolutionResultsUtil.getResultingCall(resolutionResults, context.contextDependency)?.let { call -> - call.resultingDescriptor - } ?: return null + val resolvedCall = OverloadResolutionResultsUtil.getResultingCall(resolutionResults, context.contextDependency) + resolvedCall?.resultingDescriptor ?: return null } else { - context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference)) + context.trace.report(UNRESOLVED_REFERENCE.on(expression.callableReference, expression.callableReference)) return null } - if (expression.isEmptyLHS && - (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) { - context.trace.report(CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.on(reference)) - } - - if (descriptor is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(descriptor.containingDeclaration)) { - context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference)) - } + checkReferenceIsToAllowedMember(descriptor, context.trace, expression) val ignoreReceiver = lhs is DoubleColonLHS.Expression || expression.isEmptyLHS - return createReflectionTypeForResolvedCallableReference( - expression, lhs?.type, ignoreReceiver, descriptor, context, reflectionTypes - ) + val type = createReflectionTypeForCallableDescriptor( + descriptor, lhs?.type, reflectionTypes, ignoreReceiver, context.scope.ownerDescriptor + ) ?: return null + + when (descriptor) { + is FunctionDescriptor -> bindFunctionReference(expression, type, context) + is PropertyDescriptor -> bindPropertyReference(expression, type, context) + } + + return type + } + + private fun checkReferenceIsToAllowedMember( + descriptor: CallableDescriptor, trace: BindingTrace, expression: KtCallableReferenceExpression + ) { + val simpleName = expression.callableReference + if (expression.isEmptyLHS && + (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) { + trace.report(CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.on(simpleName)) + } + if (descriptor is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(descriptor.containingDeclaration)) { + trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(simpleName)) + } + if (descriptor is CallableMemberDescriptor && isMemberExtension(descriptor)) { + trace.report(EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED.on(simpleName, descriptor)) + } + if (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) { + trace.report(UNSUPPORTED.on(simpleName, "References to variables aren't supported yet")) + } + } + + private fun isMemberExtension(descriptor: CallableMemberDescriptor): Boolean { + val original = (descriptor as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: descriptor + return original.extensionReceiverParameter != null && original.dispatchReceiverParameter != null } fun resolveCallableReference( diff --git a/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.kt b/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.kt index e676cb8a978..680fec1fb6b 100644 --- a/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.kt +++ b/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.kt @@ -1,4 +1,4 @@ -// !DIAGNOSTICS: -UNUSED_EXPRESSION +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION class A { fun Int.extInt() = 42 fun A.extA(x: String) = x @@ -6,9 +6,14 @@ class A { fun main() { Int::extInt A::extA + + eat(Int::extInt) + eat(A::extA) } } +fun eat(value: Any) {} + fun main() { A::extInt A::extA diff --git a/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.txt b/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.txt index 23e83686c9a..8f8cb02026a 100644 --- a/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.txt +++ b/compiler/testData/diagnostics/tests/callableReference/function/extensionInClassDisallowed.txt @@ -1,5 +1,6 @@ package +public fun eat(/*0*/ value: kotlin.Any): kotlin.Unit public fun main(): kotlin.Unit public final class A { diff --git a/compiler/testData/diagnostics/tests/callableReference/property/localVariable.kt b/compiler/testData/diagnostics/tests/callableReference/property/localVariable.kt index 5550b022d63..3639382638e 100644 --- a/compiler/testData/diagnostics/tests/callableReference/property/localVariable.kt +++ b/compiler/testData/diagnostics/tests/callableReference/property/localVariable.kt @@ -1,5 +1,7 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE +fun eat(value: Any) {} + fun test(param: String) { val a = ::param @@ -8,4 +10,6 @@ fun test(param: String) { val lambda = { -> } val g = ::lambda + + eat(::param) } diff --git a/compiler/testData/diagnostics/tests/callableReference/property/localVariable.txt b/compiler/testData/diagnostics/tests/callableReference/property/localVariable.txt index a9a1817783f..61a12dedf90 100644 --- a/compiler/testData/diagnostics/tests/callableReference/property/localVariable.txt +++ b/compiler/testData/diagnostics/tests/callableReference/property/localVariable.txt @@ -1,3 +1,4 @@ package +public fun eat(/*0*/ value: kotlin.Any): kotlin.Unit public fun test(/*0*/ param: kotlin.String): kotlin.Unit diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt index 454561a2172..d546ff9fcd8 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt @@ -33,7 +33,7 @@ import org.jetbrains.kotlin.idea.completion.suppressAutoInsertion import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.* -import org.jetbrains.kotlin.resolve.callableReferences.getReflectionTypeForCandidateDescriptor +import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForCallableDescriptor import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.isNothing @@ -248,8 +248,8 @@ private fun MutableCollection.addLookupElementsForNullable(factor fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade): FuzzyType? { if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references - return getReflectionTypeForCandidateDescriptor( - this, resolutionFacade.getFrontendService(ReflectionTypes::class.java), false, resolutionFacade.moduleDescriptor + return createReflectionTypeForCallableDescriptor( + this, null, resolutionFacade.getFrontendService(ReflectionTypes::class.java), false, resolutionFacade.moduleDescriptor )?.toFuzzyType(emptyList()) }