Skip to content

Fix false circular-reference detection for distinct generic instantiations #115

Closed

Description

@MessiasLima

Description

ResolverChain.detectCircularReference compares only KType.classifier, ignoring type arguments. Two different generic instantiations that share a classifier (for example List<Company> and List<Employee>) are therefore treated as the same type, and resolving the second one is falsely reported as a circular reference, throwing SomeCircularReferenceException.

This blocks any object graph where a generic type with one type argument transitively contains the same raw generic class with a different type argument. It affects List, MutableList, Set, Map, Array, and any user-defined generic type, since each shares a single classifier per raw class.

Steps to Reproduce

  1. Define mutually referencing models where at least one side uses a generic collection:
    data class Company(val name: String, val employees: List<Employee>)
    data class Employee(val name: String, val company: Company)
  2. Trigger generation with the collection as the entry point: some<List<Company>>().
  3. Resolution walks List<Company> -> Company -> employees: List<Employee>, and the last step is misidentified as circular.

Actual Behavior

dev.appoutlet.some.exception.SomeCircularReferenceException: Circular reference detected for
kotlin.collections.List<dev.appoutlet.some.resolver.Employee>.
Resolution stack: [
  kotlin.collections.List<dev.appoutlet.some.resolver.Company>,
  dev.appoutlet.some.resolver.Company
]

Expected Behavior

List<Company> and List<Employee> are distinct types and generation succeeds. A repeated type is circular only when the full type matches under the existing nullability rules, not merely when the raw classifier matches. Genuine recursion such as data class Node(val next: Node?) and data class Company(val employees: List<Company>) must still be detected.

Additional Information

  • Environment: Kotlin/JVM, some-core
  • Priority: High
  • Related Files: core/src/main/kotlin/dev/appoutlet/some/core/ResolverChain.kt (detectCircularReference), core/src/main/kotlin/dev/appoutlet/some/resolver/ListResolver.kt, SetResolver.kt, MapResolver.kt, ArrayResolver.kt
  • Workaround: Register a custom factory for the affected collection/type so resolution no longer recurses through the colliding classifier.
  • Related: Spike: Parallelize ResolverChain resolution while preserving circular-reference detection #60 (spike assumes the current classifier-equality semantics; fixing this changes that assumption)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    • Status
      Done

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions