Skip to content

Commit

Permalink
fix type inference / unresolved reference error for the case where pa…
Browse files Browse the repository at this point in the history
…ttern path is unresolved (#244)
  • Loading branch information
mkurnikov authored Nov 12, 2024
1 parent 356aa77 commit 61d6733
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import org.move.lang.core.types.ty.TyUnknown

class MvUnresolvedReferenceInspection: MvLocalInspectionTool() {

// var ignoreWithoutQuickFix: Boolean = false

override val isSyntaxOnly get() = false

override fun buildMvVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object: MvVisitor() {
Expand Down Expand Up @@ -54,15 +52,19 @@ class MvUnresolvedReferenceInspection: MvLocalInspectionTool() {

// checked in another method
if (patField.patFieldFull != null) return
// pat struct unresolved, do not highlight fields
if (patField.patStruct.path.reference?.resolve() == null) return

patField.patBinding
?.let { tryMultiResolveOrRegisterError(it, holder) }
patField.patBinding?.let { tryMultiResolveOrRegisterError(it, holder) }
}

override fun visitPatFieldFull(o: MvPatFieldFull) {
if (o.isMsl() && !isDebugModeEnabled())
override fun visitPatFieldFull(patFieldFull: MvPatFieldFull) {
if (patFieldFull.isMsl() && !isDebugModeEnabled())
return
tryMultiResolveOrRegisterError(o, holder)
// pat struct unresolved, do not highlight fields
if (patFieldFull.patStruct.path.reference?.resolve() == null) return

tryMultiResolveOrRegisterError(patFieldFull, holder)
}

override fun visitStructLitField(litField: MvStructLitField) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ private fun skipAlreadyProvidedFields(
val parent = refElement.parent
val providedFieldNames = when (parent) {
// shorthand, skip all provided fields
is MvPatField -> parent.parentPatStruct.fieldNames
is MvPatField -> parent.patStruct.fieldNames
// is MvStructLitField -> parent.parentStructLitExpr.providedFieldNames
else -> emptySet()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object StructFieldsCompletionProvider: MvCompletionProvider() {
val completionCtx = MvCompletionContext(element, element.isMsl())
when (element) {
is MvPatField -> {
val patStruct = element.parentPatStruct
val patStruct = element.patStruct
addFieldsToCompletion(
patStruct.path.maybeStruct ?: return,
patStruct.fieldNames,
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/org/move/lang/core/psi/ext/MvFieldPat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.move.lang.core.psi.MvPat
import org.move.lang.core.psi.MvPatStruct


val MvPatField.parentPatStruct: MvPatStruct get() = ancestorStrict()!!
val MvPatField.patStruct: MvPatStruct get() = parent as MvPatStruct

val MvPatField.fieldReferenceName: String
get() = if (this.patFieldFull != null) {
Expand Down
8 changes: 3 additions & 5 deletions src/main/kotlin/org/move/lang/core/psi/ext/MvFieldPatFull.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ package org.move.lang.core.psi.ext

import com.intellij.lang.ASTNode
import com.intellij.psi.PsiElement
import org.move.lang.core.psi.MvElementImpl
import org.move.lang.core.psi.MvPatFieldFull
import org.move.lang.core.psi.MvNamedElement
import org.move.lang.core.psi.MvPatStruct
import org.move.lang.core.psi.*
import org.move.lang.core.resolve.collectResolveVariants
import org.move.lang.core.resolve.ref.MvPolyVariantReference
import org.move.lang.core.resolve.ref.MvPolyVariantReferenceCached
import org.move.lang.core.resolve.ref.ResolveCacheDependency
import org.move.lang.core.resolve2.processStructPatFieldResolveVariants

val MvPatFieldFull.parentPatStruct: MvPatStruct get() = ancestorStrict()!!
val MvPatFieldFull.patField: MvPatField get() = parent as MvPatField
val MvPatFieldFull.patStruct: MvPatStruct get() = patField.patStruct

abstract class MvPatFieldFullMixin(node: ASTNode): MvElementImpl(node),
MvPatFieldFull {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ fun processStructLitFieldResolveVariants(
}

fun processStructPatFieldResolveVariants(
field: MvPatFieldFull,
patFieldFull: MvPatFieldFull,
processor: RsResolveProcessor
): Boolean {
val resolved = field.parentPatStruct.path.reference?.resolveFollowingAliases()
val resolved = patFieldFull.patStruct.path.reference?.resolveFollowingAliases()
val resolvedStruct = resolved as? MvFieldsOwner ?: return false
return processNamedFieldDeclarations(resolvedStruct, processor)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ data class InferenceResult(
fun getExpectedType(expr: MvExpr): Ty = exprExpectedTypes[expr] ?: TyUnknown
fun getCallableType(callable: MvCallable): Ty? = callableTypes[callable]

fun hasResolvedPath(path: MvPath): Boolean = path in resolvedPaths
fun getResolvedPath(path: MvPath): List<ResolvedItem>? =
resolvedPaths[path] ?: inferenceErrorOrFallback(path, null)

Expand All @@ -120,7 +119,7 @@ data class InferenceResult(
resolvedLitFields[litField].orEmpty()

override fun getPatFieldType(patField: MvPatField): Ty =
patFieldTypes[patField] ?: TyUnknown
patFieldTypes[patField] ?: inferenceErrorOrFallback(patField, TyUnknown)
}

fun inferTypesIn(element: MvInferenceContextOwner, msl: Boolean): InferenceResult {
Expand Down Expand Up @@ -332,15 +331,14 @@ class InferenceContext(
// resolvedPaths[path] = resolved
// }

override fun getPatFieldType(patField: MvPatField): Ty {
return patFieldTypes[patField] ?: TyUnknown
}
override fun getPatFieldType(patField: MvPatField): Ty =
patFieldTypes[patField] ?: inferenceErrorOrFallback(patField, TyUnknown)

override fun getResolvedLitField(litField: MvStructLitField): List<MvNamedElement> =
resolvedLitFields[litField].orEmpty()

fun getExprType(expr: MvExpr): Ty {
return exprTypes[expr] ?: TyUnknown
return exprTypes[expr] ?: inferenceErrorOrFallback(expr, TyUnknown)
}

fun combineTypes(ty1: Ty, ty2: Ty): RelateResult {
Expand Down
11 changes: 7 additions & 4 deletions src/main/kotlin/org/move/lang/core/types/infer/Patterns.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ fun MvPat.extractBindings(fcx: TypeInferenceWalker, ty: Ty, defBm: RsBindingMode
val item =
fcx.resolvePathCached(this.path, expected) as? MvFieldsOwner
?: (expected as? TyAdt)?.item as? MvStruct
?: return

if (item is MvGenericDeclaration) {
val patTy = fcx.instantiatePath<TyAdt>(this.path, item) ?: return
// val (patTy, _) = fcx.instantiateMethodOrPath<TyAdt>(this.path, item) ?: return
if (!isCompatible(expected, patTy, fcx.msl)) {
fcx.reportTypeError(TypeError.InvalidUnpacking(this, ty))
}
}
val structFields = item.namedFields.associateBy { it.name }

val structFields = item?.namedFields?.associateBy { it.name } ?: emptyMap()
for (fieldPat in this.patFieldList) {
val kind = fieldPat.kind
// wil have TyUnknown on unresolved item
val fieldType = structFields[kind.fieldName]
?.type
?.loweredType(fcx.msl)
Expand All @@ -80,7 +80,10 @@ fun MvPat.extractBindings(fcx: TypeInferenceWalker, ty: Ty, defBm: RsBindingMode
val item =
fcx.resolvePathCached(this.path, expected) as? MvFieldsOwner
?: (expected as? TyAdt)?.item as? MvStruct
?: return
if (item == null) {
patList.forEach { it.extractBindings(fcx, TyUnknown) }
return
}
val tupleFields = item.positionalFields
inferTupleFieldsTypes(fcx, patList, patBm, tupleFields.size) { indx ->
tupleFields
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,4 +541,25 @@ module 0x1::m {
}
}
""")

@MoveV2
fun `test no error for fields if destructuring unknown struct`() = checkByText("""
module 0x1::m {
fun main() {
let <error descr="Unresolved reference: `S`">S</error> { val } = 1;
let <error descr="Unresolved reference: `S`">S</error>(val) = 1;
}
}
""")

@MoveV2
fun `test no error for fields if destructuring unknown tuple struct`() = checkByText("""
module 0x1::m {
enum R {}
fun main() {
let R::<error descr="Unresolved reference: `Inner`">Inner</error> { val } = 1;
let R::<error descr="Unresolved reference: `Inner`">Inner</error>(val) = 1;
}
}
""")
}
41 changes: 41 additions & 0 deletions src/test/kotlin/org/move/lang/types/ExpressionTypesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2221,4 +2221,45 @@ module 0x1::main {
}
}
""")

fun `test struct destructuring for unknown type`() = testExpr("""
module 0x1::m {
fun main() {
let S { i } = s;
i;
//^ <unknown>
}
}
""")

fun `test enum variant destructuring for unknown type`() = testExpr("""
module 0x1::m {
enum S { }
fun main() {
let S::Inner { i } = s;
i;
//^ <unknown>
}
}
""")

fun `test tuple struct destructuring for unknown type`() = testExpr("""
module 0x1::m {
fun main() {
let S(i, j) = s;
i;
//^ <unknown>
}
}
""")
fun `test tuple enum variant destructuring for unknown type`() = testExpr("""
module 0x1::m {
enum S {}
fun main() {
let S::Inner(i, j) = s;
i;
//^ <unknown>
}
}
""")
}

0 comments on commit 61d6733

Please sign in to comment.