dol 0.8.1

DOL (Design Ontology Language) - A declarative specification language for ontology-first development
// 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);
}