weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! Release-surface contracts for Weir package/docs alignment.

use std::fs;
use std::path::Path;

// ============================================================================
// Compile-time trait assertions for public types
// ============================================================================

macro_rules! assert_public_type_core_traits {
    ($($ty:ty),* $(,)?) => {
        $(
            static_assertions::assert_impl_all!($ty: Send, Sync, Clone, std::fmt::Debug, PartialEq);
        )*
    };
}

#[cfg(feature = "serde")]
macro_rules! assert_public_type_serde_traits {
    ($($ty:ty),* $(,)?) => {
        $(
            static_assertions::assert_impl_all!($ty: serde::Serialize, serde::de::DeserializeOwned);
        )*
    };
}

assert_public_type_core_traits! {
    // Core re-exported type
    weir::DataflowEvidence<u32>,

    // analysis_family (marker/module types, nothing concrete to assert)

    // callgraph
    weir::callgraph::Callgraph,
    weir::callgraph::CallgraphBuildScratch,

    // control_dependence
    weir::control_dependence::ControlDependence,

    // cross_language
    weir::cross_language::CrossLanguage,

    // def_use
    weir::def_use::DefUse,

    // dominators
    weir::dominators::Dominators,

    // escape
    weir::escape::Escape,

    // escapes
    weir::escapes::Escapes,

    // fixed_point_batch
    weir::fixed_point_batch::CsrGraph<'static>,

    // fixed_point_execution_plan
    weir::fixed_point_execution_plan::FixedPointExecutionPlan,

    // fixed_point_execution_plan_cache
    weir::fixed_point_execution_plan_cache::FixedPointExecutionPlanCache,
    weir::fixed_point_execution_plan_cache::FixedPointExecutionPlanCacheStats,

    // fixed_point_graph
    weir::fixed_point_graph::FixedPointAnalysisKind,
    weir::fixed_point_graph::FixedPointAnalysisPlan,
    weir::fixed_point_graph::FixedPointForwardGraph,

    // fixed_point_resident
    weir::fixed_point_resident::FixedPointResidentGraph,
    weir::fixed_point_resident::FixedPointResidentBatch,
    weir::fixed_point_resident::FixedPointResidentBatchStats,
    weir::fixed_point_resident::FixedPointResidentFrontierScratch,
    weir::fixed_point_resident::FixedPointResidentGraphCache,
    weir::fixed_point_resident::FixedPointResidentPlan,
    weir::fixed_point_resident::FixedPointBorrowedResidentPlan<'static>,

    // fixed_point_resident_batch
    weir::fixed_point_resident_batch::FixedPointResidentBatch,
    weir::fixed_point_resident_batch::FixedPointResidentBatchStats,

    // fixed_point_resident_cache
    weir::fixed_point_resident_cache::FixedPointResidentGraphCache,
    weir::fixed_point_resident_cache::FixedPointResidentGraphCacheStats,

    // fixed_point_resident_frontier
    weir::fixed_point_resident_frontier::FixedPointResidentFrontierScratch,

    // fixed_point_resident_plan
    weir::fixed_point_resident_plan::FixedPointResidentPlan,
    weir::fixed_point_resident_plan::FixedPointBorrowedResidentPlan<'static>,

    // fixed_point_scratch
    weir::fixed_point_scratch::FixedPointScratch,
    weir::fixed_point_scratch::FrontierDensityTelemetry,
    weir::fixed_point_scratch::FrontierExecutionMode,
    weir::fixed_point_scratch::ScratchPool<u32>,

    // graph_layout
    weir::graph_layout::CsrGraph<'static>,
    weir::graph_layout::CsrGraphNormalizationScratch,
    weir::graph_layout::LinearDomain,
    weir::graph_layout::NormalizedCsrGraph,

    // ifds
    weir::ifds::Ifds,

    // ifds_gpu
    weir::ifds_gpu::IfdsGpu,
    weir::ifds_gpu::IfdsShape,
    weir::ifds_gpu::IfdsPrepareScratch,
    weir::ifds_gpu::IfdsSolveScratch,
    weir::ifds_gpu::IfdsBorrowedSolveScratch,
    weir::ifds_gpu::PreparedIfdsCsr,
    weir::ifds_gpu::ResidentIfdsHostScratch,
    weir::ifds_gpu::ResidentIfdsParallelHostScratch,

    // ifds_resident_batch
    weir::ifds_resident_batch::ResidentIfdsBatchStats,

    // ifds_resident_cache
    weir::ifds_resident_cache::ResidentIfdsCsrCacheStats,

    // ifds_resident_direct_batch
    weir::ifds_resident_direct_batch::DirectResidentIfdsBatchStats,
    weir::ifds_resident_direct_batch::DirectResidentIfdsGraph<'static>,
    weir::ifds_resident_direct_batch::DirectResidentIfdsGraphKey,

    // ifds_resident_direct_prepare_scratch
    weir::ifds_resident_direct_prepare_scratch::DirectResidentIfdsPrepareScratch,

    // live
    weir::live::Liveness,
    weir::live::LiveFamily,

    // live_at
    weir::live_at::LiveAt,

    // loop_sum
    weir::loop_sum::LoopSum,
    weir::loop_sum::LoopSummarizeScratch,

    // may_alias
    weir::may_alias::MayAlias,

    // must_init
    weir::must_init::MustInit,

    // points_to
    weir::points_to::PointsTo,
    weir::points_to::PointsToFamily,

    // post_dominates
    weir::post_dominates::PostDominates,

    // range
    weir::range::Range,
    weir::range::RangePropagateScratch,

    // range_check
    weir::range_check::RangeCheck,

    // reachability_witness
    weir::reachability_witness::PathSeed,
    weir::reachability_witness::ExtractedStatement,
    weir::reachability_witness::ExtractedPath,
    weir::reachability_witness::NodeAttr,
    weir::reachability_witness::PreparedWitnessGraph<'static>,
    weir::reachability_witness::PrepareWitnessGraphError,
    weir::reachability_witness::PathError,
    weir::reachability_witness::ExplodedDecodeError,

    // reaching
    weir::reaching::ReachingDefs,
    weir::reaching::ReachingFamily,

    // reaching_def
    weir::reaching_def::ReachingDef,

    // scc_query
    weir::scc_query::SccQuery,

    // slice
    weir::slice::BackwardSlice,
    weir::slice::SliceFamily,

    // soundness
    weir::soundness::DataflowEvidence<u32>,

    // ssa
    weir::ssa::Ssa,
    weir::ssa::SsaForm,
    weir::ssa::Block,
    weir::ssa::Cfg,

    // summary
    weir::summary::Summary,
    weir::summary::SummarizeFunctionScratch,

    // value_set
    weir::value_set::ValueSet,
}

