Fix type of member references without explicit class on LHS
Type of '::foo' for a function foo in a class A should be KFunction0<Unit>, not KFunction1<A, Unit>. Continue to report an error in this case, to be maybe supported in the future
This commit is contained in:
+17
-28
@@ -181,24 +181,6 @@ fun resolveCallableReferenceTarget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createReflectionTypeForFunction(
|
|
||||||
descriptor: FunctionDescriptor,
|
|
||||||
receiverType: KotlinType?,
|
|
||||||
reflectionTypes: ReflectionTypes
|
|
||||||
): KotlinType? {
|
|
||||||
val returnType = descriptor.returnType ?: return null
|
|
||||||
val valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(descriptor.valueParameters)
|
|
||||||
return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, valueParametersTypes, returnType)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createReflectionTypeForProperty(
|
|
||||||
descriptor: PropertyDescriptor,
|
|
||||||
receiverType: KotlinType?,
|
|
||||||
reflectionTypes: ReflectionTypes
|
|
||||||
): KotlinType {
|
|
||||||
return reflectionTypes.getKPropertyType(Annotations.EMPTY, receiverType, descriptor.type, descriptor.isVar)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) {
|
private fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) {
|
||||||
val functionDescriptor = AnonymousFunctionDescriptor(
|
val functionDescriptor = AnonymousFunctionDescriptor(
|
||||||
context.scope.ownerDescriptor,
|
context.scope.ownerDescriptor,
|
||||||
@@ -230,7 +212,8 @@ private fun createReflectionTypeForCallableDescriptor(
|
|||||||
lhsType: KotlinType?,
|
lhsType: KotlinType?,
|
||||||
reflectionTypes: ReflectionTypes,
|
reflectionTypes: ReflectionTypes,
|
||||||
trace: BindingTrace?,
|
trace: BindingTrace?,
|
||||||
reportOn: KtExpression?
|
reportOn: KtExpression?,
|
||||||
|
ignoreReceiver: Boolean
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val extensionReceiver = descriptor.extensionReceiverParameter
|
val extensionReceiver = descriptor.extensionReceiverParameter
|
||||||
val dispatchReceiver = descriptor.dispatchReceiverParameter?.let { dispatchReceiver ->
|
val dispatchReceiver = descriptor.dispatchReceiverParameter?.let { dispatchReceiver ->
|
||||||
@@ -248,15 +231,19 @@ private fun createReflectionTypeForCallableDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val receiverType =
|
val receiverType =
|
||||||
if (extensionReceiver != null || dispatchReceiver != null)
|
if ((extensionReceiver != null || dispatchReceiver != null) && !ignoreReceiver)
|
||||||
lhsType ?: extensionReceiver?.type ?: dispatchReceiver?.type
|
lhsType ?: extensionReceiver?.type ?: dispatchReceiver?.type
|
||||||
else null
|
else null
|
||||||
|
|
||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is FunctionDescriptor ->
|
is FunctionDescriptor -> {
|
||||||
createReflectionTypeForFunction(descriptor, receiverType, reflectionTypes)
|
val returnType = descriptor.returnType ?: return null
|
||||||
is PropertyDescriptor ->
|
val valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(descriptor.valueParameters)
|
||||||
createReflectionTypeForProperty(descriptor, receiverType, reflectionTypes)
|
return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, valueParametersTypes, returnType)
|
||||||
|
}
|
||||||
|
is PropertyDescriptor -> {
|
||||||
|
reflectionTypes.getKPropertyType(Annotations.EMPTY, receiverType, descriptor.type, descriptor.isVar)
|
||||||
|
}
|
||||||
is VariableDescriptor -> {
|
is VariableDescriptor -> {
|
||||||
if (reportOn != null) {
|
if (reportOn != null) {
|
||||||
trace?.report(UNSUPPORTED.on(reportOn, "References to variables aren't supported yet"))
|
trace?.report(UNSUPPORTED.on(reportOn, "References to variables aren't supported yet"))
|
||||||
@@ -270,9 +257,10 @@ private fun createReflectionTypeForCallableDescriptor(
|
|||||||
|
|
||||||
fun getReflectionTypeForCandidateDescriptor(
|
fun getReflectionTypeForCandidateDescriptor(
|
||||||
descriptor: CallableDescriptor,
|
descriptor: CallableDescriptor,
|
||||||
reflectionTypes: ReflectionTypes
|
reflectionTypes: ReflectionTypes,
|
||||||
|
ignoreReceiver: Boolean
|
||||||
): KotlinType? =
|
): KotlinType? =
|
||||||
createReflectionTypeForCallableDescriptor(descriptor, null, reflectionTypes, null, null)
|
createReflectionTypeForCallableDescriptor(descriptor, null, reflectionTypes, null, null, ignoreReceiver)
|
||||||
|
|
||||||
fun createReflectionTypeForResolvedCallableReference(
|
fun createReflectionTypeForResolvedCallableReference(
|
||||||
reference: KtCallableReferenceExpression,
|
reference: KtCallableReferenceExpression,
|
||||||
@@ -282,7 +270,7 @@ fun createReflectionTypeForResolvedCallableReference(
|
|||||||
reflectionTypes: ReflectionTypes
|
reflectionTypes: ReflectionTypes
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val type = createReflectionTypeForCallableDescriptor(
|
val type = createReflectionTypeForCallableDescriptor(
|
||||||
descriptor, lhsType, reflectionTypes, context.trace, reference.getCallableReference()
|
descriptor, lhsType, reflectionTypes, context.trace, reference.callableReference, reference.typeReference == null
|
||||||
) ?: return null
|
) ?: return null
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
is FunctionDescriptor -> {
|
is FunctionDescriptor -> {
|
||||||
@@ -310,7 +298,8 @@ fun getResolvedCallableReferenceShapeType(
|
|||||||
null
|
null
|
||||||
overloadResolutionResults.isSingleResult ->
|
overloadResolutionResults.isSingleResult ->
|
||||||
OverloadResolutionResultsUtil.getResultingCall(overloadResolutionResults, context.contextDependency)?.let { call ->
|
OverloadResolutionResultsUtil.getResultingCall(overloadResolutionResults, context.contextDependency)?.let { call ->
|
||||||
createReflectionTypeForCallableDescriptor(call.resultingDescriptor, lhsType, reflectionTypes, context.trace, reference)
|
createReflectionTypeForCallableDescriptor(call.resultingDescriptor, lhsType, reflectionTypes, context.trace, reference,
|
||||||
|
reference.typeReference == null)
|
||||||
}
|
}
|
||||||
expectedTypeUnknown /* && overload resolution was ambiguous */ ->
|
expectedTypeUnknown /* && overload resolution was ambiguous */ ->
|
||||||
functionPlaceholders.createFunctionPlaceholderType(emptyList(), false)
|
functionPlaceholders.createFunctionPlaceholderType(emptyList(), false)
|
||||||
|
|||||||
@@ -157,8 +157,11 @@ class CandidateResolver(
|
|||||||
private fun <D : CallableDescriptor, F : D> CallCandidateResolutionContext<D>.checkExpectedCallableType()
|
private fun <D : CallableDescriptor, F : D> CallCandidateResolutionContext<D>.checkExpectedCallableType()
|
||||||
= check {
|
= check {
|
||||||
if (!noExpectedType(expectedType)) {
|
if (!noExpectedType(expectedType)) {
|
||||||
val candidate = candidateCall.getCandidateDescriptor()
|
val candidate = candidateCall.candidateDescriptor
|
||||||
val candidateReflectionType = getReflectionTypeForCandidateDescriptor(candidate, reflectionTypes);
|
val candidateReflectionType = getReflectionTypeForCandidateDescriptor(
|
||||||
|
candidate, reflectionTypes,
|
||||||
|
call.callElement.parent.let { it is KtCallableReferenceExpression && it.typeReference == null }
|
||||||
|
);
|
||||||
if (candidateReflectionType != null) {
|
if (candidateReflectionType != null) {
|
||||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(candidateReflectionType, expectedType)) {
|
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(candidateReflectionType, expectedType)) {
|
||||||
candidateCall.addStatus(OTHER_ERROR)
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
|
|||||||
Vendored
+11
-2
@@ -1,6 +1,9 @@
|
|||||||
// !CHECK_TYPE
|
// !CHECK_TYPE
|
||||||
|
|
||||||
import kotlin.reflect.KFunction1
|
import kotlin.reflect.KFunction0
|
||||||
|
|
||||||
|
fun explicitlyExpectFunction0(f: () -> Unit) = f
|
||||||
|
fun explicitlyExpectFunction1(f: (A) -> Unit) = f
|
||||||
|
|
||||||
fun foo() {}
|
fun foo() {}
|
||||||
|
|
||||||
@@ -10,6 +13,12 @@ class A {
|
|||||||
fun main() {
|
fun main() {
|
||||||
val x = ::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!>
|
val x = ::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!>
|
||||||
|
|
||||||
checkSubtype<KFunction1<A, Unit>>(x)
|
checkSubtype<KFunction0<Unit>>(x)
|
||||||
|
|
||||||
|
explicitlyExpectFunction0(x)
|
||||||
|
explicitlyExpectFunction1(<!TYPE_MISMATCH!>x<!>)
|
||||||
|
|
||||||
|
explicitlyExpectFunction0(::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!>)
|
||||||
|
explicitlyExpectFunction1(<!TYPE_MISMATCH!>::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!><!>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
@@ -1,5 +1,7 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
|
public fun explicitlyExpectFunction0(/*0*/ f: () -> kotlin.Unit): () -> kotlin.Unit
|
||||||
|
public fun explicitlyExpectFunction1(/*0*/ f: (A) -> kotlin.Unit): (A) -> kotlin.Unit
|
||||||
public fun foo(): kotlin.Unit
|
public fun foo(): kotlin.Unit
|
||||||
|
|
||||||
public final class A {
|
public final class A {
|
||||||
|
|||||||
@@ -248,7 +248,9 @@ private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factor
|
|||||||
|
|
||||||
fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade): FuzzyType? {
|
fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade): FuzzyType? {
|
||||||
if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references
|
if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references
|
||||||
return getReflectionTypeForCandidateDescriptor(this, resolutionFacade.getFrontendService(ReflectionTypes::class.java))?.toFuzzyType(emptyList())
|
return getReflectionTypeForCandidateDescriptor(
|
||||||
|
this, resolutionFacade.getFrontendService(ReflectionTypes::class.java), false
|
||||||
|
)?.toFuzzyType(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SmartCompletionItemPriority {
|
enum class SmartCompletionItemPriority {
|
||||||
|
|||||||
Reference in New Issue
Block a user