knave 0.9.8

A small Lisp for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use rustc_hash::FxHashMap;

use super::traits::Implementor;
use super::ty::{Bound, GenericId, Type};
pub struct Requirement {
    pub bound: Bound,
    pub implementor: Type,
}

pub enum Selection {
    Implemented {
        requirements: Vec<Requirement>,
        argument: Option<Type>,
    },
    Undecided,
    Missing,
}

impl Selection {
    #[inline]
    pub fn best(self, other: Selection) -> Selection {
        match (self, other) {
            (implemented @ Selection::Implemented { .. }, _)
            | (_, implemented @ Selection::Implemented { .. }) => implemented,
            (Selection::Undecided, _) | (_, Selection::Undecided) => Selection::Undecided,
            (Selection::Missing, Selection::Missing) => Selection::Missing,
        }
    }
}

pub enum PatternMatch {
    Matched(FxHashMap<GenericId, Type>),
    Undecided,
    Missing,
}

pub struct ImplementorMatch<'s> {
    implementor: &'s Implementor,
    bindings: FxHashMap<GenericId, Type>,
    undecided: bool,
}

impl<'s> ImplementorMatch<'s> {
    pub fn select(
        implementor: &'s Implementor,
        bound: &Bound,
        target: &Type,
        associated: bool,
    ) -> Selection {
        let mut matcher = Self {
            implementor,
            bindings: FxHashMap::default(),
            undecided: false,
        };
        if !matcher.matches(&implementor.scheme.body, target) {
            return Selection::Missing;
        }
        if associated {
            matcher.associated(bound)
        } else {
            matcher.parameter(bound, target)
        }
    }

    pub fn match_pattern(
        implementor: &'s Implementor,
        pattern: &Type,
        target: &Type,
    ) -> PatternMatch {
        let mut matcher = Self {
            implementor,
            bindings: FxHashMap::default(),
            undecided: false,
        };
        match (matcher.matches(pattern, target), matcher.undecided) {
            (false, _) => PatternMatch::Missing,
            (true, true) => PatternMatch::Undecided,
            (true, false) => PatternMatch::Matched(matcher.bindings),
        }
    }

    fn associated(&mut self, bound: &Bound) -> Selection {
        if self.undecided {
            return Selection::Undecided;
        }
        let argument = self
            .implementor
            .argument
            .as_ref()
            .unwrap_or(&self.implementor.scheme.body)
            .substitute(&self.bindings);
        if let Some(expected) = &bound.argument
            && !matches!(expected, Type::Var(_))
            && !matches!(argument, Type::Var(_))
            && argument != *expected
        {
            return Selection::Missing;
        }
        Selection::Implemented {
            requirements: self.requirements(),
            argument: Some(argument),
        }
    }

    fn parameter(&mut self, bound: &Bound, target: &Type) -> Selection {
        let pattern_argument = self
            .implementor
            .argument
            .as_ref()
            .unwrap_or(&self.implementor.scheme.body);
        let target_argument = bound.argument.as_ref().unwrap_or(target);
        if !self.matches(pattern_argument, target_argument) {
            return Selection::Missing;
        }
        if self.undecided {
            return Selection::Undecided;
        }
        Selection::Implemented {
            requirements: self.requirements(),
            argument: None,
        }
    }

    fn matches(&mut self, pattern: &Type, target: &Type) -> bool {
        match (pattern, target) {
            (Type::Generic(generic), _) if self.is_parameter(*generic) => {
                self.bind(*generic, target)
            }
            (_, Type::Var(_)) => self.leave_undecided(),
            _ => {
                pattern.shares_head_with(target)
                    && self.matches_all(pattern.parts(), target.parts())
            }
        }
    }

    fn matches_all(&mut self, patterns: Vec<&Type>, targets: Vec<&Type>) -> bool {
        patterns
            .into_iter()
            .zip(targets)
            .all(|(pattern, target)| self.matches(pattern, target))
    }

    fn leave_undecided(&mut self) -> bool {
        self.undecided = true;
        true
    }

    fn is_parameter(&self, generic: GenericId) -> bool {
        self.implementor
            .scheme
            .params
            .iter()
            .any(|param| param.id == generic)
    }

    fn bind(&mut self, generic: GenericId, target: &Type) -> bool {
        let bound = self
            .bindings
            .entry(generic)
            .or_insert_with(|| target.clone());
        bound == target
    }

    fn requirements(&self) -> Vec<Requirement> {
        self.implementor
            .scheme
            .params
            .iter()
            .filter_map(|param| Some((param, self.bindings.get(&param.id)?)))
            .flat_map(|(param, implementor)| {
                param.bounds.iter().map(|bound| Requirement {
                    bound: bound.substituted(&self.bindings),
                    implementor: implementor.clone(),
                })
            })
            .collect()
    }
}