From 753a558bcbd67ccd1f461c9b7c4bbeac87038539 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 14 Oct 2016 11:55:42 +0300 Subject: [PATCH] KT-14352 Record short reference to companion object via type alias, so that it would be checked properly. --- .../kotlin/resolve/BindingContext.java | 4 +- .../resolve/QualifiedExpressionResolveUtil.kt | 2 +- .../checkers/ClassifierUsageChecker.kt | 14 +++--- .../resolve/scopes/receivers/Qualifier.kt | 4 +- .../typealiasesAsCompanionObjects.kt | 15 +++++++ .../typealiasesAsCompanionObjects.txt | 22 +++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ .../kotlin/resolve/DescriptorUtils.kt | 45 +++++++++++++------ 8 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.kt create mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 6d0d9cf3497..bce7f249edf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -117,8 +117,8 @@ public interface BindingContext { WritableSlice REFERENCE_TARGET = new BasicWritableSlice(DO_NOTHING); // if 'A' really means 'A.Companion' then this slice stores class descriptor for A, REFERENCE_TARGET stores descriptor Companion in this case - WritableSlice SHORT_REFERENCE_TO_COMPANION_OBJECT = - new BasicWritableSlice(DO_NOTHING); + WritableSlice SHORT_REFERENCE_TO_COMPANION_OBJECT = + new BasicWritableSlice(DO_NOTHING); WritableSlice> RESOLVED_CALL = new BasicWritableSlice>(DO_NOTHING); WritableSlice TAIL_RECURSION_CALL = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt index 66b74358aac..048a952637d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt @@ -89,7 +89,7 @@ private fun resolveQualifierReferenceTarget( } // TODO make decisions about short reference to companion object somewhere else - if (qualifier is ClassQualifier) { + if (qualifier is ClassifierQualifier) { val classifier = qualifier.descriptor val selectorIsCallable = selector is CallableDescriptor && (selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt index 3ac48424db9..f8f04e3f00d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ClassifierUsageChecker.kt @@ -56,15 +56,17 @@ interface ClassifierUsageChecker { val target = getReferencedClassifier(expression) ?: return - for (checker in checkers) { - checker.check(target, trace, expression, languageVersionSettings) - } + runCheckersWithTarget(target, expression) if (isReferenceToCompanionViaOuterClass(expression, target)) { val outerClass = target.containingDeclaration as ClassDescriptor - for (checker in checkers) { - checker.check(outerClass, trace, expression, languageVersionSettings) - } + runCheckersWithTarget(outerClass, expression) + } + } + + private fun runCheckersWithTarget(target: ClassifierDescriptor, expression: KtReferenceExpression) { + for (checker in checkers) { + checker.check(target, trace, expression, languageVersionSettings) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index fb488c24e7d..0fa528d0152 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -53,7 +53,9 @@ class TypeParameterQualifier( override fun toString() = "TypeParameter{$descriptor}" } -interface ClassifierQualifier : Qualifier +interface ClassifierQualifier : Qualifier { + override val descriptor: ClassifierDescriptorWithTypeParameters +} class ClassQualifier( override val referenceExpression: KtSimpleNameExpression, diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.kt new file mode 100644 index 00000000000..3378200c312 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.kt @@ -0,0 +1,15 @@ +// !API_VERSION: 1.0 + +class C { + @SinceKotlin("1.1") + companion object { + val x = 42 + } +} + +typealias CA = C + +val test1 = CA +val test2 = CA.Companion +val test3 = CA.x +val test4 = CA.Companion.x diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.txt new file mode 100644 index 00000000000..ebef14662dc --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.txt @@ -0,0 +1,22 @@ +package + +public val test1: [ERROR : Type for CA] +public val test2: [ERROR : Type for CA.Companion] +public val test3: kotlin.Int = 42 +public val test4: [ERROR : ] + +public final class C { + public constructor C() + 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 + + @kotlin.SinceKotlin(version = "1.1") public companion object Companion { + private constructor Companion() + public final val x: kotlin.Int = 42 + 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 typealias CA = C diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 07119e92a58..f0e7e4db4c2 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19574,6 +19574,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("typealiasesAsCompanionObjects.kt") + public void testTypealiasesAsCompanionObjects() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsCompanionObjects.kt"); + doTest(fileName); + } + @TestMetadata("typealiasesAsConstructors.kt") public void testTypealiasesAsConstructors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsConstructors.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index 1b01651377e..8e1375a92b0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -26,10 +26,12 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.constants.EnumValue -import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjection +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny import org.jetbrains.kotlin.types.typeUtil.makeNullable @@ -65,6 +67,13 @@ fun ModuleDescriptor.resolveTopLevelClass(topLevelClassFqName: FqName, location: return getPackage(topLevelClassFqName.parent()).memberScope.getContributedClassifier(topLevelClassFqName.shortName(), location) as? ClassDescriptor } +val ClassifierDescriptorWithTypeParameters.denotedClassDescriptor: ClassDescriptor? + get() = when (this) { + is ClassDescriptor -> this + is TypeAliasDescriptor -> classDescriptor + else -> throw UnsupportedOperationException("Unexpected descriptor kind: $this") + } + val ClassDescriptor.classId: ClassId get() { val owner = containingDeclaration @@ -77,23 +86,31 @@ val ClassDescriptor.classId: ClassId throw IllegalStateException("Illegal container: $owner") } -val ClassDescriptor.hasCompanionObject: Boolean get() = companionObjectDescriptor != null +val ClassifierDescriptorWithTypeParameters.hasCompanionObject: Boolean + get() = denotedClassDescriptor?.companionObjectDescriptor != null val ClassDescriptor.hasClassValueDescriptor: Boolean get() = classValueDescriptor != null -val ClassDescriptor.classValueDescriptor: ClassDescriptor? - get() = if (kind.isSingleton) this else companionObjectDescriptor +val ClassifierDescriptorWithTypeParameters.classValueDescriptor: ClassDescriptor? + get() = denotedClassDescriptor?.let { + if (it.kind.isSingleton) + it + else + it.companionObjectDescriptor + } -val ClassDescriptor.classValueTypeDescriptor: ClassDescriptor? - get() = when (kind) { - OBJECT -> this - ENUM_ENTRY -> { - // enum entry has the type of enum class - val container = this.containingDeclaration - assert(container is ClassDescriptor && container.kind == ENUM_CLASS) - container as ClassDescriptor +val ClassifierDescriptorWithTypeParameters.classValueTypeDescriptor: ClassDescriptor? + get() = denotedClassDescriptor?.let { + when (it.kind) { + OBJECT -> it + ENUM_ENTRY -> { + // enum entry has the type of enum class + val container = this.containingDeclaration + assert(container is ClassDescriptor && container.kind == ENUM_CLASS) + container as ClassDescriptor + } + else -> it.companionObjectDescriptor } - else -> companionObjectDescriptor } /** If a literal of this class can be used as a value, returns the type of this value */