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:
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user