logicaffeine_proof/error.rs
1//! Error types for proof search and unification.
2//!
3//! This module defines [`ProofError`], which captures all failure modes
4//! during proof construction. Errors are designed to be informative for
5//! debugging and educational feedback.
6//!
7//! # Error Categories
8//!
9//! | Category | Variants | Meaning |
10//! |----------|----------|---------|
11//! | Search | `NoProofFound`, `DepthExceeded` | Proof search terminated |
12//! | Unification | `OccursCheck`, `UnificationFailed`, `ExprUnificationFailed` | Terms cannot be unified |
13//! | Matching | `SymbolMismatch`, `ArityMismatch` | Structural incompatibility |
14//! | Higher-Order | `PatternNotDistinct`, `NotAPattern`, `ScopeViolation` | Miller pattern failures |
15//!
16//! # Example
17//!
18//! ```
19//! use logicaffeine_proof::ProofError;
20//!
21//! fn check_result(result: Result<(), ProofError>) {
22//! match result {
23//! Ok(()) => println!("Proof found"),
24//! Err(ProofError::NoProofFound) => println!("No proof exists"),
25//! Err(ProofError::DepthExceeded) => println!("Search too deep"),
26//! Err(e) => println!("Error: {}", e),
27//! }
28//! }
29//! ```
30
31use crate::{ProofExpr, ProofTerm};
32use std::fmt;
33
34/// Errors that can occur during proof search.
35#[derive(Debug, Clone)]
36pub enum ProofError {
37 /// No proof was found for the given goal.
38 NoProofFound,
39
40 /// The proof search exceeded the maximum depth limit.
41 DepthExceeded,
42
43 /// Unification failed due to occurs check.
44 /// This prevents infinite types like x = f(x).
45 OccursCheck {
46 variable: String,
47 term: ProofTerm,
48 },
49
50 /// Unification failed because terms could not be unified.
51 UnificationFailed {
52 left: ProofTerm,
53 right: ProofTerm,
54 },
55
56 /// Expression-level unification failed.
57 ExprUnificationFailed {
58 left: ProofExpr,
59 right: ProofExpr,
60 },
61
62 /// Symbol mismatch during unification.
63 SymbolMismatch {
64 left: String,
65 right: String,
66 },
67
68 /// Arity mismatch during unification.
69 ArityMismatch {
70 expected: usize,
71 found: usize,
72 },
73
74 // --- Higher-Order Pattern Unification ---
75
76 /// The pattern has non-distinct arguments (e.g., ?F(x, x))
77 /// Miller patterns require distinct bound variables.
78 PatternNotDistinct(String),
79
80 /// Expression is not a valid Miller pattern.
81 /// Pattern arguments must be Term(BoundVarRef(...)).
82 NotAPattern(ProofExpr),
83
84 /// RHS uses variables not in pattern scope.
85 /// In ?P(x) = Body, Body must only use variables that appear in the pattern.
86 ScopeViolation {
87 var: String,
88 allowed: Vec<String>,
89 },
90}
91
92impl fmt::Display for ProofError {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 match self {
95 ProofError::NoProofFound => {
96 write!(f, "No proof found: the goal could not be derived from the knowledge base")
97 }
98 ProofError::DepthExceeded => {
99 write!(f, "Proof search exceeded maximum depth limit")
100 }
101 ProofError::OccursCheck { variable, term } => {
102 write!(
103 f,
104 "Occurs check failed: variable '{}' appears in term '{}' (would create infinite type)",
105 variable, term
106 )
107 }
108 ProofError::UnificationFailed { left, right } => {
109 write!(f, "Unification failed: cannot unify '{}' with '{}'", left, right)
110 }
111 ProofError::ExprUnificationFailed { left, right } => {
112 write!(f, "Expression unification failed: cannot unify '{}' with '{}'", left, right)
113 }
114 ProofError::SymbolMismatch { left, right } => {
115 write!(f, "Symbol mismatch: '{}' vs '{}'", left, right)
116 }
117 ProofError::ArityMismatch { expected, found } => {
118 write!(f, "Arity mismatch: expected {} arguments, found {}", expected, found)
119 }
120 ProofError::PatternNotDistinct(var) => {
121 write!(f, "Pattern has duplicate variable '{}': Miller patterns require distinct bound variables", var)
122 }
123 ProofError::NotAPattern(expr) => {
124 write!(f, "Not a valid Miller pattern: '{}' (arguments must be bound variable references)", expr)
125 }
126 ProofError::ScopeViolation { var, allowed } => {
127 write!(f, "Scope violation: variable '{}' not in pattern scope {:?}", var, allowed)
128 }
129 }
130 }
131}
132
133impl std::error::Error for ProofError {}
134
135/// Result type for proof operations.
136pub type ProofResult<T> = Result<T, ProofError>;