From 64f076639dcfa385aa4d78a25c1043bee8a51c57 Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Fri, 30 Aug 2024 21:32:18 +0300 Subject: [PATCH] restrict types visibility, add binding completion for match arms --- .../move/ide/annotator/MvErrorAnnotator.kt | 2 +- .../utils/imports/ImportCandidateCollector.kt | 5 +- .../completion/CommonCompletionContributor.kt | 3 +- .../lang/core/completion/LookupElements.kt | 8 +- .../lang/core/completion/LookupElements2.kt | 4 +- .../lang/core/completion/MvLookupElement.kt | 2 +- .../providers/CommonCompletionProvider.kt | 4 - .../MethodOrFieldCompletionProvider.kt | 4 +- .../providers/MvPathCompletionProvider2.kt | 37 +++-- .../providers/ReferenceCompletionProvider.kt | 77 ++++++++++ .../SchemaFieldsCompletionProvider.kt | 4 +- .../StructFieldsCompletionProvider.kt | 18 +-- .../providers/StructPatCompletionProvider.kt | 4 +- .../org/move/lang/core/psi/MvFunctionLike.kt | 4 +- .../org/move/lang/core/psi/ext/MvFieldPat.kt | 2 +- .../lang/core/psi/ext/MvStructLitField.kt | 2 +- .../core/psi/ext/MvStructOrEnumItemElement.kt | 18 +-- .../org/move/lang/core/psi/ext/MvStructPat.kt | 3 +- .../lang/core/psi/ext/MvVisibilityOwner.kt | 2 - .../org/move/lang/core/resolve/Processors.kt | 14 +- .../core/resolve/ref/MoveReferenceElement.kt | 4 - .../move/lang/core/resolve/ref/Namespace.kt | 1 + .../move/lang/core/resolve2/ItemResolution.kt | 6 +- .../core/resolve2/LexicalDeclarations2.kt | 19 +-- .../lang/core/resolve2/NameResolution2.kt | 7 +- .../move/lang/core/resolve2/Visibility2.kt | 33 +++-- .../kotlin/org/move/stdext/Collections.kt | 5 +- .../lookups/BuiltInFunctionLookupTest.kt | 4 +- .../completion/lookups/LookupElementTest.kt | 4 +- .../completion/names/StructsCompletionTest.kt | 53 +++++++ .../move/lang/parser/PartialParsingTest.kt | 2 + .../org/move/lang/resolve/ResolveTypesTest.kt | 32 +++- .../move/lang/parser/partial/enum_match.move | 9 ++ .../move/lang/parser/partial/enum_match.txt | 138 ++++++++++++++++++ 34 files changed, 420 insertions(+), 114 deletions(-) create mode 100644 src/main/kotlin/org/move/lang/core/completion/providers/ReferenceCompletionProvider.kt create mode 100644 src/test/resources/org/move/lang/parser/partial/enum_match.move create mode 100644 src/test/resources/org/move/lang/parser/partial/enum_match.txt diff --git a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt index e6cd38d68..a36aeb0f3 100644 --- a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt @@ -153,7 +153,7 @@ class MvErrorAnnotator: MvAnnotatorBase() { val nameElement = o.path.referenceNameElement ?: return val refStruct = o.path.maybeStruct ?: return checkMissingFields( - moveHolder, nameElement, o.providedFieldNames, refStruct + moveHolder, nameElement, o.fieldNames, refStruct ) } diff --git a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt index b352af71a..54d42b1cd 100644 --- a/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt +++ b/src/main/kotlin/org/move/ide/utils/imports/ImportCandidateCollector.kt @@ -3,6 +3,8 @@ package org.move.ide.utils.imports import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement import org.move.ide.inspections.imports.ImportContext import org.move.lang.core.psi.MvQualNamedElement import org.move.lang.core.resolve.VisibilityStatus.Visible @@ -41,13 +43,12 @@ object ImportCandidateCollector { } fun getCompletionCandidates( - parameters: CompletionParameters, + project: Project, prefixMatcher: PrefixMatcher, processedPathNames: Set, importContext: ImportContext, // itemFilter: (PsiElement) -> Boolean = { true } ): List { - val project = parameters.position.project val keys = hashSetOf().apply { val names = MvNamedElementIndex.getAllKeys(project) addAll(names) diff --git a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt index 101441c85..aac24bebd 100644 --- a/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt +++ b/src/main/kotlin/org/move/lang/core/completion/CommonCompletionContributor.kt @@ -9,7 +9,6 @@ import org.move.lang.core.MvPsiPattern import org.move.lang.core.completion.providers.* import org.move.lang.core.completion.sort.COMPLETION_WEIGHERS_GROUPED import org.move.lang.core.psi.MvModule -import org.move.lang.core.psi.ext.nextNonWsSibling import org.move.lang.core.psi.ext.prevNonWsSibling class CommonCompletionContributor: CompletionContributor() { @@ -35,7 +34,7 @@ class CommonCompletionContributor: CompletionContributor() { extend(CompletionType.BASIC, VectorLiteralCompletionProvider) extend(CompletionType.BASIC, MethodOrFieldCompletionProvider) -// extend(CompletionType.BASIC, CommonCompletionProvider) + extend(CompletionType.BASIC, ReferenceCompletionProvider) } fun extend(type: CompletionType?, provider: MvCompletionProvider) { diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt index fce866db4..f5a113e25 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements.kt @@ -54,7 +54,7 @@ fun MvNamedElement.createLookupElementWithIcon(): LookupElementBuilder { .withLookupString(this.name ?: "") } -data class CompletionContext( +data class MvCompletionContext( val contextElement: MvElement, val msl: Boolean, val expectedTy: Ty? = null, @@ -63,7 +63,7 @@ data class CompletionContext( ) fun MvNamedElement.createLookupElement( - completionContext: CompletionContext, + completionContext: MvCompletionContext, subst: Substitution = emptySubstitution, priority: Double = DEFAULT_PRIORITY, insertHandler: InsertHandler = DefaultInsertHandler(completionContext), @@ -126,7 +126,7 @@ class AngleBracketsInsertHandler: InsertHandler { } } -open class DefaultInsertHandler(val completionCtx: CompletionContext? = null): InsertHandler { +open class DefaultInsertHandler(val completionCtx: MvCompletionContext? = null): InsertHandler { final override fun handleInsert(context: InsertionContext, item: LookupElement) { val element = item.psiElement as? MvElement ?: return @@ -205,7 +205,7 @@ open class DefaultInsertHandler(val completionCtx: CompletionContext? = null): I } private fun MvNamedElement.getLookupElementBuilder( - completionCtx: CompletionContext, + completionCtx: MvCompletionContext, subst: Substitution = emptySubstitution, structAsType: Boolean = false ): LookupElementBuilder { diff --git a/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt b/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt index 4980a14d8..f59b6f2c0 100644 --- a/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/LookupElements2.kt @@ -15,7 +15,7 @@ import org.move.lang.core.types.ty.TyUnknown fun createLookupElement( scopeEntry: ScopeEntry, - completionContext: CompletionContext, + completionContext: MvCompletionContext, subst: Substitution = emptySubstitution, priority: Double = DEFAULT_PRIORITY, insertHandler: InsertHandler = DefaultInsertHandler(completionContext) @@ -29,7 +29,7 @@ fun createLookupElement( } private fun MvNamedElement.getLookupElementBuilder( - context: CompletionContext, + context: MvCompletionContext, scopeName: String, subst: Substitution = emptySubstitution, ): LookupElementBuilder { diff --git a/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt b/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt index 7e2fc6f33..b0495cba6 100644 --- a/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt +++ b/src/main/kotlin/org/move/lang/core/completion/MvLookupElement.kt @@ -56,7 +56,7 @@ data class LookupElementProperties( fun getLookupElementProperties( element: MvNamedElement, subst: Substitution, - context: CompletionContext + context: MvCompletionContext ): LookupElementProperties { var props = LookupElementProperties() val expectedTy = context.expectedTy diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/CommonCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/CommonCompletionProvider.kt index 420cbd486..50e0b9fc5 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/CommonCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/CommonCompletionProvider.kt @@ -6,13 +6,9 @@ import com.intellij.patterns.ElementPattern import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext -import org.jetbrains.annotations.VisibleForTesting -import org.move.lang.core.completion.CompletionContext -import org.move.lang.core.completion.getOriginalOrSelf import org.move.lang.core.completion.safeGetOriginalOrSelf import org.move.lang.core.psi.ext.isMsl import org.move.lang.core.psiElement -import org.move.lang.core.resolve.collectCompletionVariants import org.move.lang.core.resolve.ref.MvReferenceElement import org.move.lang.core.resolve2.ref.ResolutionContext diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt index 734e889c6..774073f7f 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MethodOrFieldCompletionProvider.kt @@ -7,7 +7,7 @@ import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext import org.jetbrains.annotations.VisibleForTesting -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvFunction import org.move.lang.core.psi.ext.* @@ -44,7 +44,7 @@ object MethodOrFieldCompletionProvider: MvCompletionProvider() { val receiverTy = element.inferReceiverTy(msl).knownOrNull() ?: return val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(element, msl) - val ctx = CompletionContext(element, msl, expectedTy) + val ctx = MvCompletionContext(element, msl, expectedTy) val tyAdt = receiverTy.derefIfNeeded() as? TyAdt if (tyAdt != null) { diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt index 1c9795368..50f7c4889 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/MvPathCompletionProvider2.kt @@ -9,7 +9,7 @@ import org.move.ide.inspections.imports.ImportContext import org.move.ide.utils.imports.ImportCandidate import org.move.ide.utils.imports.ImportCandidateCollector import org.move.lang.core.MvPsiPattern.path -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.completion.UNIMPORTED_ITEM_PRIORITY import org.move.lang.core.completion.createLookupElement import org.move.lang.core.completion.getOriginalOrSelf @@ -50,7 +50,7 @@ object MvPathCompletionProvider2: MvCompletionProvider() { val ns = pathKind.ns val structAsType = TYPES_N_ENUMS.intersects(ns) - val completionContext = CompletionContext( + val completionContext = MvCompletionContext( pathElement, msl, expectedTy, @@ -66,7 +66,7 @@ object MvPathCompletionProvider2: MvCompletionProvider() { fun addPathVariants( pathElement: MvPath, parameters: CompletionParameters, - completionContext: CompletionContext, + completionContext: MvCompletionContext, ns: Set, result: CompletionResultSet, ) { @@ -91,20 +91,38 @@ object MvPathCompletionProvider2: MvCompletionProvider() { ) } + addCompletionsForOutOfScopeItems( + parameters, + pathElement, + result, + completionContext, + ns, + processedNames + ) + } + + private fun addCompletionsForOutOfScopeItems( + parameters: CompletionParameters, + path: MvPath, + result: CompletionResultSet, + completionContext: MvCompletionContext, + ns: Set, + processedNames: MutableSet, + ) { // disable auto-import in module specs for now - if (pathElement.containingModuleSpec != null) return + if (path.containingModuleSpec != null) return // no out-of-scope completions for use specks - if (pathElement.isUseSpeck) return + if (path.isUseSpeck) return // no import candidates for qualified paths - if (pathElement.pathKind(true) is PathKind.QualifiedPath) return + if (path.pathKind(true) is PathKind.QualifiedPath) return val originalPathElement = parameters.originalPosition?.parent as? MvPath ?: return val importContext = ImportContext.from(originalPathElement, true, ns) ?: return val candidates = ImportCandidateCollector.getCompletionCandidates( - parameters, + path.project, result.prefixMatcher, processedNames, importContext, @@ -118,7 +136,8 @@ object MvPathCompletionProvider2: MvCompletionProvider() { ) result.addElement(lookupElement) } - candidatesCollector = applySharedCompletionFilters(ns, resolutionCtx, candidatesCollector) + candidatesCollector = + applySharedCompletionFilters(ns, completionContext.resolutionCtx!!, candidatesCollector) candidatesCollector.processAll( candidates.map { CandidateScopeEntry(it.qualName.itemName, it.element, ns, it) } ) @@ -149,7 +168,7 @@ fun applySharedCompletionFilters( } fun filterCompletionVariantsByVisibility( - context: MvMethodOrPath, + context: MvElement, processor: RsResolveProcessor ): RsResolveProcessor { return processor.wrapWithFilter { e -> diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/ReferenceCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/ReferenceCompletionProvider.kt new file mode 100644 index 000000000..1a5dccaaf --- /dev/null +++ b/src/main/kotlin/org/move/lang/core/completion/providers/ReferenceCompletionProvider.kt @@ -0,0 +1,77 @@ +package org.move.lang.core.completion.providers + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.patterns.ElementPattern +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.util.ProcessingContext +import org.move.lang.core.completion.MvCompletionContext +import org.move.lang.core.psi.MvPatBinding +import org.move.lang.core.psi.MvPatField +import org.move.lang.core.psi.ext.fieldNames +import org.move.lang.core.psi.ext.isMsl +import org.move.lang.core.psi.ext.parentPatStruct +import org.move.lang.core.psiElement +import org.move.lang.core.resolve.RsResolveProcessor +import org.move.lang.core.resolve.collectCompletionVariants +import org.move.lang.core.resolve.ref.MvReferenceElement +import org.move.lang.core.resolve.wrapWithFilter +import org.move.lang.core.resolve2.processPatBindingResolveVariants + +object ReferenceCompletionProvider: MvCompletionProvider() { + override val elementPattern: ElementPattern + get() = PlatformPatterns.psiElement().withParent(psiElement()) + + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + // Use original position if possible to re-use caches of the real file + val position = parameters.position + val element = position.parent as MvReferenceElement + if (position !== element.referenceNameElement) return + + val msl = element.isMsl() + val expectedTy = getExpectedTypeForEnclosingPathOrDotExpr(element, msl) + + val completionCtx = MvCompletionContext(element, msl, expectedTy) + + addCompletionVariants(element, result, completionCtx) + } + + fun addCompletionVariants( + element: MvReferenceElement, + result: CompletionResultSet, + context: MvCompletionContext, + ) { + collectCompletionVariants(result, context) { + val processor0 = filterCompletionVariantsByVisibility(element, it) + // todo: filter test functions + when (element) { + // `let Res/*caret*/ =` + // catches all modules, enums, enum variants and struct patterns + is MvPatBinding -> { + // for struct pat / lit, it filters out all the fields already existing in the body + val processor = skipAlreadyProvidedFields(element, processor0) + processPatBindingResolveVariants(element, true, processor) + } + } + } + } +} + +private fun skipAlreadyProvidedFields( + refElement: MvReferenceElement, + processor0: RsResolveProcessor +): RsResolveProcessor { + val parent = refElement.parent + val providedFieldNames = when (parent) { + // shorthand, skip all provided fields + is MvPatField -> parent.parentPatStruct.fieldNames +// is MvStructLitField -> parent.parentStructLitExpr.providedFieldNames + else -> emptySet() + } + return processor0.wrapWithFilter { e -> e.name !in providedFieldNames } +} \ No newline at end of file diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt index 0712d200b..6f1ab8c0f 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/SchemaFieldsCompletionProvider.kt @@ -6,7 +6,7 @@ import com.intellij.patterns.ElementPattern import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.completion.getOriginalOrSelf import org.move.lang.core.psi.MvSchemaLitField import org.move.lang.core.psi.ext.fields @@ -35,7 +35,7 @@ object SchemaFieldsCompletionProvider: MvCompletionProvider() { .filter { !it.textRange.contains(pos.textOffset) } .map { it.referenceName } - val completionCtx = CompletionContext(literalField, literalField.isMsl()) + val completionCtx = MvCompletionContext(literalField, literalField.isMsl()) collectCompletionVariants(result, completionCtx) { val processor = it.wrapWithFilter { e -> e.name !in existingFieldNames } processSchemaLitFieldResolveVariants(literalField, processor) diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt index 1e62f2ca5..9f282a382 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructFieldsCompletionProvider.kt @@ -7,13 +7,11 @@ import com.intellij.patterns.PlatformPatterns import com.intellij.patterns.StandardPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext -import org.move.lang.core.MvPsiPattern.bindingPat -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* import org.move.lang.core.withParent -import org.move.lang.core.withSuperParent object StructFieldsCompletionProvider: MvCompletionProvider() { override val elementPattern: ElementPattern @@ -24,8 +22,8 @@ object StructFieldsCompletionProvider: MvCompletionProvider() { PlatformPatterns .psiElement() .withParent(), - bindingPat() - .withSuperParent(2), +// bindingPat() +// .withSuperParent(2), ) override fun addCompletions( @@ -38,19 +36,19 @@ object StructFieldsCompletionProvider: MvCompletionProvider() { if (element is MvPatBinding) element = element.parent as MvElement - val completionCtx = CompletionContext(element, element.isMsl()) + val completionCtx = MvCompletionContext(element, element.isMsl()) when (element) { is MvPatField -> { - val patStruct = element.patStruct + val patStruct = element.parentPatStruct addFieldsToCompletion( patStruct.path.maybeStruct ?: return, - patStruct.providedFieldNames, + patStruct.fieldNames, result, completionCtx ) } is MvStructLitField -> { - val structLit = element.structLitExpr + val structLit = element.parentStructLitExpr addFieldsToCompletion( structLit.path.maybeStruct ?: return, structLit.providedFieldNames, @@ -66,7 +64,7 @@ object StructFieldsCompletionProvider: MvCompletionProvider() { referredStruct: MvStruct, providedFieldNames: Set, result: CompletionResultSet, - completionContext: CompletionContext, + completionContext: MvCompletionContext, ) { for (field in referredStruct.namedFields.filter { it.name !in providedFieldNames }) { result.addElement( diff --git a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt index 438c71336..71e91b241 100644 --- a/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt +++ b/src/main/kotlin/org/move/lang/core/completion/providers/StructPatCompletionProvider.kt @@ -6,7 +6,7 @@ import com.intellij.patterns.ElementPattern import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.psi.MvPatBinding import org.move.lang.core.psi.MvLetStmt import org.move.lang.core.psi.containingModule @@ -31,7 +31,7 @@ object StructPatCompletionProvider: MvCompletionProvider() { ) { val bindingPat = parameters.position.parent as MvPatBinding val module = bindingPat.containingModule ?: return - val completionCtx = CompletionContext(bindingPat, bindingPat.isMsl()) + val completionCtx = MvCompletionContext(bindingPat, bindingPat.isMsl()) collectCompletionVariants(result, completionCtx) { processItemDeclarations(module, setOf(Namespace.TYPE), it) 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 9e92f0ecd..70baee89d 100644 --- a/src/main/kotlin/org/move/lang/core/psi/MvFunctionLike.kt +++ b/src/main/kotlin/org/move/lang/core/psi/MvFunctionLike.kt @@ -5,7 +5,7 @@ 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 +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.psi.ext.* import org.move.lang.core.stubs.MvModuleStub import org.move.lang.core.types.infer.InferenceContext @@ -117,7 +117,7 @@ val MvFunction.selfSignatureText: String return "$paramsText$retTypeSuffix" } -fun MvFunctionLike.requiresExplicitlyProvidedTypeArguments(completionContext: CompletionContext?): Boolean { +fun MvFunctionLike.requiresExplicitlyProvidedTypeArguments(completionContext: MvCompletionContext?): Boolean { val msl = this.isMslOnlyItem val callTy = this.functionTy(msl).substitute(this.tyVarsSubst) as TyFunction diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvFieldPat.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvFieldPat.kt index 7272336dd..89d10bdaa 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvFieldPat.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvFieldPat.kt @@ -7,7 +7,7 @@ import org.move.lang.core.psi.MvPat import org.move.lang.core.psi.MvPatStruct -val MvPatField.patStruct: MvPatStruct get() = ancestorStrict()!! +val MvPatField.parentPatStruct: MvPatStruct get() = ancestorStrict()!! val MvPatField.fieldReferenceName: String get() = if (this.patFieldFull != null) { diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt index 4547033f6..0e48537bf 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructLitField.kt @@ -6,7 +6,7 @@ import org.move.lang.core.resolve.ref.MvMandatoryReferenceElement import org.move.lang.core.resolve.ref.MvPolyVariantReference import org.move.lang.core.resolve2.ref.MvStructLitFieldReferenceImpl -val MvStructLitField.structLitExpr: MvStructLitExpr +val MvStructLitField.parentStructLitExpr: MvStructLitExpr get() = ancestorStrict()!! //inline fun MvStructLitField.resolveToElement(): T? = diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructOrEnumItemElement.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructOrEnumItemElement.kt index 503b598a5..f06620e16 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructOrEnumItemElement.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructOrEnumItemElement.kt @@ -12,22 +12,8 @@ interface MvStructOrEnumItemElement: MvQualNamedElement, val abilitiesList: MvAbilitiesList? -// override fun declaredType(msl: Boolean): Ty { -// val typeParameters = this.tyTypeParams -// val itemTy = TyAdt(this, typeParameters, this.generics) -//// if (this is MvFieldsOwner && this.tupleFields != null) { -//// // tuple struct or tuple enum variant -//// val paramTypes = this.positionalFields.map { it.type.loweredType(msl) } -//// return TyFunction( -//// this, -//// typeParameters, -//// paramTypes, -//// returnType = itemTy, -//// acquiresTypes = emptyList(), -//// ) -//// } -// return itemTy -// } + // it's public except for the lit/pat usages, which are checked separately + override val isPublic: Boolean get() = true } val MvStructOrEnumItemElement.psiAbilities: List diff --git a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt index 61734a8c5..6e036f88b 100644 --- a/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt +++ b/src/main/kotlin/org/move/lang/core/psi/ext/MvStructPat.kt @@ -1,9 +1,8 @@ package org.move.lang.core.psi.ext import org.move.lang.core.psi.MvPatStruct -import org.move.lang.core.psi.MvStruct -val MvPatStruct.providedFieldNames: Set +val MvPatStruct.fieldNames: Set get() = patFieldList.map { it.fieldReferenceName }.toSet() 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 c5836de24..fbb1d25b3 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 @@ -9,8 +9,6 @@ import org.move.lang.core.resolve.ref.Visibility2 interface MvVisibilityOwner: MvElement { val visibilityModifier: MvVisibilityModifier? get() = childOfType() -// get() = PsiTreeUtil.getStubChildOfType(this, MvVisibilityModifier::class.java) - // restricted visibility considered as public val isPublic: Boolean get() = visibilityModifier != null } 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 9fb93e487..e0c4794ef 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/Processors.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/Processors.kt @@ -2,7 +2,7 @@ package org.move.lang.core.resolve import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.util.SmartList -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.* import org.move.lang.core.psi.NamedItemScope.MAIN @@ -416,7 +416,7 @@ private class ResolveSingleScopeEntryCollector( fun collectCompletionVariants( result: CompletionResultSet, - context: CompletionContext, + context: MvCompletionContext, subst: Substitution = emptySubstitution, f: (RsResolveProcessor) -> Unit ) { @@ -427,7 +427,7 @@ fun collectCompletionVariants( private class CompletionVariantsCollector( private val result: CompletionResultSet, private val subst: Substitution, - private val context: CompletionContext, + private val context: MvCompletionContext, ): RsResolveProcessorBase { override val names: Set? get() = null @@ -514,21 +514,21 @@ fun Map.entriesWithNames(names: Set?): Map { } fun interface VisibilityFilter { - fun filter(methodOrPath: MvMethodOrPath, ns: Set): VisibilityStatus + fun filter(context: MvElement, ns: Set): VisibilityStatus } -fun ScopeEntry.getVisibilityStatusFrom(methodOrPath: MvMethodOrPath): VisibilityStatus = +fun ScopeEntry.getVisibilityStatusFrom(contextElement: MvElement): VisibilityStatus = if (this is ScopeEntryWithVisibility) { val visFilter = this.element .visInfo(adjustScope = this.adjustedItemScope) .createFilter() - visFilter.filter(methodOrPath, this.namespaces) + visFilter.filter(contextElement, this.namespaces) } else { Visible } -fun ScopeEntry.isVisibleFrom(context: MvMethodOrPath): Boolean = getVisibilityStatusFrom(context) == Visible +fun ScopeEntry.isVisibleFrom(context: MvElement): Boolean = getVisibilityStatusFrom(context) == Visible enum class VisibilityStatus { Visible, diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt index 3752f6230..a6b2da2bc 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/MoveReferenceElement.kt @@ -62,10 +62,6 @@ interface MvNameAccessChainReferenceElement : MvReferenceElement { // override fun getReference(): MvFQModuleReference? //} -//interface MvStructPatFieldReferenceElement : MvMandatoryReferenceElement - -interface MvStructFieldLitReferenceElement : MvMandatoryReferenceElement - interface MvSchemaRefFieldReferenceElement : MvMandatoryReferenceElement interface MvItemSpecParameterReferenceElement: MvMandatoryReferenceElement diff --git a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt index 478f82cf6..18e6df58e 100644 --- a/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt +++ b/src/main/kotlin/org/move/lang/core/resolve/ref/Namespace.kt @@ -47,6 +47,7 @@ val TYPES_N_ENUMS = setOf(Namespace.TYPE, Namespace.ENUM) val TYPES_N_NAMES = setOf(Namespace.TYPE, Namespace.NAME) val ENUMS_N_MODULES = setOf(Namespace.ENUM, Namespace.MODULE) val TYPES_N_ENUMS_N_MODULES = setOf(Namespace.TYPE, Namespace.ENUM, Namespace.MODULE) +//val TYPES_N_ENUMS_N_MODULES_N_NAMES = setOf(Namespace.TYPE, Namespace.ENUM, Namespace.MODULE, Namespace.NAME) val ALL_NAMESPACES = Namespace.all() val ITEM_NAMESPACES = diff --git a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt index 87a0107cc..9cdf4784a 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/ItemResolution.kt @@ -17,7 +17,7 @@ import java.util.* val MvNamedElement.namespace get() = when (this) { - is MvFunctionLike -> Namespace.FUNCTION + is MvFunctionLike -> FUNCTION is MvStruct -> Namespace.TYPE is MvEnum -> Namespace.ENUM is MvConst -> Namespace.NAME @@ -44,7 +44,7 @@ fun processMethodResolveVariants( selfTy.deepFoldTyTypeParameterWith { tp -> TyInfer.TyVar(tp) } TyReference.isCompatibleWithAutoborrow(receiverTy, selfTyWithTyVars, msl) } - .processAllItems(setOf(Namespace.FUNCTION), itemModule.allNonTestFunctions()) + .processAllItems(setOf(FUNCTION), itemModule.allNonTestFunctions()) } fun processEnumVariantDeclarations( @@ -102,7 +102,7 @@ fun processItemsFromModuleSpecs( val thisNs = setOf(namespace) for (moduleSpec in module.allModuleSpecs()) { val matched = when (namespace) { - Namespace.FUNCTION -> + FUNCTION -> processor.processAll( thisNs, moduleSpec.specFunctions(), 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 50674eb1a..c20b8148b 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/LexicalDeclarations2.kt @@ -185,12 +185,18 @@ fun processItemsInScope( } found } - Namespace.TYPE -> { if (scope is MvGenericDeclaration) { if (processor.processAll(elementNs, scope.typeParameters)) return true } val found = when (scope) { + is MvModule -> { + if (processor.processAll(TYPES, scope.enumVariants())) return true + processor.processAllItems( + TYPES, + scope.structs(), + ) + } is MvItemSpec -> { val funcItem = scope.funcItem if (funcItem != null) { @@ -199,38 +205,27 @@ fun processItemsInScope( false } } - is MvModule -> { - if (processor.processAll(TYPES, scope.enumVariants())) return true - processor.processAllItems( - TYPES, - scope.structs(), - ) - } is MvApplySchemaStmt -> { val toPatterns = scope.applyTo?.functionPatternList.orEmpty() val patternTypeParams = toPatterns.flatMap { it.typeParameterList?.typeParameterList.orEmpty() } processor.processAll(elementNs, patternTypeParams) } - else -> false } found } - Namespace.ENUM -> { if (scope is MvModule) { if (processor.processAllItems(ENUMS, scope.enumList)) return true } false } - Namespace.SCHEMA -> when (scope) { is MvModule -> processor.processAllItems(ns, scope.schemaList) is MvModuleSpecBlock -> processor.processAllItems(ns, scope.schemaList, scope.specFunctionList) else -> false } - else -> false } if (stop) return true diff --git a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt index 118683d54..4b171938c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/NameResolution2.kt @@ -53,7 +53,7 @@ fun processStructLitFieldResolveVariants( isCompletion: Boolean, processor: RsResolveProcessor, ): Boolean { - val fieldsOwner = litField.structLitExpr.path.reference?.resolveFollowingAliases() as? MvFieldsOwner + val fieldsOwner = litField.parentStructLitExpr.path.reference?.resolveFollowingAliases() as? MvFieldsOwner if (fieldsOwner != null && processNamedFieldDeclarations(fieldsOwner, processor)) return true // if it's a shorthand, try to resolve to the underlying binding pat if (!isCompletion && litField.expr == null) { @@ -94,7 +94,7 @@ fun processPatBindingResolveVariants( val element = entry.element val isConstantLike = element.isConstantLike val isPathOrDestructable = when (element) { - is MvEnum, is MvEnumVariant, is MvStruct -> true + /*is MvModule, */is MvEnum, is MvEnumVariant, is MvStruct -> true else -> false } isConstantLike || (isCompletion && isPathOrDestructable) @@ -102,8 +102,9 @@ fun processPatBindingResolveVariants( false } } + val ns = if (isCompletion) (TYPES_N_ENUMS_N_MODULES + NAMES) else NAMES val ctx = ResolutionContext(binding, isCompletion) - return processNestedScopesUpwards(binding, if (isCompletion) TYPES_N_NAMES else NAMES, ctx, processor) + return processNestedScopesUpwards(binding, ns, ctx, processor) } fun resolveBindingForFieldShorthand( 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 7351364fc..2e0e4593c 100644 --- a/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt +++ b/src/main/kotlin/org/move/lang/core/resolve2/Visibility2.kt @@ -13,6 +13,7 @@ import org.move.lang.core.resolve.VisibilityStatus.Visible import org.move.lang.core.resolve.ref.Namespace.* import org.move.lang.core.resolve.ref.Visibility2 import org.move.lang.core.resolve.ref.Visibility2.* +import org.move.stdext.containsAny data class ItemVisibilityInfo( val item: MvNamedElement, @@ -28,29 +29,31 @@ fun MvNamedElement.visInfo(adjustScope: NamedItemScope = MAIN): ItemVisibilityIn /** Creates filter which determines whether item with [this] visibility is visible from specific [ModInfo] */ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { val (item, itemScopeAdjustment, visibility) = this - return VisibilityFilter { methodOrPath, namespaces -> + return VisibilityFilter { context, itemNs -> // inside msl everything is visible - if (methodOrPath.isMsl()) return@VisibilityFilter Visible + if (context.isMsl()) return@VisibilityFilter Visible // if inside MvAttrItem like abort_code= - val attrItem = methodOrPath.ancestorStrict() + val attrItem = context.ancestorStrict() if (attrItem != null) return@VisibilityFilter Visible - val pathUsageScope = methodOrPath.usageScope + val pathUsageScope = context.usageScope - val path = methodOrPath as? MvPath + val path = context as? MvPath if (path != null) { val useSpeck = path.useSpeck if (useSpeck != null) { - // inside import, all visibilities except for private work - if (visibility !is Private) return@VisibilityFilter Visible + // for use specks, items needs to be public to be visible, no other rules apply + if (item is MvItemElement && item.isPublic) return@VisibilityFilter Visible + + // if item does not support visibility, then it is always private // msl-only items are available from imports if (item.isMslOnlyItem) return@VisibilityFilter Visible // consts are importable in tests - if (pathUsageScope.isTest && namespaces.contains(NAME)) return@VisibilityFilter Visible + if (pathUsageScope.isTest && itemNs.contains(NAME)) return@VisibilityFilter Visible } } @@ -71,12 +74,18 @@ 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 = methodOrPath.containingModule + val pathModule = context.containingModule // local methods, Self::method - everything is visible if (itemModule == pathModule) return@VisibilityFilter Visible - // types visibility is ignored, their correct usage is checked in a separate inspection - if (namespaces.contains(TYPE) || namespaces.contains(ENUM)) return@VisibilityFilter Visible + // item is type, check whether it's allowed in the context + if (itemNs.containsAny(TYPE, ENUM)) { + val rootPath = path?.rootPath() + when (rootPath?.parent) { + // todo: when structs and enums can be public, conditions for struct lit/pat should be added here + is MvPathType -> return@VisibilityFilter Visible + } + } when (visibility) { is Restricted -> { @@ -95,7 +104,7 @@ fun ItemVisibilityInfo.createFilter(): VisibilityFilter { return@VisibilityFilter Invisible } val pathPackage = - methodOrPath.containingMovePackage ?: return@VisibilityFilter Invisible + context.containingMovePackage ?: return@VisibilityFilter Invisible val itemPackage = item.containingMovePackage ?: return@VisibilityFilter Invisible // val originPackage = visibility.originPackage.value ?: return@VisibilityFilter Invisible if (pathPackage == itemPackage) Visible else Invisible diff --git a/src/main/kotlin/org/move/stdext/Collections.kt b/src/main/kotlin/org/move/stdext/Collections.kt index e034cbc9f..f26d080a3 100644 --- a/src/main/kotlin/org/move/stdext/Collections.kt +++ b/src/main/kotlin/org/move/stdext/Collections.kt @@ -129,8 +129,9 @@ inline fun Iterable.mapToSet(transform: (T) -> R): Set = inline fun Iterable.mapNotNullToSet(transform: (T) -> R?): Set = mapNotNullTo(HashSet(mapCapacity(collectionSizeOrDefault(10))), transform) -fun Set.intersects(other: Iterable): Boolean = - other.any { this.contains(it) } +fun Set.intersects(other: Iterable): Boolean = other.any { this.contains(it) } + +fun Set.containsAny(vararg items: T): Boolean = items.any { this.contains(it) } inline fun Iterable.joinToWithBuffer( buffer: StringBuilder, diff --git a/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt b/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt index 0cc3dbfd7..788756387 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/BuiltInFunctionLookupTest.kt @@ -2,7 +2,7 @@ package org.move.lang.completion.lookups import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementPresentation -import org.move.lang.core.completion.CompletionContext +import org.move.lang.core.completion.MvCompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.psi.MvModule import org.move.lang.core.psi.ext.builtinFunctions @@ -43,7 +43,7 @@ class BuiltInFunctionLookupTest: MvTestBase() { val moduleElement = myFixture.findElementInEditor() val lookup = moduleElement.builtinFunctions().single { it.name == name }.let { - it.createLookupElement(CompletionContext(it, false)) + it.createLookupElement(MvCompletionContext(it, false)) // it.createLookupElement(CompletionContext(it, ContextScopeInfo.default())) } checkLookupPresentation( 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 fb3dc5059..968ca42f5 100644 --- a/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt +++ b/src/test/kotlin/org/move/lang/completion/lookups/LookupElementTest.kt @@ -9,7 +9,7 @@ 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.MvCompletionContext import org.move.lang.core.completion.createLookupElement import org.move.lang.core.completion.providers.MethodOrFieldCompletionProvider import org.move.lang.core.psi.MvElement @@ -197,7 +197,7 @@ class LookupElementTest: MvTestBase() { val element = myFixture.findElementInEditor() as? MvNamedElement ?: error("Marker `^` should point to the MvNamedElement") - val completionCtx = CompletionContext(element, false) + val completionCtx = MvCompletionContext(element, false) // val completionCtx = CompletionContext(element, ContextScopeInfo.default()) val lookup = element.createLookupElement(completionCtx) checkLookupPresentation( diff --git a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt index 22cca3c3c..36adcb5b0 100644 --- a/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt +++ b/src/test/kotlin/org/move/lang/completion/names/StructsCompletionTest.kt @@ -198,6 +198,19 @@ class StructsCompletionTest: CompletionTestCase() { } """) + fun `test no completion in struct lit if field already specified`() = checkNoCompletion(""" + module 0x1::M { + struct T { offered: u8, collateral: u8 } + fun main() { + T { + off/*caret*/ + offered: _, + collateral + }; + } + } + """) + fun `test module struct completion in type position`() = doSingleCompletion(""" module 0x1::Transaction { struct Type { @@ -282,4 +295,44 @@ class StructsCompletionTest: CompletionTestCase() { } } """) + + fun `test match expr enum variant completion`() = doSingleCompletion(""" + module 0x1::m { + enum Color { Red, Blue } + fun main(s: Color) { + match (s) { + Re/*caret*/ + } + } + } + """, """ + module 0x1::m { + enum Color { Red, Blue } + fun main(s: Color) { + match (s) { + Red/*caret*/ + } + } + } + """) + + fun `test match expr enum item completion`() = doSingleCompletion(""" + module 0x1::m { + enum Color { Red, Blue } + fun main(s: Color) { + match (s) { + Col/*caret*/ + } + } + } + """, """ + module 0x1::m { + enum Color { Red, Blue } + fun main(s: Color) { + match (s) { + Color/*caret*/ + } + } + } + """) } diff --git a/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt b/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt index 8ed83461f..a096178f5 100644 --- a/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt +++ b/src/test/kotlin/org/move/lang/parser/PartialParsingTest.kt @@ -22,4 +22,6 @@ class PartialParsingTest: MvParsingTestCase("partial") { fun `test expressions`() = doTest(true) fun `test assignments`() = doTest(true) fun `test dot exprs`() = doTest(true) + + fun `test enum match`() = doTest(true) } diff --git a/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt b/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt index f883ead3d..62ff9cc8a 100644 --- a/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt +++ b/src/test/kotlin/org/move/lang/resolve/ResolveTypesTest.kt @@ -41,9 +41,9 @@ class ResolveTypesTest : ResolveTestCase() { """ ) - fun `test resolve struct as struct literal`() = checkByCode( + fun `test resolve struct for struct literal`() = checkByCode( """ - module M { + module 0x1::m { struct MyStruct {} //X @@ -55,6 +55,34 @@ class ResolveTypesTest : ResolveTestCase() { """ ) + fun `test cannot resolve struct for struct literal from another module`() = checkByCode( + """ + module 0x1::s { + struct MyStruct {} + } + module 0x1::m { + use 0x1::s::MyStruct; + fun call() { + let a = MyStruct {}; + //^ unresolved + } + } + """ + ) + + fun `test resolve struct from another module for import`() = checkByCode( + """ + module 0x1::s { + struct MyStruct {} + //X + } + module 0x1::m { + use 0x1::s::MyStruct; + //^ + } + """ + ) + fun `test resolve struct as struct pattern destructuring`() = checkByCode( """ module M { diff --git a/src/test/resources/org/move/lang/parser/partial/enum_match.move b/src/test/resources/org/move/lang/parser/partial/enum_match.move new file mode 100644 index 000000000..ca7d3743e --- /dev/null +++ b/src/test/resources/org/move/lang/parser/partial/enum_match.move @@ -0,0 +1,9 @@ +module 0x1::enum_match { + enum Color { Red, Blue } + fun main() { + match (s) {} + match (s) { Red } + match (s) { Red => } + match (s) { Red => true, Blue => } + } +} diff --git a/src/test/resources/org/move/lang/parser/partial/enum_match.txt b/src/test/resources/org/move/lang/parser/partial/enum_match.txt new file mode 100644 index 000000000..464e36131 --- /dev/null +++ b/src/test/resources/org/move/lang/parser/partial/enum_match.txt @@ -0,0 +1,138 @@ +FILE + MvModuleImpl(MODULE) + PsiElement(module)('module') + PsiWhiteSpace(' ') + MvAddressRefImpl(ADDRESS_REF) + PsiElement(DIEM_ADDRESS)('0x1') + PsiElement(::)('::') + PsiElement(IDENTIFIER)('enum_match') + PsiWhiteSpace(' ') + PsiElement({)('{') + PsiWhiteSpace('\n ') + MvEnumImpl(ENUM) + PsiElement(enum_kw)('enum') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('Color') + PsiWhiteSpace(' ') + MvEnumBodyImpl(ENUM_BODY) + PsiElement({)('{') + PsiWhiteSpace(' ') + MvEnumVariantImpl(ENUM_VARIANT) + PsiElement(IDENTIFIER)('Red') + PsiElement(,)(',') + PsiWhiteSpace(' ') + MvEnumVariantImpl(ENUM_VARIANT) + PsiElement(IDENTIFIER)('Blue') + PsiWhiteSpace(' ') + PsiElement(})('}') + PsiWhiteSpace('\n ') + MvFunctionImpl(FUNCTION) + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('main') + MvFunctionParameterListImpl(FUNCTION_PARAMETER_LIST) + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + MvCodeBlockImpl(CODE_BLOCK) + PsiElement({)('{') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvMatchExprImpl(MATCH_EXPR) + PsiElement(match_kw)('match') + PsiWhiteSpace(' ') + MvMatchArgumentImpl(MATCH_ARGUMENT) + PsiElement(()('(') + MvPathExprImpl(PATH_EXPR) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('s') + PsiElement())(')') + PsiWhiteSpace(' ') + MvMatchBodyImpl(MATCH_BODY) + PsiElement({)('{') + PsiElement(})('}') + PsiErrorElement:';' expected, got 'match' + + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvMatchExprImpl(MATCH_EXPR) + PsiElement(match_kw)('match') + PsiWhiteSpace(' ') + MvMatchArgumentImpl(MATCH_ARGUMENT) + PsiElement(()('(') + MvPathExprImpl(PATH_EXPR) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('s') + PsiElement())(')') + PsiWhiteSpace(' ') + MvMatchBodyImpl(MATCH_BODY) + PsiElement({)('{') + PsiWhiteSpace(' ') + MvMatchArmImpl(MATCH_ARM) + MvPatBindingImpl(PAT_BINDING) + PsiElement(IDENTIFIER)('Red') + PsiErrorElement:'=>' or if expected, got '}' + + PsiWhiteSpace(' ') + PsiElement(})('}') + PsiWhiteSpace('\n ') + MvExprStmtImpl(EXPR_STMT) + MvMatchExprImpl(MATCH_EXPR) + PsiElement(match_kw)('match') + PsiWhiteSpace(' ') + MvMatchArgumentImpl(MATCH_ARGUMENT) + PsiElement(()('(') + MvPathExprImpl(PATH_EXPR) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('s') + PsiElement())(')') + PsiWhiteSpace(' ') + MvMatchBodyImpl(MATCH_BODY) + PsiElement({)('{') + PsiWhiteSpace(' ') + MvMatchArmImpl(MATCH_ARM) + MvPatBindingImpl(PAT_BINDING) + PsiElement(IDENTIFIER)('Red') + PsiWhiteSpace(' ') + PsiElement(=>)('=>') + PsiErrorElement: expected, got '}' + + PsiWhiteSpace(' ') + PsiElement(})('}') + PsiWhiteSpace('\n ') + MvMatchExprImpl(MATCH_EXPR) + PsiElement(match_kw)('match') + PsiWhiteSpace(' ') + MvMatchArgumentImpl(MATCH_ARGUMENT) + PsiElement(()('(') + MvPathExprImpl(PATH_EXPR) + MvPathImpl(PATH) + PsiElement(IDENTIFIER)('s') + PsiElement())(')') + PsiWhiteSpace(' ') + MvMatchBodyImpl(MATCH_BODY) + PsiElement({)('{') + PsiWhiteSpace(' ') + MvMatchArmImpl(MATCH_ARM) + MvPatBindingImpl(PAT_BINDING) + PsiElement(IDENTIFIER)('Red') + PsiWhiteSpace(' ') + PsiElement(=>)('=>') + PsiWhiteSpace(' ') + MvLitExprImpl(LIT_EXPR) + PsiElement(BOOL_LITERAL)('true') + PsiElement(,)(',') + PsiWhiteSpace(' ') + MvMatchArmImpl(MATCH_ARM) + MvPatBindingImpl(PAT_BINDING) + PsiElement(IDENTIFIER)('Blue') + PsiWhiteSpace(' ') + PsiElement(=>)('=>') + PsiErrorElement: expected, got '}' + + PsiWhiteSpace(' ') + PsiElement(})('}') + PsiWhiteSpace('\n ') + PsiElement(})('}') + PsiWhiteSpace('\n') + PsiElement(})('}') \ No newline at end of file