// Effect System Error Test: E0401 - Deep Effect Chain Error
// ==========================================================
//
// What this test validates:
// - Error E0401 is raised even when effects are deeply nested
// - Effect inference correctly traces through call chains
// - Error message shows the full effect propagation path
// - Indirect effectful calls still violate pure trait contracts
//
// Expected error:
// E0401: effectful implementation of pure trait method
// - Effect originates from 'deep_effectful_helper' (IO)
// - Propagates through: log_computation -> helper_2 -> helper_1 -> compute
// - Reaches trait method 'compute' which must be pure
trait Calculator @0.1.0 {
"""
A pure calculation trait.
All computation methods must be deterministic and side-effect free.
"""
fn compute(self, input: Int) -> Int;
fn validate(self, input: Int) -> Bool;
}
gene DeepChainCalculator @0.1.0 {
"""
Calculator that violates purity through a deep call chain.
The effect is 5 levels deep from the trait method.
"""
// Level 5 (deepest): The actual effectful operation
fn deep_effectful_helper(msg: String) -> Unit {
@io.println("[LOG] " + msg)
}
// Level 4: Calls the effectful helper
fn log_computation(value: Int) -> Int {
deep_effectful_helper("Processing: " + @fmt.int(value));
value
}
// Level 3: Calls log_computation
fn helper_3(x: Int) -> Int {
log_computation(x * 2)
}
// Level 2: Calls helper_3
fn helper_2(x: Int) -> Int {
helper_3(x + 10) - 5
}
// Level 1: Calls helper_2
fn helper_1(x: Int) -> Int {
helper_2(x) * 3
}
// Level 0: Trait method implementation - calls helper_1
// ERROR E0401: Effect propagates through 5 levels
impl Calculator {
fn compute(self, input: Int) -> Int {
helper_1(input) + 100
}
// This one is pure and should pass
fn validate(self, input: Int) -> Bool {
input >= 0 && input <= 1000
}
}
}
gene AnotherDeepChain @0.1.0 {
"""
Another example with messaging effect deep in the chain.
"""
// Deep effect: messaging
fn send_metric(name: String, value: Int) -> Unit {
@msg.send(@msg.self(), { type: "metric", name: name, value: value })
}
// Chain to trait method
fn record_metric(x: Int) -> Int {
send_metric("computation", x);
x
}
fn process_with_metrics(x: Int) -> Int {
record_metric(x * x)
}
fn transform(x: Int) -> Int {
process_with_metrics(x + 1)
}
// ERROR E0401: Msg effect propagates through chain
impl Calculator {
fn compute(self, input: Int) -> Int {
transform(input)
}
fn validate(self, input: Int) -> Bool {
input > 0
}
}
}
gene MutationDeepChain @0.1.0 {
"""
Deep chain with mutation effect.
"""
mut call_count: Int = 0
// Deep effect: mutation
fn increment_counter() -> Unit {
self.call_count = self.call_count + 1
}
fn counted_operation(x: Int) -> Int {
increment_counter();
x * 2
}
fn wrapper_a(x: Int) -> Int {
counted_operation(x) + 1
}
fn wrapper_b(x: Int) -> Int {
wrapper_a(x) - 1
}
// ERROR E0401: Mut effect from increment_counter
impl Calculator {
fn compute(self, input: Int) -> Int {
wrapper_b(input)
}
fn validate(self, input: Int) -> Bool {
true
}
}
}
// Expected diagnostic output with full trace:
// error[E0401]: effectful implementation of pure trait method
// --> e0401_deep_chain.dol:52:9
// |
// 52 | fn compute(self, input: Int) -> Int {
// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// |
// = note: trait 'Calculator' declares 'compute' as pure
// = note: effect trace:
// -> compute (line 52)
// -> helper_1 (line 43)
// -> helper_2 (line 38)
// -> helper_3 (line 33)
// -> log_computation (line 28)
// -> deep_effectful_helper (line 23) [IO effect here]
// = help: remove effectful operations from the call chain
test expect_error {
// All compute implementations should fail
assert_error(E0401, DeepChainCalculator.compute);
assert_error(E0401, AnotherDeepChain.compute);
assert_error(E0401, MutationDeepChain.compute);
// Validate implementations should pass (they're pure)
assert_no_error(DeepChainCalculator.validate);
assert_no_error(AnotherDeepChain.validate);
assert_no_error(MutationDeepChain.validate);
}