//! Automatic invariant synthesis for Trident programs.
//!
//! Techniques:
//! 1. Template-based synthesis: match common patterns (accumulation, counting,
//!    monotonic updates) and instantiate invariant templates.
//! 2. Counterexample-guided inductive synthesis (CEGIS): propose candidate
//!    invariants, verify with solver, refine using counterexamples.
//! 3. Specification inference: suggest postconditions from code analysis.

mod infer;
mod templates;
#[cfg(test)]
mod tests;

pub(crate) use infer::{cegis_refine, infer_postconditions_from_body, infer_preconditions};
pub(crate) use templates::match_templates;

#[cfg(test)]
pub(crate) use infer::{infer_postconditions_from_constraints, verify_candidate, weaken_candidate};

pub(crate) use crate::ast::*;
pub(crate) use crate::solve;
pub(crate) use crate::sym::{self, ConstraintSystem, SymValue};
use std::collections::BTreeMap;

// โ”€โ”€โ”€ Data Structures โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// A synthesized invariant or specification.
#[derive(Clone, Debug)]
pub struct SynthesizedSpec {
    /// The function this applies to.
    pub function: String,
    /// The kind of spec.
    pub kind: SpecKind,
    /// The invariant/spec expression as a string.
    pub expression: String,
    /// Confidence level (0-100 percent).
    pub confidence: u8,
    /// Human-readable explanation.
    pub explanation: String,
}

impl SynthesizedSpec {
    /// Format this spec as a human-readable suggestion.
    pub fn format(&self) -> String {
        let kind_str = match &self.kind {
            SpecKind::LoopInvariant { loop_var } => {
                format!("loop invariant (over {})", loop_var)
            }
            SpecKind::Postcondition => "postcondition (#[ensures])".to_string(),
            SpecKind::Precondition => "precondition (#[requires])".to_string(),
            SpecKind::Assertion => "assertion".to_string(),
        };
        let confidence_str = if self.confidence >= 90 {
            "high"
        } else if self.confidence >= 60 {
            "medium"
        } else {
            "low"
        };
        format!(
            "  [{}] {} {}: {}\n    {}",
            confidence_str, self.function, kind_str, self.expression, self.explanation,
        )
    }
}

/// The kind of synthesized specification.
#[derive(Clone, Debug, PartialEq)]
pub enum SpecKind {
    /// Loop invariant for a specific loop.
    LoopInvariant { loop_var: String },
    /// Function postcondition (`#[ensures]`).
    Postcondition,
    /// Function precondition (`#[requires]`).
    Precondition,
    /// Assertion that could be added.
    Assertion,
}

// โ”€โ”€โ”€ Pattern Descriptors โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// Describes an accumulation pattern found in a loop.
#[derive(Clone, Debug)]
struct AccumulationPattern {
    /// The accumulator variable name.
    acc_var: String,
    /// The loop iteration variable name.
    loop_var: String,
    /// Initial value of the accumulator (as source text).
    init_value: String,
    /// The operation applied each iteration.
    op: AccumulationOp,
}

/// The kind of accumulation operation.
#[derive(Clone, Debug, PartialEq)]
enum AccumulationOp {
    /// `acc = acc + expr`
    Additive,
    /// `acc = acc * expr`
    Multiplicative,
    /// `acc = acc + 1` inside a conditional (counting)
    Counting,
}

/// Describes a monotonic update pattern.
#[derive(Clone, Debug)]
struct MonotonicPattern {
    /// The variable being updated.
    var: String,
    /// The loop iteration variable.
    loop_var: String,
    /// Initial value expression.
    init_value: String,
}

// โ”€โ”€โ”€ Top-Level Entry Points โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// Analyze a file and synthesize specifications for all functions.
pub fn synthesize_specs(file: &File) -> Vec<SynthesizedSpec> {
    let mut specs = Vec::new();
    for item in &file.items {
        if let Item::Fn(func) = &item.node {
            if func.body.is_some() {
                let mut fn_specs = synthesize_for_function(func, file);
                specs.append(&mut fn_specs);
            }
        }
    }
    specs
}

