From 7b59864ed9cd0703d6ab17f2df8782e877df9400 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 1 Jul 2016 16:05:40 +0300 Subject: [PATCH] Refine double colon LHS resolution if expression is an object --- .../DoubleColonExpressionResolver.kt | 20 ++++++++-- .../bound/classVsStarImportedCompanion.kt | 18 +++++++++ .../bound/classVsStarImportedCompanion.txt | 29 +++++++++++++++ .../bound/classVsStarImportedObject.kt | 19 ++++++++++ .../bound/classVsStarImportedObject.txt | 37 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 12 ++++++ 6 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.txt create mode 100644 compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 04d8b194162..c6dd25d33b0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -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( diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.kt b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.kt new file mode 100644 index 00000000000..870501ae0fb --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.kt @@ -0,0 +1,18 @@ +// FILE: 1.kt + +package a + +import b.B.* +import kotlin.reflect.KClass + +class Companion + +val f: KClass = Companion::class + +// FILE: 2.kt + +package b + +class B { + companion object Companion +} diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.txt b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.txt new file mode 100644 index 00000000000..21bc781e9ab --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedCompanion.txt @@ -0,0 +1,29 @@ +package + +package a { + public val f: kotlin.reflect.KClass + + 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 + } + } +} diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.kt b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.kt new file mode 100644 index 00000000000..0b2434d7c0d --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.kt @@ -0,0 +1,19 @@ +// FILE: 1.kt + +package a + +import b.* +import kotlin.reflect.KClass + +class A +object B + +val f: KClass = A::class +val g: KClass = B::class + +// FILE: 2.kt + +package b + +object A +object B diff --git a/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.txt b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.txt new file mode 100644 index 00000000000..813785eae8e --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/bound/classVsStarImportedObject.txt @@ -0,0 +1,37 @@ +package + +package a { + public val f: kotlin.reflect.KClass + public val g: kotlin.reflect.KClass + + 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 + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 3315bcfe0c1..c945bb57e74 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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");