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:
Alexander Udalov
2016-04-11 13:29:11 +03:00
parent d8263eb0b8
commit 76d3246514
5 changed files with 38 additions and 33 deletions
@@ -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)
@@ -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<!><!>)
} }
} }
@@ -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 {