diff --git a/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt b/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt index b3be171c5..5f3e18bf2 100644 --- a/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt +++ b/src/main/kotlin/org/move/cli/settings/MvProjectSettingsService.kt @@ -36,6 +36,7 @@ class MvProjectSettingsService( val skipFetchLatestGitDeps: Boolean get() = state.skipFetchLatestGitDeps val dumpStateOnTestFailure: Boolean get() = state.dumpStateOnTestFailure + val enableReceiverStyleFunctions: Boolean get() = state.enableReceiverStyleFunctions val enableResourceAccessControl: Boolean get() = state.enableResourceAccessControl val enableIndexExpr: Boolean get() = state.enableIndexExpr val enablePublicPackage: Boolean get() = state.enablePublicPackage @@ -49,6 +50,9 @@ class MvProjectSettingsService( @AffectsMoveProjectsMetadata var localAptosPath: String? by string() + @AffectsHighlighting + var enableReceiverStyleFunctions: Boolean by property(false) + @AffectsParseTree var enableResourceAccessControl: Boolean by property(false) diff --git a/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt b/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt index 55dc6933b..84336e0ec 100644 --- a/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt +++ b/src/main/kotlin/org/move/cli/settings/PerProjectAptosConfigurable.kt @@ -17,131 +17,139 @@ class PerProjectAptosConfigurable(val project: Project): BoundConfigurable("Apto override fun createPanel(): DialogPanel { val chooseAptosCliPanel = ChooseAptosCliPanel(versionUpdateListener = null) - val configurablePanel = - panel { - val settings = project.moveSettings - val state = settings.state.copy() + this.disposable?.let { + Disposer.register(it, chooseAptosCliPanel) + } + return panel { + val settings = project.moveSettings + val state = settings.state.copy() - chooseAptosCliPanel.attachToLayout(this) + chooseAptosCliPanel.attachToLayout(this) - group { + group { + row { + checkBox("Fetch external packages on project reload") + .bindSelected(state::fetchAptosDeps) + link("Configure project reload schedule") { + ProjectManager.getInstance().defaultProject.showSettingsDialog() + } + .align(AlignX.RIGHT) + } + group("Compiler V2") { row { - checkBox("Fetch external packages on project reload") - .bindSelected(state::fetchAptosDeps) - link("Configure project reload schedule") { - ProjectManager.getInstance().defaultProject.showSettingsDialog() - } - .align(AlignX.RIGHT) + checkBox("Set Compiler V2 flags for CLI") + .comment( + "Adds `--compiler-version v2 --language-version 2.0` " + + "to all generated Aptos CLI commands" + ) + .bindSelected(state::addCompilerV2CLIFlags) } - group("Compiler V2") { + group("Language features") { row { - checkBox("Set Compiler V2 for CLI") + checkBox("Receiver-Style functions") .comment( - "Adds `--compiler-version v2 --language-version 2.0` " + - "to all generated Aptos CLI commands" + "Allows calling functions with special " + + "first self parameter as a methods through dot expression." ) - .bindSelected(state::addCompilerV2CLIFlags) + .bindSelected(state::enableReceiverStyleFunctions) } row { - checkBox("Enable resource-access control") + checkBox("Resource-Access control") .comment( - "Enables resource access control specifies " + - "(reads, writes, pure for functions) in the parser. " + + "Allows specifying resource access attributes " + + "(reads, writes, pure for functions). " + "Requires re-parsing of all Move files in the project, can be slow." ) .bindSelected(state::enableResourceAccessControl) } row { - checkBox("Enable indexing") + checkBox("Index notation") .comment( - "Enables resource and vector indexing " + - "(i.e. v[0], R[@0x1]) for the Move files." + "Allows resource (R[@0x1]) and vector (v[0]) index operators." ) .bindSelected(state::enableIndexExpr) } row { - checkBox("Enable public(package) visibility modifier") + checkBox("public(package) visibility modifier") .comment( - "Enables using public(package) visibility modifier " + + "Allows public(package) visibility modifier " + "to specify functions accessible to any module of the same package." ) .bindSelected(state::enablePublicPackage) } } - group("Command Line Options") { - row { - checkBox("Disable telemetry for new Run Configurations") - .comment( - "Adds APTOS_DISABLE_TELEMETRY=true to every generated Aptos command." - ) - .bindSelected(state::disableTelemetry) - } - row { - checkBox("Skip updating to the latest git dependencies") - .comment( - "Adds --skip-fetch-latest-git-deps to the sync and test runs." - ) - .bindSelected(state::skipFetchLatestGitDeps) - - } - row { - checkBox("Dump storage to console on test failures") - .comment( - "Adds --dump to generated test runs." - ) - .bindSelected(state::dumpStateOnTestFailure) - } - } } + group("Command Line Options") { + row { + checkBox("Disable telemetry for new Run Configurations") + .comment( + "Adds APTOS_DISABLE_TELEMETRY=true to every generated Aptos command." + ) + .bindSelected(state::disableTelemetry) + } + row { + checkBox("Skip updating to the latest git dependencies") + .comment( + "Adds --skip-fetch-latest-git-deps to the sync and test runs." + ) + .bindSelected(state::skipFetchLatestGitDeps) - if (!project.isDefault) { + } row { - link("Set default project settings") { - ProjectManager.getInstance().defaultProject.showSettingsDialog() - } - .align(AlignX.RIGHT) + checkBox("Dump storage to console on test failures") + .comment( + "Adds --dump to generated test runs." + ) + .bindSelected(state::dumpStateOnTestFailure) } } + } - // saves values from Swing form back to configurable (OK / Apply) - onApply { - settings.modify { - it.aptosExecType = chooseAptosCliPanel.data.aptosExecType + if (!project.isDefault) { + row { + link("Set default project settings") { + ProjectManager.getInstance().defaultProject.showSettingsDialog() + } + .align(AlignX.RIGHT) + } + } - val localAptosSdkPath = chooseAptosCliPanel.data.localAptosPath - if (localAptosSdkPath != null) { - chooseAptosCliPanel.updateAptosSdks(localAptosSdkPath) - } - it.localAptosPath = localAptosSdkPath + // saves values from Swing form back to configurable (OK / Apply) + onApply { + settings.modify { + it.aptosExecType = chooseAptosCliPanel.data.aptosExecType - it.disableTelemetry = state.disableTelemetry - it.skipFetchLatestGitDeps = state.skipFetchLatestGitDeps - it.dumpStateOnTestFailure = state.dumpStateOnTestFailure - it.enableResourceAccessControl = state.enableResourceAccessControl - it.enableIndexExpr = state.enableIndexExpr - it.enablePublicPackage = state.enablePublicPackage - it.addCompilerV2CLIFlags = state.addCompilerV2CLIFlags - it.fetchAptosDeps = state.fetchAptosDeps + val localAptosSdkPath = chooseAptosCliPanel.data.localAptosPath + if (localAptosSdkPath != null) { + chooseAptosCliPanel.updateAptosSdks(localAptosSdkPath) } - } + it.localAptosPath = localAptosSdkPath - // loads settings from configurable to swing form - onReset { - chooseAptosCliPanel.data = - ChooseAptosCliPanel.Data(state.aptosExecType, state.localAptosPath) + it.disableTelemetry = state.disableTelemetry + it.skipFetchLatestGitDeps = state.skipFetchLatestGitDeps + it.dumpStateOnTestFailure = state.dumpStateOnTestFailure + it.enableReceiverStyleFunctions = state.enableReceiverStyleFunctions + it.enableResourceAccessControl = state.enableResourceAccessControl + it.enableIndexExpr = state.enableIndexExpr + it.enablePublicPackage = state.enablePublicPackage + it.addCompilerV2CLIFlags = state.addCompilerV2CLIFlags + it.fetchAptosDeps = state.fetchAptosDeps } + } - /// checks whether any settings are modified (should be fast) - onIsModified { - val aptosPanelData = chooseAptosCliPanel.data - aptosPanelData.aptosExecType != settings.aptosExecType - || aptosPanelData.localAptosPath != settings.localAptosPath - } + // loads settings from configurable to swing form + onReset { + chooseAptosCliPanel.data = + ChooseAptosCliPanel.Data(state.aptosExecType, state.localAptosPath) + } + + /// checks whether any settings are modified (should be fast) + onIsModified { + val aptosPanelData = chooseAptosCliPanel.data + aptosPanelData.aptosExecType != settings.aptosExecType + || aptosPanelData.localAptosPath != settings.localAptosPath } - this.disposable?.let { - Disposer.register(it, chooseAptosCliPanel) } - return configurablePanel } // override fun disposeUIResources() { diff --git a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt index 05e7cd9bc..4a7e757f8 100644 --- a/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/HighlightingAnnotator.kt @@ -3,6 +3,7 @@ package org.move.ide.annotator import com.intellij.lang.annotation.AnnotationHolder import com.intellij.psi.PsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.move.cli.settings.moveSettings import org.move.ide.colors.MvColor import org.move.lang.MvElementTypes.HEX_INTEGER_LITERAL import org.move.lang.MvElementTypes.IDENTIFIER @@ -61,7 +62,7 @@ class HighlightingAnnotator: MvAnnotatorBase() { if (element is MvAbility) return MvColor.ABILITY if (element is MvTypeParameter) return MvColor.TYPE_PARAMETER if (element is MvItemSpecTypeParameter) return MvColor.TYPE_PARAMETER - if (element is MvModuleRef && element.isSelf) return MvColor.KEYWORD + if (element is MvModuleRef && element.isSelfModuleRef) return MvColor.KEYWORD if (element is MvUseItem && element.text == "Self") return MvColor.KEYWORD if (element is MvFunction) return when { @@ -90,7 +91,9 @@ class HighlightingAnnotator: MvAnnotatorBase() { private fun highlightBindingPat(bindingPat: MvBindingPat): MvColor { val bindingOwner = bindingPat.parent - if (bindingOwner is MvFunctionParameter && bindingOwner.isSelf) { + if (bindingPat.isReceiverStyleFunctionsEnabled && + bindingOwner is MvFunctionParameter && bindingOwner.isSelfParam + ) { return MvColor.SELF_PARAMETER } val msl = bindingPat.isMslOnlyItem @@ -147,7 +150,9 @@ class HighlightingAnnotator: MvAnnotatorBase() { item is MvConst -> MvColor.CONSTANT else -> { val itemParent = item.parent - if (itemParent is MvFunctionParameter && itemParent.isSelf) { + if (itemParent.isReceiverStyleFunctionsEnabled + && itemParent is MvFunctionParameter && itemParent.isSelfParam + ) { MvColor.SELF_PARAMETER } else { val msl = path.isMslScope @@ -185,4 +190,8 @@ class HighlightingAnnotator: MvAnnotatorBase() { itemTy is TyStruct && itemTy.item.hasKey -> MvColor.KEY_OBJECT else -> MvColor.VARIABLE } + + private val PsiElement.isReceiverStyleFunctionsEnabled + get() = + project.moveSettings.enableReceiverStyleFunctions } diff --git a/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt index 2a0d7c340..4c60f5dc5 100644 --- a/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/MvSyntaxErrorAnnotator.kt @@ -22,6 +22,7 @@ class MvSyntaxErrorAnnotator: MvAnnotatorBase() { override fun visitFunction(o: MvFunction) = checkFunction(moveHolder, o) override fun visitSpecFunction(o: MvSpecFunction) = checkSpecFunction(moveHolder, o) override fun visitIndexExpr(o: MvIndexExpr) = checkIndexExpr(moveHolder, o) + override fun visitMethodCall(o: MvMethodCall) = checkMethodCall(moveHolder, o) override fun visitModule(o: MvModule) { checkVisibilityModifiers(moveHolder, o) @@ -107,6 +108,13 @@ class MvSyntaxErrorAnnotator: MvAnnotatorBase() { } } + private fun checkMethodCall(holder: MvAnnotationHolder, methodCall: MvMethodCall) { + if (!methodCall.project.moveSettings.enableReceiverStyleFunctions) { + Diagnostic.ReceiverStyleFunctionsIsNotSupportedInCompilerV1(methodCall) + .addToHolder(holder) + } + } + private fun checkLitExpr(holder: MvAnnotationHolder, litExpr: MvLitExpr) { val lit = litExpr.literal when (lit) { diff --git a/src/main/kotlin/org/move/ide/inspections/fixes/EnableCompilerV2FeatureFix.kt b/src/main/kotlin/org/move/ide/inspections/fixes/EnableCompilerV2FeatureFix.kt index 714144152..4d6155981 100644 --- a/src/main/kotlin/org/move/ide/inspections/fixes/EnableCompilerV2FeatureFix.kt +++ b/src/main/kotlin/org/move/ide/inspections/fixes/EnableCompilerV2FeatureFix.kt @@ -12,6 +12,7 @@ import org.move.ide.inspections.fixes.CompilerV2Feat.* enum class CompilerV2Feat(val title: String) { INDEXING("Index notation"), + RECEIVER_STYLE_FUNCTIONS("Receiver-Style functions"), RESOURCE_CONTROL("Resource access control"), PUBLIC_PACKAGE("`public(package)` function visibility"); } @@ -31,6 +32,7 @@ class EnableCompilerV2FeatureFix( project.moveSettings.modify { when (feature) { INDEXING -> it.enableIndexExpr = true + RECEIVER_STYLE_FUNCTIONS -> it.enableReceiverStyleFunctions = true RESOURCE_CONTROL -> it.enableResourceAccessControl = true PUBLIC_PACKAGE -> it.enablePublicPackage = true } diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt index da36aa471..a71efc7a9 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ImportsCompletionProvider.kt @@ -13,7 +13,7 @@ import org.move.lang.core.completion.createSelfLookup import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.MvUseItem import org.move.lang.core.psi.MvUseItemGroup -import org.move.lang.core.psi.ext.isSelf +import org.move.lang.core.psi.ext.isSelfModuleRef import org.move.lang.core.psi.ext.itemUseSpeck import org.move.lang.core.psi.ext.names import org.move.lang.core.psi.refItemScopes @@ -47,7 +47,7 @@ object ImportsCompletionProvider: MvCompletionProvider() { } val vs = when { - moduleRef.isSelf -> setOf(Visibility.Internal) + moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) else -> Visibility.visibilityScopesForElement(itemImport) } val ns = setOf(Namespace.NAME, Namespace.TYPE, Namespace.FUNCTION) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt index 78b3acc23..35dd00cb6 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider.kt @@ -15,7 +15,7 @@ import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.ancestors import org.move.lang.core.psi.ext.endOffset import org.move.lang.core.psi.ext.isMslScope -import org.move.lang.core.psi.ext.isSelf +import org.move.lang.core.psi.ext.isSelfModuleRef import org.move.lang.core.resolve.* import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve.ref.Namespace @@ -62,7 +62,7 @@ abstract class MvPathCompletionProvider: MvCompletionProvider() { val module = moduleRef.reference?.resolveWithAliases() as? MvModule ?: return val vs = when { - moduleRef.isSelf -> setOf(Visibility.Internal) + moduleRef.isSelfModuleRef -> setOf(Visibility.Internal) else -> Visibility.visibilityScopesForElement(pathElement) } processModuleItems(module, namespaces, vs, pathScopeInfo) { diff --git a/src/main/kotlin/org/move/lang/core/psi/MvFunctionLike.kt b/src/main/kotlin/org/move/lang/core/psi/MvFunctionLike.kt index 8cf105bb6..b085168d8 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvFunctionLike.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvFunctionLike.kt @@ -2,6 +2,7 @@ package org.move.lang.core.psi import com.intellij.ide.projectView.PresentationData import com.intellij.openapi.editor.colors.TextAttributesKey +import org.move.cli.settings.moveSettings import org.move.ide.MoveIcons import org.move.lang.MvElementTypes import org.move.lang.core.completion.CompletionContext @@ -119,8 +120,10 @@ val MvFunctionLike.signatureText: String return "$paramsText$retTypeSuffix" } -val MvFunction.selfParam: MvFunctionParameter? get() = - this.parameters.firstOrNull()?.takeIf { it.name == "self" } +val MvFunction.selfParam: MvFunctionParameter? get() { + if (!project.moveSettings.enableReceiverStyleFunctions) return null + return this.parameters.firstOrNull()?.takeIf { it.name == "self" } +} fun MvFunction.selfParamTy(msl: Boolean): Ty? = this.selfParam?.type?.loweredType(msl) diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvFunctionParameter.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvFunctionParameter.kt index 1d0508f6d..20f4a27da 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvFunctionParameter.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvFunctionParameter.kt @@ -13,7 +13,7 @@ val MvFunctionParameter.name: String get() = this.bindingPat.name val MvFunctionParameter.paramIndex: Int get() = (this.parent as MvFunctionParameterList).functionParameterList.indexOf(this) -val MvFunctionParameter.isSelf: Boolean get() = +val MvFunctionParameter.isSelfParam: Boolean get() = this.bindingPat.name == "self" && this.paramIndex == 0 var MvFunctionParameter.resolveContext: MvFunction? diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt index 8758c9de8..f4623a808 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvModuleRef.kt @@ -8,7 +8,7 @@ import org.move.lang.core.psi.containingModule import org.move.lang.core.resolve.ref.MvModuleReferenceImpl import org.move.lang.core.resolve.ref.MvPolyVariantReference -val MvModuleRef.isSelf: Boolean +val MvModuleRef.isSelfModuleRef: Boolean get() = this !is MvFQModuleRef && this.referenceName == "Self" diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt index 5cb249d59..81eacd948 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveModuleReferenceImpl.kt @@ -1,7 +1,7 @@ package org.move.lang.core.resolve.ref import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.isSelf +import org.move.lang.core.psi.ext.isSelfModuleRef import org.move.lang.core.psi.ext.itemUseSpeck import org.move.lang.core.resolve.resolveLocalItem import org.move.stdext.wrapWithList @@ -11,7 +11,7 @@ class MvModuleReferenceImpl( ): MvPolyVariantReferenceCached(element) { override fun multiResolveInner(): List { - if (element.isSelf) return element.containingModule.wrapWithList() + if (element.isSelfModuleRef) return element.containingModule.wrapWithList() check(element !is MvFQModuleRef) { "That element has different reference item" diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt index 12a010263..367110ef7 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MovePathReferenceImpl.kt @@ -1,7 +1,7 @@ package org.move.lang.core.resolve.ref import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.isSelf +import org.move.lang.core.psi.ext.isSelfModuleRef import org.move.lang.core.psi.ext.isUpdateFieldArg2 import org.move.lang.core.psi.ext.itemUseSpeck import org.move.lang.core.psi.ext.namespaces @@ -33,7 +33,7 @@ class MvPathReferenceImpl( // second, // if it's MODULE::NAME -> resolve MODULE into corresponding FQModuleRef using imports if (moduleRef != null) { - if (moduleRef.isSelf) { + if (moduleRef.isSelfModuleRef) { val containingModule = moduleRef.containingModule ?: return emptyList() return resolveModuleItem( containingModule, diff --git a/src/main/kotlin/org/move/lang/utils/Diagnostic.kt b/src/main/kotlin/org/move/lang/utils/Diagnostic.kt index 52e674385..81451bd59 100644 --- a/src/main/kotlin/org/move/lang/utils/Diagnostic.kt +++ b/src/main/kotlin/org/move/lang/utils/Diagnostic.kt @@ -13,10 +13,10 @@ import org.move.ide.annotator.MvAnnotationHolder import org.move.ide.annotator.fixes.ItemSpecSignatureFix import org.move.ide.annotator.fixes.WrapWithParensExprFix import org.move.ide.annotator.pluralise -import org.move.ide.inspections.fixes.CompilerV2Feat.INDEXING -import org.move.ide.inspections.fixes.CompilerV2Feat.PUBLIC_PACKAGE +import org.move.ide.inspections.fixes.CompilerV2Feat.* import org.move.ide.inspections.fixes.EnableCompilerV2FeatureFix import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.dotExpr import org.move.lang.core.psi.ext.endOffset import org.move.lang.core.psi.ext.itemSpecBlock import org.move.lang.core.psi.ext.startOffset @@ -196,6 +196,17 @@ sealed class Diagnostic( } } + class ReceiverStyleFunctionsIsNotSupportedInCompilerV1(methodCall: MvMethodCall): Diagnostic(methodCall) { + + override fun prepare(): PreparedAnnotation { + return PreparedAnnotation( + ERROR, + "receiver-style functions are not supported in Aptos Move V1", + fixes = listOf(EnableCompilerV2FeatureFix(element, RECEIVER_STYLE_FUNCTIONS)) + ) + } + } + class PackageAndFriendModifiersCannotBeUsedTogether(modifier: MvVisibilityModifier): Diagnostic(modifier) { override fun prepare(): PreparedAnnotation { return PreparedAnnotation( diff --git a/src/main/kotlin/org/move/utils/tests/MvTestBase.kt b/src/main/kotlin/org/move/utils/tests/MvTestBase.kt index 3aca4c53b..3ae890610 100644 --- a/src/main/kotlin/org/move/utils/tests/MvTestBase.kt +++ b/src/main/kotlin/org/move/utils/tests/MvTestBase.kt @@ -44,6 +44,7 @@ fun UsefulTestCase.handleCompilerV2Annotations(project: Project) { for (feature in enabledCompilerV2.features) { when (feature) { RESOURCE_CONTROL -> it.enableResourceAccessControl = true + RECEIVER_STYLE_FUNCTIONS -> it.enableReceiverStyleFunctions = true INDEXING -> it.enableIndexExpr = true PUBLIC_PACKAGE -> it.enablePublicPackage = true } diff --git a/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt b/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt index f8e37fa08..378da39d8 100644 --- a/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/HighlightingAnnotatorTest.kt @@ -1,6 +1,7 @@ package org.move.ide.annotator import org.move.ide.colors.MvColor +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.ide.inspections.fixes.CompilerV2Feat.RESOURCE_CONTROL import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.AnnotatorTestCase @@ -318,6 +319,7 @@ class HighlightingAnnotatorTest: AnnotatorTestCase(HighlightingAnnotator::class) """ ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test highlight methods`() = checkHighlighting( """ module 0x1::m { @@ -332,6 +334,20 @@ class HighlightingAnnotatorTest: AnnotatorTestCase(HighlightingAnnotator::class) """ ) + fun `test do not highlight methods if compiler v1`() = checkHighlighting( + """ + module 0x1::m { + struct S { field: u8 } + fun receiver(self: S, self: u8): u8 { + self.field + } + fun main(s: S) { + s.receiver(); + } + } + """ + ) + @CompilerV2Features(RESOURCE_CONTROL) fun `test resource access control keywords highlighting`() = checkHighlighting( """ diff --git a/src/test/kotlin/org/move/ide/annotator/errors/NeedsTypeAnnotationTest.kt b/src/test/kotlin/org/move/ide/annotator/errors/NeedsTypeAnnotationTest.kt index e391f5c9d..2b29e7fa4 100644 --- a/src/test/kotlin/org/move/ide/annotator/errors/NeedsTypeAnnotationTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/errors/NeedsTypeAnnotationTest.kt @@ -2,6 +2,8 @@ package org.move.ide.annotator.errors import org.move.ide.annotator.MvErrorAnnotator import org.move.ide.inspections.MvTypeCheckInspection +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.WithEnabledInspections import org.move.utils.tests.annotation.AnnotatorTestCase @@ -128,6 +130,7 @@ class NeedsTypeAnnotationTest: AnnotatorTestCase(MvErrorAnnotator::class) { } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test method type arguments uninferrable`() = checkErrors(""" module 0x1::main { struct S { field: u8 } diff --git a/src/test/kotlin/org/move/ide/annotator/errors/TypeParametersNumberErrorTest.kt b/src/test/kotlin/org/move/ide/annotator/errors/TypeParametersNumberErrorTest.kt index 0b2c0c109..4c4a575f0 100644 --- a/src/test/kotlin/org/move/ide/annotator/errors/TypeParametersNumberErrorTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/errors/TypeParametersNumberErrorTest.kt @@ -1,6 +1,8 @@ package org.move.ide.annotator.errors import org.move.ide.annotator.MvErrorAnnotator +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.AnnotatorTestCase class TypeParametersNumberErrorTest: AnnotatorTestCase(MvErrorAnnotator::class) { @@ -175,6 +177,7 @@ class TypeParametersNumberErrorTest: AnnotatorTestCase(MvErrorAnnotator::class) } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test receiver style method missing type parameter`() = checkErrors(""" module 0x1::main { struct S { field: T } diff --git a/src/test/kotlin/org/move/ide/annotator/errors/ValueArgumentsNumberErrorTest.kt b/src/test/kotlin/org/move/ide/annotator/errors/ValueArgumentsNumberErrorTest.kt index bd956f24b..d904975c5 100644 --- a/src/test/kotlin/org/move/ide/annotator/errors/ValueArgumentsNumberErrorTest.kt +++ b/src/test/kotlin/org/move/ide/annotator/errors/ValueArgumentsNumberErrorTest.kt @@ -1,6 +1,8 @@ package org.move.ide.annotator.errors import org.move.ide.annotator.MvErrorAnnotator +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.AnnotatorTestCase class ValueArgumentsNumberErrorTest: AnnotatorTestCase(MvErrorAnnotator::class) { @@ -33,6 +35,7 @@ class ValueArgumentsNumberErrorTest: AnnotatorTestCase(MvErrorAnnotator::class) } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test invalid number of parameters receiver style`() = checkErrors(""" module 0x1::M { struct S { field: u8 } diff --git a/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/ReceiverStyleFunctionsTest.kt b/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/ReceiverStyleFunctionsTest.kt new file mode 100644 index 000000000..4258d5c36 --- /dev/null +++ b/src/test/kotlin/org/move/ide/annotator/syntaxErrors/compilerV2/ReceiverStyleFunctionsTest.kt @@ -0,0 +1,30 @@ +package org.move.ide.annotator.syntaxErrors.compilerV2 + +import org.move.ide.annotator.MvSyntaxErrorAnnotator +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features +import org.move.utils.tests.annotation.AnnotatorTestCase + +class ReceiverStyleFunctionsTest: AnnotatorTestCase(MvSyntaxErrorAnnotator::class) { + @CompilerV2Features() + fun `test cannot use receiver style functions in compiler v1`() = checkWarnings(""" + module 0x1::m { + struct S { field: u8 } + fun receiver(self: &S): u8 { self.field } + fun call(s: S) { + s.receiver(); + } + } + """) + + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) + fun `test receiver style functions in compiler v2`() = checkWarnings(""" + module 0x1::m { + struct S { field: u8 } + fun receiver(self: &S): u8 { self.field } + fun call(s: S) { + s.receiver(); + } + } + """) +} \ No newline at end of file diff --git a/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt b/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt index 5be3723c0..61762aeb3 100644 --- a/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt +++ b/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt @@ -2,6 +2,8 @@ package org.move.ide.hints import com.intellij.codeInsight.daemon.impl.HintRenderer import org.intellij.lang.annotations.Language +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.MvTestBase class InlayParameterHintsTest: MvTestBase() { @@ -61,6 +63,7 @@ class InlayParameterHintsTest: MvTestBase() { """ ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test receiver style fun`() = checkByText( """ module 0x1::m { diff --git a/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt b/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt index 7905a1328..3deb162d0 100644 --- a/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt +++ b/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt @@ -1,6 +1,8 @@ package org.move.ide.hints +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.lang.core.psi.MvValueArgumentList +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.ParameterInfoHandlerTestCase class ParameterInfoHandlerTest @@ -153,6 +155,7 @@ class ParameterInfoHandlerTest """, "val1: u8, val2: u8, val3: u8", 2 ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test receiver style fun`() = checkByText( """ module 0x1::m { diff --git a/src/test/kotlin/org/move/ide/inspections/MvMissingAcquiresInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvMissingAcquiresInspectionTest.kt index e9277ee20..df5ede9e7 100644 --- a/src/test/kotlin/org/move/ide/inspections/MvMissingAcquiresInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/MvMissingAcquiresInspectionTest.kt @@ -1,6 +1,7 @@ package org.move.ide.inspections import org.move.ide.inspections.fixes.CompilerV2Feat.INDEXING +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.InspectionTestBase @@ -197,6 +198,7 @@ module 0x1::main { } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test missing acquires with receiver style`() = checkErrors( """ module 0x1::M { diff --git a/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt index 01852e8ad..abe67c34b 100644 --- a/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/MvUnusedAcquiresTypeInspectionTest.kt @@ -1,6 +1,7 @@ package org.move.ide.inspections import org.move.ide.inspections.fixes.CompilerV2Feat.INDEXING +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.InspectionTestBase @@ -25,6 +26,7 @@ class MvUnusedAcquiresTypeInspectionTest: InspectionTestBase(MvUnusedAcquiresTyp } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test no error if acquires type with receiver style`() = checkWarnings( """ module 0x1::M { diff --git a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt b/src/test/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithMethodCallInspectionProjectTest.kt similarity index 94% rename from src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt rename to src/test/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithMethodCallInspectionProjectTest.kt index 14782ca85..c0a071dff 100644 --- a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionProjectTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithMethodCallInspectionProjectTest.kt @@ -1,11 +1,14 @@ -package org.move.ide.inspections +package org.move.ide.inspections.compilerV2 import org.intellij.lang.annotations.Language +import org.move.ide.inspections.ReplaceWithMethodCallInspection import org.move.ide.inspections.fixes.CompilerV2Feat.INDEXING +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.FileTreeBuilder import org.move.utils.tests.annotation.InspectionProjectTestBase +@CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) class ReplaceWithMethodCallInspectionProjectTest: InspectionProjectTestBase(ReplaceWithMethodCallInspection::class) { @@ -110,7 +113,7 @@ class ReplaceWithMethodCallInspectionProjectTest: } """) - @CompilerV2Features(INDEXING) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS, INDEXING) fun `test replace with method call with index expr`() = doFixTest( { namedMoveToml("MyPackage") diff --git a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt b/src/test/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithMethodCallInspectionTest.kt similarity index 93% rename from src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt rename to src/test/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithMethodCallInspectionTest.kt index 083217fa1..cc55ff28d 100644 --- a/src/test/kotlin/org/move/ide/inspections/ReplaceWithMethodCallInspectionTest.kt +++ b/src/test/kotlin/org/move/ide/inspections/compilerV2/ReplaceWithMethodCallInspectionTest.kt @@ -1,8 +1,12 @@ -package org.move.ide.inspections +package org.move.ide.inspections.compilerV2 import org.intellij.lang.annotations.Language +import org.move.ide.inspections.ReplaceWithMethodCallInspection +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.annotation.InspectionTestBase +@CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) class ReplaceWithMethodCallInspectionTest: InspectionTestBase(ReplaceWithMethodCallInspection::class) { fun `test no warning if first parameter is not self`() = doTest( @@ -17,6 +21,19 @@ class ReplaceWithMethodCallInspectionTest: InspectionTestBase(ReplaceWithMethodC """ ) + @CompilerV2Features() + fun `test no warning if compiler v1`() = doTest( + """ + module 0x1::main { + struct S { field: u8 } + fun get_field(self: &S): u8 { self.field } + fun main(s: S) { + get_field(&s); + } + } + """ + ) + fun `test no warning if first parameter has different type`() = doTest( """ module 0x1::main { diff --git a/src/test/kotlin/org/move/lang/completion/CompletionPrioritiesTest.kt b/src/test/kotlin/org/move/lang/completion/CompletionPrioritiesTest.kt index 6382671ec..aa4c49fdf 100644 --- a/src/test/kotlin/org/move/lang/completion/CompletionPrioritiesTest.kt +++ b/src/test/kotlin/org/move/lang/completion/CompletionPrioritiesTest.kt @@ -1,7 +1,9 @@ package org.move.lang.completion import org.intellij.lang.annotations.Language +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.lang.core.psi.MvQualNamedElement +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.completion.CompletionTestCase class CompletionPrioritiesTest : CompletionTestCase() { @@ -139,6 +141,7 @@ module 0x1::Main { """ ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test method return type`() = checkCompletionsOrder( listOf("get_member2", "get_member1"), """ @@ -153,6 +156,7 @@ module 0x1::Main { """ ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test method return type with ref`() = checkCompletionsOrder( listOf("borrow", "borrow_with_default", "borrow_buckets"), """ diff --git a/src/test/kotlin/org/move/lang/completion/compilerV2/ReceiverStyleCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/compilerV2/ReceiverStyleCompletionTest.kt new file mode 100644 index 000000000..f309637c5 --- /dev/null +++ b/src/test/kotlin/org/move/lang/completion/compilerV2/ReceiverStyleCompletionTest.kt @@ -0,0 +1,115 @@ +package org.move.lang.completion.compilerV2 + +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features +import org.move.utils.tests.completion.CompletionTestCase + +@CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) +class ReceiverStyleCompletionTest: CompletionTestCase() { + @CompilerV2Features() + fun `test no function completion if compiler v1`() = checkNoCompletion(""" + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): u8 {} + fun main(s: S) { + s.rece/*caret*/ + } + } + """) + + fun `test function completion`() = doSingleCompletion(""" + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): u8 {} + fun main(s: S) { + s.rece/*caret*/ + } + } + """, """ + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): u8 {} + fun main(s: S) { + s.receiver()/*caret*/ + } + } + """) + + fun `test function completion with assignment`() = doSingleCompletion(""" + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): Z {} + fun main(s: S) { + let f: u8 = s.rece/*caret*/ + } + } + """, """ + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): Z {} + fun main(s: S) { + let f: u8 = s.receiver()/*caret*/ + } + } + """) + + fun `test function completion from another module`() = doSingleCompletion(""" + module 0x1::m { + struct S { field: u8 } + public fun receiver(self: &S): u8 {} + } + module 0x1::main { + use 0x1::m::S; + fun main(s: S) { + s.rece/*caret*/ + } + } + """, """ + module 0x1::m { + struct S { field: u8 } + public fun receiver(self: &S): u8 {} + } + module 0x1::main { + use 0x1::m::S; + fun main(s: S) { + s.receiver()/*caret*/ + } + } + """) + + fun `test function completion type annotation required`() = doSingleCompletion(""" + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): Z {} + fun main(s: S) { + s.rece/*caret*/; + } + } + """, """ + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): Z {} + fun main(s: S) { + s.receiver::(); + } + } + """) + + fun `test function completion type annotation required with angle brackets present`() = doSingleCompletion(""" + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): Z {} + fun main(s: S) { + s.rece/*caret*/::<>() + } + } + """, """ + module 0x1::main { + struct S { field: u8 } + fun receiver(self: &S): Z {} + fun main(s: S) { + s.receiver::() + } + } + """) +} \ No newline at end of file diff --git a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt index 601a3dd84..0189e0077 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt @@ -8,6 +8,7 @@ import com.intellij.codeInsight.lookup.LookupElementPresentation import com.intellij.patterns.ElementPattern import com.intellij.psi.NavigatablePsiElement import org.intellij.lang.annotations.Language +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.lang.core.completion.CompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.completion.providers.MethodOrFieldCompletionProvider @@ -16,11 +17,12 @@ import org.move.lang.core.psi.MvNamedElement import org.move.lang.core.psi.ext.MvMethodOrField import org.move.lang.core.resolve.ContextScopeInfo import org.move.lang.core.resolve.ref.MvReferenceElement +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.MvTestBase import org.move.utils.tests.base.findElementInEditor class LookupElementTest: MvTestBase() { - fun `test function param`() = check( + fun `test function param`() = checkNamedItem( """ module 0x1::M { fun call(a: u8) { @@ -30,7 +32,7 @@ class LookupElementTest: MvTestBase() { """, typeText = "u8" ) - fun `test function`() = check( + fun `test function`() = checkNamedItem( """ module 0x1::M { fun call(x: u64, account: &signer): u8 {} @@ -39,7 +41,7 @@ class LookupElementTest: MvTestBase() { """, tailText = "(x: u64, account: &signer): u8", typeText = "main.move" ) - fun `test multiline params function`() = check( + fun `test multiline params function`() = checkNamedItem( """ module 0x1::M { fun call(x: u64, @@ -49,7 +51,7 @@ class LookupElementTest: MvTestBase() { """, tailText = "(x: u64, account: &signer): u8", typeText = "main.move" ) - fun `test const item`() = check( + fun `test const item`() = checkNamedItem( """ module 0x1::M { const MY_CONST: u8 = 1; @@ -58,7 +60,7 @@ class LookupElementTest: MvTestBase() { """, typeText = "u8" ) - fun `test struct`() = check( + fun `test struct`() = checkNamedItem( """ module 0x1::M { struct MyStruct { val: u8 } @@ -67,7 +69,7 @@ class LookupElementTest: MvTestBase() { """, tailText = " { ... }", typeText = "main.move" ) - fun `test module`() = check( + fun `test module`() = checkNamedItem( """ address 0x1 { module M {} @@ -76,7 +78,7 @@ class LookupElementTest: MvTestBase() { """, tailText = " 0x1", typeText = "main.move" ) - fun `test module with named address`() = check( + fun `test module with named address`() = checkNamedItem( """ module Std::M {} //^ @@ -96,6 +98,22 @@ class LookupElementTest: MvTestBase() { """, typeText = "u8" ) + @CompilerV2Features() + fun `test self method without receiver style enabled`() = checkNamedItem( + """ + module 0x1::main { + struct S { field: T } + fun receiver(self: S): T {} + //^ + fun main() { + let s = S { field: 1u8 }; + receiver(s); + } + } + """, tailText = "(self: S): T", typeText = "main.move" + ) + + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test generic method`() = checkMethodOrFieldProvider( """ module 0x1::main { @@ -110,6 +128,7 @@ class LookupElementTest: MvTestBase() { """, tailText = "(self)", typeText = "u8" ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test generic method ref`() = checkMethodOrFieldProvider( """ module 0x1::main { @@ -124,6 +143,7 @@ class LookupElementTest: MvTestBase() { """, tailText = "(&self)", typeText = "u8" ) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test generic method ref mut`() = checkMethodOrFieldProvider( """ module 0x1::main { @@ -138,7 +158,7 @@ class LookupElementTest: MvTestBase() { """, tailText = "(&mut self)", typeText = "u8" ) - fun `test import module lookup`() = check(""" + fun `test import module lookup`() = checkNamedItem(""" module 0x1::m { public fun identity(a: u8): u8 { a } } @@ -148,7 +168,7 @@ class LookupElementTest: MvTestBase() { } """, tailText = " 0x1", typeText = "main.move") - fun `test import function lookup`() = check(""" + fun `test import function lookup`() = checkNamedItem(""" module 0x1::m { public fun identity(a: u8): u8 { a } } @@ -158,7 +178,7 @@ class LookupElementTest: MvTestBase() { } """, tailText = "(a: u8): u8", typeText = "main.move") - private fun check( + private fun checkNamedItem( @Language("Move") code: String, tailText: String? = null, typeText: String? = null, diff --git a/src/test/kotlin/org/move/lang/completion/names/DotAccessCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/DotAccessCompletionTest.kt index 7fef96c55..18c3d3447 100644 --- a/src/test/kotlin/org/move/lang/completion/names/DotAccessCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/DotAccessCompletionTest.kt @@ -74,102 +74,6 @@ module 0x1::M { } """) - fun `test receiver style function completion`() = doSingleCompletion(""" - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): u8 {} - fun main(s: S) { - s.rece/*caret*/ - } - } - """, """ - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): u8 {} - fun main(s: S) { - s.receiver()/*caret*/ - } - } - """) - - fun `test receiver style function completion with assignment`() = doSingleCompletion(""" - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): Z {} - fun main(s: S) { - let f: u8 = s.rece/*caret*/ - } - } - """, """ - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): Z {} - fun main(s: S) { - let f: u8 = s.receiver()/*caret*/ - } - } - """) - - fun `test receiver style function completion from another module`() = doSingleCompletion(""" - module 0x1::m { - struct S { field: u8 } - public fun receiver(self: &S): u8 {} - } - module 0x1::main { - use 0x1::m::S; - fun main(s: S) { - s.rece/*caret*/ - } - } - """, """ - module 0x1::m { - struct S { field: u8 } - public fun receiver(self: &S): u8 {} - } - module 0x1::main { - use 0x1::m::S; - fun main(s: S) { - s.receiver()/*caret*/ - } - } - """) - - fun `test receiver style function completion type annotation required`() = doSingleCompletion(""" - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): Z {} - fun main(s: S) { - s.rece/*caret*/; - } - } - """, """ - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): Z {} - fun main(s: S) { - s.receiver::(); - } - } - """) - - fun `test receiver style function completion type annotation required with angle brackets present`() = doSingleCompletion(""" - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): Z {} - fun main(s: S) { - s.rece/*caret*/::<>() - } - } - """, """ - module 0x1::main { - struct S { field: u8 } - fun receiver(self: &S): Z {} - fun main(s: S) { - s.receiver::() - } - } - """) - fun `test fields are not available from another module`() = checkNoCompletion(""" module 0x1::m { struct S { field: u8 } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt index 0f93076c0..c45580f16 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveFunctionTest.kt @@ -725,176 +725,4 @@ module 0x1::mod { } } """) - - fun `test resolve receiver function`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver(self: S, y: u64): u64 { - //X - self.x + y - } - fun test_call_styles(s: S): u64 { - s.receiver(1) - //^ - } - } - """) - - fun `test resolve receiver function with reference`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver_ref(self: &S, y: u64): u64 { - //X - self.x + y - } - fun test_call_styles(s: S): u64 { - s.receiver_ref(1) - //^ - } - } - """) - - fun `test resolve receiver function with mut reference`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver_mut_ref(self: &mut S, y: u64): u64 { - //X - self.x + y - } - fun test_call_styles(s: S): u64 { - s.receiver_mut_ref(1) - //^ - } - } - """) - - fun `test resolve receiver function with inline mut reference`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - inline fun receiver_mut_ref(self: &mut S, y: u64): u64 { - //X - self.x + y - } - fun test_call_styles(s: S): u64 { - s.receiver_mut_ref(1) - //^ - } - } - """) - - fun `test cannot be resolved if self has another type`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - struct T { x: u64 } - fun receiver(self: T, y: u64): u64 { - self.x + y - } - fun test_call_styles(s: S): u64 { - s.receiver(1) - //^ unresolved - } - } - """) - - fun `test cannot be resolved if self requires mutable reference`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver(self: &mut S, y: u64): u64 { - self.x + y - } - fun test_call_styles(s: &S): u64 { - s.receiver(1) - //^ unresolved - } - } - """) - - fun `test cannot be resolved if self requires no reference`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver(self: S, y: u64): u64 { - self.x + y - } - fun test_call_styles(s: &mut S): u64 { - s.receiver(1) - //^ unresolved - } - } - """) - - fun `test receiver resolvable if self requires reference but mut reference exists`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver(self: &S, y: u64): u64 { - //X - self.x + y - } - fun test_call_styles(s: &mut S): u64 { - s.receiver(1) - //^ - } - } - """) - - fun `test public receiver style from another module`() = checkByCode(""" - module 0x1::m { - struct S { x: u64 } - public fun receiver(self: S, y: u64): u64 { - //X - self.x + y - } - } - module 0x1::main { - use 0x1::m::S; - - fun test_call_styles(s: S): u64 { - s.receiver(1) - //^ - } - } - """) - - fun `test unresolved private receiver style from another module`() = checkByCode(""" - module 0x1::m { - struct S { x: u64 } - fun receiver(self: S, y: u64): u64 { - self.x + y - } - } - module 0x1::main { - use 0x1::m::S; - - fun test_call_styles(s: S): u64 { - s.receiver(1) - //^ unresolved - } - } - """) - - fun `test resolve receiver style with generic argument`() = checkByCode(""" - module 0x1::main { - struct S { field: T } - fun receiver(self: S): T { - //X - self.field - } - fun main(s: S) { - s.receiver() - //^ - } - } - """) - - fun `test method cannot be resolved if self is not the first parameter`() = checkByCode(""" - module 0x1::main { - struct S { x: u64 } - fun receiver(y: u64, self: &S): u64 { - self.x + y - } - fun test_call_styles(s: S): u64 { - s.receiver(&s) - //^ unresolved - } - } - """) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt index 208e9d077..b10298c30 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveItemsTreeProjectTest.kt @@ -540,77 +540,4 @@ module 0x1::main { """) } } - - fun `test resolve vector method if stdlib vector module present`() = checkByFileTree { - namedMoveToml("MyPackage") - sources { - move("vector.move", """ - module 0x1::vector { - public native fun length(self: &vector): u8; - //X - } - """) - main(""" - module 0x1::main { - fun main() { - vector[1].length(); - //^ - } - } - """) - } - } - - fun `test resolve vector reference method if stdlib vector module present`() = checkByFileTree { - namedMoveToml("MyPackage") - sources { - move("vector.move", """ - module 0x1::vector { - public native fun length(self: &vector): u8; - //X - } - """) - main(""" - module 0x1::main { - fun main() { - (&vector[1]).length(); - //^ - } - } - """) - } - } - - fun `test vector method unresolved if no stdlib module`() = checkByFileTree { - namedMoveToml("MyPackage") - sources { - main(""" - module 0x1::main { - fun main() { - vector[1].length(); - //^ unresolved - } - } - """) - } - } - - fun `test vector method unresolved if address of vector module is different`() = checkByFileTree { - namedMoveToml("MyPackage") - sources { - move("vector.move", """ - module 0x2::vector { - public native fun length(self: &vector): u8; - } - """) - main(""" - module 0x1::main { - fun main() { - vector[1].length(); - //^ unresolved - } - } - """) - } - } } diff --git a/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionProjectTest.kt b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionProjectTest.kt new file mode 100644 index 000000000..d9f0ac907 --- /dev/null +++ b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionProjectTest.kt @@ -0,0 +1,82 @@ +package org.move.lang.resolve.compilerV2 + +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features +import org.move.utils.tests.resolve.ResolveProjectTestCase + +@CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) +class ReceiverStyleFunctionProjectTest: ResolveProjectTestCase() { + + fun `test resolve vector method if stdlib vector module present`() = checkByFileTree { + namedMoveToml("MyPackage") + sources { + move("vector.move", """ + module 0x1::vector { + public native fun length(self: &vector): u8; + //X + } + """) + main(""" + module 0x1::main { + fun main() { + vector[1].length(); + //^ + } + } + """) + } + } + + fun `test resolve vector reference method if stdlib vector module present`() = checkByFileTree { + namedMoveToml("MyPackage") + sources { + move("vector.move", """ + module 0x1::vector { + public native fun length(self: &vector): u8; + //X + } + """) + main(""" + module 0x1::main { + fun main() { + (&vector[1]).length(); + //^ + } + } + """) + } + } + + fun `test vector method unresolved if no stdlib module`() = checkByFileTree { + namedMoveToml("MyPackage") + sources { + main(""" + module 0x1::main { + fun main() { + vector[1].length(); + //^ unresolved + } + } + """) + } + } + + fun `test vector method unresolved if address of vector module is different`() = checkByFileTree { + namedMoveToml("MyPackage") + sources { + move("vector.move", """ + module 0x2::vector { + public native fun length(self: &vector): u8; + } + """) + main(""" + module 0x1::main { + fun main() { + vector[1].length(); + //^ unresolved + } + } + """) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt new file mode 100644 index 000000000..4c24c29db --- /dev/null +++ b/src/test/kotlin/org/move/lang/resolve/compilerV2/ReceiverStyleFunctionTest.kt @@ -0,0 +1,181 @@ +package org.move.lang.resolve.compilerV2 + +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features +import org.move.utils.tests.resolve.ResolveTestCase + +@CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) +class ReceiverStyleFunctionTest: ResolveTestCase() { + + fun `test resolve receiver function`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver(self: S, y: u64): u64 { + //X + self.x + y + } + fun test_call_styles(s: S): u64 { + s.receiver(1) + //^ + } + } + """) + + fun `test resolve receiver function with reference`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver_ref(self: &S, y: u64): u64 { + //X + self.x + y + } + fun test_call_styles(s: S): u64 { + s.receiver_ref(1) + //^ + } + } + """) + + fun `test resolve receiver function with mut reference`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver_mut_ref(self: &mut S, y: u64): u64 { + //X + self.x + y + } + fun test_call_styles(s: S): u64 { + s.receiver_mut_ref(1) + //^ + } + } + """) + + fun `test resolve receiver function with inline mut reference`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + inline fun receiver_mut_ref(self: &mut S, y: u64): u64 { + //X + self.x + y + } + fun test_call_styles(s: S): u64 { + s.receiver_mut_ref(1) + //^ + } + } + """) + + fun `test cannot be resolved if self has another type`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + struct T { x: u64 } + fun receiver(self: T, y: u64): u64 { + self.x + y + } + fun test_call_styles(s: S): u64 { + s.receiver(1) + //^ unresolved + } + } + """) + + fun `test cannot be resolved if self requires mutable reference`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver(self: &mut S, y: u64): u64 { + self.x + y + } + fun test_call_styles(s: &S): u64 { + s.receiver(1) + //^ unresolved + } + } + """) + + fun `test cannot be resolved if self requires no reference`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver(self: S, y: u64): u64 { + self.x + y + } + fun test_call_styles(s: &mut S): u64 { + s.receiver(1) + //^ unresolved + } + } + """) + + fun `test receiver resolvable if self requires reference but mut reference exists`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver(self: &S, y: u64): u64 { + //X + self.x + y + } + fun test_call_styles(s: &mut S): u64 { + s.receiver(1) + //^ + } + } + """) + + fun `test public receiver style from another module`() = checkByCode(""" + module 0x1::m { + struct S { x: u64 } + public fun receiver(self: S, y: u64): u64 { + //X + self.x + y + } + } + module 0x1::main { + use 0x1::m::S; + + fun test_call_styles(s: S): u64 { + s.receiver(1) + //^ + } + } + """) + + fun `test unresolved private receiver style from another module`() = checkByCode(""" + module 0x1::m { + struct S { x: u64 } + fun receiver(self: S, y: u64): u64 { + self.x + y + } + } + module 0x1::main { + use 0x1::m::S; + + fun test_call_styles(s: S): u64 { + s.receiver(1) + //^ unresolved + } + } + """) + + fun `test resolve receiver style with generic argument`() = checkByCode(""" + module 0x1::main { + struct S { field: T } + fun receiver(self: S): T { + //X + self.field + } + fun main(s: S) { + s.receiver() + //^ + } + } + """) + + fun `test method cannot be resolved if self is not the first parameter`() = checkByCode(""" + module 0x1::main { + struct S { x: u64 } + fun receiver(y: u64, self: &S): u64 { + self.x + y + } + fun test_call_styles(s: S): u64 { + s.receiver(&s) + //^ unresolved + } + } + """) +} \ No newline at end of file diff --git a/src/test/kotlin/org/move/lang/types/CallableTypeTest.kt b/src/test/kotlin/org/move/lang/types/CallableTypeTest.kt index 356565b55..53bd1f67b 100644 --- a/src/test/kotlin/org/move/lang/types/CallableTypeTest.kt +++ b/src/test/kotlin/org/move/lang/types/CallableTypeTest.kt @@ -1,16 +1,19 @@ package org.move.lang.types import org.intellij.lang.annotations.Language +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS import org.move.ide.presentation.text import org.move.lang.core.psi.MvMethodCall import org.move.lang.core.psi.ext.MvCallable import org.move.lang.core.psi.ext.isMsl import org.move.lang.core.types.infer.inference +import org.move.utils.tests.CompilerV2Features import org.move.utils.tests.InlineFile import org.move.utils.tests.base.findElementAndDataInEditor import org.move.utils.tests.types.TypificationTestCase class CallableTypeTest: TypificationTestCase() { + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test infer method type`() = testMethodType(""" module 0x1::main { struct S { field: T } @@ -24,6 +27,7 @@ class CallableTypeTest: TypificationTestCase() { } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test infer method type not enough parameters`() = testMethodType(""" module 0x1::main { struct S { field: T } @@ -37,6 +41,7 @@ class CallableTypeTest: TypificationTestCase() { } """) + @CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) fun `test infer method type cannot autoborrow unknown function`() = testMethodType(""" module 0x1::main { struct S { field: T } diff --git a/src/test/kotlin/org/move/lang/types/ExpressionTypeInferenceTest.kt b/src/test/kotlin/org/move/lang/types/ExpressionTypeInferenceTest.kt index 055e50d31..bc813d555 100644 --- a/src/test/kotlin/org/move/lang/types/ExpressionTypeInferenceTest.kt +++ b/src/test/kotlin/org/move/lang/types/ExpressionTypeInferenceTest.kt @@ -521,44 +521,4 @@ module 0x1::main { // } // """ // ) - - fun `test infer receiver style function type generic self`() = testExpr(""" - module 0x1::main { - struct S { field: T } - fun receiver(self: S): T { - self.field - } - fun main(s: S) { - s.receiver(); - //^ u8 - } - } - """) - - fun `test infer receiver style function type generic param`() = testExpr(""" - module 0x1::main { - struct S { field: u8 } - fun receiver(self: S, p: T): T { - p - } - fun main(s: S) { - s.receiver(1u8); - //^ u8 - } - } - """) - - fun `test method infer parameter type`() = testExpr(""" - module 0x1::main { - struct S { field: T } - fun receiver(self: &S, param: U): U { - param - } - fun main(s: S) { - let a = s.receiver(1); - a; - //^ integer - } - } - """) } diff --git a/src/test/kotlin/org/move/lang/types/compilerV2/ReceiverStyleFunctionsTest.kt b/src/test/kotlin/org/move/lang/types/compilerV2/ReceiverStyleFunctionsTest.kt new file mode 100644 index 000000000..c3ccda5b5 --- /dev/null +++ b/src/test/kotlin/org/move/lang/types/compilerV2/ReceiverStyleFunctionsTest.kt @@ -0,0 +1,48 @@ +package org.move.lang.types.compilerV2 + +import org.move.ide.inspections.fixes.CompilerV2Feat.RECEIVER_STYLE_FUNCTIONS +import org.move.utils.tests.CompilerV2Features +import org.move.utils.tests.types.TypificationTestCase + +@CompilerV2Features(RECEIVER_STYLE_FUNCTIONS) +class ReceiverStyleFunctionsTest: TypificationTestCase() { + fun `test infer receiver style function type generic self`() = testExpr(""" + module 0x1::main { + struct S { field: T } + fun receiver(self: S): T { + self.field + } + fun main(s: S) { + s.receiver(); + //^ u8 + } + } + """) + + fun `test infer receiver style function type generic param`() = testExpr(""" + module 0x1::main { + struct S { field: u8 } + fun receiver(self: S, p: T): T { + p + } + fun main(s: S) { + s.receiver(1u8); + //^ u8 + } + } + """) + + fun `test method infer parameter type`() = testExpr(""" + module 0x1::main { + struct S { field: T } + fun receiver(self: &S, param: U): U { + param + } + fun main(s: S) { + let a = s.receiver(1); + a; + //^ integer + } + } + """) +} \ No newline at end of file