Skip to content

Commit

Permalink
add tuple struct pattern missing fields check
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurnikov committed Sep 15, 2024
1 parent 296a6ef commit 5d41ac4
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ class MvErrorAnnotator: MvAnnotatorBase() {
}
}

override fun visitPatTupleStruct(o: MvPatTupleStruct) = checkPatTupleStruct(moveHolder, o)

override fun visitStructLitExpr(o: MvStructLitExpr) {
val nameElement = o.path.referenceNameElement ?: return
val struct = o.path.maybeStruct ?: return
Expand Down Expand Up @@ -356,6 +358,23 @@ class MvErrorAnnotator: MvAnnotatorBase() {
}
}
}

private fun checkPatTupleStruct(holder: MvAnnotationHolder, patTupleStruct: MvPatTupleStruct) {
val declaration = patTupleStruct.path.reference?.resolveFollowingAliases() as? MvFieldsOwner ?: return

val declarationFieldsAmount = declaration.fields.size
// Rest is non-binding, meaning it is accepted even if all fields are already bound
val bodyFieldsAmount = patTupleStruct.patList.filterNot { it is MvPatRest }.size

if (bodyFieldsAmount < declarationFieldsAmount && patTupleStruct.patRest == null) {
Diagnostic.MissingFieldsInTuplePattern(
patTupleStruct,
declaration,
declarationFieldsAmount,
bodyFieldsAmount
).addToHolder(holder)
}
}
}

private fun checkMissingFields(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.move.lang.core.psi.ext

import org.move.lang.core.psi.MvPatRest
import org.move.lang.core.psi.MvPatTupleStruct

val MvPatTupleStruct.patRest: MvPatRest? get() = patList.firstOrNull { it is MvPatRest } as? MvPatRest
17 changes: 17 additions & 0 deletions src/main/kotlin/org/move/lang/utils/Diagnostic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,23 @@ sealed class Diagnostic(
}
}

class MissingFieldsInTuplePattern(
pat: MvPat,
private val declaration: MvFieldsOwner,
private val expectedAmount: Int,
private val actualAmount: Int
): Diagnostic(pat) {

override fun prepare(): PreparedAnnotation {
val itemType = if (declaration is MvEnumVariant) "Enum variant" else "Tuple struct"
return PreparedAnnotation(
ERROR,
"$itemType pattern does not correspond to its declaration: " +
"expected $expectedAmount ${pluralize("field", expectedAmount)}, found $actualAmount"
)
}
}

class MissingFieldsInStructPattern(
patStruct: MvPatStruct,
private val declaration: MvFieldsOwner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,30 @@ class StructFieldsNumberErrorTest: AnnotatorTestCase(MvErrorAnnotator::class) {
}
""")

fun `test missing positional fields for struct`() = checkErrors("""
module 0x1::m {
struct S(u8, u8);
fun main(s: S) {
let <error descr="Tuple struct pattern does not correspond to its declaration: expected 2 fields, found 1">S (val)</error> = s;
}
}
""")

fun `test missing positional fields with rest`() = checkErrors("""
module 0x1::m {
struct S(u8, u8);
fun main(s: S) {
let S(val, ..) = s;
}
}
""")

fun `test missing positional fields for enum variant`() = checkErrors("""
module 0x1::m {
enum S { Inner(u8, u8) }
fun main(s: S) {
let <error descr="Enum variant pattern does not correspond to its declaration: expected 2 fields, found 1">S::Inner(val)</error> = s;
}
}
""")
}

0 comments on commit 5d41ac4

Please sign in to comment.