Effect System Implementation Plan
NOTE THAT THIS DOCUMENT IS OUTDATED AS RELEVANT CODE IS BEING REWRITTEN
Goal
Enable type checking for the simplest effects example in tests/tyck/effects-basic.chester.todo
by implementing the necessary compiler components for the built-in effects system.
Current Status
- We have a basic effects syntax design specified in
docs/src/dev/effects-system.md
- A simple test file
tests/tyck/effects-basic.chester.todo
exists but doesn’t type check yet - Some of the infrastructure for effects already exists in the codebase
Implementation Tasks
1. Parser Enhancements
- Add parsing support for the
/
effect annotation syntax in function types - Parse built-in effect names (
IO
,State
, etc.) as identifiers - Parse effect combinations using the
&
operator - Generate AST nodes that correctly represent effects in function signatures
// Example parser implementation:
def functionDef(): FunctionDef = {
// Parse function signature...
// Check for effect annotation
val effects = if (consume("/")) {
parseEffects()
} else {
Effects.Empty
}
FunctionDef(name, params, returnType, effects, body)
}
2. Built-in Effects Registry
- Define a registry for built-in effect types
- Implement recognition of built-in effects like
IO
andState
- Add a mechanism to validate that effect identifiers refer to built-in effects
// Example registry:
object BuiltinEffects {
val IO = "IO"
val State = "State"
val Exception = "Exception"
val NonTermination = "NonTermination"
val all = Set(IO, State, Exception, NonTermination)
def isBuiltinEffect(name: String): Boolean = all.contains(name)
}
3. Type Representation
- Enhance the
Effects
class to handle built-in effects - Implement function type representation that includes effects
- Support effect combinations (union of effects)
// Example Effects class:
case class Effects(effectMap: Map[String, Term]) {
def combine(other: Effects): Effects = {
Effects(this.effectMap ++ other.effectMap)
}
def contains(effect: String): Boolean = effectMap.contains(effect)
}
4. Type Checking
- Implement effect checking during function definition
- Verify that function bodies only use effects that are declared
- Track effect requirements in the function call chain
- Ensure effects are properly propagated from callee to caller
// Example type checker for function calls:
def checkFunctionCall(call: FunctionCall, context: Context): Type = {
val funcType = checkExpr(call.function, context)
// Check argument types...
// Extract function effects
val functionEffects = extractEffects(funcType)
// Ensure the current context allows these effects
checkEffectsAllowed(functionEffects, context.allowedEffects)
// Return function's return type with effects
ReturnType(funcType, functionEffects)
}
5. Effect Propagation
- Implement a mechanism to accumulate effects from function calls
- Ensure effects are propagated up the call chain
- Handle effect combinations correctly
// Example propagation:
def propagateEffects(callerEffects: Effects, calleeEffects: Effects): Effects = {
// Combine effects from caller and callee
callerEffects.combine(calleeEffects)
}
6. Error Reporting
- Add clear error messages for effect-related type errors
- Report when a function uses unauthorized effects
- Report when effect types are invalid or unknown
// Example error generation:
def unauthorizedEffectError(effect: String, context: Context): Error = {
Error(s"Function uses effect '$effect' but it is not declared in the function signature",
context.location)
}
Implementation Order
-
First Phase: Basic Type Representation
- Enhance the AST and type system to represent effects
- Implement the built-in effects registry
- Add effect annotations to function types
-
Second Phase: Parser Integration
- Update the parser to handle effect annotations
- Parse effect combinations
- Generate correct AST nodes with effects
-
Third Phase: Type Checking
- Implement basic effect checking for function bodies
- Add effect validation in function calls
- Ensure effects are correctly propagated
-
Fourth Phase: Error Handling
- Add descriptive error messages
- Implement suggestions for fixing effect-related errors
-
Fifth Phase: Testing
- Convert the
.todo
test to a regular test file - Add additional tests for more complex effect scenarios
- Verify compatibility with existing code
- Convert the
Timeline
- Days 1-2: First Phase implementation
- Days 3-4: Second Phase implementation
- Days 5-7: Third Phase implementation
- Days 8-9: Fourth Phase implementation
- Day 10: Testing and refinement
Success Criteria
- The
tests/tyck/effects-basic.chester.todo
file can be renamed totests/tyck/effects-basic.chester
and passes type checking - The type checker correctly enforces effect constraints
- Effect propagation works as expected in nested function calls
- Pure functions don’t require effect annotations
- Clear error messages are provided for effect-related type errors