Merge pull request #4398 from roc-lang/emplace-type-variables

Leave variables behind when converting `Type`s to variables
This commit is contained in:
Ayaz 2022-10-26 12:41:55 -05:00 committed by GitHub
commit 316ae7d30b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 158 additions and 73 deletions

View file

@ -1,3 +1,5 @@
use std::cell::Cell;
use crate::abilities::SpecializationId;
use crate::exhaustive::{ExhaustiveContext, SketchedRows};
use crate::expected::{Expected, PExpected};
@ -8,17 +10,16 @@ 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<Constraint>,
pub types: Vec<Type>,
pub types: Vec<Cell<Type>>,
pub variables: Vec<Variable>,
pub loc_symbols: Vec<(Symbol, Region)>,
pub let_constraints: Vec<LetConstraint>,
pub categories: Vec<Category>,
pub pattern_categories: Vec<PatternCategory>,
pub expectations: Vec<Expected<Type>>,
pub pattern_expectations: Vec<PExpected<Type>>,
pub expectations: Vec<Expected<Cell<Type>>>,
pub pattern_expectations: Vec<PExpected<Cell<Type>>>,
pub includes_tags: Vec<IncludesTag>,
pub strings: Vec<&'static str>,
pub sketched_rows: Vec<SketchedRows>,
@ -27,12 +28,39 @@ pub struct Constraints {
pub cycles: Vec<Cycle>,
}
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", &"<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", &"<expectations>")
.field("pattern_expectations", &"<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<Cell<Type>>;
pub type ExpectedTypeIndex = Index<Expected<Cell<Type>>>;
pub type PExpectedTypeIndex = Index<PExpected<Cell<Type>>>;
pub type TypeOrVar = EitherIndex<Cell<Type>, Variable>;
impl Constraints {
pub fn new() -> Self {
let constraints = Vec::new();
@ -52,9 +80,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 +135,9 @@ impl Constraints {
}
}
pub const EMPTY_RECORD: Index<Type> = Index::new(0);
pub const EMPTY_TAG_UNION: Index<Type> = Index::new(1);
pub const STR: Index<Type> = Index::new(2);
pub const EMPTY_RECORD: Index<Cell<Type>> = Index::new(0);
pub const EMPTY_TAG_UNION: Index<Cell<Type>> = Index::new(1);
pub const STR: Index<Cell<Type>> = Index::new(2);
pub const CATEGORY_RECORD: Index<Category> = Index::new(0);
pub const CATEGORY_FOREIGNCALL: Index<Category> = Index::new(1);
@ -139,7 +167,7 @@ impl Constraints {
pub const PCATEGORY_CHARACTER: Index<PatternCategory> = Index::new(10);
#[inline(always)]
pub fn push_type(&mut self, typ: Type) -> EitherIndex<Type, Variable> {
pub fn push_type(&mut self, typ: Type) -> EitherIndex<Cell<Type>, Variable> {
match typ {
Type::EmptyRec => EitherIndex::from_left(Self::EMPTY_RECORD),
Type::EmptyTagUnion => EitherIndex::from_left(Self::EMPTY_TAG_UNION),
@ -148,7 +176,7 @@ impl Constraints {
}
Type::Variable(var) => Self::push_type_variable(var),
other => {
let index: Index<Type> = Index::push_new(&mut self.types, other);
let index: Index<Cell<Type>> = Index::push_new(&mut self.types, Cell::new(other));
EitherIndex::from_left(index)
}
}
@ -175,7 +203,7 @@ impl Constraints {
}
#[inline(always)]
const fn push_type_variable(var: Variable) -> EitherIndex<Type, Variable> {
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<Variable> = Index::new(var.index());
@ -183,9 +211,8 @@ impl Constraints {
EitherIndex::from_right(index)
}
#[inline(always)]
pub fn push_expected_type(&mut self, expected: Expected<Type>) -> Index<Expected<Type>> {
Index::push_new(&mut self.expectations, expected)
pub fn push_expected_type(&mut self, expected: Expected<Type>) -> Index<Expected<Cell<Type>>> {
Index::push_new(&mut self.expectations, expected.map(Cell::new))
}
#[inline(always)]
@ -227,7 +254,6 @@ impl Constraints {
}
}
#[inline(always)]
pub fn equal_types(
&mut self,
typ: Type,
@ -236,13 +262,12 @@ impl Constraints {
region: Region,
) -> Constraint {
let type_index = self.push_type(typ);
let expected_index = Index::push_new(&mut self.expectations, expected);
let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let category_index = Self::push_category(self, category);
Constraint::Eq(Eq(type_index, expected_index, category_index, region))
}
#[inline(always)]
pub fn equal_types_var(
&mut self,
var: Variable,
@ -251,13 +276,12 @@ impl Constraints {
region: Region,
) -> Constraint {
let type_index = Self::push_type_variable(var);
let expected_index = Index::push_new(&mut self.expectations, expected);
let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let category_index = Self::push_category(self, category);
Constraint::Eq(Eq(type_index, expected_index, category_index, region))
}
#[inline(always)]
pub fn equal_types_with_storage(
&mut self,
typ: Type,
@ -267,7 +291,7 @@ impl Constraints {
storage_var: Variable,
) -> Constraint {
let type_index = self.push_type(typ);
let expected_index = Index::push_new(&mut self.expectations, expected);
let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let category_index = Self::push_category(self, category);
let equal = Constraint::Eq(Eq(type_index, expected_index, category_index, region));
@ -293,7 +317,8 @@ impl Constraints {
region: Region,
) -> Constraint {
let type_index = self.push_type(typ);
let expected_index = Index::push_new(&mut self.pattern_expectations, expected);
let expected_index =
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new));
let category_index = Self::push_pattern_category(self, category);
Constraint::Pattern(type_index, expected_index, category_index, region)
@ -307,7 +332,8 @@ impl Constraints {
region: Region,
) -> Constraint {
let type_index = self.push_type(typ);
let expected_index = Index::push_new(&mut self.pattern_expectations, expected);
let expected_index =
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new));
let category_index = Index::push_new(&mut self.pattern_categories, category);
Constraint::PatternPresence(type_index, expected_index, category_index, region)
@ -330,9 +356,9 @@ impl Constraints {
where
I: IntoIterator<Item = Type>,
{
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));
}
@ -551,7 +577,7 @@ impl Constraints {
) -> Constraint {
Constraint::Lookup(
symbol,
Index::push_new(&mut self.expectations, expected),
Index::push_new(&mut self.expectations, expected.map(Cell::new)),
region,
)
}
@ -605,7 +631,7 @@ impl Constraints {
pub fn store_index(
&mut self,
type_index: EitherIndex<Type, Variable>,
type_index: TypeOrVar,
variable: Variable,
filename: &'static str,
line_number: u32,
@ -633,14 +659,15 @@ impl Constraints {
let equality = match category_and_expectation {
Ok((category, expected)) => {
let category = Index::push_new(&mut self.categories, category);
let expected = Index::push_new(&mut self.expectations, expected);
let expected = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let equality = Eq(real_var, expected, category, real_region);
let equality = Index::push_new(&mut self.eq, equality);
Ok(equality)
}
Err((category, expected)) => {
let category = Index::push_new(&mut self.pattern_categories, category);
let expected = Index::push_new(&mut self.pattern_expectations, expected);
let expected =
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new));
let equality = PatternEq(real_var, expected, category, real_region);
let equality = Index::push_new(&mut self.pattern_eq, equality);
Err(equality)
@ -682,16 +709,16 @@ roc_error_macros::assert_sizeof_aarch64!(Constraint, 3 * 8);
#[derive(Clone, Copy, Debug)]
pub struct Eq(
pub EitherIndex<Type, Variable>,
pub Index<Expected<Type>>,
pub TypeOrVar,
pub Index<Expected<Cell<Type>>>,
pub Index<Category>,
pub Region,
);
#[derive(Clone, Copy, Debug)]
pub struct PatternEq(
pub EitherIndex<Type, Variable>,
pub Index<PExpected<Type>>,
pub TypeOrVar,
pub PExpectedTypeIndex,
pub Index<PatternCategory>,
pub Region,
);
@ -723,16 +750,11 @@ pub struct OpportunisticResolve {
#[derive(Clone, Copy)]
pub enum Constraint {
Eq(Eq),
Store(
EitherIndex<Type, Variable>,
Variable,
Index<&'static str>,
u32,
),
Lookup(Symbol, Index<Expected<Type>>, Region),
Store(TypeOrVar, Variable, Index<&'static str>, u32),
Lookup(Symbol, ExpectedTypeIndex, Region),
Pattern(
EitherIndex<Type, Variable>,
Index<PExpected<Type>>,
TypeOrVar,
PExpectedTypeIndex,
Index<PatternCategory>,
Region,
),
@ -747,11 +769,11 @@ pub enum Constraint {
Let(Index<LetConstraint>, Slice<Variable>),
And(Slice<Constraint>),
/// Presence constraints
IsOpenType(EitherIndex<Type, Variable>), // 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<IncludesTag>),
PatternPresence(
EitherIndex<Type, Variable>,
Index<PExpected<Type>>,
TypeOrVar,
PExpectedTypeIndex,
Index<PatternCategory>,
Region,
),
@ -782,9 +804,9 @@ pub struct LetConstraint {
#[derive(Debug, Clone)]
pub struct IncludesTag {
pub type_index: Index<Type>,
pub type_index: TypeIndex,
pub tag_name: TagName,
pub types: Slice<Type>,
pub types: Slice<Cell<Type>>,
pub pattern_category: Index<PatternCategory>,
pub region: Region,
}

View file

@ -38,6 +38,16 @@ impl<T> PExpected<T> {
}
}
#[inline(always)]
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> PExpected<U> {
match self {
PExpected::NoExpectation(val) => PExpected::NoExpectation(f(val)),
PExpected::ForReason(reason, val, region) => {
PExpected::ForReason(reason, f(val), region)
}
}
}
pub fn replace<U>(self, new: U) -> PExpected<U> {
match self {
PExpected::NoExpectation(_val) => PExpected::NoExpectation(new),
@ -89,6 +99,17 @@ impl<T> Expected<T> {
}
}
#[inline(always)]
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Expected<U> {
match self {
Expected::NoExpectation(val) => Expected::NoExpectation(f(val)),
Expected::ForReason(reason, val, region) => Expected::ForReason(reason, f(val), region),
Expected::FromAnnotation(pattern, size, source, val) => {
Expected::FromAnnotation(pattern, size, source, f(val))
}
}
}
pub fn replace<U>(self, new: U) -> Expected<U> {
match self {
Expected::NoExpectation(_val) => Expected::NoExpectation(new),