From d3e14550d8f0f60ae622ee45dfa3ed646654ad4b Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Mon, 24 Oct 2022 11:42:35 -0500 Subject: [PATCH] Leave variables behind when converting `Type`s to variables This is part one of addressing the present issues with emplacing type directly where type variables should be reused. Now, when an `Index` is converted to a variable in solving, we leave the converted variable in the `Type`'s place. Specifically, we keep an index to a `Cell`. Note that this transformation is only temporary, it will be removed once we merge this with the `Type` SoA representation, but it is needed in the meantime as I transform the `Constrain` API to get rid of type-emplacement. --- crates/compiler/can/src/constraint.rs | 77 +++++++++++++++++---------- crates/compiler/solve/src/solve.rs | 76 +++++++++++++++++--------- 2 files changed, 101 insertions(+), 52 deletions(-) diff --git a/crates/compiler/can/src/constraint.rs b/crates/compiler/can/src/constraint.rs index 3fc45b5320..25e81922ca 100644 --- a/crates/compiler/can/src/constraint.rs +++ b/crates/compiler/can/src/constraint.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use crate::abilities::SpecializationId; use crate::exhaustive::{ExhaustiveContext, SketchedRows}; use crate::expected::{Expected, PExpected}; @@ -8,10 +10,9 @@ use roc_region::all::{Loc, Region}; use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, Variable}; use roc_types::types::{Category, PatternCategory, Type}; -#[derive(Debug)] pub struct Constraints { pub constraints: Vec, - pub types: Vec, + pub types: Vec>, pub variables: Vec, pub loc_symbols: Vec<(Symbol, Region)>, pub let_constraints: Vec, @@ -27,12 +28,37 @@ pub struct Constraints { pub cycles: Vec, } +impl std::fmt::Debug for Constraints { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Constraints") + .field("constraints", &self.constraints) + .field("types", &"") + .field("variables", &self.variables) + .field("loc_symbols", &self.loc_symbols) + .field("let_constraints", &self.let_constraints) + .field("categories", &self.categories) + .field("pattern_categories", &self.pattern_categories) + .field("expectations", &self.expectations) + .field("pattern_expectations", &self.pattern_expectations) + .field("includes_tags", &self.includes_tags) + .field("strings", &self.strings) + .field("sketched_rows", &self.sketched_rows) + .field("eq", &self.eq) + .field("pattern_eq", &self.pattern_eq) + .field("cycles", &self.cycles) + .finish() + } +} + impl Default for Constraints { fn default() -> Self { Self::new() } } +pub type TypeIndex = Index>; +pub type TypeOrVar = EitherIndex, Variable>; + impl Constraints { pub fn new() -> Self { let constraints = Vec::new(); @@ -52,9 +78,9 @@ impl Constraints { let cycles = Vec::new(); types.extend([ - Type::EmptyRec, - Type::EmptyTagUnion, - Type::Apply(Symbol::STR_STR, vec![], Region::zero()), + Cell::new(Type::EmptyRec), + Cell::new(Type::EmptyTagUnion), + Cell::new(Type::Apply(Symbol::STR_STR, vec![], Region::zero())), ]); categories.extend([ @@ -107,9 +133,9 @@ impl Constraints { } } - pub const EMPTY_RECORD: Index = Index::new(0); - pub const EMPTY_TAG_UNION: Index = Index::new(1); - pub const STR: Index = Index::new(2); + pub const EMPTY_RECORD: Index> = Index::new(0); + pub const EMPTY_TAG_UNION: Index> = Index::new(1); + pub const STR: Index> = Index::new(2); pub const CATEGORY_RECORD: Index = Index::new(0); pub const CATEGORY_FOREIGNCALL: Index = Index::new(1); @@ -139,7 +165,7 @@ impl Constraints { pub const PCATEGORY_CHARACTER: Index = Index::new(10); #[inline(always)] - pub fn push_type(&mut self, typ: Type) -> EitherIndex { + pub fn push_type(&mut self, typ: Type) -> EitherIndex, Variable> { match typ { Type::EmptyRec => EitherIndex::from_left(Self::EMPTY_RECORD), Type::EmptyTagUnion => EitherIndex::from_left(Self::EMPTY_TAG_UNION), @@ -148,7 +174,7 @@ impl Constraints { } Type::Variable(var) => Self::push_type_variable(var), other => { - let index: Index = Index::push_new(&mut self.types, other); + let index: Index> = Index::push_new(&mut self.types, Cell::new(other)); EitherIndex::from_left(index) } } @@ -175,7 +201,7 @@ impl Constraints { } #[inline(always)] - const fn push_type_variable(var: Variable) -> EitherIndex { + const fn push_type_variable(var: Variable) -> TypeOrVar { // that's right, we use the variable's integer value as the index // that way, we don't need to push anything onto a vector let index: Index = Index::new(var.index()); @@ -330,9 +356,9 @@ impl Constraints { where I: IntoIterator, { - let type_index = Index::push_new(&mut self.types, typ); + let type_index = Index::push_new(&mut self.types, Cell::new(typ)); let category_index = Index::push_new(&mut self.pattern_categories, category); - let types_slice = Slice::extend_new(&mut self.types, types); + let types_slice = Slice::extend_new(&mut self.types, types.into_iter().map(Cell::new)); let includes_tag = IncludesTag { type_index, @@ -377,7 +403,7 @@ impl Constraints { for (symbol, loc_type) in it { let Loc { region, value } = loc_type; - self.types.push(value); + self.types.push(Cell::new(value)); self.loc_symbols.push((symbol, region)); } @@ -605,7 +631,7 @@ impl Constraints { pub fn store_index( &mut self, - type_index: EitherIndex, + type_index: TypeOrVar, variable: Variable, filename: &'static str, line_number: u32, @@ -682,7 +708,7 @@ roc_error_macros::assert_sizeof_aarch64!(Constraint, 3 * 8); #[derive(Clone, Copy, Debug)] pub struct Eq( - pub EitherIndex, + pub TypeOrVar, pub Index>, pub Index, pub Region, @@ -690,7 +716,7 @@ pub struct Eq( #[derive(Clone, Copy, Debug)] pub struct PatternEq( - pub EitherIndex, + pub TypeOrVar, pub Index>, pub Index, pub Region, @@ -723,15 +749,10 @@ pub struct OpportunisticResolve { #[derive(Clone, Copy)] pub enum Constraint { Eq(Eq), - Store( - EitherIndex, - Variable, - Index<&'static str>, - u32, - ), + Store(TypeOrVar, Variable, Index<&'static str>, u32), Lookup(Symbol, Index>, Region), Pattern( - EitherIndex, + TypeOrVar, Index>, Index, Region, @@ -747,10 +768,10 @@ pub enum Constraint { Let(Index, Slice), And(Slice), /// Presence constraints - IsOpenType(EitherIndex), // Theory; always applied to a variable? if yes the use that + IsOpenType(TypeOrVar), // Theory; always applied to a variable? if yes the use that IncludesTag(Index), PatternPresence( - EitherIndex, + TypeOrVar, Index>, Index, Region, @@ -782,9 +803,9 @@ pub struct LetConstraint { #[derive(Debug, Clone)] pub struct IncludesTag { - pub type_index: Index, + pub type_index: TypeIndex, pub tag_name: TagName, - pub types: Slice, + pub types: Slice>, pub pattern_category: Index, pub region: Region, } diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 2676d6f25c..30d4d2e1b9 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -11,7 +11,7 @@ use crate::specialize::{ use bumpalo::Bump; use roc_can::abilities::{AbilitiesStore, MemberSpecializationInfo}; use roc_can::constraint::Constraint::{self, *}; -use roc_can::constraint::{Constraints, Cycle, LetConstraint, OpportunisticResolve}; +use roc_can::constraint::{Constraints, Cycle, LetConstraint, OpportunisticResolve, TypeOrVar}; use roc_can::expected::{Expected, PExpected}; use roc_can::expr::PendingDerives; use roc_can::module::ExposedByModule; @@ -1323,24 +1323,47 @@ fn solve( region, } = includes_tag; - let typ = &constraints.types[type_index.index()]; - let tys = &constraints.types[types.indices()]; + let typ_cell = &constraints.types[type_index.index()]; + let tys_cells = &constraints.types[types.indices()]; let pattern_category = &constraints.pattern_categories[pattern_category.index()]; - let actual = type_to_var( - subs, - rank, - problems, - abilities_store, - obligation_cache, - pools, - aliases, - typ, - ); - let tag_ty = Type::TagUnion( - vec![(tag_name.clone(), tys.to_vec())], - TypeExtension::Closed, - ); + let actual = { + let typ = typ_cell.replace(Type::EmptyTagUnion); + let actual = type_to_var( + subs, + rank, + problems, + abilities_store, + obligation_cache, + pools, + aliases, + &typ, + ); + typ_cell.replace(Type::Variable(actual)); + actual + }; + + let tys = { + let mut tys = Vec::with_capacity(tys_cells.len()); + for cell in tys_cells { + let ty = cell.replace(Type::EmptyTagUnion); + let actual = type_to_var( + subs, + rank, + problems, + abilities_store, + obligation_cache, + pools, + aliases, + &ty, + ); + cell.replace(Type::Variable(actual)); + tys.push(Type::Variable(actual)); + } + tys + }; + + let tag_ty = Type::TagUnion(vec![(tag_name.clone(), tys)], TypeExtension::Closed); let includes = type_to_var( subs, rank, @@ -2033,7 +2056,8 @@ impl LocalDefVarsVec<(Symbol, Loc)> { let mut local_def_vars = Self::with_length(types_slice.len()); - for (&(symbol, region), typ) in (loc_symbols_slice.iter()).zip(types_slice) { + for (&(symbol, region), typ_cell) in (loc_symbols_slice.iter()).zip(types_slice) { + let typ = typ_cell.replace(Type::EmptyTagUnion); let var = type_to_var( subs, rank, @@ -2042,8 +2066,9 @@ impl LocalDefVarsVec<(Symbol, Loc)> { obligation_cache, pools, aliases, - typ, + &typ, ); + typ_cell.replace(Type::Variable(var)); local_def_vars.push((symbol, Loc { value: var, region })); } @@ -2078,13 +2103,14 @@ fn either_type_index_to_var( abilities_store: &mut AbilitiesStore, obligation_cache: &mut ObligationCache, aliases: &mut Aliases, - either_type_index: roc_collections::soa::EitherIndex, + either_type_index: TypeOrVar, ) -> Variable { match either_type_index.split() { Ok(type_index) => { - let typ = &constraints.types[type_index.index()]; + let typ_cell = &constraints.types[type_index.index()]; - type_to_var( + let typ = typ_cell.replace(Type::EmptyTagUnion); + let var = type_to_var( subs, rank, problems, @@ -2092,8 +2118,10 @@ fn either_type_index_to_var( obligation_cache, pools, aliases, - typ, - ) + &typ, + ); + typ_cell.replace(Type::Variable(var)); + var } Err(var_index) => { // we cheat, and store the variable directly in the index