Hide away the niche representation

This commit is contained in:
Ayaz Hafiz 2022-12-27 16:41:35 -06:00
parent 321ac0b06f
commit 6722dc3b84
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
2 changed files with 55 additions and 54 deletions

View file

@ -6,7 +6,7 @@ use ven_pretty::{Arena, DocAllocator, DocBuilder};
use crate::{
ir::{Parens, ProcLayout},
layout::{Layout, Niche},
layout::Layout,
};
use super::{
@ -478,20 +478,9 @@ where
f.reflow(" -> "),
result.to_doc(f, interner, Parens::NotNeeded),
]);
let niche = match captures_niche {
Niche::NONE => f.reflow("(no niche)"),
Niche::Captures(captures_niche) => f.concat([
f.reflow("(niche {"),
f.intersperse(
captures_niche
.captures()
.iter()
.map(|&c| interner.get(c).to_doc(f, interner, Parens::NotNeeded)),
f.reflow(", "),
),
f.reflow("})"),
]),
};
let niche = (f.text("("))
.append(captures_niche.to_doc(f, interner))
.append(f.text(")"));
f.concat([fun, f.space(), niche])
}

View file

@ -1221,42 +1221,57 @@ impl std::fmt::Debug for LambdaSet<'_> {
}
}
/// Sometimes we can end up with lambdas of the same name and different captures in the same
/// lambda set, like `fun` having lambda set `[[thunk U64, thunk U8]]` due to the following program:
///
/// ```roc
/// capture : _ -> ({} -> Str)
/// capture = \val ->
/// thunk = \{} -> Num.toStr val
/// thunk
///
/// fun = \x ->
/// when x is
/// True -> capture 123u64
/// False -> capture 18u8
/// ```
///
/// By recording the captures layouts this lambda expects in its identifier, we can distinguish
/// between such differences when constructing closure capture data.
///
/// See also https://github.com/roc-lang/roc/issues/3336.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Captures<'a>(&'a [InLayout<'a>]);
impl<'a> Captures<'a> {
pub(crate) fn captures(&self) -> &'a [Layout<'a>] {
self.0
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
enum NichePriv<'a> {
/// Sometimes we can end up with lambdas of the same name and different captures in the same
/// lambda set, like `fun` having lambda set `[[thunk U64, thunk U8]]` due to the following program:
///
/// ```roc
/// capture : _ -> ({} -> Str)
/// capture = \val ->
/// thunk = \{} -> Num.toStr val
/// thunk
///
/// fun = \x ->
/// when x is
/// True -> capture 123u64
/// False -> capture 18u8
/// ```
///
/// By recording the captures layouts this lambda expects in its identifier, we can distinguish
/// between such differences when constructing closure capture data.
///
/// See also https://github.com/roc-lang/roc/issues/3336.
Captures(&'a [InLayout<'a>]),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Niche<'a> {
/// A niche for a proc are its captures.
Captures(Captures<'a>),
}
#[repr(transparent)]
pub struct Niche<'a>(NichePriv<'a>);
impl<'a> Niche<'a> {
pub const NONE: Niche<'a> = Niche::Captures(Captures(&[]));
pub const NONE: Niche<'a> = Niche(NichePriv::Captures(&[]));
pub fn to_doc<'b, D, A, I>(self, alloc: &'b D, interner: &I) -> DocBuilder<'b, D, A>
where
D: DocAllocator<'b, A>,
D::Doc: Clone,
A: Clone,
I: Interner<'a, Layout<'a>>,
{
match self.0 {
NichePriv::Captures(captures) => alloc.concat([
alloc.reflow("(niche {"),
alloc.intersperse(
captures
.iter()
.map(|c| c.to_doc(alloc, interner, Parens::NotNeeded)),
alloc.reflow(", "),
),
alloc.reflow("})"),
]),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@ -1278,9 +1293,8 @@ impl<'a> LambdaName<'a> {
#[inline(always)]
pub(crate) fn no_captures(&self) -> bool {
match self.niche {
Niche::NONE => true,
Niche::Captures(captures) => captures.0.is_empty(),
match self.niche.0 {
NichePriv::Captures(captures) => captures.is_empty(),
}
}
@ -1390,7 +1404,7 @@ impl<'a> LambdaSet<'a> {
self.set.iter().map(|(name, captures_layouts)| {
let niche = match captures_layouts {
[] => Niche::NONE,
_ => Niche::Captures(Captures(captures_layouts)),
_ => Niche(NichePriv::Captures(captures_layouts)),
};
LambdaName { name: *name, niche }
})
@ -1416,9 +1430,7 @@ impl<'a> LambdaSet<'a> {
{
debug_assert!(self.contains(lambda_name.name));
let captures = match lambda_name.niche {
Niche::Captures(captures) => captures.0,
};
let NichePriv::Captures(captures) = lambda_name.niche.0;
let comparator = |other_name: Symbol, other_captures_layouts: &[InLayout]| {
other_name == lambda_name.name
@ -1472,7 +1484,7 @@ impl<'a> LambdaSet<'a> {
LambdaName {
name: *name,
niche: Niche::Captures(Captures(layouts)),
niche: Niche(NichePriv::Captures(layouts)),
}
}