Monomorphize numbers

This commit is contained in:
Richard Feldman 2024-11-09 00:44:27 -05:00
parent 8b73efc2ec
commit 2c2a45d9d9
No known key found for this signature in database
GPG key ID: DAC334802F365236
4 changed files with 226 additions and 19 deletions

View file

@ -7,6 +7,7 @@ impl<T> Push<T> for Vec<T> {
self.push(entry);
}
}
impl<T> Push<T> for &mut Vec<T> {
fn push(&mut self, entry: T) {
(*self).push(entry);

View file

@ -263,7 +263,7 @@ fn to_num(primitive: Primitive, val: IntValue, problems: &mut impl Push<Problem>
})),
Primitive::U128 => MonoExpr::Number(Number::U128(val.as_u128())),
Primitive::I128 => MonoExpr::Number(Number::I128(val.as_i128())),
Primitive::Str => {
Primitive::Str | Primitive::Crash => {
let problem = Problem::NumSpecializedToWrongType(Some(MonoType::Primitive(primitive)));
problems.push(problem);
MonoExpr::CompilerBug(problem)
@ -289,7 +289,8 @@ fn to_frac(primitive: Primitive, val: f64, problems: &mut impl Push<Problem>) ->
| Primitive::I64
| Primitive::U128
| Primitive::I128
| Primitive::Str => {
| Primitive::Str
| Primitive::Crash => {
let problem = Problem::NumSpecializedToWrongType(Some(MonoType::Primitive(primitive)));
problems.push(problem);
MonoExpr::CompilerBug(problem)
@ -312,7 +313,7 @@ fn char_to_int(primitive: Primitive, ch: char, problems: &mut impl Push<Problem>
Primitive::I128 => MonoExpr::Number(Number::I128(ch as i128)),
Primitive::I16 => MonoExpr::Number(Number::I16(ch as i16)),
Primitive::I8 => MonoExpr::Number(Number::I8(ch as i8)),
Primitive::Str | Primitive::Dec | Primitive::F32 | Primitive::F64 => {
Primitive::Str | Primitive::Dec | Primitive::F32 | Primitive::F64 | Primitive::Crash => {
let problem = Problem::CharSpecializedToWrongType(Some(MonoType::Primitive(primitive)));
problems.push(problem);
MonoExpr::CompilerBug(problem)

View file

@ -7,6 +7,68 @@ pub struct MonoTypeId {
}
impl MonoTypeId {
pub const CRASH: Self = Self {
inner: Index::new(0),
};
pub const STR: Self = Self {
inner: Index::new(1),
};
pub const U8: Self = Self {
inner: Index::new(2),
};
pub const I8: Self = Self {
inner: Index::new(3),
};
pub const U16: Self = Self {
inner: Index::new(4),
};
pub const I16: Self = Self {
inner: Index::new(5),
};
pub const U32: Self = Self {
inner: Index::new(6),
};
pub const I32: Self = Self {
inner: Index::new(7),
};
pub const U64: Self = Self {
inner: Index::new(8),
};
pub const I64: Self = Self {
inner: Index::new(9),
};
pub const U128: Self = Self {
inner: Index::new(10),
};
pub const I128: Self = Self {
inner: Index::new(11),
};
pub const F32: Self = Self {
inner: Index::new(12),
};
pub const F64: Self = Self {
inner: Index::new(13),
};
pub const DEC: Self = Self {
inner: Index::new(14),
};
pub const DEFAULT_INT: Self = Self::I64; // TODO change this to I128
pub const DEFAULT_FRAC: Self = Self::DEC;
fn new(inner: Index<MonoType>) -> Self {
Self { inner }
}
@ -22,7 +84,23 @@ pub struct MonoTypes {
impl MonoTypes {
pub fn new() -> Self {
Self {
entries: Vec::new(),
entries: vec![
MonoType::Primitive(Primitive::Crash),
MonoType::Primitive(Primitive::Str),
MonoType::Primitive(Primitive::U8),
MonoType::Primitive(Primitive::I8),
MonoType::Primitive(Primitive::U16),
MonoType::Primitive(Primitive::I16),
MonoType::Primitive(Primitive::U32),
MonoType::Primitive(Primitive::I32),
MonoType::Primitive(Primitive::U64),
MonoType::Primitive(Primitive::I64),
MonoType::Primitive(Primitive::U128),
MonoType::Primitive(Primitive::I128),
MonoType::Primitive(Primitive::F32),
MonoType::Primitive(Primitive::F64),
MonoType::Primitive(Primitive::Dec),
],
ids: Vec::new(),
slices: Vec::new(),
}
@ -150,10 +228,8 @@ impl MonoTypes {
/// In the future, we may promote common builtin types to Primitives, e.g. List U8, List Str, etc.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Primitive {
Crash,
Str,
Dec,
F32,
F64,
U8,
I8,
U16,
@ -164,6 +240,9 @@ pub enum Primitive {
I64,
U128,
I128,
F32,
F64,
Dec,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]

View file

@ -9,10 +9,14 @@ use crate::{
MonoFieldId, MonoType,
};
use roc_collections::{Push, VecMap};
use roc_module::ident::{Lowercase, TagName};
use roc_module::{
ident::{Lowercase, TagName},
symbol::Symbol,
};
use roc_solve::module::Solved;
use roc_types::subs::{
Content, FlatType, RecordFields, Subs, TagExt, TupleElems, UnionLabels, UnionTags, Variable,
Content, FlatType, RecordFields, Subs, SubsSlice, TagExt, TupleElems, UnionLabels, UnionTags,
Variable,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -30,6 +34,7 @@ pub enum Problem {
CharSpecializedToWrongType(
Option<MonoType>, // `None` means it specialized to Unit
),
BadNumTypeParam,
}
/// For MonoTypes that are records, store their field indices.
@ -98,19 +103,31 @@ fn lower_var<P: Push<Problem>>(
// TODO: we could replace this cache by having Subs store a Content::Monomorphic(MonoTypeId)
// and then overwrite it rather than having a separate cache. That memory is already in cache
// for sure, and the lookups should be faster because they're O(1) but don't require hashing.
// Kinda creates a cyclic dep though.
if let Some(mono_id) = env.cache.inner.get(&root_var) {
return Some(*mono_id);
}
// Convert the Content to a MonoType, often by passing an iterator. None of these iterators introduce allocations.
let opt_mono_id = match *subs.get_content_without_compacting(root_var) {
let mono_id = match *subs.get_content_without_compacting(root_var) {
Content::Structure(flat_type) => match flat_type {
FlatType::Apply(symbol, args) => {
let new_args = args
.into_iter()
.flat_map(|var_index| lower_var(env, subs, subs[var_index]));
if symbol.is_builtin() {
if symbol == Symbol::NUM_NUM {
num_args_to_mono_id(args, subs, env.problems)
} else if symbol == Symbol::LIST_LIST {
todo!();
// let mut new_args = args
// .into_iter()
// .flat_map(|var_index| lower_var(env, subs, subs[var_index]));
todo!("maybe instead of making new_args, branch and then call lower_var to create Primitive, List, Box, etc.");
// let arg = new_args.next();
} else {
todo!()
}
} else {
todo!("handle non-builtin Apply");
}
}
// FlatType::Func(args, _capture, ret) => {
// let mono_args = args
@ -240,13 +257,122 @@ fn lower_var<P: Push<Problem>>(
}
};
if let Some(mono_id) = opt_mono_id {
// This var is now known to be monomorphic, so we don't repeat this work again later.
// (We don't insert entries for Unit values.)
env.cache.inner.insert(root_var, mono_id);
// This var is now known to be monomorphic, so we don't repeat this work again later.
// (We don't insert entries for Unit values.)
env.cache.inner.insert(root_var, mono_id);
Some(mono_id)
}
fn num_args_to_mono_id(
args: SubsSlice<Variable>,
subs: &Subs,
problems: &mut impl Push<Problem>,
) -> MonoTypeId {
match args.into_iter().next() {
Some(arg_index) if args.len() == 1 => {
match subs.get_content_without_compacting(subs[arg_index]) {
Content::Structure(flat_type) => {
if let FlatType::Apply(outer_symbol, args) = flat_type {
let outer_symbol = *outer_symbol;
match args.into_iter().next() {
Some(arg_index) if args.len() == 1 => {
match subs.get_content_without_compacting(subs[arg_index]) {
Content::Structure(flat_type) => {
if let FlatType::Apply(inner_symbol, args) = flat_type {
let inner_symbol = *inner_symbol;
if args.is_empty() {
if outer_symbol == Symbol::NUM_INTEGER {
if inner_symbol == Symbol::NUM_UNSIGNED8 {
return MonoTypeId::U8;
} else if inner_symbol == Symbol::NUM_SIGNED8 {
return MonoTypeId::I8;
} else if inner_symbol == Symbol::NUM_UNSIGNED16
{
return MonoTypeId::U16;
} else if inner_symbol == Symbol::NUM_SIGNED16 {
return MonoTypeId::I16;
} else if inner_symbol == Symbol::NUM_UNSIGNED32
{
return MonoTypeId::U32;
} else if inner_symbol == Symbol::NUM_SIGNED32 {
return MonoTypeId::I32;
} else if inner_symbol == Symbol::NUM_UNSIGNED64
{
return MonoTypeId::U64;
} else if inner_symbol == Symbol::NUM_SIGNED64 {
return MonoTypeId::I64;
} else if inner_symbol
== Symbol::NUM_UNSIGNED128
{
return MonoTypeId::U128;
} else if inner_symbol == Symbol::NUM_SIGNED128
{
return MonoTypeId::I128;
}
} else if outer_symbol == Symbol::NUM_FLOATINGPOINT
{
if inner_symbol == Symbol::NUM_BINARY32 {
return MonoTypeId::F32;
} else if inner_symbol == Symbol::NUM_BINARY64 {
return MonoTypeId::F64;
} else if inner_symbol == Symbol::NUM_DECIMAL {
return MonoTypeId::DEC;
}
}
}
}
}
Content::FlexVar(_) => {
if outer_symbol == Symbol::NUM_INTEGER {
// Int *
return MonoTypeId::DEFAULT_INT;
} else if outer_symbol == Symbol::NUM_FLOATINGPOINT {
// Frac *
return MonoTypeId::DEFAULT_FRAC;
}
}
Content::Alias(
symbol,
alias_variables,
variable,
alias_kind,
) => todo!(),
Content::RangedNumber(numeric_range) => todo!(),
_ => {
// no-op
}
}
}
_ => {
// no-op
}
}
}
}
Content::FlexVar(subs_index) => {
// Num *
return MonoTypeId::DEFAULT_INT;
}
Content::Alias(symbol, alias_variables, variable, alias_kind) => todo!(),
Content::RangedNumber(numeric_range) => todo!(),
_ => {
// fall through
}
}
}
_ => {
// fall through
}
}
opt_mono_id
// If we got here, it's because the Num type parameter(s) don't fit the form we expect.
// Specialize to a crash!
problems.push(Problem::BadNumTypeParam);
MonoTypeId::CRASH
}
fn resolve_tag_ext(