Report cyclic scopes properly
This commit introduces proper handling of recursion in scopes, which
could occur when some of companion object supertypes are members of
that companion owner:
```
class Container {
open class Base
companion object : Base()
}
```
To resolve `Base`, we have to build member scope for `Container`.
In the member scope of `Container`, we see all classifiers from
companion and his supertypes
So, we have to resolve companion objects supertype, which happens to be
`Base` again - therefore, we encounter recursion here.
Previously, we created `ThrowingLexicalScope` for such recursive calls,
but didn't checked for loop explicitly, which lead to a wide variety of
bugs (see https://jetbrains.quip.com/dc5aABhZoaQY and KT-10532).
To report such cyclic declarations properly, we first change
`ThrowingLexicalScope` to `ErrorLexicalScope` -- the main difference is
that latter doesn't throws ISE when someone tries to resolve type in it,
allowing us to report error instead of crashing with exception.
Then, we add additional fake edge in supertypes graph (from
host-class to companion object) which allows us to piggyback on existing
supertypes loops detection mechanism, and report such cycles for user.
This commit is contained in:
@@ -262,6 +262,7 @@ public interface Errors {
|
||||
DiagnosticFactory0.create(ERROR, VARIANCE_IN_PROJECTION);
|
||||
|
||||
DiagnosticFactory0<PsiElement> CYCLIC_INHERITANCE_HIERARCHY = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> CYCLIC_SCOPES_WITH_COMPANION = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
DiagnosticFactory0<KtSuperTypeEntry> SUPERTYPE_NOT_INITIALIZED = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
+2
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-9
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -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,
|
||||
|
||||
@@ -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<ImportingScope>, 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("<FAKE PARENT FOR ERROR LEXICAL SCOPE>")
|
||||
}
|
||||
|
||||
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<VariableDescriptor> = emptySet()
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<VariableDescriptor> =
|
||||
throw IllegalStateException()
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptySet()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> =
|
||||
throw IllegalStateException()
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> = emptySet()
|
||||
}
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> =
|
||||
throw IllegalStateException()
|
||||
override fun printStructure(p: Printer) {
|
||||
p.print("<ERROR_SCOPE>")
|
||||
}
|
||||
|
||||
override val ownerDescriptor: DeclarationDescriptor = ErrorUtils.createErrorClass("<ERROR CLASS FOR ERROR SCOPE>")
|
||||
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<VariableDescriptor> = emptySet()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptySet()
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> = emptySet()
|
||||
}
|
||||
|
||||
+14
@@ -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 <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : <!UNRESOLVED_REFERENCE!>Base<!>()
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract() {
|
||||
<!NOTHING_TO_OVERRIDE!>override<!> fun m() {}
|
||||
}
|
||||
}
|
||||
+31
@@ -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
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// see https://youtrack.jetbrains.com/issue/KT-21515
|
||||
|
||||
abstract class <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : C.Base() {
|
||||
open class Data
|
||||
}
|
||||
|
||||
public class C {
|
||||
|
||||
open class <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!> ()
|
||||
|
||||
class Foo : Data()
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract()
|
||||
}
|
||||
+43
@@ -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
|
||||
}
|
||||
}
|
||||
+17
@@ -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 <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : <!UNRESOLVED_REFERENCE!>Base<!>
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract {
|
||||
<!NOTHING_TO_OVERRIDE!>override<!> fun m() {}
|
||||
}
|
||||
}
|
||||
+29
@@ -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
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// see https://youtrack.jetbrains.com/issue/KT-21515
|
||||
|
||||
abstract class <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : C.Base() {
|
||||
override abstract fun m()
|
||||
}
|
||||
|
||||
public class C {
|
||||
class Data
|
||||
|
||||
open class <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!> () {
|
||||
open fun m() {}
|
||||
}
|
||||
|
||||
// Note that Data is resolved succesfully here because we don't step on error-scope
|
||||
val data: Data = Data()
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract() {
|
||||
override fun m() {}
|
||||
}
|
||||
}
|
||||
+40
@@ -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
|
||||
}
|
||||
Vendored
+19
@@ -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 <!CYCLIC_SCOPES_WITH_COMPANION!>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 <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!>() : <!UNRESOLVED_REFERENCE!>SomeIrrelevantInterface<!>
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract()
|
||||
}
|
||||
Vendored
+43
@@ -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
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// see https://youtrack.jetbrains.com/issue/KT-21515
|
||||
|
||||
object WithFunctionInBase {
|
||||
abstract class <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : C.Base()
|
||||
|
||||
class Data
|
||||
|
||||
public class C {
|
||||
// error-scope
|
||||
val data: <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>Data<!> = Data()
|
||||
|
||||
open class <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!>() {
|
||||
// error-scope
|
||||
fun foo(): <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>Int<!> = 42
|
||||
}
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract()
|
||||
}
|
||||
}
|
||||
|
||||
object WithPropertyInBase {
|
||||
// This case is very similar to previous one, but there are subtle differences from POV of implementation
|
||||
|
||||
abstract class <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : C.Base()
|
||||
|
||||
class Data
|
||||
|
||||
public class C {
|
||||
|
||||
open class <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!>() {
|
||||
// error-scope
|
||||
val foo: <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>Int<!> = 42
|
||||
}
|
||||
|
||||
// error-scope
|
||||
val data: <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>Data<!> = Data()
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_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 <!CYCLIC_SCOPES_WITH_COMPANION!>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 <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!>() {
|
||||
// Now it is unresolved (vs. ErrorType like in the previous case)
|
||||
val foo: <!UNRESOLVED_REFERENCE!>Int<!> = 42
|
||||
|
||||
}
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract()
|
||||
}
|
||||
}
|
||||
+139
@@ -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 : <ERROR CLASS: 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 final fun foo(): [ERROR : <ERROR CLASS: Int>]
|
||||
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 : <ERROR CLASS: Int>]
|
||||
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 : <ERROR CLASS: Int>]
|
||||
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 : <ERROR CLASS: 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 : <ERROR CLASS: 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 : WithPropertyInBase.DerivedAbstract {
|
||||
private constructor Companion()
|
||||
public final override /*1*/ /*fake_override*/ val foo: [ERROR : <ERROR CLASS: 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 : WithPropertyInBase.C.Base {
|
||||
public constructor DerivedAbstract()
|
||||
public final override /*1*/ /*fake_override*/ val foo: [ERROR : <ERROR CLASS: 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 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
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// see https://youtrack.jetbrains.com/issue/KT-21515
|
||||
|
||||
abstract class <!CYCLIC_SCOPES_WITH_COMPANION!>DerivedAbstract<!> : C.Base()
|
||||
|
||||
class Data
|
||||
|
||||
open class C {
|
||||
open class <!CYCLIC_SCOPES_WITH_COMPANION!>Base<!> {
|
||||
open fun m() {}
|
||||
}
|
||||
|
||||
val field = Data()
|
||||
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : DerivedAbstract() {
|
||||
override fun m() {}
|
||||
}
|
||||
}
|
||||
+40
@@ -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
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
class Test {
|
||||
@`InnerAnnotation` <!REPEATED_ANNOTATION!>@InnerAnnotation<!>
|
||||
companion object : StaticClass(), <!UNRESOLVED_REFERENCE, MANY_CLASSES_IN_SUPERTYPE_LIST, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>InnerClass<!>() {
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION, CYCLIC_SCOPES_WITH_COMPANION!>object<!> : StaticClass(), <!UNRESOLVED_REFERENCE, MANY_CLASSES_IN_SUPERTYPE_LIST, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>InnerClass<!>() {
|
||||
|
||||
}
|
||||
|
||||
annotation class InnerAnnotation
|
||||
open class StaticClass
|
||||
open class <!CYCLIC_SCOPES_WITH_COMPANION!>StaticClass<!>
|
||||
|
||||
open inner class InnerClass
|
||||
open inner class <!CYCLIC_SCOPES_WITH_COMPANION!>InnerClass<!>
|
||||
}
|
||||
@@ -5,7 +5,7 @@ class TestSome<P> {
|
||||
}
|
||||
|
||||
class Test {
|
||||
companion object : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>InnerClass<!>() {
|
||||
companion <!CYCLIC_SCOPES_WITH_COMPANION!>object<!> : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>InnerClass<!>() {
|
||||
val a = object: <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>InnerClass<!>() {
|
||||
}
|
||||
|
||||
@@ -22,5 +22,5 @@ class Test {
|
||||
val inClass = 12
|
||||
fun foo() {}
|
||||
|
||||
open inner class InnerClass
|
||||
open inner class <!CYCLIC_SCOPES_WITH_COMPANION!>InnerClass<!>
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
+51
@@ -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")
|
||||
|
||||
@@ -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<KotlinType> getAdditionalNeighboursInSupertypeGraph() {
|
||||
protected Collection<KotlinType> getAdditionalNeighboursInSupertypeGraph(boolean useCompanions) {
|
||||
DeclarationDescriptor containingDeclaration = getDeclarationDescriptor().getContainingDeclaration();
|
||||
|
||||
if (!(containingDeclaration instanceof ClassDescriptor)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Collection<KotlinType> additionalNeighbours = new SmartList<KotlinType>();
|
||||
|
||||
// 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.<KotlinType>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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KotlinType>) ?: resultWithoutCycles.toList()
|
||||
})
|
||||
|
||||
private fun TypeConstructor.computeNeighbours(): Collection<KotlinType> =
|
||||
private fun TypeConstructor.computeNeighbours(useCompanions: Boolean): Collection<KotlinType> =
|
||||
(this as? AbstractTypeConstructor)?.let {
|
||||
abstractClassifierDescriptor ->
|
||||
abstractClassifierDescriptor.supertypes().allSupertypes +
|
||||
abstractClassifierDescriptor.getAdditionalNeighboursInSupertypeGraph()
|
||||
abstractClassifierDescriptor.getAdditionalNeighboursInSupertypeGraph(useCompanions)
|
||||
} ?: supertypes
|
||||
|
||||
protected abstract fun computeSupertypes(): Collection<KotlinType>
|
||||
protected abstract val supertypeLoopChecker: SupertypeLoopChecker
|
||||
protected open fun reportSupertypeLoopError(type: KotlinType) {}
|
||||
protected open fun getAdditionalNeighboursInSupertypeGraph(): Collection<KotlinType> = emptyList()
|
||||
|
||||
// TODO: overload in AbstractTypeParameterDescriptor?
|
||||
protected open fun reportScopesLoopError(type: KotlinType) {}
|
||||
|
||||
protected open fun getAdditionalNeighboursInSupertypeGraph(useCompanions: Boolean): Collection<KotlinType> = emptyList()
|
||||
protected open fun defaultSupertypeIfEmpty(): KotlinType? = null
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user