Refine double colon LHS resolution if expression is an object

This commit is contained in:
Alexander Udalov
2016-07-01 16:05:40 +03:00
parent 5a6237b357
commit 7b59864ed9
6 changed files with 131 additions and 4 deletions
@@ -51,7 +51,7 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
import javax.inject.Inject
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
}
@@ -160,8 +160,10 @@ class DoubleColonExpressionResolver(
private fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? {
val resultForExpr = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS)
if (resultForExpr != null) {
val lhs = resultForExpr.lhs
if (lhs != null) {
val lhs = resultForExpr.lhs as DoubleColonLHS.Expression?
// 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()
}
}
@@ -171,6 +173,12 @@ class DoubleColonExpressionResolver(
}
if (resultForType != null) {
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) {
return resultForType.commit()
}
@@ -235,13 +243,17 @@ class DoubleColonExpressionResolver(
if (resultingDescriptor is FakeCallableDescriptorForObject) {
val classDescriptor = resultingDescriptor.classDescriptor
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"
if (expression.canBeConsideredProperType() && resultingDescriptor !is VariableDescriptor) return null
}
return DoubleColonLHS.Expression(typeInfo)
return DoubleColonLHS.Expression(typeInfo, isObject = false)
}
private fun resolveTypeOnLHS(
@@ -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
}
@@ -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
}
}
}
@@ -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
@@ -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);
}
@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")
public void testCompanionObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/companionObject.kt");