[kotlin] Remove custom seq in favor of stdlib sequence

I found a bug in TransformingIterator: hasNext isn't side-effect-free,
and because of that calling hasNext() twice skips two elements.

But then, I found that in comment in review IJ-MR-107533,
where the custom seq was implemented, it was said that
this seq is a temporary solution.

So, let's remove it then.

^KTIJ-32260

GitOrigin-RevId: 0679789333698ec3a994ab05bd9f62fb75c2bc49
This commit is contained in:
Roman Efremov
2024-11-26 11:42:26 +00:00
committed by intellij-monorepo-bot
parent 4653aff32e
commit 8b15cc6700
4 changed files with 34 additions and 111 deletions
@@ -45,17 +45,17 @@ private annotation class ModuleInfoDsl
@ModuleInfoDsl
@K1ModeProjectStructureApi
fun SeqScope<Result<IdeaModuleInfo>>.register(moduleInfo: IdeaModuleInfo) = yield { Result.success(moduleInfo) }
suspend fun SequenceScope<Result<IdeaModuleInfo>>.register(moduleInfo: IdeaModuleInfo): Unit = yield(Result.success(moduleInfo))
@ModuleInfoDsl
@K1ModeProjectStructureApi
fun SeqScope<Result<IdeaModuleInfo>>.register(block: () -> IdeaModuleInfo?) = yield {
block()?.let(Result.Companion::success)
suspend fun SequenceScope<Result<IdeaModuleInfo>>.register(block: () -> IdeaModuleInfo?) {
block()?.let { register(it) }
}
@ModuleInfoDsl
@K1ModeProjectStructureApi
fun SeqScope<Result<IdeaModuleInfo>>.reportError(error: Throwable) = yield { Result.failure(error) }
suspend fun SequenceScope<Result<IdeaModuleInfo>>.reportError(error: Throwable): Unit = yield(Result.failure(error))
@K1ModeProjectStructureApi
interface ModuleInfoProviderExtension {
@@ -64,15 +64,15 @@ interface ModuleInfoProviderExtension {
ExtensionPointName("org.jetbrains.kotlin.idea.base.projectStructure.moduleInfoProviderExtension")
}
fun SeqScope<Result<IdeaModuleInfo>>.collectByElement(element: PsiElement, file: PsiFile, virtualFile: VirtualFile)
fun SeqScope<Result<IdeaModuleInfo>>.collectByFile(
suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByElement(element: PsiElement, file: PsiFile, virtualFile: VirtualFile)
suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByFile(
project: Project,
virtualFile: VirtualFile,
isLibrarySource: Boolean,
config: ModuleInfoProvider.Configuration,
)
fun SeqScope<Module>.findContainingModules(project: Project, virtualFile: VirtualFile)
suspend fun SequenceScope<Module>.findContainingModules(project: Project, virtualFile: VirtualFile)
}
@Service(Service.Level.PROJECT)
@@ -110,7 +110,7 @@ class ModuleInfoProvider(private val project: Project) {
private val libraryInfoCache by lazy { LibraryInfoCache.getInstance(project) }
fun collect(element: PsiElement, config: Configuration = Configuration.Default): Sequence<Result<IdeaModuleInfo>> {
return seq {
return sequence {
collectByElement(element, config)
}
}
@@ -120,12 +120,12 @@ class ModuleInfoProvider(private val project: Project) {
isLibrarySource: Boolean = false,
config: Configuration = Configuration.Default,
): Sequence<Result<IdeaModuleInfo>> {
return seq {
return sequence {
collectByFile(virtualFile, isLibrarySource, config)
}
}
private fun SeqScope<Result<IdeaModuleInfo>>.collectByElement(element: PsiElement, config: Configuration) {
private suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByElement(element: PsiElement, config: Configuration) {
PsiUtilCore.ensureValid(element)
val containingFile = element.containingFile
@@ -229,7 +229,7 @@ class ModuleInfoProvider(private val project: Project) {
return if (config.createSourceLibraryInfoForLibraryBinaries) isCompiled else !isCompiled
}
private fun SeqScope<Result<IdeaModuleInfo>>.collectByLightElement(element: KtLightElement<*, *>, config: Configuration) {
private suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByLightElement(element: KtLightElement<*, *>, config: Configuration) {
if (element.getNonStrictParentOfType<KtLightClassForDecompiledDeclaration>() != null) {
val virtualFile = element.containingFile.virtualFile ?: error("Decompiled class should be build from physical file")
collectByFile(virtualFile, isLibrarySource = false, config)
@@ -248,7 +248,7 @@ class ModuleInfoProvider(private val project: Project) {
}
}
private fun SeqScope<Result<IdeaModuleInfo>>.collectByFile(
private suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByFile(
virtualFile: VirtualFile,
isLibrarySource: Boolean,
config: Configuration,
@@ -263,14 +263,12 @@ class ModuleInfoProvider(private val project: Project) {
val visited = hashSetOf<IdeaModuleInfo>()
val collectionRequest = VirtualFileCollectionRequest(virtualFile, isLibrarySource, config, visited, project)
yield {
// Several libraries may include the same JAR files.
// Below, we use an index for getting order entries for a file, but entries come in an arbitrary order.
// So if we are already inside a library, we scan it first.
// Several libraries may include the same JAR files.
// Below, we use an index for getting order entries for a file, but entries come in an arbitrary order.
// So if we are already inside a library, we scan it first.
val contextualModuleResult = contextByContextualBinaryModule(collectionRequest)
contextualModuleResult?.let(Result.Companion::success)
}
val contextualModuleResult = contextByContextualBinaryModule(collectionRequest)
contextualModuleResult?.let { yield(Result.success(it)) }
yieldAll(object : Iterable<Result<IdeaModuleInfo>> {
override fun iterator(): Iterator<Result<IdeaModuleInfo>> {
@@ -322,16 +320,16 @@ class ModuleInfoProvider(private val project: Project) {
}
}
private fun SeqScope<Result<IdeaModuleInfo>>.collectSourceRelatedByFile(virtualFile: VirtualFile, config: Configuration) {
private suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectSourceRelatedByFile(virtualFile: VirtualFile, config: Configuration) {
yieldAll(object : Iterable<Result<IdeaModuleInfo>> {
override fun iterator(): Iterator<Result<IdeaModuleInfo>> {
val modules = seq {
val modules = sequence {
withCallExtensions(
config = config,
extensionBlock = { findContainingModules(project, virtualFile) },
) {
runReadAction { fileIndex.getModuleForFile(virtualFile) }?.let { module ->
yield { module }
yield(module)
}
}
}
@@ -433,7 +431,7 @@ class ModuleInfoProvider(private val project: Project) {
return service.hasDependentModule(this, contextualModuleInfo.module)
}
private fun SeqScope<Result<IdeaModuleInfo>>.collectByUserData(container: UserDataModuleContainer) {
private suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByUserData(container: UserDataModuleContainer) {
register {
val sourceRootType = container.customSourceRootType
if (sourceRootType == null) return@register null
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.idea.base.projectStructure.ModuleInfoProviderExtensi
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.IdeaModuleInfo
import org.jetbrains.kotlin.idea.base.projectStructure.register
import org.jetbrains.kotlin.idea.base.util.SeqScope
/**
* An extension to provide the correct [IdeaModuleInfo] for synthetic forward declaration files.
@@ -21,7 +20,7 @@ import org.jetbrains.kotlin.idea.base.util.SeqScope
* Results are tracked per-project by the [KotlinForwardDeclarationsFileOwnerTracker].
*/
internal class KotlinForwardDeclarationsModuleInfoProviderExtension : ModuleInfoProviderExtension {
override fun SeqScope<Result<IdeaModuleInfo>>.collectByElement(
override suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByElement(
element: PsiElement,
file: PsiFile,
virtualFile: VirtualFile
@@ -29,7 +28,7 @@ internal class KotlinForwardDeclarationsModuleInfoProviderExtension : ModuleInfo
registerByVirtualFile(file.project, virtualFile)
}
override fun SeqScope<Result<IdeaModuleInfo>>.collectByFile(
override suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByFile(
project: Project,
virtualFile: VirtualFile,
isLibrarySource: Boolean,
@@ -39,9 +38,9 @@ internal class KotlinForwardDeclarationsModuleInfoProviderExtension : ModuleInfo
}
// Kotlin/Native forward declarations can't belong to a module
override fun SeqScope<Module>.findContainingModules(project: Project, virtualFile: VirtualFile) {}
override suspend fun SequenceScope<Module>.findContainingModules(project: Project, virtualFile: VirtualFile) {}
private fun SeqScope<Result<IdeaModuleInfo>>.registerByVirtualFile(project: Project, virtualFile: VirtualFile) {
private suspend fun SequenceScope<Result<IdeaModuleInfo>>.registerByVirtualFile(project: Project, virtualFile: VirtualFile) {
if (!virtualFile.isValid) return
KotlinForwardDeclarationsFileOwnerTracker.getInstance(project).getFileOwner(virtualFile)?.let { kaModule ->
register(kaModule.moduleInfo)
@@ -1,39 +1,6 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.base.util
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
fun <T> seq(block: SeqScope<T>.() -> Unit): Sequence<T> = Sequence {
val secScope = DefaultSeqScope<T>()
block(secScope)
val lazySequence = secScope.values
SeqIterator(lazySequence)
}
private class DefaultSeqScope<T> : SeqScope<T>() {
val values: MutableList<Iterable<T>> = mutableListOf()
override fun yield(value: () -> T?) {
values.add(object : Iterable<T> {
override fun iterator(): Iterator<T> = object : TransformingIterator<T>() {
private var provider: (() -> T?)? = value
override fun calculateHasNext(): Boolean = provider != null
override fun calculateNext(): T? {
val p = provider ?: throw NoSuchElementException()
provider = null
return p()
}
}
})
}
override fun yieldAll(value: Iterable<T>) {
values.add(value)
}
}
abstract class TransformingIterator<T> : Iterator<T> {
protected var next: T? = null
@@ -75,40 +42,3 @@ class MappingIterator<K, T>(
override fun calculateNext(): T? = mapping(iterator.next())
}
private class SeqIterator<T>(providers: List<Iterable<T?>>) : TransformingIterator<T>() {
private var providersIterator: Iterator<Iterable<T?>>? = providers.iterator()
private var iterator: Iterator<T?>? = null
override fun calculateHasNext(): Boolean {
while (providersIterator != null) {
if (iterator?.hasNext() == true) return true
val providersIt = providersIterator
if (providersIt?.hasNext() != true) {
return false
}
val next = providersIt.next()
val nextIterator = next.iterator()
iterator = nextIterator
if (nextIterator.hasNext()) return true
}
return false
}
override fun calculateNext(): T? = iterator?.next()
override fun hasNext(): Boolean {
val hasNext = super.hasNext()
if (!hasNext) {
iterator = null
providersIterator = null
}
return hasNext
}
}
@ApiStatus.Internal
abstract class SeqScope<in T> internal constructor() {
abstract fun yield(value: () -> T?)
abstract fun yieldAll(value: Iterable<T>)
}
@@ -21,16 +21,16 @@ import org.jetbrains.kotlin.idea.base.scripting.projectStructure.ScriptDependenc
import org.jetbrains.kotlin.idea.base.scripting.projectStructure.ScriptModuleInfo
import org.jetbrains.kotlin.idea.base.scripting.projectStructure.scriptLibraryDependencies
import org.jetbrains.kotlin.idea.base.util.K1ModeProjectStructureApi
import org.jetbrains.kotlin.idea.base.util.SeqScope
import org.jetbrains.kotlin.idea.core.script.ScriptDependencyAware
import org.jetbrains.kotlin.idea.core.script.ScriptRelatedModuleNameFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.utils.yieldIfNotNull
@OptIn(K1ModeProjectStructureApi::class)
internal class ScriptingModuleInfoProviderExtension : ModuleInfoProviderExtension {
override fun SeqScope<Result<IdeaModuleInfo>>.collectByElement(
override suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByElement(
element: PsiElement,
file: PsiFile,
virtualFile: VirtualFile
@@ -46,7 +46,7 @@ internal class ScriptingModuleInfoProviderExtension : ModuleInfoProviderExtensio
}
}
override fun SeqScope<Result<IdeaModuleInfo>>.collectByFile(
override suspend fun SequenceScope<Result<IdeaModuleInfo>>.collectByFile(
project: Project,
virtualFile: VirtualFile,
isLibrarySource: Boolean,
@@ -57,7 +57,7 @@ internal class ScriptingModuleInfoProviderExtension : ModuleInfoProviderExtensio
if (isBinary) {
if (KotlinPluginModeProvider.isK2Mode()) {
val scriptFile = (config.contextualModuleInfo as? ScriptModuleInfo)?.scriptFile
scriptFile?.scriptLibraryDependencies(project)?.filter { virtualFile in it.contentScope }?.forEach(::register)
scriptFile?.scriptLibraryDependencies(project)?.filter { virtualFile in it.contentScope }?.forEach { register(it) }
} else if (ScriptDependencyAware.getInstance(project).getAllScriptsDependenciesClassFilesScope().contains(virtualFile)) {
if (isLibrarySource) {
register(ScriptDependenciesSourceInfo.ForProject(project))
@@ -92,15 +92,11 @@ internal class ScriptingModuleInfoProviderExtension : ModuleInfoProviderExtensio
}
}
override fun SeqScope<Module>.findContainingModules(project: Project, virtualFile: VirtualFile) {
yield {
if (ScratchFileService.getInstance().getRootType(virtualFile) is ScratchRootType) {
ScriptRelatedModuleNameFile[project, virtualFile]?.let { scratchModuleName ->
val moduleManager = ModuleManager.getInstance(project)
moduleManager.findModuleByName(scratchModuleName)
}
} else {
null
override suspend fun SequenceScope<Module>.findContainingModules(project: Project, virtualFile: VirtualFile) {
if (ScratchFileService.getInstance().getRootType(virtualFile) is ScratchRootType) {
ScriptRelatedModuleNameFile[project, virtualFile]?.let { scratchModuleName ->
val moduleManager = ModuleManager.getInstance(project)
yieldIfNotNull(moduleManager.findModuleByName(scratchModuleName))
}
}
}