/// Format all synthesized specs as a human-readable report.
pub fn format_report(specs: &[SynthesizedSpec]) -> String {
    if specs.is_empty() {
        return "No specifications synthesized.\n".to_string();
    }
    let mut report = String::new();
    report.push_str(&format!(
        "Synthesized {} specification(s):\n\n",
        specs.len()
    ));
    for spec in specs {
        report.push_str(&spec.format());
        report.push('\n');
    }
    report
}

// โ”€โ”€โ”€ Per-Function Synthesis โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// Synthesize specs for a single function.
fn synthesize_for_function(func: &FnDef, file: &File) -> Vec<SynthesizedSpec> {
    let fn_name = &func.name.node;
    let mut specs = Vec::new();

    // 1. Template-based pattern matching
    let mut template_specs = match_templates(func);
    specs.append(&mut template_specs);

    // 2. Infer preconditions from assertions
    let mut pre_specs = infer_preconditions(func);
    specs.append(&mut pre_specs);

    // 3. Infer postconditions from symbolic execution
    if let Some(ref body) = func.body {
        let mut post_specs = infer_postconditions_from_body(func, &body.node);
        specs.append(&mut post_specs);
    }

    // 4. CEGIS refinement: verify template candidates against the solver
    let candidates: Vec<String> = specs.iter().map(|s| s.expression.clone()).collect();
    if !candidates.is_empty() {
        let refined = cegis_refine(func, file, &candidates);
        // Update confidence for candidates that were verified
        for spec in &mut specs {
            if refined.iter().any(|r| r.expression == spec.expression) {
                spec.confidence = spec.confidence.max(90);
            }
        }
    }

    // Set function name on all specs
    for spec in &mut specs {
        spec.function = fn_name.clone();
    }

    specs
}

// โ”€โ”€โ”€ AST Utility Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// Collect mutable variable initializations from a block.
/// Returns `(variable_name, init_expression)` pairs.
pub(crate) fn collect_mut_inits(block: &Block) -> Vec<(String, Expr)> {
    let mut inits = Vec::new();
    for stmt in &block.stmts {
        if let Stmt::Let {
            mutable: true,
            pattern: Pattern::Name(name),
            init,
            ..
        } = &stmt.node
        {
            inits.push((name.node.clone(), init.node.clone()));
        }
    }
    inits
}

/// Check if a `Place` is a simple variable reference to the given name.
pub(crate) fn place_is_var(place: &Place, name: &str) -> bool {
    matches!(place, Place::Var(n) if n == name)
}

/// Check if an expression is a simple variable reference to the given name.
pub(crate) fn expr_is_var(expr: &Expr, name: &str) -> bool {
    matches!(expr, Expr::Var(n) if n == name)
}

/// Convert an expression to a human-readable string (best effort).
pub(crate) fn expr_to_string(expr: &Expr) -> String {
    match expr {
        Expr::Literal(Literal::Integer(n)) => n.to_string(),
        Expr::Literal(Literal::Bool(b)) => b.to_string(),
        Expr::Var(name) => name.clone(),
        Expr::BinOp { op, lhs, rhs } => {
            let l = expr_to_string(&lhs.node);
            let r = expr_to_string(&rhs.node);
            format!("({} {} {})", l, op.as_str(), r)
        }
        Expr::Call { path, args, .. } => {
            let name = path.node.as_dotted();
            let arg_strs: Vec<String> = args.iter().map(|a| expr_to_string(&a.node)).collect();
            format!("{}({})", name, arg_strs.join(", "))
        }
        Expr::Index { expr, index } => {
            format!(
                "{}[{}]",
                expr_to_string(&expr.node),
                expr_to_string(&index.node)
            )
        }
        Expr::FieldAccess { expr, field } => {
            format!("{}.{}", expr_to_string(&expr.node), field.node)
        }
        Expr::Tuple(elems) => {
            let parts: Vec<String> = elems.iter().map(|e| expr_to_string(&e.node)).collect();
            format!("({})", parts.join(", "))
        }
        Expr::ArrayInit(elems) => {
            let parts: Vec<String> = elems.iter().map(|e| expr_to_string(&e.node)).collect();
            format!("[{}]", parts.join(", "))
        }
        Expr::StructInit { path, fields } => {
            let name = path.node.as_dotted();
            let field_strs: Vec<String> = fields
                .iter()
                .map(|(n, v)| format!("{}: {}", n.node, expr_to_string(&v.node)))
                .collect();
            format!("{} {{ {} }}", name, field_strs.join(", "))
        }
    }
}

