KT-14352 Record short reference to companion object via type alias,

so that it would be checked properly.
This commit is contained in:
Dmitry Petrov
2016-10-14 11:55:42 +03:00
parent ac675784c1
commit 753a558bcb
8 changed files with 88 additions and 24 deletions
@@ -117,8 +117,8 @@ public interface BindingContext {
WritableSlice<KtReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET = WritableSlice<KtReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET =
new BasicWritableSlice<KtReferenceExpression, DeclarationDescriptor>(DO_NOTHING); new BasicWritableSlice<KtReferenceExpression, DeclarationDescriptor>(DO_NOTHING);
// if 'A' really means 'A.Companion' then this slice stores class descriptor for A, REFERENCE_TARGET stores descriptor Companion in this case // if 'A' really means 'A.Companion' then this slice stores class descriptor for A, REFERENCE_TARGET stores descriptor Companion in this case
WritableSlice<KtReferenceExpression, ClassDescriptor> SHORT_REFERENCE_TO_COMPANION_OBJECT = WritableSlice<KtReferenceExpression, ClassifierDescriptorWithTypeParameters> SHORT_REFERENCE_TO_COMPANION_OBJECT =
new BasicWritableSlice<KtReferenceExpression, ClassDescriptor>(DO_NOTHING); new BasicWritableSlice<KtReferenceExpression, ClassifierDescriptorWithTypeParameters>(DO_NOTHING);
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<Call, ResolvedCall<?>>(DO_NOTHING); WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<Call, ResolvedCall<?>>(DO_NOTHING);
WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice(); WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
@@ -89,7 +89,7 @@ private fun resolveQualifierReferenceTarget(
} }
// TODO make decisions about short reference to companion object somewhere else // TODO make decisions about short reference to companion object somewhere else
if (qualifier is ClassQualifier) { if (qualifier is ClassifierQualifier) {
val classifier = qualifier.descriptor val classifier = qualifier.descriptor
val selectorIsCallable = selector is CallableDescriptor && val selectorIsCallable = selector is CallableDescriptor &&
(selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) (selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null)
@@ -56,15 +56,17 @@ interface ClassifierUsageChecker {
val target = getReferencedClassifier(expression) ?: return val target = getReferencedClassifier(expression) ?: return
for (checker in checkers) { runCheckersWithTarget(target, expression)
checker.check(target, trace, expression, languageVersionSettings)
}
if (isReferenceToCompanionViaOuterClass(expression, target)) { if (isReferenceToCompanionViaOuterClass(expression, target)) {
val outerClass = target.containingDeclaration as ClassDescriptor val outerClass = target.containingDeclaration as ClassDescriptor
for (checker in checkers) { runCheckersWithTarget(outerClass, expression)
checker.check(outerClass, trace, expression, languageVersionSettings) }
} }
private fun runCheckersWithTarget(target: ClassifierDescriptor, expression: KtReferenceExpression) {
for (checker in checkers) {
checker.check(target, trace, expression, languageVersionSettings)
} }
} }
@@ -53,7 +53,9 @@ class TypeParameterQualifier(
override fun toString() = "TypeParameter{$descriptor}" override fun toString() = "TypeParameter{$descriptor}"
} }
interface ClassifierQualifier : Qualifier interface ClassifierQualifier : Qualifier {
override val descriptor: ClassifierDescriptorWithTypeParameters
}
class ClassQualifier( class ClassQualifier(
override val referenceExpression: KtSimpleNameExpression, override val referenceExpression: KtSimpleNameExpression,
@@ -0,0 +1,15 @@
// !API_VERSION: 1.0
class C {
@SinceKotlin("1.1")
companion object {
val x = 42
}
}
typealias CA = C
val test1 = <!NO_COMPANION_OBJECT!>CA<!>
val test2 = CA.<!UNRESOLVED_REFERENCE!>Companion<!>
val test3 = <!API_NOT_AVAILABLE!>CA<!>.x
val test4 = CA.<!UNRESOLVED_REFERENCE!>Companion<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!>
@@ -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 : <ERROR PROPERTY TYPE>]
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
@@ -19574,6 +19574,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); 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") @TestMetadata("typealiasesAsConstructors.kt")
public void testTypealiasesAsConstructors() throws Exception { public void testTypealiasesAsConstructors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsConstructors.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesAsConstructors.kt");
@@ -26,10 +26,12 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.EnumValue 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.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.makeNullable 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 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 val ClassDescriptor.classId: ClassId
get() { get() {
val owner = containingDeclaration val owner = containingDeclaration
@@ -77,23 +86,31 @@ val ClassDescriptor.classId: ClassId
throw IllegalStateException("Illegal container: $owner") 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.hasClassValueDescriptor: Boolean get() = classValueDescriptor != null
val ClassDescriptor.classValueDescriptor: ClassDescriptor? val ClassifierDescriptorWithTypeParameters.classValueDescriptor: ClassDescriptor?
get() = if (kind.isSingleton) this else companionObjectDescriptor get() = denotedClassDescriptor?.let {
if (it.kind.isSingleton)
it
else
it.companionObjectDescriptor
}
val ClassDescriptor.classValueTypeDescriptor: ClassDescriptor? val ClassifierDescriptorWithTypeParameters.classValueTypeDescriptor: ClassDescriptor?
get() = when (kind) { get() = denotedClassDescriptor?.let {
OBJECT -> this when (it.kind) {
ENUM_ENTRY -> { OBJECT -> it
// enum entry has the type of enum class ENUM_ENTRY -> {
val container = this.containingDeclaration // enum entry has the type of enum class
assert(container is ClassDescriptor && container.kind == ENUM_CLASS) val container = this.containingDeclaration
container as ClassDescriptor 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 */ /** If a literal of this class can be used as a value, returns the type of this value */