diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index dcb29dd6cf9..d8972b26709 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -262,6 +262,7 @@ public interface Errors { DiagnosticFactory0.create(ERROR, VARIANCE_IN_PROJECTION); DiagnosticFactory0 CYCLIC_INHERITANCE_HIERARCHY = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 CYCLIC_SCOPES_WITH_COMPANION = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 SUPERTYPE_NOT_INITIALIZED = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index b0fc0e13a5a..66d39a66786 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -538,6 +538,8 @@ public class DefaultErrorMessages { MAP.put(TYPE_MISMATCH_IN_RANGE, "Type mismatch: incompatible types of range and element checked in it"); MAP.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type"); MAP.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds"); + MAP.put(CYCLIC_SCOPES_WITH_COMPANION, "There's a cycle in scopes for that type. Most probably, there's a companion object that inherits some nested class (see KT-21515).\n" + + "Such code is currently unstable, and its behavior may change in future releases"); MAP.put(MANY_CLASSES_IN_SUPERTYPE_LIST, "Only one class may appear in a supertype list"); MAP.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Only classes and interfaces may serve as supertypes"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/findLoopsInSupertypes.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/findLoopsInSupertypes.kt index 419ddbe7851..cf9aeacbe22 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/findLoopsInSupertypes.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/findLoopsInSupertypes.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker +import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.utils.DFS @@ -38,6 +39,12 @@ class SupertypeLoopCheckerImpl : SupertypeLoopChecker { if (isReachable(superType.constructor, currentTypeConstructor, graph)) { superTypesToRemove.add(superType) reportLoop(superType) + + currentTypeConstructor.declarationDescriptor?.let { + if (it.isCompanionObject()) { + reportLoop(it.defaultType) + } + } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt index fcaee8eee89..8bcd4bb1cdc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny import org.jetbrains.kotlin.resolve.scopes.* -import org.jetbrains.kotlin.resolve.scopes.utils.ThrowingLexicalScope +import org.jetbrains.kotlin.resolve.scopes.utils.ErrorLexicalScope import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* @@ -46,26 +46,26 @@ class ClassResolutionScopesSupport( scopeWithGenerics(inheritanceScopeWithMe()) } - private val inheritanceScopeWithoutMe: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createThrowingLexicalScope) { + private val inheritanceScopeWithoutMe: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createErrorLexicalScope) { classDescriptor.getAllSuperclassesWithoutAny().asReversed().fold(getOuterScope()) { scope, currentClass -> createInheritanceScope(parent = scope, ownerDescriptor = classDescriptor, classDescriptor = currentClass) } } - private val inheritanceScopeWithMe: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createThrowingLexicalScope) { + private val inheritanceScopeWithMe: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createErrorLexicalScope) { createInheritanceScope(parent = inheritanceScopeWithoutMe(), ownerDescriptor = classDescriptor, classDescriptor = classDescriptor) } - val scopeForCompanionObjectHeaderResolution: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createThrowingLexicalScope) { + val scopeForCompanionObjectHeaderResolution: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createErrorLexicalScope) { createInheritanceScope(inheritanceScopeWithoutMe(), classDescriptor, classDescriptor, withCompanionObject = false) } - val scopeForMemberDeclarationResolution: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createThrowingLexicalScope) { + val scopeForMemberDeclarationResolution: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createErrorLexicalScope) { val scopeWithGenerics = scopeWithGenerics(inheritanceScopeWithMe()) LexicalScopeImpl(scopeWithGenerics, classDescriptor, true, classDescriptor.thisAsReceiverParameter, LexicalScopeKind.CLASS_MEMBER_SCOPE) } - val scopeForStaticMemberDeclarationResolution: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createThrowingLexicalScope) { + val scopeForStaticMemberDeclarationResolution: () -> LexicalScope = storageManager.createLazyValue(onRecursion = createErrorLexicalScope) { if (classDescriptor.kind.isSingleton) { scopeForMemberDeclarationResolution() } @@ -116,9 +116,7 @@ class ClassResolutionScopesSupport( createLazyValueWithPostCompute(compute, onRecursion, {}) companion object { - private val createThrowingLexicalScope: (Boolean) -> LexicalScope = { - ThrowingLexicalScope() - } + private val createErrorLexicalScope: (Boolean) -> LexicalScope = { ErrorLexicalScope() } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java index 5787eace720..bb0b13cf786 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -607,6 +607,19 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes } } + @Override + protected void reportScopesLoopError(@NotNull KotlinType type) { + PsiElement reportOn = DescriptorToSourceUtils.getSourceFromDescriptor(type.getConstructor().getDeclarationDescriptor()); + + if (reportOn instanceof KtClass) { + reportOn = ((KtClass) reportOn).getNameIdentifier(); + } + + if (reportOn != null) { + c.getTrace().report(CYCLIC_SCOPES_WITH_COMPANION.on(reportOn)); + } + } + private void reportCyclicInheritanceHierarchyError( @NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt index 7eb021a35ff..bd78a00c28f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.* +import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.util.collectionUtils.concat import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.SmartList @@ -245,31 +246,37 @@ fun chainImportingScopes(scopes: List, tail: ImportingScope? = n } } -class ThrowingLexicalScope : LexicalScope { - override val parent: HierarchicalScope - get() = throw IllegalStateException() +class ErrorLexicalScope : LexicalScope { + override val parent: HierarchicalScope = object : HierarchicalScope { + override val parent: HierarchicalScope? = null - override val ownerDescriptor: DeclarationDescriptor - get() = throw IllegalStateException() - override val isOwnerDescriptorAccessibleByLabel: Boolean - get() = throw IllegalStateException() - override val implicitReceiver: ReceiverParameterDescriptor? - get() = throw IllegalStateException() - override val kind: LexicalScopeKind - get() = LexicalScopeKind.THROWING + override fun printStructure(p: Printer) { + p.print("") + } - override fun printStructure(p: Printer) = - throw IllegalStateException() + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null - override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = - throw IllegalStateException() + override fun getContributedVariables(name: Name, location: LookupLocation): Collection = emptySet() - override fun getContributedVariables(name: Name, location: LookupLocation): Collection = - throw IllegalStateException() + override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = emptySet() - override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = - throw IllegalStateException() + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection = emptySet() + } - override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection = - throw IllegalStateException() + override fun printStructure(p: Printer) { + p.print("") + } + + override val ownerDescriptor: DeclarationDescriptor = ErrorUtils.createErrorClass("") + override val isOwnerDescriptorAccessibleByLabel: Boolean = false + override val implicitReceiver: ReceiverParameterDescriptor? = null + override val kind: LexicalScopeKind = LexicalScopeKind.THROWING + + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null + + override fun getContributedVariables(name: Name, location: LookupLocation): Collection = emptySet() + + override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = emptySet() + + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection = emptySet() } diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.kt new file mode 100644 index 00000000000..84b65570cda --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.kt @@ -0,0 +1,14 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +open class Container { + open class Base { + open fun m() {} + } + + // note that Base() supertype will be resolved in scope that was created on recursion + abstract class DerivedAbstract : Base() + + companion object : DerivedAbstract() { + override fun m() {} + } +} diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.txt new file mode 100644 index 00000000000..cf0c77ae1f6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.txt @@ -0,0 +1,31 @@ +package + +public open class Container { + public constructor Container() + 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 open class Base { + public constructor Base() + 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 fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public companion object Companion : Container.DerivedAbstract { + 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 fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public abstract class DerivedAbstract { + public constructor DerivedAbstract() + 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/cyclicHierarchy/withCompanion/noMembers.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.kt new file mode 100644 index 00000000000..638d0e388e3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.kt @@ -0,0 +1,14 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +abstract class DerivedAbstract : C.Base() { + open class Data +} + +public class C { + + open class Base () + + class Foo : Data() + + companion object : DerivedAbstract() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.txt new file mode 100644 index 00000000000..f7d7d5a2636 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.txt @@ -0,0 +1,43 @@ +package + +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 + + public open class Base { + public constructor Base() + 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 : DerivedAbstract { + 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 + } + + public final class Foo : DerivedAbstract.Data { + public constructor Foo() + 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 abstract class DerivedAbstract : C.Base { + public constructor DerivedAbstract() + 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 open class Data { + public constructor Data() + 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/cyclicHierarchy/withCompanion/onlyInterfaces.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.kt new file mode 100644 index 00000000000..e2e3643a16c --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.kt @@ -0,0 +1,17 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +open class Container { + // Note that here we also have errors and diagnostics, even though there are actually no loops. + // (this is case because we can't know if there are any loops without resolving, but resolving + // itself provokes loops) + + interface Base { + open fun m() {} + } + + interface DerivedAbstract : Base + + companion object : DerivedAbstract { + override fun m() {} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.txt new file mode 100644 index 00000000000..5ed1a8282b3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.txt @@ -0,0 +1,29 @@ +package + +public open class Container { + public constructor Container() + 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 interface Base { + 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 fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public companion object Companion : Container.DerivedAbstract { + 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 fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public interface DerivedAbstract { + 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/cyclicHierarchy/withCompanion/typeIsLowEnough.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.kt new file mode 100644 index 00000000000..39572b1c951 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.kt @@ -0,0 +1,20 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +abstract class DerivedAbstract : C.Base() { + override abstract fun m() +} + +public class C { + class Data + + open class Base () { + open fun m() {} + } + + // Note that Data is resolved succesfully here because we don't step on error-scope + val data: Data = Data() + + companion object : DerivedAbstract() { + override fun m() {} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.txt new file mode 100644 index 00000000000..40a85227d41 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.txt @@ -0,0 +1,40 @@ +package + +public final class C { + public constructor C() + public final val data: C.Data + 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 open class Base { + public constructor Base() + 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 fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public companion object Companion : DerivedAbstract { + 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*/ fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class Data { + public constructor Data() + 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 abstract class DerivedAbstract : C.Base { + public constructor DerivedAbstract() + 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 abstract override /*1*/ fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.kt new file mode 100644 index 00000000000..4b5a114b8e3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.kt @@ -0,0 +1,19 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +interface SomeIrrelevantInterface + +// note that C.Base() supertype will be resolved in normal scope +abstract class DerivedAbstract : C.Base() + +class Data + +public class C { + + val data: Data = Data() + + // Note that any supertype of Base will be resolved in error-scope, even if it absolutely irrelevant + // to the types in cycle. + open class Base() : SomeIrrelevantInterface + + companion object : DerivedAbstract() +} diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.txt new file mode 100644 index 00000000000..6152bd8f01f --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.txt @@ -0,0 +1,43 @@ +package + +public final class C { + public constructor C() + public final val data: Data + 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 open class Base { + public constructor Base() + 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 : DerivedAbstract { + 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 + } +} + +public final class Data { + public constructor Data() + 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 abstract class DerivedAbstract : C.Base { + public constructor DerivedAbstract() + 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 interface SomeIrrelevantInterface { + 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/cyclicHierarchy/withCompanion/withMembers.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.kt new file mode 100644 index 00000000000..3922425564d --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.kt @@ -0,0 +1,63 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +object WithFunctionInBase { + abstract class DerivedAbstract : C.Base() + + class Data + + public class C { + // error-scope + val data: Data = Data() + + open class Base() { + // error-scope + fun foo(): Int = 42 + } + + companion object : DerivedAbstract() + } +} + +object WithPropertyInBase { + // This case is very similar to previous one, but there are subtle differences from POV of implementation + + abstract class DerivedAbstract : C.Base() + + class Data + + public class C { + + open class Base() { + // error-scope + val foo: Int = 42 + } + + // error-scope + val data: Data = Data() + + companion object : DerivedAbstract() + } +} + +object WithPropertyInBaseDifferentOrder { + // This case is very similar to previous one, but there are subtle differences from POV of implementation + // Note how position of property in file affected order of resolve, and, consequently, its results and + // diagnostics. + + abstract class DerivedAbstract : C.Base() + + class Data + + public class C { + // Now it is succesfully resolved (vs. ErrorType like in the previous case) + val data: Data = Data() + + open class Base() { + // Now it is unresolved (vs. ErrorType like in the previous case) + val foo: Int = 42 + + } + + companion object : DerivedAbstract() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.txt new file mode 100644 index 00000000000..5be70fc4d9c --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.txt @@ -0,0 +1,139 @@ +package + +public object WithFunctionInBase { + private constructor WithFunctionInBase() + 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 final class C { + public constructor C() + public final val data: [ERROR : ] + 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 open class Base { + public constructor Base() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(): [ERROR : ] + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public companion object Companion : WithFunctionInBase.DerivedAbstract { + private constructor Companion() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun foo(): [ERROR : ] + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public final class Data { + public constructor Data() + 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 abstract class DerivedAbstract : WithFunctionInBase.C.Base { + public constructor DerivedAbstract() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun foo(): [ERROR : ] + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public object WithPropertyInBase { + private constructor WithPropertyInBase() + 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 final class C { + public constructor C() + public final val data: [ERROR : ] + 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 open class Base { + public constructor Base() + public final val foo: [ERROR : ] + 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 : WithPropertyInBase.DerivedAbstract { + private constructor Companion() + public final override /*1*/ /*fake_override*/ val foo: [ERROR : ] + 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 final class Data { + public constructor Data() + 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 abstract class DerivedAbstract : WithPropertyInBase.C.Base { + public constructor DerivedAbstract() + public final override /*1*/ /*fake_override*/ val foo: [ERROR : ] + 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 WithPropertyInBaseDifferentOrder { + private constructor WithPropertyInBaseDifferentOrder() + 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 final class C { + public constructor C() + public final val data: WithPropertyInBaseDifferentOrder.Data + 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 open class Base { + public constructor Base() + public final val foo: [ERROR : Int] + 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 : WithPropertyInBaseDifferentOrder.DerivedAbstract { + private constructor Companion() + public final override /*1*/ /*fake_override*/ val foo: [ERROR : Int] + 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 final class Data { + public constructor Data() + 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 abstract class DerivedAbstract : WithPropertyInBaseDifferentOrder.C.Base { + public constructor DerivedAbstract() + public final override /*1*/ /*fake_override*/ val foo: [ERROR : Int] + 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/cyclicHierarchy/withCompanion/withoutTypeReference.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.kt new file mode 100644 index 00000000000..97dd7b8dec0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.kt @@ -0,0 +1,17 @@ +// see https://youtrack.jetbrains.com/issue/KT-21515 + +abstract class DerivedAbstract : C.Base() + +class Data + +open class C { + open class Base { + open fun m() {} + } + + val field = Data() + + companion object : DerivedAbstract() { + override fun m() {} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.txt b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.txt new file mode 100644 index 00000000000..0cc501588da --- /dev/null +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.txt @@ -0,0 +1,40 @@ +package + +public open class C { + public constructor C() + public final val field: Data + 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 open class Base { + public constructor Base() + 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 fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public companion object Companion : DerivedAbstract { + 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*/ fun m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class Data { + public constructor Data() + 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 abstract class DerivedAbstract : C.Base { + public constructor DerivedAbstract() + 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 m(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.kt b/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.kt index 2c7492d2812..1702c497333 100644 --- a/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.kt +++ b/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.kt @@ -1,11 +1,11 @@ class Test { @`InnerAnnotation` @InnerAnnotation - companion object : StaticClass(), InnerClass() { + companion object : StaticClass(), InnerClass() { } annotation class InnerAnnotation - open class StaticClass + open class StaticClass - open inner class InnerClass + open inner class InnerClass } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt b/compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt index cf5fb902ea0..42df6333fee 100644 --- a/compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt +++ b/compiler/testData/diagnostics/tests/inner/innerErrorForClassObjects.kt @@ -5,7 +5,7 @@ class TestSome

{ } class Test { - companion object : InnerClass() { + companion object : InnerClass() { val a = object: InnerClass() { } @@ -22,5 +22,5 @@ class Test { val inClass = 12 fun foo() {} - open inner class InnerClass + open inner class InnerClass } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 0c706440ecd..10f9f25e199 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4854,6 +4854,57 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/twoClassesWithNestedCycle.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class WithCompanion extends AbstractDiagnosticsTest { + public void testAllFilesPresentInWithCompanion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("everythingInOneScope.kt") + public void testEverythingInOneScope() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.kt"); + doTest(fileName); + } + + @TestMetadata("noMembers.kt") + public void testNoMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.kt"); + doTest(fileName); + } + + @TestMetadata("onlyInterfaces.kt") + public void testOnlyInterfaces() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.kt"); + doTest(fileName); + } + + @TestMetadata("typeIsLowEnough.kt") + public void testTypeIsLowEnough() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.kt"); + doTest(fileName); + } + + @TestMetadata("withIrrelevantInterface.kt") + public void testWithIrrelevantInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.kt"); + doTest(fileName); + } + + @TestMetadata("withMembers.kt") + public void testWithMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.kt"); + doTest(fileName); + } + + @TestMetadata("withoutTypeReference.kt") + public void testWithoutTypeReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/dataClasses") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index a42862f317b..0df2fd13e20 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -4854,6 +4854,57 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/twoClassesWithNestedCycle.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class WithCompanion extends AbstractDiagnosticsUsingJavacTest { + public void testAllFilesPresentInWithCompanion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("everythingInOneScope.kt") + public void testEverythingInOneScope() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/everythingInOneScope.kt"); + doTest(fileName); + } + + @TestMetadata("noMembers.kt") + public void testNoMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/noMembers.kt"); + doTest(fileName); + } + + @TestMetadata("onlyInterfaces.kt") + public void testOnlyInterfaces() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/onlyInterfaces.kt"); + doTest(fileName); + } + + @TestMetadata("typeIsLowEnough.kt") + public void testTypeIsLowEnough() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/typeIsLowEnough.kt"); + doTest(fileName); + } + + @TestMetadata("withIrrelevantInterface.kt") + public void testWithIrrelevantInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withIrrelevantInterface.kt"); + doTest(fileName); + } + + @TestMetadata("withMembers.kt") + public void testWithMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withMembers.kt"); + doTest(fileName); + } + + @TestMetadata("withoutTypeReference.kt") + public void testWithoutTypeReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy/withCompanion/withoutTypeReference.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/dataClasses") diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java index 1935bfd3100..4d675d805e3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.storage.StorageManager; +import org.jetbrains.kotlin.utils.SmartList; import java.util.Collection; import java.util.Collections; @@ -124,17 +125,39 @@ public abstract class AbstractClassTypeConstructor extends AbstractTypeConstruct @NotNull @Override - protected Collection getAdditionalNeighboursInSupertypeGraph() { + protected Collection getAdditionalNeighboursInSupertypeGraph(boolean useCompanions) { + DeclarationDescriptor containingDeclaration = getDeclarationDescriptor().getContainingDeclaration(); + + if (!(containingDeclaration instanceof ClassDescriptor)) { + return Collections.emptyList(); + } + + Collection additionalNeighbours = new SmartList(); + // We suppose that there is an edge from C to A in graph when disconnecting loops in supertypes, // because such cyclic declarations should be prohibited (see p.10.2.1 of Kotlin spec) // class A : B { // static class C {} // } // class B : A.C {} - DeclarationDescriptor containingDeclaration = getDeclarationDescriptor().getContainingDeclaration(); - if (containingDeclaration instanceof ClassDescriptor) { - return Collections.singleton(((ClassDescriptor) containingDeclaration).getDefaultType()); + ClassDescriptor containingClassDescriptor = (ClassDescriptor) containingDeclaration; + additionalNeighbours.add(containingClassDescriptor.getDefaultType()); + + // Also we add edge from host-class to companion object. Together with previous edges + // (from nesteds to containing class), they can create visibility loops like in the + // following example: + // + // class ContainingClass { + // open class Nested {} // to create scope for resolving Nested, we have to resolve CO header + // companion object : Nested() {} // to resolve CO header, we have to resolve Nested + // } + // + // Relates to KT-21515 + ClassDescriptor companion = containingClassDescriptor.getCompanionObjectDescriptor(); + if (useCompanions && companion != null) { + additionalNeighbours.add(companion.getDefaultType()); } - return Collections.emptyList(); + + return additionalNeighbours; } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt index 62e37b49c00..9cf888532d7 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt @@ -41,27 +41,41 @@ abstract class AbstractTypeConstructor(storageManager: StorageManager) : TypeCon var resultWithoutCycles = supertypeLoopChecker.findLoopsInSupertypesAndDisconnect( this, supertypes.allSupertypes, - { it.computeNeighbours() }, - { reportSupertypeLoopError(it) }) + { it.computeNeighbours(useCompanions = false) }, + { reportSupertypeLoopError(it) } + ) if (resultWithoutCycles.isEmpty()) { resultWithoutCycles = defaultSupertypeIfEmpty()?.let { listOf(it) }.orEmpty() } + // We also check if there are a loop with additional edges going from owner of companion to + // the companion itself. + // Note that we use already disconnected types to not report two diagnostics on cyclic supertypes + supertypeLoopChecker.findLoopsInSupertypesAndDisconnect( + this, resultWithoutCycles, + { it.computeNeighbours(useCompanions = true) }, + { reportScopesLoopError(it) } + ) + supertypes.supertypesWithoutCycles = (resultWithoutCycles as? List) ?: resultWithoutCycles.toList() }) - private fun TypeConstructor.computeNeighbours(): Collection = + private fun TypeConstructor.computeNeighbours(useCompanions: Boolean): Collection = (this as? AbstractTypeConstructor)?.let { abstractClassifierDescriptor -> abstractClassifierDescriptor.supertypes().allSupertypes + - abstractClassifierDescriptor.getAdditionalNeighboursInSupertypeGraph() + abstractClassifierDescriptor.getAdditionalNeighboursInSupertypeGraph(useCompanions) } ?: supertypes protected abstract fun computeSupertypes(): Collection protected abstract val supertypeLoopChecker: SupertypeLoopChecker protected open fun reportSupertypeLoopError(type: KotlinType) {} - protected open fun getAdditionalNeighboursInSupertypeGraph(): Collection = emptyList() + + // TODO: overload in AbstractTypeParameterDescriptor? + protected open fun reportScopesLoopError(type: KotlinType) {} + + protected open fun getAdditionalNeighboursInSupertypeGraph(useCompanions: Boolean): Collection = emptyList() protected open fun defaultSupertypeIfEmpty(): KotlinType? = null }