E08254: MutexLock cannot appear in a generic type parameter — move the lock to a class or component field

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

What went wrong

MutexLock (or a parameterised MutexLock of T) was used as a type argument to another generic — for example List of MutexLock, Optional of MutexLock of Integer, or Dict of (K, MutexLock).

EK9's compile-time concurrency safety relies on every lock having a stable, field-rooted home. Locks buried inside collections defeat static lock-identity analysis and indicate a misuse of the lock idiom: the natural pattern is one MutexLock per shared payload, held as a field on a class or component.

Rationale

EK9 needs to know, at compile time, *which* physical lock each acquisition operates on. This makes data-race detection (slice 1) and deadlock detection (slice 2) tractable. A collection of locks breaks this:

  • Which lock guards which element?
  • Does the iteration order match the lock acquisition order?
  • Is the collection itself shared (and so its mutations need a separate lock)?

These questions don't have static answers, and runtime tracking would defeat the goal of compile-time guarantees.

In practice, code that reaches for "a list of locks" almost always has a structural problem — usually it should be "one lock guarding a list of payloads" instead.

How to fix it

  1. Move the MutexLock to a field on a class or component (the [EXAMPLE] section below: a 'LockableText' class holds the lock as its field, and the List holds LockableText objects)
  2. If you need many independent locks, make a class per protected payload and have the collection hold instances of that class — each instance holds its own lock and its own payload as fields.
  3. Use the Consumer / async-pipeline patterns for fan-out, where the pipeline runtime handles synchronisation invisibly.

Common causes

  • "I want a cache of independently-lockable values" → use a Dict whose value type is a class holding both the lock and the payload, not a Dict whose value type is the lock itself.
  • "I have N similar resources each needing their own lock" → wrap each resource in a class that holds its own MutexLock as a field.

Worked examples

  • ek9 -q 158 (How do I protect shared data from concurrent access in EK9?)

See also

  • E08250: 'this' escapes constructor — related slice-1 rule
  • E08256: MutexLock construction outside field initialiser

Examples

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

Fails with E08254: MutexLock cannot appear in a generic type parameter — move the lock to a class or component field

#!ek9
defines module error.e08254.bad

  defines function

    badListOfLocks()
      locks <- List() of MutexLock of String
      require locks?

    badOptionalLock()
      maybeLock <- Optional() of MutexLock of Integer
      require maybeLock?

Fixed: Hold each lock in a field of a type, and collect that type

#!ek9
defines module error.e08254.good

  defines class

    LockableText
      text as MutexLock of String: MutexLock("")

      default operator ?

  defines function

    listOfLockables()
      <- rtn as List of LockableText: [LockableText(), LockableText()]

Questions and answers

These Q&A entries show E08254 and its fix: