diff --git a/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt b/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt index bd8aaef2b..7bf151a5a 100644 --- a/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt +++ b/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt @@ -110,6 +110,7 @@ class PerProjectAptosConfigurable(val project: Project): BoundConfigurable("Apto it.skipFetchLatestGitDeps = state.skipFetchLatestGitDeps it.dumpStateOnTestFailure = state.dumpStateOnTestFailure it.enableResourceAccessControl = state.enableResourceAccessControl + it.enableIndexExpr = state.enableIndexExpr it.addCompilerV2CLIFlags = state.addCompilerV2CLIFlags it.fetchAptosDeps = state.fetchAptosDeps } diff --git a/src/main/kotlin/org/move/lang/core/types/infer/Acquires.kt b/src/main/kotlin/org/move/lang/core/types/infer/Acquires.kt index 5525d2831..6b1be6951 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/Acquires.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/Acquires.kt @@ -38,10 +38,10 @@ abstract class AcquireTypesOwnerVisitor: PsiRecursiveElementVisitor() { abstract fun visitAcquireTypesOwner(acqTypesOwner: MvAcquireTypesOwner) override fun visitElement(element: PsiElement) { - when (element) { - is MvAcquireTypesOwner -> visitAcquireTypesOwner(element) - else -> super.visitElement(element) + if (element is MvAcquireTypesOwner) { + visitAcquireTypesOwner(element) } + super.visitElement(element) } } diff --git a/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt b/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt index 6a3f0f472..c1a345bba 100644 --- a/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt +++ b/src/main/kotlin/org/move/lang/core/types/infer/TypeInferenceWalker.kt @@ -672,26 +672,25 @@ class TypeInferenceWalker( return TyUnknown } - return when (receiverTy) { - is TyVector -> { + val derefTy = receiverTy.derefIfNeeded() + return when { + derefTy is TyVector -> { // argExpr can be either TyInteger or TyRange when (argTy) { - is TyRange -> receiverTy - is TyInteger, is TyInfer.IntVar, is TyNum -> receiverTy.item + is TyRange -> derefTy + is TyInteger, is TyInfer.IntVar, is TyNum -> derefTy.item else -> { coerce(indexExpr.argExpr, argTy, if (ctx.msl) TyNum else TyInteger.DEFAULT) TyUnknown } } } - is TyStruct -> { + receiverTy is TyStruct -> { coerce(indexExpr.argExpr, argTy, TyAddress) receiverTy } else -> { - if (!ctx.msl) { - ctx.reportTypeError(TypeError.IndexingIsNotAllowed(indexExpr.receiverExpr, receiverTy)) - } + ctx.reportTypeError(TypeError.IndexingIsNotAllowed(indexExpr.receiverExpr, receiverTy)) TyUnknown } } diff --git a/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt index 2db91a57c..d799be557 100644 --- a/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt @@ -190,6 +190,42 @@ module 0x1::main { inline fun f() { StakePool[pool_address]; } +} + """ + ) + + fun `test no unused acquires for deep borrow global dot`() = checkWarnings( + """ +module 0x1::main { + /// The enabled features, represented by a bitset stored on chain. + struct Features has key { + features: vector, + } + + #[view] + /// Check whether the feature is enabled. + public fun is_enabled(feature: u64): bool acquires Features { + exists(@0x1) && + contains(&borrow_global(@0x1).features, feature) + } +} + """ + ) + + @CompilerV2Features(INDEXING) + fun `test no unused acquires for deep borrow global dot with index expr`() = checkWarnings( + """ +module 0x1::main { + /// The enabled features, represented by a bitset stored on chain. + struct Features has key { + features: vector, + } + #[view] + /// Check whether the feature is enabled. + public fun is_enabled(feature: u64): bool acquires Features { + exists(@0x1) && + contains(Features[@0x1].features, feature) + } } """ ) diff --git a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt b/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt index 9823886ca..ecc144722 100644 --- a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt @@ -1,6 +1,8 @@ package org.move.ide.inspections import org.intellij.lang.annotations.Language +import org.move.utils.tests.CompilerV2Feat.INDEXING +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.FileTreeBuilder import org.move.utils.tests.annotation.InspectionProjectTestBase @@ -108,6 +110,44 @@ class ReplaceWithMethodCallInspectionProjectTest: } """) + @CompilerV2Features(INDEXING) + fun `test replace with method call with index expr`() = doFixTest( + { + namedMoveToml("MyPackage") + sources { + move( + "vector.move", """ + module 0x1::vector { + #[bytecode_instruction] + /// Add element `e` to the end of the vector `v`. + native public fun push_back(self: &mut vector, e: Element); + } + """ + ) + main( + """ + module 0x1::m { + use 0x1::vector::push_back; + fun main() { + let v = vector[1, 2]; + let vec = vector[]; + /*caret*/push_back(&mut vec, v[0]); + } + } + """ + ) + } + }, """ + module 0x1::m { + use 0x1::vector::push_back; + fun main() { + let v = vector[1, 2]; + let vec = vector[]; + vec.push_back(v[0]); + } + } + """) + private fun doTest(code: FileTreeBuilder.() -> Unit) = checkByFileTree(code, checkWarn = false, checkWeakWarn = true) diff --git a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt index 083217fa1..f5539962b 100644 --- a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt @@ -1,6 +1,8 @@ package org.move.ide.inspections import org.intellij.lang.annotations.Language +import org.move.utils.tests.CompilerV2Feat.INDEXING +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.InspectionTestBase class ReplaceWithMethodCallInspectionTest: InspectionTestBase(ReplaceWithMethodCallInspection::class) { diff --git a/src/test/kotlin/org/move/ide/inspections/compilerV2/TypeCheckIndexExprTest.kt b/src/test/kotlin/org/move/ide/inspections/compilerV2/TypeCheckIndexExprTest.kt index ac82b45c2..ddb01d92a 100644 --- a/src/test/kotlin/org/move/ide/inspections/compilerV2/TypeCheckIndexExprTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/compilerV2/TypeCheckIndexExprTest.kt @@ -9,43 +9,52 @@ import org.move.utils.tests.annotation.InspectionTestBase class TypeCheckIndexExprTest: InspectionTestBase(MvTypeCheckInspection::class) { @CompilerV2Features() - fun `test no error receiver of vector index expr without compiler v2 feature`() = checkByText(""" + fun `test no error receiver of vector index expr without compiler v2 feature`() = checkByText( + """ module 0x1::m { fun main() { let b = false; b[0]; } } - """) + """ + ) - fun `test error receiver of vector index expr`() = checkByText(""" + fun `test error receiver of vector index expr`() = checkByText( + """ module 0x1::m { fun main() { let b = false; b[0]; } } - """) + """ + ) - fun `test error receiver of resource index expr`() = checkByText(""" + fun `test error receiver of resource index expr`() = checkByText( + """ module 0x1::m { fun main() { let b = false; b[@0x1]; } } - """) + """ + ) - fun `test vector index expr argument is not an integer`() = checkByText(""" + fun `test vector index expr argument is not an integer`() = checkByText( + """ module 0x1::m { fun main() { let v = vector[1, 2]; v[false]; } } - """) + """ + ) - fun `test vector index expr argument is not an integer in spec`() = checkByText(""" + fun `test vector index expr argument is not an integer in spec`() = checkByText( + """ module 0x1::m { spec fun main(): u8 { let v = vector[1, 2]; @@ -53,24 +62,28 @@ class TypeCheckIndexExprTest: InspectionTestBase(MvTypeCheckInspection::class) { 1 } } - """) + """ + ) - fun `test resource index expr argument is not an address`() = checkByText(""" + fun `test resource index expr argument is not an address`() = checkByText( + """ module 0x1::m { struct S has key {} fun main() { S[false]; } } - """) + """ + ) - fun `test no error for vector reference inside specs`() = checkByText(""" + fun `test no error for vector reference`() = checkByText( + """ module 0x1::m { - fun main() {} - spec main { + fun main() { let v = vector[1, 2]; (&v)[1]; } } - """) + """ + ) } \ No newline at end of file