yulang-runtime 0.1.1

Runtime IR, validation, monomorphization, and VM support for Yulang
Documentation
use super::*;

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct DemandQueue {
    semantics: DemandSemantics,
    queue: std::collections::VecDeque<Demand>,
    seen: std::collections::HashSet<DemandKey>,
    profile: DemandQueueProfile,
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct DemandQueueProfile {
    pub attempted: usize,
    pub pushed: usize,
    pub pushed_open: usize,
    pub pushed_closed: usize,
    pub skipped_duplicate: usize,
    pub skipped_covered_by_closed: usize,
}

impl DemandQueue {
    pub(super) fn with_semantics(semantics: DemandSemantics) -> Self {
        Self {
            semantics,
            ..Self::default()
        }
    }

    pub fn push(&mut self, target: typed_ir::Path, expected: RuntimeType) -> bool {
        let demand = Demand::new_with_semantics(&self.semantics, target, expected);
        self.push_demand(demand)
    }

    pub fn push_signature(
        &mut self,
        target: typed_ir::Path,
        expected: RuntimeType,
        signature: DemandSignature,
    ) -> bool {
        let demand =
            Demand::with_signature_and_semantics(&self.semantics, target, expected, signature);
        self.push_demand(demand)
    }

    fn push_demand(&mut self, demand: Demand) -> bool {
        self.profile.attempted += 1;
        if !demand.key.signature.is_closed()
            && self.seen.iter().any(|key| {
                key.target == demand.target
                    && key.signature.is_closed()
                    && closed_signature_covers_open(&key.signature, &demand.key.signature)
            })
        {
            self.profile.skipped_covered_by_closed += 1;
            return false;
        }
        if !self.seen.insert(demand.key.clone()) {
            self.profile.skipped_duplicate += 1;
            return false;
        }
        if demand.key.signature.is_closed() {
            self.profile.pushed_closed += 1;
        } else {
            self.profile.pushed_open += 1;
        }
        self.profile.pushed += 1;
        self.queue.push_back(demand);
        true
    }

    pub fn pop_front(&mut self) -> Option<Demand> {
        self.queue.pop_front()
    }

    pub fn len(&self) -> usize {
        self.queue.len()
    }

    pub fn is_empty(&self) -> bool {
        self.queue.is_empty()
    }

    pub fn profile(&self) -> DemandQueueProfile {
        self.profile
    }

    pub fn iter(&self) -> impl Iterator<Item = &Demand> {
        self.queue.iter()
    }
}

impl DemandQueueProfile {
    pub fn merge(&mut self, other: Self) {
        self.attempted += other.attempted;
        self.pushed += other.pushed;
        self.pushed_open += other.pushed_open;
        self.pushed_closed += other.pushed_closed;
        self.skipped_duplicate += other.skipped_duplicate;
        self.skipped_covered_by_closed += other.skipped_covered_by_closed;
    }
}

fn closed_signature_covers_open(closed: &DemandSignature, open: &DemandSignature) -> bool {
    match (closed, open) {
        (_, DemandSignature::Ignored | DemandSignature::Hole(_)) => true,
        (DemandSignature::Core(closed), DemandSignature::Core(open)) => {
            closed_core_type_covers_open(closed, open)
        }
        (
            DemandSignature::Fun {
                param: closed_param,
                ret: closed_ret,
            },
            DemandSignature::Fun {
                param: open_param,
                ret: open_ret,
            },
        ) => {
            closed_signature_covers_open(closed_param, open_param)
                && closed_signature_covers_open(closed_ret, open_ret)
        }
        (
            DemandSignature::Thunk {
                effect: closed_effect,
                value: closed_value,
            },
            DemandSignature::Thunk {
                effect: open_effect,
                value: open_value,
            },
        ) => {
            closed_effect_covers_open(closed_effect, open_effect)
                && closed_signature_covers_open(closed_value, open_value)
        }
        _ => false,
    }
}

fn closed_effect_covers_open(closed: &DemandEffect, open: &DemandEffect) -> bool {
    match (closed, open) {
        (_, DemandEffect::Hole(_)) => true,
        (DemandEffect::Empty, DemandEffect::Empty) => true,
        (DemandEffect::Atom(closed), DemandEffect::Atom(open)) => {
            closed_core_type_covers_open(closed, open)
        }
        (DemandEffect::Row(closed), DemandEffect::Row(open)) => {
            closed.len() == open.len()
                && closed
                    .iter()
                    .zip(open)
                    .all(|(closed, open)| closed_effect_covers_open(closed, open))
        }
        _ => false,
    }
}

fn closed_core_type_covers_open(closed: &DemandCoreType, open: &DemandCoreType) -> bool {
    match (closed, open) {
        (_, DemandCoreType::Any | DemandCoreType::Hole(_)) => true,
        (DemandCoreType::Never, DemandCoreType::Never) => true,
        (
            DemandCoreType::Named {
                path: closed_path,
                args: closed_args,
            },
            DemandCoreType::Named {
                path: open_path,
                args: open_args,
            },
        ) => {
            closed_path == open_path
                && closed_args.len() == open_args.len()
                && closed_args
                    .iter()
                    .zip(open_args)
                    .all(|(closed, open)| closed_type_arg_covers_open(closed, open))
        }
        (
            DemandCoreType::Fun {
                param: closed_param,
                param_effect: closed_param_effect,
                ret_effect: closed_ret_effect,
                ret: closed_ret,
            },
            DemandCoreType::Fun {
                param: open_param,
                param_effect: open_param_effect,
                ret_effect: open_ret_effect,
                ret: open_ret,
            },
        ) => {
            closed_core_type_covers_open(closed_param, open_param)
                && closed_effect_covers_open(closed_param_effect, open_param_effect)
                && closed_effect_covers_open(closed_ret_effect, open_ret_effect)
                && closed_core_type_covers_open(closed_ret, open_ret)
        }
        (DemandCoreType::Tuple(closed), DemandCoreType::Tuple(open))
        | (DemandCoreType::Union(closed), DemandCoreType::Union(open))
        | (DemandCoreType::Inter(closed), DemandCoreType::Inter(open)) => {
            closed.len() == open.len()
                && closed
                    .iter()
                    .zip(open)
                    .all(|(closed, open)| closed_core_type_covers_open(closed, open))
        }
        (DemandCoreType::Record(closed), DemandCoreType::Record(open)) => {
            closed.len() == open.len()
                && closed.iter().zip(open).all(|(closed, open)| {
                    closed.name == open.name
                        && closed.optional == open.optional
                        && closed_core_type_covers_open(&closed.value, &open.value)
                })
        }
        (DemandCoreType::Variant(closed), DemandCoreType::Variant(open)) => {
            closed.len() == open.len()
                && closed.iter().zip(open).all(|(closed, open)| {
                    closed.name == open.name
                        && closed.payloads.len() == open.payloads.len()
                        && closed
                            .payloads
                            .iter()
                            .zip(&open.payloads)
                            .all(|(closed, open)| closed_core_type_covers_open(closed, open))
                })
        }
        (DemandCoreType::RowAsValue(closed), DemandCoreType::RowAsValue(open)) => {
            closed.len() == open.len()
                && closed
                    .iter()
                    .zip(open)
                    .all(|(closed, open)| closed_effect_covers_open(closed, open))
        }
        (
            DemandCoreType::Recursive {
                var: closed_var,
                body: closed_body,
            },
            DemandCoreType::Recursive {
                var: open_var,
                body: open_body,
            },
        ) => closed_var == open_var && closed_core_type_covers_open(closed_body, open_body),
        _ => false,
    }
}

fn closed_type_arg_covers_open(closed: &DemandTypeArg, open: &DemandTypeArg) -> bool {
    match (closed, open) {
        (DemandTypeArg::Type(closed), DemandTypeArg::Type(open)) => {
            closed_core_type_covers_open(closed, open)
        }
        (
            DemandTypeArg::Bounds {
                lower: closed_lower,
                upper: closed_upper,
            },
            DemandTypeArg::Bounds {
                lower: open_lower,
                upper: open_upper,
            },
        ) => {
            optional_closed_core_type_covers_open(closed_lower.as_ref(), open_lower.as_ref())
                && optional_closed_core_type_covers_open(closed_upper.as_ref(), open_upper.as_ref())
        }
        _ => false,
    }
}

fn optional_closed_core_type_covers_open(
    closed: Option<&DemandCoreType>,
    open: Option<&DemandCoreType>,
) -> bool {
    match (closed, open) {
        (_, None) => true,
        (Some(closed), Some(open)) => closed_core_type_covers_open(closed, open),
        (None, Some(_)) => false,
    }
}