E08263: construction can never complete - every path through it constructs the same type again, so it overflows the stack at run time; construct the recursive part only under a condition, or hold it in an 'Optional of Type' or a 'List of Type', which start empty

Category: E08xxx Pre-IR checks (flow analysis) · Reported in phase: PRE_IR_CHECKS · Classification: CONSTRUCTION_RECURSION · All error codes

What went wrong

Constructing this type ALWAYS constructs the same type again, on every path, so construction can never complete - at run time it overflows the stack. The message shows the cycle, for example:

Node property initialisers -> Node() -> Node property initialisers

The compiler follows only what always runs when an object is built: its super constructor, its property initialisers, and the calls in a constructor body, function or closed method that are not inside a condition, loop or catch.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 1403 (Why does a type that constructs itself in a property ...)

Rationale

A property initialiser runs for EVERY instance, before the constructor body, so a Node whose property is initialised with 'Node()' builds a Node for every Node (the [EXAMPLE] section below). The same happens when the cycle goes through more than one step - two types whose initialisers build each other, a constructor calling a function that builds the type, a this(...) delegation cycle, or a generic that constructs T where T is the type being built ('Node extends Base of Node' with 'me as T: T()' in Base). Recursion under a condition is legal: the compiler cannot prove it ends, and does not need to - the fix's Tree builds its children only while 'depth > 0'.

How to fix it

  1. Hold the link in an Optional, which starts empty, and fill it when needed (the fix's Node holds 'next' as an 'Optional of Node')
  2. Or hold the values in a collection ('List of Node') that starts empty
  3. Or build the recursive part only under a condition that ends it
  4. For a this(...) cycle, make one constructor do the work without delegating

A plain 'next as Node?' does not help on its own: every property must be initialised before use (E08060), so it still needs a value when built.

Common causes

  • A linked structure written as 'next as Node: Node()' instead of an Optional
  • A self-typed generic base ('Node extends Base of Node') whose base constructs its type parameter in a property initialiser
  • Two constructors that each delegate to the other with this(...)

See also

  • E08061: the object used before it is fully constructed
  • E08060: a property used before it is initialised

https://ek9.io/classes.html

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E08263: construction can never complete - every path through it constructs the same type again, so it overflows the stack at run time; construct the recursive part only under a condition, or hold it in an 'Optional of Type' or a 'List of Type', which start empty

#!ek9
defines module error.e08263.bad

  defines class

    Node
      next as Node: Node()

      default Node() as pure

      default operator ?

    Pair
      amount as Integer: 0

      Pair()
        -> initial as Integer
        this($initial)

      Pair()
        -> text as String
        this(length text)

      default operator ?

Fixed: Construct the recursive part only under a condition, or hold it unset until linked

#!ek9
defines module error.e08263.good

  defines class

    Node
      label as String: String()
      next as Optional of Node: Optional() of Node

      Node()
        -> text as String
        label: text

      link()
        -> node as Node
        next: Optional(node)

      override operator ? as pure
        <- rtn as Boolean: label?

    Tree
      children as List of Tree: List() of Tree

      Tree()
        -> depth as Integer
        if depth > 0
          children += Tree(depth - 1)

      default operator ?

Questions and answers

These Q&A entries show E08263 and its fix: