use crate::expected::{Expected, PExpected}; use roc_collections::all::{MutSet, SendMap}; use roc_module::symbol::Symbol; use roc_region::all::{Located, Region}; use roc_types::types::{Category, PatternCategory, Type}; use roc_types::{subs::Variable, types::VariableDetail}; pub struct Constraints { constraints: Vec, types: Vec, variables: Vec, def_types: Vec<(Symbol, Located>)>, let_constraints: Vec, categories: Vec, pattern_categories: Vec, expectations: Vec>, pattern_expectations: Vec>, } impl Constraints { pub fn equal_types( &mut self, typ: Type, expected: Expected, category: Category, region: Region, ) -> Constraint { let type_index = Index::new(self.types.len() as _); let expected_index = Index::new(self.expectations.len() as _); let category_index = Index::new(self.categories.len() as _); self.types.push(typ); self.expectations.push(expected); self.categories.push(category); Constraint::Eq(type_index, expected_index, category_index, region) } pub fn equal_pattern_types( &mut self, typ: Type, expected: PExpected, category: PatternCategory, region: Region, ) -> Constraint { let type_index = Index::new(self.types.len() as _); let expected_index = Index::new(self.pattern_expectations.len() as _); let category_index = Index::new(self.pattern_categories.len() as _); self.types.push(typ); self.pattern_expectations.push(expected); self.pattern_categories.push(category); Constraint::Pattern(type_index, expected_index, category_index, region) } fn variable_slice(&mut self, it: I) -> Slice where I: IntoIterator, { let start = self.variables.len(); self.variables.extend(it); let length = self.variables.len() - start; Slice::new(start as _, length as _) } fn def_types_slice(&mut self, it: I) -> Slice<(Symbol, Located)> where I: IntoIterator)>, { let start = self.def_types.len(); for (symbol, loc_type) in it { let type_index = Index::new(self.types.len() as _); let Located { region, value } = loc_type; self.types.push(value); self.def_types .push((symbol, Located::at(region, type_index))); } let length = self.def_types.len() - start; Slice::new(start as _, length as _) } pub fn let_contraint( &mut self, rigid_vars: I1, flex_vars: I2, def_types: I3, defs_constraint: Constraint, ret_constraint: Constraint, ) -> Constraint where I1: IntoIterator, I2: IntoIterator, I3: IntoIterator)>, { let defs_and_ret_constraint = Index::new(self.constraints.len() as _); self.constraints.push(defs_constraint); self.constraints.push(ret_constraint); let let_contraint = LetConstraint { rigid_vars: self.variable_slice(rigid_vars), flex_vars: self.variable_slice(flex_vars), def_types: self.def_types_slice(def_types), defs_and_ret_constraint, }; let let_index = Index::new(self.let_constraints.len() as _); self.let_constraints.push(let_contraint); Constraint::Let(let_index) } } static_assertions::assert_eq_size!([u8; 4 * 8], Constraint); static_assertions::assert_eq_size!([u8; 3 * 8 + 4], LetConstraint); #[derive(Debug, Clone, PartialEq)] pub enum Constraint { Eq(Index, Index>, Index, Region), Store(Index, Variable, &'static str, u32), Lookup(Symbol, Index>, Region), Pattern( Index, Index>, Index, Region, ), True, // Used for things that always unify, e.g. blanks and runtime errors SaveTheEnvironment, Let(Index), And(Slice), } #[derive(Debug, Clone, PartialEq)] pub struct LetConstraint { pub rigid_vars: Slice, pub flex_vars: Slice, pub def_types: Slice<(Symbol, Located)>, pub defs_and_ret_constraint: Index<(Constraint, Constraint)>, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Index { index: u32, _marker: std::marker::PhantomData, } impl Index { pub const fn new(index: u32) -> Self { Self { index, _marker: std::marker::PhantomData, } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Slice { start: u32, length: u16, _marker: std::marker::PhantomData, } impl Slice { pub const fn new(start: u32, length: u16) -> Self { Self { start, length, _marker: std::marker::PhantomData, } } pub const fn len(&self) -> usize { self.length as _ } pub const fn is_empty(&self) -> bool { self.length == 0 } pub const fn indices(&self) -> std::ops::Range { self.start as usize..(self.start as usize + self.length as usize) } pub fn into_iter(&self) -> impl Iterator> { self.indices().map(|i| Index::new(i as _)) } }