E05260: dispatcher on sealed type must have handlers for all permitted types

Category: E05xxx Explicit type symbol definition · Reported in phase: PRE_IR_CHECKS · Classification: DISPATCHER_NOT_EXHAUSTIVE · All error codes

What went wrong

A dispatcher method's parameter type is a sealed type (a trait or class with an 'allow only' clause), but the dispatcher class does not have handlers for all permitted types. When a type declares its complete set of concrete implementations via 'allow only', the compiler can verify that the dispatcher handles every possible runtime type — providing compile-time exhaustiveness checking similar to Java's sealed switch or Kotlin's sealed when.

This works identically for both sealed traits and sealed classes.

The dispatcher entry point (marked 'as dispatcher') acts as the declarative marker. Each permitted type in the 'allow only' list must have a corresponding handler method with the same name and a parameter of that specific type. Missing handlers mean that at runtime, certain types would fall through to the generic entry point rather than being handled specifically — defeating the purpose of the sealed type pattern.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 618 (How do sealed dispatchers enforce exhaustive handler cove...)

How to fix it

Add handler methods for all types listed in the sealed type's 'allow only' clause. Each handler must have the same method name as the dispatcher entry point and accept a parameter of the specific permitted type.

This exhaustiveness requirement is the primary value of sealed types: when a new type is added to the 'allow only' list, every dispatcher that operates on that type will fail to compile until a handler is added. This guarantees that all dispatch points are updated — no runtime surprises.

Common causes

  • Adding a new type to the 'allow only' list without updating dispatchers
  • Forgetting to add a handler for one of the permitted types
  • Relying on the generic entry point to handle specific types

See also

  • E05240: type is not permitted to extend/implement this sealed type
  • E05250: abstract type cannot be in 'allow only' list
  • E05270: sealed class must be declared 'as open'
  • E05230: dispatcher has ambiguous handler resolution
  • E05210: dispatcher handler type not in hierarchy

Examples

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

Fails with E05260: dispatcher on sealed type must have handlers for all permitted types

#!ek9
defines module error.e05260.bad

  defines trait

    Shape allow only Circle, Square, Triangle
      area() as abstract
        <- rtn as Float?

  defines class

    Circle with trait of Shape
      override area()
        <- rtn as Float: 3.14

    Square with trait of Shape
      override area()
        <- rtn as Float: 1.0

    Triangle with trait of Shape
      override area()
        <- rtn as Float: 0.5

    <?-
      IncompleteProcessor only handles Circle.
      Missing handlers for Square and Triangle.
    -?>
    IncompleteProcessor

      process()
        -> circle as Circle
        content <- "Circle"
        require content?

      process() as dispatcher
        -> shape as Shape
        content <- "Unknown shape"
        require content?

    <?-
      CompleteProcessor handles all three types.
      No error expected — all permitted types are covered.
    -?>
    CompleteProcessor

      process()
        -> circle as Circle
        content <- "Circle"
        require content?

      process() as dispatcher
        -> shape as Shape
        content <- "Unknown shape"
        require content?

      process()
        -> square as Square
        content <- "Square"
        require content?

      process()
        -> triangle as Triangle
        content <- "Triangle"
        require content?

Fixed: Give the dispatcher a handler for every type the sealed trait allows

#!ek9
defines module error.e05260.good

  defines trait

    Shape allow only Circle, Square, Triangle
      area() as abstract
        <- rtn as Float?

  defines class

    Circle with trait of Shape
      override area()
        <- rtn as Float: 3.14

    Square with trait of Shape
      override area()
        <- rtn as Float: 1.0

    Triangle with trait of Shape
      override area()
        <- rtn as Float: 0.5

    CompleteProcessor

      process()
        -> circle as Circle
        <- rtn as String: "Circle"

      process() as dispatcher
        -> shape as Shape
        <- rtn as String: "Unknown shape"

      process()
        -> square as Square
        <- rtn as String: "Square"

      process()
        -> triangle as Triangle
        <- rtn as String: "Triangle"

Questions and answers

These Q&A entries show E05260 and its fix: