E05240: type is not permitted to extend/implement this sealed type
What went wrong
A class extends or implements a sealed type (trait or class) that uses 'allow only', but the class is not in the permitted list. The 'allow only' clause creates a sealed type -- only the explicitly named classes may extend or implement it. This restriction is enforced after the full type hierarchy has been established (PRE_IR_CHECKS phase).
This works identically for both sealed traits and sealed classes:
- Sealed trait: 'Shape allow only Circle, Square' on a trait
- Sealed class: 'Shape allow only Circle, Square as open' on a class
Enforcement is TRANSITIVE. Every concrete descendant must appear in the 'allow only' list of every sealed type above it -- at any depth, not just the direct subclasses. A grandchild that extends a permitted subclass (rather than the sealed type itself) must STILL be named in the sealed type's list. For example, given 'Vehicle allow only Car, Sedan as open' where 'Sedan extends Car' (not Vehicle directly), Sedan must still appear in Vehicle's list because Vehicle is sealed. See 'ek9 -q 303'.
Abstract classes are exempt from this check because they cannot be instantiated. The sealed set controls which concrete runtime types exist. If an abstract helper class implements a sealed type, only its concrete subclasses are checked -- and each of those must still appear in the sealed type's 'allow only' list even though it inherits the type transitively rather than declaring it directly.
Dynamic classes (anonymous classes created inline) are always rejected because their generated names cannot appear in an 'allow only' list.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 101 (Why are types closed by default in EK9?)
- ek9 -q 303 (Can a permitted subclass also be sealed in EK9?)
How to fix it
Either add the class to the sealed type's 'allow only' list, or remove the extension/implementation from the class. If the class is an intermediate abstract helper, mark it 'as abstract' to exempt it from the check.
Common causes
- Refactoring: extracting a new class that extends a sealed type without updating the 'allow only' list
- Adding a new implementation of a sealed type without checking constraints
- Dynamic classes implementing sealed types (always rejected)
- Forgetting to update 'allow only' after splitting a class hierarchy
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E05240: type is not permitted to extend/implement this sealed type
#!ek9 defines module error.e05240.bad defines trait SealedTrait allow only AllowedClass1, AllowedClass2 process() as abstract defines class AllowedClass1 with trait of SealedTrait override process() content <- "Allowed 1" require content? AllowedClass2 with trait of SealedTrait override process() content <- "Allowed 2" require content? AddedLater with trait of SealedTrait override process() content <- "Added later" require content? AlsoAddedLater with trait of SealedTrait override process() content <- "Also added later" require content? defines function testDynamic() processor <- () trait of SealedTrait as class override process() content <- "Dynamic" require content? require processor?
Fixed: Add each class to the allow only list - a dynamic class can never be on it, so use one that is
#!ek9 defines module error.e05240.good.fix defines trait SealedTrait allow only AllowedClass1, AllowedClass2, AddedLater, AlsoAddedLater process() as abstract defines class AllowedClass1 with trait of SealedTrait override process() content <- "Allowed 1" require content? AllowedClass2 with trait of SealedTrait override process() content <- "Allowed 2" require content? AddedLater with trait of SealedTrait override process() content <- "Added later" require content? AlsoAddedLater with trait of SealedTrait override process() content <- "Also added later" require content? defines function testDynamic() processor <- AllowedClass1() require processor?
Fixed: Only the types the sealed trait names take it on; any other type uses composition
#!ek9 defines module error.e05240.good defines trait SealedTrait allow only AllowedClass1, AllowedClass2 process() as abstract defines class AllowedClass1 with trait of SealedTrait override process() content <- "Allowed 1" require content? AllowedClass2 with trait of SealedTrait override process() content <- "Allowed 2" require content? //Not in the list: it holds an allowed type rather than taking on the trait Composed delegate as AllowedClass1: AllowedClass1() process() delegate.process() default operator ?
Questions and answers
These Q&A entries show E05240 and its fix:
- Q101: Why are types closed by default in EK9?
- Q298: What is allow only on traits in EK9?
- Q299: How does allow only work with dispatchers in EK9?
- Q300: Can abstract classes be in an allow only list in EK9?
- Q301: How do I restrict which classes can extend my class in EK9?
- Q302: How do dispatchers work with sealed classes in EK9?
- Q303: Can a permitted subclass also be sealed in EK9?
- Q1121: Write a dispatcher over a sealed Shape hierarchy with Circle, Square, and Triangle.
- Q1171: Define a sealed Shape class that permits only Circle, Square, and Triangle.
- Q1172: Build a chained sealed hierarchy: Vehicle permits Car and Truck, Car permits Sedan and Hatchback.