yulang-runtime-refine 0.1.0

Runtime type refinement, validation, invariant checks, and hygiene printing for Yulang.
Documentation
use super::*;

pub(super) fn pure_handler_bindings(
    module: &Module,
) -> HashMap<typed_ir::Path, Vec<typed_ir::Path>> {
    module
        .bindings
        .iter()
        .filter_map(|binding| {
            expr_pure_handler_consumes(&binding.body)
                .map(|consumes| (binding.name.clone(), consumes))
        })
        .collect()
}

pub(super) fn expr_pure_handler_consumes(expr: &Expr) -> Option<Vec<typed_ir::Path>> {
    match &expr.kind {
        ExprKind::Handle { handler, .. }
            if handler.residual_after.as_ref().is_some_and(effect_is_empty) =>
        {
            Some(handler.consumes.clone())
        }
        ExprKind::Lambda { body, .. }
        | ExprKind::BindHere { expr: body }
        | ExprKind::Thunk { expr: body, .. }
        | ExprKind::LocalPushId { body, .. }
        | ExprKind::AddId { thunk: body, .. }
        | ExprKind::Coerce { expr: body, .. }
        | ExprKind::Pack { expr: body, .. } => expr_pure_handler_consumes(body),
        ExprKind::Block {
            tail: Some(tail), ..
        } => expr_pure_handler_consumes(tail),
        ExprKind::Block { stmts, tail: None } => match stmts.last() {
            Some(Stmt::Expr(expr)) => expr_pure_handler_consumes(expr),
            _ => None,
        },
        _ => None,
    }
}

pub(super) fn effect_path_sets_intersect(
    left: &[typed_ir::Path],
    right: &[typed_ir::Path],
) -> bool {
    left.iter()
        .any(|left| right.iter().any(|right| effect_paths_match(left, right)))
}