Ignore resolution to function without arguments on LHS of '::'
In the expression "Runnable::run" we were resolving the left-hand side to the SAM constructor of Runnable. Now we detect this situation, ignore the result of such resolution, and continue resolving the LHS as a type
This commit is contained in:
+21
-1
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -123,6 +124,18 @@ class DoubleColonExpressionResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KtExpression.canBeConsideredProperType(): Boolean {
|
||||||
|
return when (this) {
|
||||||
|
is KtSimpleNameExpression -> true
|
||||||
|
is KtDotQualifiedExpression -> {
|
||||||
|
receiverExpression.canBeConsideredProperType() && selectorExpression.let { selector ->
|
||||||
|
selector is KtSimpleNameExpression || (selector is KtCallExpression && selector.isWithoutValueArguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun shouldTryResolveLHSAsExpression(expression: KtDoubleColonExpression): Boolean {
|
private fun shouldTryResolveLHSAsExpression(expression: KtDoubleColonExpression): Boolean {
|
||||||
// TODO: improve diagnostic when bound callable references are disabled
|
// TODO: improve diagnostic when bound callable references are disabled
|
||||||
if (!languageFeatureSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) return false
|
if (!languageFeatureSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) return false
|
||||||
@@ -143,6 +156,8 @@ class DoubleColonExpressionResolver(
|
|||||||
val type = typeInfo.type
|
val type = typeInfo.type
|
||||||
|
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
|
// Be careful not to call a utility function to get a resolved call by an expression which may accidentally
|
||||||
|
// deparenthesize that expression, as this is undesirable here
|
||||||
val call = traceForExpr.trace.bindingContext[BindingContext.CALL, expression.getQualifiedElementSelector()]
|
val call = traceForExpr.trace.bindingContext[BindingContext.CALL, expression.getQualifiedElementSelector()]
|
||||||
val resolvedCall = call.getResolvedCall(traceForExpr.trace.bindingContext)
|
val resolvedCall = call.getResolvedCall(traceForExpr.trace.bindingContext)
|
||||||
val implicitReferenceToCompanion =
|
val implicitReferenceToCompanion =
|
||||||
@@ -152,7 +167,12 @@ class DoubleColonExpressionResolver(
|
|||||||
result.classDescriptor.companionObjectDescriptor != null
|
result.classDescriptor.companionObjectDescriptor != null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!implicitReferenceToCompanion) {
|
val resolvedToFunctionWithoutArguments =
|
||||||
|
resolvedCall != null &&
|
||||||
|
expression.canBeConsideredProperType() &&
|
||||||
|
resolvedCall.resultingDescriptor !is VariableDescriptor
|
||||||
|
|
||||||
|
if (!implicitReferenceToCompanion && !resolvedToFunctionWithoutArguments) {
|
||||||
traceForExpr.commit()
|
traceForExpr.commit()
|
||||||
return DoubleColonLHS.Expression(typeInfo).apply {
|
return DoubleColonLHS.Expression(typeInfo).apply {
|
||||||
c.trace.record(BindingContext.DOUBLE_COLON_LHS, expression, this)
|
c.trace.record(BindingContext.DOUBLE_COLON_LHS, expression, this)
|
||||||
|
|||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
fun test() = ("").<!FUNCTION_CALL_EXPECTED!>hashCode<!>::hashCode
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test(): kotlin.reflect.KFunction0<kotlin.Int>
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// FILE: Foo.kt
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
fun bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
import test.Foo
|
||||||
|
|
||||||
|
fun Foo(): String = ""
|
||||||
|
|
||||||
|
val f = Foo::bar
|
||||||
|
val g = Foo::<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public val f: kotlin.reflect.KFunction1<test.Foo, kotlin.Unit>
|
||||||
|
public val g: [ERROR : Type for Foo::length]
|
||||||
|
public fun Foo(): kotlin.String
|
||||||
|
|
||||||
|
package test {
|
||||||
|
|
||||||
|
public final class Foo {
|
||||||
|
public constructor Foo()
|
||||||
|
public final fun bar(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// FILE: test/GenericSam.java
|
||||||
|
|
||||||
|
package test;
|
||||||
|
|
||||||
|
public interface GenericSam<T> {
|
||||||
|
void invoke(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
import test.GenericSam
|
||||||
|
|
||||||
|
fun f1() = Runnable::class
|
||||||
|
fun f2() = Runnable::run
|
||||||
|
fun f3() = java.lang.Runnable::class
|
||||||
|
fun f4() = java.lang.Runnable::run
|
||||||
|
|
||||||
|
fun f5() = GenericSam::class
|
||||||
|
fun f6() = GenericSam<*>::invoke
|
||||||
|
fun f7() = test.GenericSam::class
|
||||||
|
fun f8() = test.GenericSam<String>::invoke
|
||||||
|
|
||||||
|
fun g1() = Runnable {}::class
|
||||||
|
fun g2() = Runnable {}::run
|
||||||
|
fun g3() = java.lang.Runnable {}::class
|
||||||
|
fun g4() = java.lang.Runnable {}::run
|
||||||
|
|
||||||
|
fun g5() = GenericSam<String> {}::class
|
||||||
|
fun g6() = GenericSam<String> {}::invoke
|
||||||
|
fun g7() = test.GenericSam<String> {}::class
|
||||||
|
fun g8() = test.GenericSam<String> {}::invoke
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun f1(): kotlin.reflect.KClass<java.lang.Runnable>
|
||||||
|
public fun f2(): kotlin.reflect.KFunction1<java.lang.Runnable, kotlin.Unit>
|
||||||
|
public fun f3(): kotlin.reflect.KClass<java.lang.Runnable>
|
||||||
|
public fun f4(): kotlin.reflect.KFunction1<java.lang.Runnable, kotlin.Unit>
|
||||||
|
public fun f5(): kotlin.reflect.KClass<test.GenericSam<*>>
|
||||||
|
public fun f6(): kotlin.reflect.KFunction2<test.GenericSam<*>, kotlin.Nothing!, kotlin.Unit>
|
||||||
|
public fun f7(): kotlin.reflect.KClass<test.GenericSam<*>>
|
||||||
|
public fun f8(): kotlin.reflect.KFunction2<test.GenericSam<kotlin.String>, kotlin.String!, kotlin.Unit>
|
||||||
|
public fun g1(): kotlin.reflect.KClass<java.lang.Runnable>
|
||||||
|
public fun g2(): kotlin.reflect.KFunction0<kotlin.Unit>
|
||||||
|
public fun g3(): kotlin.reflect.KClass<java.lang.Runnable>
|
||||||
|
public fun g4(): kotlin.reflect.KFunction0<kotlin.Unit>
|
||||||
|
public fun g5(): kotlin.reflect.KClass<test.GenericSam<kotlin.String>>
|
||||||
|
public fun g6(): kotlin.reflect.KFunction1<kotlin.String!, kotlin.Unit>
|
||||||
|
public fun g7(): kotlin.reflect.KClass<test.GenericSam<kotlin.String>>
|
||||||
|
public fun g8(): kotlin.reflect.KFunction1<kotlin.String!, kotlin.Unit>
|
||||||
@@ -1701,6 +1701,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sam.kt")
|
||||||
|
public void testSam() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/sam.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("unused.kt")
|
@TestMetadata("unused.kt")
|
||||||
public void testUnused() throws Exception {
|
public void testUnused() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/unused.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/unused.kt");
|
||||||
@@ -1727,6 +1733,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionCallWithoutArguments.kt")
|
||||||
|
public void testFunctionCallWithoutArguments() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/functionCallWithoutArguments.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("object.kt")
|
@TestMetadata("object.kt")
|
||||||
public void testObject() throws Exception {
|
public void testObject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/object.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/object.kt");
|
||||||
@@ -1766,6 +1778,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classMemberVsConstructorLikeFunction.kt")
|
||||||
|
public void testClassMemberVsConstructorLikeFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/function/classMemberVsConstructorLikeFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("constructorFromClass.kt")
|
@TestMetadata("constructorFromClass.kt")
|
||||||
public void testConstructorFromClass() throws Exception {
|
public void testConstructorFromClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/function/constructorFromClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/function/constructorFromClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user