Refine double colon LHS resolution if expression is an object
This commit is contained in:
+16
-4
@@ -51,7 +51,7 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
sealed class DoubleColonLHS(val type: KotlinType) {
|
sealed class DoubleColonLHS(val type: KotlinType) {
|
||||||
class Expression(typeInfo: KotlinTypeInfo) : DoubleColonLHS(typeInfo.type!!) {
|
class Expression(typeInfo: KotlinTypeInfo, val isObject: Boolean) : DoubleColonLHS(typeInfo.type!!) {
|
||||||
val dataFlowInfo: DataFlowInfo = typeInfo.dataFlowInfo
|
val dataFlowInfo: DataFlowInfo = typeInfo.dataFlowInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,8 +160,10 @@ class DoubleColonExpressionResolver(
|
|||||||
private fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? {
|
private fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? {
|
||||||
val resultForExpr = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS)
|
val resultForExpr = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS)
|
||||||
if (resultForExpr != null) {
|
if (resultForExpr != null) {
|
||||||
val lhs = resultForExpr.lhs
|
val lhs = resultForExpr.lhs as DoubleColonLHS.Expression?
|
||||||
if (lhs != null) {
|
// If expression result is an object, we remember this and skip it here, because there are valid situations where
|
||||||
|
// another type (representing another classifier) should win
|
||||||
|
if (lhs != null && !lhs.isObject) {
|
||||||
return resultForExpr.commit()
|
return resultForExpr.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,6 +173,12 @@ class DoubleColonExpressionResolver(
|
|||||||
}
|
}
|
||||||
if (resultForType != null) {
|
if (resultForType != null) {
|
||||||
val lhs = resultForType.lhs
|
val lhs = resultForType.lhs
|
||||||
|
if (resultForExpr != null && lhs != null && lhs.type == resultForExpr.lhs?.type) {
|
||||||
|
// If we skipped an object expression result before and the type result is the same, this means that
|
||||||
|
// there were no other classifier except that object that could win. We prefer to treat the LHS as an expression here,
|
||||||
|
// to have a bound callable reference / class literal
|
||||||
|
return resultForExpr.commit()
|
||||||
|
}
|
||||||
if (lhs != null) {
|
if (lhs != null) {
|
||||||
return resultForType.commit()
|
return resultForType.commit()
|
||||||
}
|
}
|
||||||
@@ -235,13 +243,17 @@ class DoubleColonExpressionResolver(
|
|||||||
if (resultingDescriptor is FakeCallableDescriptorForObject) {
|
if (resultingDescriptor is FakeCallableDescriptorForObject) {
|
||||||
val classDescriptor = resultingDescriptor.classDescriptor
|
val classDescriptor = resultingDescriptor.classDescriptor
|
||||||
if (classDescriptor.companionObjectDescriptor != null) return null
|
if (classDescriptor.companionObjectDescriptor != null) return null
|
||||||
|
|
||||||
|
if (DescriptorUtils.isObject(classDescriptor)) {
|
||||||
|
return DoubleColonLHS.Expression(typeInfo, isObject = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is resolved to a function (with the error "arguments expected"), such as in "Runnable::class"
|
// Check if this is resolved to a function (with the error "arguments expected"), such as in "Runnable::class"
|
||||||
if (expression.canBeConsideredProperType() && resultingDescriptor !is VariableDescriptor) return null
|
if (expression.canBeConsideredProperType() && resultingDescriptor !is VariableDescriptor) return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return DoubleColonLHS.Expression(typeInfo)
|
return DoubleColonLHS.Expression(typeInfo, isObject = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveTypeOnLHS(
|
private fun resolveTypeOnLHS(
|
||||||
|
|||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
import b.B.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class Companion
|
||||||
|
|
||||||
|
val f: KClass<a.Companion> = Companion::class
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
package b
|
||||||
|
|
||||||
|
class B {
|
||||||
|
companion object Companion
|
||||||
|
}
|
||||||
Vendored
+29
@@ -0,0 +1,29 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package a {
|
||||||
|
public val f: kotlin.reflect.KClass<a.Companion>
|
||||||
|
|
||||||
|
public final class Companion {
|
||||||
|
public constructor Companion()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package b {
|
||||||
|
|
||||||
|
public final class B {
|
||||||
|
public constructor B()
|
||||||
|
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
|
||||||
|
|
||||||
|
public companion object Companion {
|
||||||
|
private constructor Companion()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
import b.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class A
|
||||||
|
object B
|
||||||
|
|
||||||
|
val f: KClass<a.A> = A::class
|
||||||
|
val g: KClass<a.B> = B::class
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
package b
|
||||||
|
|
||||||
|
object A
|
||||||
|
object B
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package a {
|
||||||
|
public val f: kotlin.reflect.KClass<a.A>
|
||||||
|
public val g: kotlin.reflect.KClass<a.B>
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
public constructor A()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
public object B {
|
||||||
|
private constructor B()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package b {
|
||||||
|
|
||||||
|
public object A {
|
||||||
|
private constructor A()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
public object B {
|
||||||
|
private constructor B()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1721,6 +1721,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/bound"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVsStarImportedCompanion.kt")
|
||||||
|
public void testClassVsStarImportedCompanion() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classVsStarImportedObject.kt")
|
||||||
|
public void testClassVsStarImportedObject() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("companionObject.kt")
|
@TestMetadata("companionObject.kt")
|
||||||
public void testCompanionObject() throws Exception {
|
public void testCompanionObject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/companionObject.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/companionObject.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user