// Generic types with type parameters, assert with concrete instantiations
assert_public_type_core_traits! {
    weir::fixed_point_batch::FixedPointBatch<'static, ()>,
    weir::fixed_point_resident_plan::PlanBuilder<weir::fixed_point_resident::FixedPointResidentGraph>,
}

#[cfg(feature = "serde")]
assert_public_type_serde_traits! {
    weir::DataflowEvidence<u32>,
    weir::reachability_witness::PathSeed,
    weir::reachability_witness::ExtractedStatement,
    weir::reachability_witness::ExtractedPath,
    weir::reachability_witness::PrepareWitnessGraphError,
    weir::reachability_witness::PathError,
    weir::reachability_witness::ExplodedDecodeError,
    weir::soundness::DataflowEvidence<u32>,
}

// ============================================================================
// Existing release-surface contract tests (updated)
// ============================================================================

#[test]
fn readme_release_token_matches_package_version() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let manifest = fs::read_to_string(root.join("Cargo.toml"))
        .expect("Cargo.toml should be readable for release-surface contract");
    let readme = fs::read_to_string(root.join("README.md"))
        .expect("README.md should be readable for release-surface contract");

    let version = package_version(&manifest).expect("package.version should be declared");
    let release_token = format!("weir@{version}");
    let version_sentence = format!("Weir `{version}` is the standalone dataflow crate");

    assert!(
        readme.contains(&version_sentence),
        "README must name the exact package version `{version}` in the release surface"
    );
    assert!(
        readme.contains(&release_token),
        "README must expose the exact release package token `{release_token}`"
    );
    assert!(
        !readme.contains("weir@0.0.1") && !readme.contains("Weir `0.0.1`"),
        "README must not advertise stale Weir 0.0.1 release tokens"
    );
}

#[test]
fn readme_keeps_cpu_helpers_oracle_only() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let readme = fs::read_to_string(root.join("README.md"))
        .expect("README.md should be readable for release-surface contract");

    assert!(
        readme.contains("CPU reference routines live under `weir::oracle`"),
        "README must route CPU references through the oracle namespace"
    );
    assert!(
        readme.contains("not part of the production surface"),
        "README must say direct CPU helpers are not production APIs"
    );
    assert!(
        !readme.contains("deprecated compatibility paths"),
        "README must not describe CPU helpers as a compatibility execution path"
    );
}

#[test]
fn internal_gpu_abi_helpers_are_not_public_modules() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let source = fs::read_to_string(root.join("src/lib.rs"))
        .expect("src/lib.rs should be readable for release-surface contract");

    for internal_module in [
        // "dispatch_decode" is intentionally pub mod for ABI decoding helpers
        "output_scratch",
        "dispatch_input_cache",
        "staging_reserve",
    ] {
        assert!(
            source.contains(&format!("mod {internal_module};")),
            "internal module `{internal_module}` must be declared"
        );
        assert!(
            !source.contains(&format!("pub mod {internal_module};")),
            "internal GPU ABI helper `{internal_module}` must not be exposed as public Weir API"
        );
    }
}

#[test]
fn reaching_def_summary_checked_fold_rejects_truncated_triples() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let source = fs::read_to_string(root.join("src/reaching_def_summary.rs"))
        .expect("reaching_def_summary source should be readable for release-surface contract");
    let fold_body = function_body(&source, "try_fold_summary_partials");

    assert!(
        fold_body.contains("partials.len() % 3 != 0")
            && fold_body.contains("not divisible by 3")
            && fold_body.contains("chunks_exact(3)"),
        "try_fold_summary_partials must reject non-triple-aligned GPU summary output before chunks_exact folding"
    );
}

fn package_version(manifest: &str) -> Option<&str> {
    manifest.lines().find_map(|line| {
        let trimmed = line.trim();
        let value = trimmed.strip_prefix("version = ")?;
        value.trim_matches('"').split('"').next()
    })
}

fn function_body<'a>(source: &'a str, name: &str) -> &'a str {
    let start = source
        .find(&format!("fn {name}"))
        .unwrap_or_else(|| panic!("{name} must exist in source"));
    let after_start = &source[start..];
    let open = after_start
        .find('{')
        .unwrap_or_else(|| panic!("{name} must have a body"));
    let mut depth = 0usize;
    for (offset, byte) in after_start[open..].bytes().enumerate() {
        match byte {
            b'{' => depth += 1,
            b'}' => {
                depth -= 1;
                if depth == 0 {
                    return &after_start[open..=open + offset];
                }
            }
            _ => {}
        }
    }
    panic!("{name} body must close");
}