diff --git a/Cargo.lock b/Cargo.lock index 3cd24a5c1f..ee75ebfb7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3208,6 +3208,7 @@ dependencies = [ "roc_problem", "roc_region", "roc_types", + "static_assertions", "ven_graph", ] diff --git a/compiler/can/Cargo.toml b/compiler/can/Cargo.toml index 2e8bd639dd..edec9d23ff 100644 --- a/compiler/can/Cargo.toml +++ b/compiler/can/Cargo.toml @@ -15,6 +15,7 @@ roc_types = { path = "../types" } roc_builtins = { path = "../builtins" } ven_graph = { path = "../../vendor/pathfinding" } bumpalo = { version = "3.8.0", features = ["collections"] } +static_assertions = "1.1.0" [dev-dependencies] pretty_assertions = "1.0.0" diff --git a/compiler/can/src/constraint_soa.rs b/compiler/can/src/constraint_soa.rs new file mode 100644 index 0000000000..a25c630755 --- /dev/null +++ b/compiler/can/src/constraint_soa.rs @@ -0,0 +1,194 @@ +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 _)) + } +} diff --git a/compiler/can/src/lib.rs b/compiler/can/src/lib.rs index 7230ab1a36..5cd16be75a 100644 --- a/compiler/can/src/lib.rs +++ b/compiler/can/src/lib.rs @@ -4,6 +4,7 @@ pub mod annotation; pub mod builtins; pub mod constraint; +pub mod constraint_soa; pub mod def; pub mod env; pub mod expected;