Dimensions

trident/src/diagnostic/mod.rs
trident/src/ir/mod.rs
trident/src/deploy/mod.rs
trident/src/syntax/mod.rs
trident/src/api/mod.rs
nebu/rs/extension/mod.rs
optica/src/render/mod.rs
trident/src/config/mod.rs
trident/src/field/mod.rs
trident/src/cli/mod.rs
optica/src/parser/mod.rs
trident/src/neural/mod.rs
trident/src/cost/mod.rs
trident/src/typecheck/mod.rs
optica/src/server/mod.rs
trident/src/package/mod.rs
optica/src/scanner/mod.rs
optica/src/output/mod.rs
trident/src/verify/mod.rs
optica/src/graph/mod.rs
trident/src/ast/mod.rs
trident/src/lsp/mod.rs
trident/src/runtime/mod.rs
trident/src/gpu/mod.rs
optica/src/query/mod.rs
trident/src/lsp/semantic/mod.rs
trident/src/verify/equiv/mod.rs
trident/src/package/hash/mod.rs
trident/src/neural/training/mod.rs
trident/src/ir/tir/mod.rs
rs/macros/src/addressed/mod.rs
trident/src/package/registry/mod.rs
rs/rsc/src/lints/mod.rs
trident/src/verify/report/mod.rs
trident/src/config/resolve/mod.rs
trident/src/verify/solve/mod.rs
rs/macros/src/registers/mod.rs
trident/src/verify/smt/mod.rs
rs/macros/src/cell/mod.rs
rs/core/src/fixed_point/mod.rs
trident/src/neural/data/mod.rs
rs/core/src/bounded/mod.rs
trident/src/lsp/util/mod.rs
trident/src/typecheck/tests/mod.rs
trident/src/neural/model/mod.rs
trident/src/cost/stack_verifier/mod.rs
trident/src/syntax/grammar/mod.rs
trident/src/package/manifest/mod.rs
trident/src/syntax/parser/mod.rs
trident/src/ir/kir/mod.rs
trident/src/neural/inference/mod.rs
trident/src/syntax/lexer/mod.rs
trident/src/cost/model/mod.rs
trident/src/ir/lir/mod.rs
trident/src/syntax/format/mod.rs
trident/src/config/scaffold/mod.rs
trident/src/verify/sym/mod.rs
trident/src/api/tests/mod.rs
trident/src/package/store/mod.rs
trident/src/ir/tree/mod.rs
trident/src/ir/kir/lower/mod.rs
trident/src/ir/lir/lower/mod.rs
trident/src/ir/tir/lower/mod.rs
trident/src/ir/tir/builder/mod.rs
trident/src/ir/tir/neural/mod.rs
trident/src/neural/data/tir_graph/mod.rs
trident/src/syntax/parser/tests/mod.rs
cw-cyber/packages/cyber-std/src/tokenfactory/mod.rs
trident/src/ir/tree/lower/mod.rs
trident/src/ir/tir/stack/mod.rs
cw-cyber/contracts/cybernet/src/tests/mod.rs
trident/src/ir/tir/optimize/mod.rs

Local Graph