From 627cbc920b4b982e5aaea3bc7cd9ac3d0e751e76 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Fri, 9 Aug 2024 23:39:26 +0300 Subject: [PATCH] remove old code, performance improvements --- .../ide/annotator/MvSyntaxErrorAnnotator.kt | 2 + .../inspections/MvUnusedImportInspection.kt | 1 - .../ide/inspections/imports/BasePathType.kt | 61 +++++---- .../ide/inspections/imports/ImportAnalyzer.kt | 36 +++--- .../move/ide/inspections/imports/UseItem.kt | 13 +- .../org/move/ide/utils/imports/ImportUtils.kt | 5 +- .../org/move/lang/core/psi/NamedItemScope.kt | 117 +----------------- .../lang/core/psi/ext/MvVisibilityOwner.kt | 1 - .../org/move/lang/core/psi/ext/PsiElement.kt | 5 + .../org/move/lang/core/resolve/Processors.kt | 8 +- .../core/resolve2/LexicalDeclarations2.kt | 12 +- .../move/lang/core/resolve2/Visibility2.kt | 27 ++-- .../core/resolve2/ref/Path2ReferenceImpl.kt | 9 +- .../syntaxErrors/compilerV2/IndexExprTest.kt | 8 ++ .../MvUnresolvedReferenceInspectionTest.kt | 13 ++ .../org/move/lang/resolve/ResolveSpecsTest.kt | 22 ++++ 16 files changed, 141 insertions(+), 199 deletions(-) diff --git a/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt index 4c60f5dc5..4db8a9ca3 100644 --- a/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt @@ -64,6 +64,8 @@ class MvSyntaxErrorAnnotator: MvAnnotatorBase() { } private fun checkIndexExpr(holder: MvAnnotationHolder, indexExpr: MvIndexExpr) { + // always supported in specs + if (indexExpr.isMsl()) return if (!indexExpr.project.moveSettings.enableIndexExpr) { Diagnostic .IndexExprIsNotSupportedInCompilerV1(indexExpr) diff --git a/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt b/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt index fa8d1da7f..114a56e09 100644 --- a/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt +++ b/src/main/kotlin/org/move/ide/inspections/MvUnusedImportInspection.kt @@ -9,7 +9,6 @@ import org.move.ide.inspections.imports.ImportAnalyzer2 class MvUnusedImportInspection: MvLocalInspectionTool() { override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = ImportAnalyzer2(holder) -// override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = ImportAnalyzer(holder) @Suppress("CompanionObjectInExtension") companion object { diff --git a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt index 2f2d2df16..0218a7ede 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/BasePathType.kt @@ -1,7 +1,16 @@ package org.move.ide.inspections.imports +import com.intellij.openapi.util.Key +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValueProvider.Result +import com.intellij.psi.util.PsiModificationTracker import org.move.lang.core.psi.* +import org.move.lang.core.psi.NamedItemScope.* import org.move.lang.core.psi.ext.* +import org.move.utils.cache +import org.move.utils.cacheManager +import org.move.utils.cacheResult // classifies foo of `foo::bar::baz` sealed class BasePathType { @@ -34,42 +43,30 @@ fun MvPath.basePathType(): BasePathType? { return qualifier.referenceName?.let { BasePathType.Module(it) } } -// only Main/Test for now -val MvElement.usageScope: NamedItemScope - get() { - var parentElement = this.parent - while (parentElement != null) { -// if (parentElement is MslOnlyElement) return ItemScope.MAIN - if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { - return NamedItemScope.TEST - } - if (parentElement is MvDocAndAttributeOwner && parentElement.hasVerifyOnlyAttr) { - return NamedItemScope.VERIFY +private val USAGE_SCOPE_KEY: Key> = Key.create("USAGE_SCOPE_KEY") + +class UsageScopeProvider(val scopeElement: MvElement): CachedValueProvider { + override fun compute(): Result { + var scope = MAIN + for (ancestor in scopeElement.ancestorsOfType()) { + // msl items + if (scopeElement is MvSpecCodeBlock || scopeElement is MvItemSpecRef) { + scope = VERIFY + break } - if (parentElement is MvFunction && parentElement.hasTestAttr) { - return NamedItemScope.TEST + // explicit attrs, #[test], #[test_only], #[verify_only] + val attributeScope = ancestor.itemScopeFromAttributes() + if (attributeScope != null) { + scope = attributeScope + break } - parentElement = parentElement.parent } - return NamedItemScope.MAIN + return scopeElement.cacheResult(scope, listOf(PsiModificationTracker.MODIFICATION_COUNT)) } +} -// only Main/Test for now -val MvUseStmt.declaredItemScope: NamedItemScope +val MvElement.usageScope: NamedItemScope get() { - if (this.hasTestOnlyAttr) { - return NamedItemScope.TEST - } - var parentElement = this.parent - while (parentElement != null) { -// if (parentElement is MslOnlyElement) return ItemScope.MAIN - if (parentElement is MvDocAndAttributeOwner && parentElement.hasTestOnlyAttr) { - return NamedItemScope.TEST - } - if (parentElement is MvFunction && parentElement.hasTestAttr) { - return NamedItemScope.TEST - } - parentElement = parentElement.parent - } - return NamedItemScope.MAIN + return project.cacheManager + .cache(this, USAGE_SCOPE_KEY, UsageScopeProvider(this)) } diff --git a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt index 7754a22c4..ea4a0af08 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/ImportAnalyzer.kt @@ -10,9 +10,7 @@ import org.move.stdext.chain class ImportAnalyzer2(val holder: ProblemsHolder): MvVisitor() { override fun visitModule(o: MvModule) = analyzeImportsOwner(o) -// override fun visitModuleBlock(o: MvModuleBlock) = analyzeImportsOwner(o) override fun visitScript(o: MvScript) = analyzeImportsOwner(o) -// override fun visitScriptBlock(o: MvScriptBlock) = analyzeImportsOwner(o) override fun visitModuleSpecBlock(o: MvModuleSpecBlock) = analyzeImportsOwner(o) fun analyzeImportsOwner(importsOwner: MvItemsOwner) { @@ -24,28 +22,36 @@ class ImportAnalyzer2(val holder: ProblemsHolder): MvVisitor() { val allUseItemsHit = mutableSetOf() val rootItemOwnerWithSiblings = rootItemsOwner.itemsOwnerWithSiblings - val paths = rootItemOwnerWithSiblings - .flatMap { it.descendantsOfType() } - .filter { it.basePath() == it } - .filter { it.usageScope == itemScope } - .filter { !it.hasAncestor() } + val allFiles = rootItemOwnerWithSiblings.mapNotNull { it.containingMoveFile }.distinct() + val fileItemOwners = allFiles + // collect every possible MvItemOwner + .flatMap { it.descendantsOfType().flatMap { i -> i.itemsOwnerWithSiblings } } + .distinct() + .associateWith { itemOwner -> + itemOwner.useItems.filter { it.scope == itemScope } + } + + val reachablePaths = + rootItemOwnerWithSiblings + .flatMap { it.descendantsOfType() } + .filter { it.basePath() == it } + .filter { it.usageScope == itemScope } + .filter { !it.hasAncestor() } - for (path in paths) { + for (path in reachablePaths) { val basePathType = path.basePathType() for (itemsOwner in path.ancestorsOfType()) { - val useItems = - itemsOwner.itemsOwnerWithSiblings - .flatMap { it.useItems }.filter { it.scope == itemScope } - + val reachableUseItems = + itemsOwner.itemsOwnerWithSiblings.flatMap { fileItemOwners[it]!! } val useItemHit = when (basePathType) { is BasePathType.Item -> { - useItems.filter { it.type == ITEM } + reachableUseItems.filter { it.type == ITEM } // only hit first encountered to remove duplicates .firstOrNull { it.nameOrAlias == basePathType.itemName } } is BasePathType.Module -> { - useItems.filter { it.type == MODULE || it.type == SELF_MODULE } + reachableUseItems.filter { it.type == MODULE || it.type == SELF_MODULE } // only hit first encountered to remove duplicates .firstOrNull { it.nameOrAlias == basePathType.moduleName } } @@ -63,7 +69,7 @@ class ImportAnalyzer2(val holder: ProblemsHolder): MvVisitor() { // includes self val reachableItemsOwners = rootItemsOwner.descendantsOfTypeOrSelf() for (itemsOwner in reachableItemsOwners) { - val scopeUseStmts = itemsOwner.useStmtList.filter { it.declaredItemScope == itemScope } + val scopeUseStmts = itemsOwner.useStmtList.filter { it.usageScope == itemScope } for (useStmt in scopeUseStmts) { val unusedUseItems = useStmt.useItems.toSet() - allUseItemsHit holder.registerStmtSpeckError2(useStmt, unusedUseItems) diff --git a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt index 4305a93af..7d3f91aa9 100644 --- a/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt +++ b/src/main/kotlin/org/move/ide/inspections/imports/UseItem.kt @@ -21,17 +21,16 @@ data class UseItem( val scope: NamedItemScope ) -val MvItemsOwner.useItems: List - get() = this.useStmtList.flatMap { it.useItems } +val MvItemsOwner.useItems: List get() = this.useStmtList.flatMap { it.useItems } val MvUseStmt.useItems: List get() { val items = mutableListOf() - val stmtItemScope = this.declaredItemScope - this.forEachLeafSpeck { path, useAlias -> - val useSpeck = path.parent as MvUseSpeck - val nameOrAlias = useAlias?.name ?: path.referenceName ?: return@forEachLeafSpeck false - val pathKind = path.pathKind() + val stmtItemScope = this.usageScope + this.forEachLeafSpeck { speckPath, useAlias -> + val useSpeck = speckPath.parent as MvUseSpeck + val nameOrAlias = useAlias?.name ?: speckPath.referenceName ?: return@forEachLeafSpeck false + val pathKind = speckPath.pathKind() when (pathKind) { is PathKind.QualifiedPath.Module -> items.add(UseItem(useSpeck, nameOrAlias, MODULE, stmtItemScope)) diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt index 9f63e6b98..70f86c011 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportUtils.kt @@ -1,5 +1,6 @@ package org.move.ide.utils.imports +import org.move.ide.inspections.imports.usageScope import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.types.ItemQualName @@ -13,8 +14,8 @@ fun ImportCandidate.import(context: MvElement) { checkWriteAccessAllowed() val insertionScope = context.containingModule ?: context.containingScript ?: return val insertTestOnly = - insertionScope.itemScope == NamedItemScope.MAIN - && context.itemScope == NamedItemScope.TEST + insertionScope.usageScope == NamedItemScope.MAIN + && context.usageScope == NamedItemScope.TEST insertionScope.insertUseItem(qualName, insertTestOnly) } diff --git a/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt b/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt index 60b8bef2f..8d7f04f67 100644 --- a/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt +++ b/src/main/kotlin/org/move/lang/core/psi/NamedItemScope.kt @@ -1,10 +1,6 @@ package org.move.lang.core.psi -import com.intellij.openapi.util.Key -import com.intellij.psi.util.CachedValue -import com.intellij.psi.util.CachedValuesManager import org.move.lang.core.psi.ext.* -import org.move.lang.core.resolve.ref.MvReferenceElement enum class NamedItemScope { MAIN, @@ -19,129 +15,22 @@ enum class NamedItemScope { } return this } - - companion object { - fun all(): Set = setOf(MAIN, TEST, VERIFY) - } -} - -//fun MvElement.isVisibleInContext(contextScope: NamedItemScope): Boolean { -// val itemScope = this.itemScope -// // MAIN scope items are visible from any context -// return itemScope == NamedItemScope.MAIN || itemScope == contextScope -//} - -fun MvNamedElement.isVisibleInContext(refItemScopes: Set): Boolean { -// for (requiredScope in this.itemScopes) { -// if (!contextScopes.contains(requiredScope)) return false -// } - val requiredScopes = this.namedItemScopes - return (requiredScopes - refItemScopes).isEmpty() - // MAIN scope items are visible from any context -// return itemScope == ItemScope.MAIN || itemScope == contextScope -} - - -private val ITEM_SCOPES_KEY = - Key.create>>("org.move.ITEM_SCOPES_KEY") - -val MvReferenceElement.refItemScopes: Set - get() { - return (this as MvElement).itemScopes - } - -val MvNamedElement.namedItemScopes: Set - get() { - return (this as MvElement).itemScopes - } - -val MvElement.itemScopes: Set - get() { - // TODO: special case module items to use stub-only in some cases -// project.cacheManager.cache(this, ITEM_SCOPES_KEY) { - val scopes = mutableSetOf(NamedItemScope.MAIN) - var element: MvElement? = this - if (element is MvStruct || element is MvFunction) { - val attributeScopes = (element as MvDocAndAttributeOwner).explicitItemScopes() - return attributeScopes - } - while (element != null) { - when (element) { - is MvDocAndAttributeOwner -> { - val attributeScopes = element.explicitItemScopes() - scopes.addAll(attributeScopes) -// val ownerItemScope = element.explicitAttributeItemScope() -// if (ownerItemScope != null) { -// scopes.add(ownerItemScope) -// } - } - is MvSpecCodeBlock, is MvItemSpecRef -> scopes.add(NamedItemScope.VERIFY) - } - element = element.parent as? MvElement - } - return scopes -// cacheResult(scopes, listOf(PsiModificationTracker.MODIFICATION_COUNT)) - } - -val MvElement.itemScope: NamedItemScope - get() { - return CachedValuesManager.getProjectPsiDependentCache(this) { - var element = it - while (element != null) { - when (element) { - is MvDocAndAttributeOwner -> { - val ownerItemScope = element.explicitAttributeItemScope() - if (ownerItemScope != null) { - return@getProjectPsiDependentCache ownerItemScope - } - } - is MvSpecCodeBlock, is MvItemSpecRef -> return@getProjectPsiDependentCache NamedItemScope.VERIFY - } - element = element.parent as? MvElement - } - NamedItemScope.MAIN - } - } - -private fun MvDocAndAttributeOwner.explicitItemScopes(): Set { - val scopes = mutableSetOf() - when { - this.hasTestOnlyAttr -> scopes.add(NamedItemScope.TEST) - this.hasVerifyOnlyAttr -> scopes.add(NamedItemScope.VERIFY) - this is MvStruct -> { - scopes.addAll(this.module.explicitItemScopes()) - } - this is MvFunction -> { - if (this.hasTestAttr) { - scopes.add(NamedItemScope.TEST) - } - scopes.addAll(this.module?.explicitItemScopes().orEmpty()) - } - } -// if (this.hasTestOnlyAttr || (this is MvFunction && this.hasTestAttr)) { -// scopes.add(NamedItemScope.TEST) -// } -// if (this.hasVerifyOnlyAttr) { -// scopes.add(NamedItemScope.VERIFY) -// } - return scopes } -private fun MvDocAndAttributeOwner.explicitAttributeItemScope(): NamedItemScope? = +fun MvDocAndAttributeOwner.itemScopeFromAttributes(): NamedItemScope? = when (this) { -// is MvSpecInlineFunction -> ItemScope.MAIN is MvFunction -> when { this.hasTestOnlyAttr || this.hasTestAttr -> NamedItemScope.TEST this.hasVerifyOnlyAttr -> NamedItemScope.VERIFY else -> - this.module?.explicitAttributeItemScope() ?: NamedItemScope.MAIN + this.module?.itemScopeFromAttributes() ?: NamedItemScope.MAIN } is MvStruct -> when { this.hasTestOnlyAttr -> NamedItemScope.TEST this.hasVerifyOnlyAttr -> NamedItemScope.VERIFY - else -> this.module.explicitAttributeItemScope() ?: NamedItemScope.MAIN + else -> this.module.itemScopeFromAttributes() ?: NamedItemScope.MAIN } else -> when { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt index f8b9e426f..96e839347 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvVisibilityOwner.kt @@ -42,7 +42,6 @@ val MvVisibilityOwner.visibility2: Visibility2 PACKAGE -> containingMovePackage?.let { Visibility2.Restricted.Package(it) } ?: Visibility2.Public FRIEND -> { val module = this.containingModule ?: return Visibility2.Private - // todo: make lazy Visibility2.Restricted.Friend(lazy { module.friendModules }) } SCRIPT -> Visibility2.Restricted.Script diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/PsiElement.kt b/src/main/kotlin/org/move/lang/core/psi/ext/PsiElement.kt index 6b07bc495..7ac2f3ff6 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/PsiElement.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/PsiElement.kt @@ -142,6 +142,11 @@ inline fun PsiElement.ancestorsOfType(): Sequence { return this.ancestors.filterIsInstance() } +inline fun PsiElement.ancestorsOfTypeWithSelf(): Sequence { + return (sequenceOf(this) + this.ancestors).filterIsInstance() +// return this.ancestors.filterIsInstance() +} + fun PsiElement.findFirstParent(strict: Boolean = true, cond: Condition) = PsiTreeUtil.findFirstParent(this, strict, cond) diff --git a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt index 2b76c71a1..3e42bec52 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -558,10 +558,10 @@ fun RsResolveProcessor.processAllItems( namespaces: Set, vararg collections: Iterable, ): Boolean { - return sequenceOf(*collections).flatten().any { e -> - val name = e.name ?: return false - val visibilityFilter = e.visInfo().createFilter() - process(ScopeEntryWithVisibility(name, e, namespaces, visibilityFilter)) + return sequenceOf(*collections).flatten().any { itemElement -> + val name = itemElement.name ?: return false + val visibilityFilter = itemElement.visInfo().createFilter() + process(ScopeEntryWithVisibility(name, itemElement, namespaces, visibilityFilter)) } } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt index ef5d6b8cc..4a63c071e 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -227,18 +227,19 @@ fun processItemsInScope( private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: RsResolveProcessor): Boolean { var stop = false for (useStmt in this.useStmtList) { - useStmt.forEachLeafSpeck { path, alias -> + val stmtUsageScope = useStmt.usageScope + useStmt.forEachLeafSpeck { speckPath, alias -> val name = if (alias != null) { alias.name ?: return@forEachLeafSpeck false } else { - var n = path.referenceName ?: return@forEachLeafSpeck false + var n = speckPath.referenceName ?: return@forEachLeafSpeck false // 0x1::m::Self -> 0x1::m if (n == "Self") { - n = path.qualifier?.referenceName ?: return@forEachLeafSpeck false + n = speckPath.qualifier?.referenceName ?: return@forEachLeafSpeck false } n } - val resolvedItem = path.reference?.resolve() + val resolvedItem = speckPath.reference?.resolve() if (resolvedItem == null) { if (alias != null) { // aliased element cannot be resolved, but alias itself is valid, resolve to it @@ -250,9 +251,8 @@ private fun MvItemsOwner.processUseSpeckElements(ns: Set, processor: val element = alias ?: resolvedItem val namespace = resolvedItem.namespace - val useSpeckUsageScope = path.usageScope val visibilityFilter = - resolvedItem.visInfo(adjustScope = useSpeckUsageScope).createFilter() + resolvedItem.visInfo(adjustScope = stmtUsageScope).createFilter() if (namespace in ns && processor.process(name, element, ns, visibilityFilter)) { stop = true diff --git a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt index aee6ab9d5..6a0341bee 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -17,32 +17,30 @@ import org.move.lang.core.resolve.ref.Visibility2.* data class ItemVisibilityInfo( val item: MvNamedElement, - val usageScope: NamedItemScope, + val itemScopeAdjustment: NamedItemScope, val vis: Visibility2, ) fun MvNamedElement.visInfo(adjustScope: NamedItemScope = MAIN): ItemVisibilityInfo { - // todo: can be lazy - val itemUsageScope = this.itemScope.shrinkScope(adjustScope) val visibility = (this as? MvVisibilityOwner)?.visibility2 ?: Public - return ItemVisibilityInfo(this, usageScope = itemUsageScope, vis = visibility) + return ItemVisibilityInfo(this, itemScopeAdjustment = adjustScope, vis = visibility) } /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { - val (item, itemUsageScope, visibility) = this - return VisibilityFilter { element, namespaces -> + val (item, itemScopeAdjustment, visibility) = this + return VisibilityFilter { methodOrPath, namespaces -> // inside msl everything is visible - if (element.isMsl()) return@VisibilityFilter Visible + if (methodOrPath.isMsl()) return@VisibilityFilter Visible // if inside MvAttrItem like abort_code= - val attrItem = element.ancestorStrict() + val attrItem = methodOrPath.ancestorStrict() if (attrItem != null) return@VisibilityFilter Visible - val pathUsageScope = element.usageScope + val pathUsageScope = methodOrPath.usageScope - val path = element as? MvPath + val path = methodOrPath as? MvPath if (path != null) { val useSpeck = path.useSpeck if (useSpeck != null) { @@ -64,6 +62,7 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { // 0x0::builtins module items are always visible if (itemModule != null && itemModule.isBuiltins) return@VisibilityFilter Visible + val itemUsageScope = item.usageScope.shrinkScope(itemScopeAdjustment) // #[test_only] items in non-test-only scope if (itemUsageScope != MAIN) { // cannot be used everywhere, need to check for scope compatibility @@ -73,7 +72,7 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { // we're in non-msl scope at this point, msl only items aren't available if (item is MslOnlyElement) return@VisibilityFilter Invisible - val pathModule = element.containingModule + val pathModule = methodOrPath.containingModule // local methods, Self::method - everything is visible if (itemModule == pathModule) return@VisibilityFilter Visible @@ -91,19 +90,19 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { Invisible } is Restricted.Script -> { - val containingFunction = element.containingFunction + val containingFunction = methodOrPath.containingFunction if (containingFunction != null) { if (containingFunction.isEntry || containingFunction.isPublicScript ) return@VisibilityFilter Visible } - if (element.containingScript != null) return@VisibilityFilter Visible + if (methodOrPath.containingScript != null) return@VisibilityFilter Visible Invisible } is Restricted.Package -> { if (!item.project.moveSettings.enablePublicPackage) { return@VisibilityFilter Invisible } - val pathPackage = element.containingMovePackage ?: return@VisibilityFilter Invisible + val pathPackage = methodOrPath.containingMovePackage ?: return@VisibilityFilter Invisible if (visibility.originPackage == pathPackage) Visible else Invisible } } diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt index 22a4a16f8..cb0b9ca97 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ref/Path2ReferenceImpl.kt @@ -40,11 +40,14 @@ class Path2ReferenceImpl(element: MvPath): fun rawMultiResolve(): List> = rawCachedMultiResolve() private fun rawCachedMultiResolve(): List> { - val rawResult = MvResolveCache.getInstance(element.project) - .resolveWithCaching(element, ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE, Resolver) - return rawResult.orEmpty() + return MvResolveCache + .getInstance(element.project) + .resolveWithCaching(element, cacheDependency, Resolver) + .orEmpty() } + private val cacheDependency: ResolveCacheDependency get() = ResolveCacheDependency.LOCAL_AND_RUST_STRUCTURE + private object Resolver: (MvElement) -> List> { override fun invoke(path: MvElement): List> { // should not really happen diff --git a/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/IndexExprTest.kt b/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/IndexExprTest.kt index acfcb260c..68d27b7ca 100644 --- a/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/IndexExprTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/IndexExprTest.kt @@ -37,4 +37,12 @@ class IndexExprTest: AnnotatorTestCase(MvSyntaxErrorAnnotator::class) { } } """) + + fun `test no error for specs in compiler v1`() = checkWarnings(""" + module 0x1::m { + spec module { + invariant forall ind in 0..10: vec[ind] < 10; + } + } + """) } \ No newline at end of file diff --git a/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt index 5dfabd524..cba7d8981 100644 --- a/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/MvUnresolvedReferenceInspectionTest.kt @@ -1,5 +1,7 @@ package org.move.ide.inspections +import org.move.ide.inspections.fixes.CompilerV2Feat.INDEXING +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.DebugMode import org.move.utils.tests.NamedAddress import org.move.utils.tests.annotation.InspectionTestBase @@ -461,4 +463,15 @@ module 0x1::m { use std::m; } """) + + fun `test no error for invariant index variable`() = checkByText( + """ + module 0x1::m { + spec module { + let vec = vector[1, 2, 3]; + invariant forall ind in 0..10: vec[ind] < 10; + } + } + """ + ) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt index df7d9365b..7a3b3b971 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveSpecsTest.kt @@ -1,5 +1,7 @@ package org.move.lang.resolve +import org.move.ide.inspections.fixes.CompilerV2Feat.INDEXING +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.resolve.ResolveTestCase class ResolveSpecsTest: ResolveTestCase() { @@ -955,4 +957,24 @@ module 0x1::main { } """) + + fun `test resolve invariant index variable in loop condition spec`() = checkByCode( + """ + module 0x1::m { + fun main() { + while ({ + spec { + invariant forall ind in 0..10: + //X + ind < 10; + //^ + }; + true + }) { + + } + } + } + """ + ) }