Skip to content

Commit

Permalink
index expr fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurnikov committed Jul 2, 2024
1 parent 54e23cb commit c49f019
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/org/move/lang/core/types/infer/Acquires.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
}
#[view]
/// Check whether the feature is enabled.
public fun is_enabled(feature: u64): bool acquires Features {
exists<Features>(@0x1) &&
contains(&borrow_global<Features>(@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<u8>,
}
#[view]
/// Check whether the feature is enabled.
public fun is_enabled(feature: u64): bool acquires Features {
exists<Features>(@0x1) &&
contains(Features[@0x1].features, feature)
}
}
"""
)
Expand Down
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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<Element>(self: &mut vector<Element>, e: Element);
}
"""
)
main(
"""
module 0x1::m {
use 0x1::vector::push_back;
fun main() {
let v = vector[1, 2];
let vec = vector[];
<weak_warning descr="Can be replaced with method call">/*caret*/push_back(&mut vec, v[0])</weak_warning>;
}
}
"""
)
}
}, """
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)

Expand Down
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,68 +9,81 @@ 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;
<error descr="Indexing receiver type should be vector or resource, got 'bool'">b</error>[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;
<error descr="Indexing receiver type should be vector or resource, got 'bool'">b</error>[@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[<error descr="Incompatible type 'bool', expected 'integer'">false</error>];
}
}
""")
"""
)

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];
v[<error descr="Incompatible type 'bool', expected 'num'">false</error>];
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[<error descr="Incompatible type 'bool', expected 'address'">false</error>];
}
}
""")
"""
)

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];
}
}
""")
"""
)
}

0 comments on commit c49f019

Please sign in to comment.