Refactor CallableReferencesResolutionUtils.kt
Get rid of trace & reportOn parameters of createReflectionTypeForCallableDescriptor: move the two checks that required them to DoubleColonExpressionResolver and combine with other checks into a single function that checks the validity of the referenced symbol. This also makes these checks reported only once when invalid expressions are passed as function arguments (previously they were also reported from getResolvedCallableReferenceShapeType). Also inline getReflectionTypeForCandidateDescriptor after this, and refactor its usages
This commit is contained in:
+11
-60
@@ -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("<anonymous>"),
|
||||
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 */ ->
|
||||
|
||||
@@ -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 <D : CallableDescriptor> CallCandidateResolutionContext<D>.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)
|
||||
}
|
||||
}
|
||||
|
||||
+42
-22
@@ -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(
|
||||
|
||||
Vendored
+6
-1
@@ -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::<!EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED!>extInt<!>
|
||||
A::<!EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED!>extA<!>
|
||||
|
||||
eat(Int::<!EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED!>extInt<!>)
|
||||
eat(A::<!EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED!>extA<!>)
|
||||
}
|
||||
}
|
||||
|
||||
fun eat(value: Any) {}
|
||||
|
||||
fun main() {
|
||||
A::<!UNRESOLVED_REFERENCE!>extInt<!>
|
||||
A::<!UNRESOLVED_REFERENCE!>extA<!>
|
||||
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
package
|
||||
|
||||
public fun eat(/*0*/ value: kotlin.Any): kotlin.Unit
|
||||
public fun main(): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
|
||||
+4
@@ -1,5 +1,7 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
fun eat(value: Any) {}
|
||||
|
||||
fun test(param: String) {
|
||||
val a = ::<!UNSUPPORTED!>param<!>
|
||||
|
||||
@@ -8,4 +10,6 @@ fun test(param: String) {
|
||||
|
||||
val lambda = { -> }
|
||||
val g = ::<!UNSUPPORTED!>lambda<!>
|
||||
|
||||
eat(::<!UNSUPPORTED!>param<!>)
|
||||
}
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
package
|
||||
|
||||
public fun eat(/*0*/ value: kotlin.Any): kotlin.Unit
|
||||
public fun test(/*0*/ param: kotlin.String): kotlin.Unit
|
||||
|
||||
@@ -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<LookupElement>.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())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user