874267b79d
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.
63 lines
1.9 KiB
Kotlin
Vendored
63 lines
1.9 KiB
Kotlin
Vendored
// 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()
|
|
}
|
|
} |