This is a pseudo-follow up to Kotlin Data Class Wildcard: taking in advice from that question I came upon a better but quite different solution to the same problem.The problem: fuzzy matching AST nodes. All regular properties should be checked for equality normally (via ==), but allowing any absent value to match a real value and recursing the fuzzy match down the Node hierarchy. The second requirement is that this does not require anything extra within the Nodes themselves as this would be prohibitive towards adding new nodes and the fuzzy match is purely the domain of testing.The reason for creating this is that the structure of a parsed AST can be very complex and in order to make writing tests easier, I want to be able to say I don't care about this part of the parsed AST, and just test a portion of it.NodeMatching.ktpackage nafi.grammarimport nafi.grammar.ast.Nodeimport nafi.grammar.ast.Positionimport kotlin.reflect.memberPropertiesinfix fun Node.matches(that: Node): Boolean {    if (this.javaClass != that.javaClass)        return false    else return this.javaClass.kotlin.memberProperties            .map { it.get(this) matches it.get(that) }            .fold(true, Boolean::and)}private infix fun Position.matches(that: Position) =        this.start == that.start &&                (this.end == that.end || this.end == null || that.end == null)private infix fun <T : Collection<*>> T.matches(that: T): Boolean {    if (this.size != that.size) return false    else return this.indices            .map { this.elementAt(it) matches that.elementAt(it) }            .fold(true, Boolean::and)}private infix fun Any?.matches(that: Any?): Boolean = when {    this == null || that == null                   -> true    this is Node && that is Node                   -> this matches that    this is Position && that is Position           -> this matches that    this is Collection<*> && that is Collection<*> -> this matches that    else                                           -> this == that}ASTMatcherTest.ktpackage nafi.grammarimport nafi.grammar.ast.ConstantDefinitionimport nafi.grammar.ast.IntegerLiteralimport nafi.grammar.ast.NafiFileimport nafi.grammar.ast.Positionimport org.junit.jupiter.api.Testimport kotlin.test.assertEqualsclass ASTMatcherTest {    fun testCompile(code: String, ast: NafiFile, expectedMatch: Boolean) {        val parsed = NafiParserFacade.parse(code)        assertEquals(expectedMatch, ast matches parsed,                     expected $ast, got $parsed, should ${if (!expectedMatch) not  else }match        )    }    @Test fun passNoPosition() = testCompile(            constant id = 5,            NafiFile(ConstantDefinition(id, IntegerLiteral(5))),            true    )    @Test fun failBadPosition() = testCompile(            constant id = 5,            NafiFile(ConstantDefinition(id, IntegerLiteral(5, Position(10, 14)))),            false    )    @Test fun passGoodPosition() = testCompile(            constant id = 5,            NafiFile(ConstantDefinition(id, IntegerLiteral(5, Position(1, 14, 1, 15)), Position(1, 0))),            true    )}Because Kotlin extensions are resolved statically, NodeMatching.kt includes a definition of matches for two Any?s and does a manual virtual dispatch to the appropriate matches or ==.Key Points:Position.matches and <T : Collection<*>>.matches can be inline, but should they be?This requires data which is non-nullable in application logic to be nullable to allow fuzzy matching. Is there a way around that?Any kotlin-isms that would make the code more readable or kotlin-abuses that are making the code less readableThe minimal AST Model that I'm using for testing can be found on GitHub along with the rest of the project. The project is a Maven project and you can run the tests with maven test.
Kotlin fuzzy matching
kotlin