mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Monomorphize numbers
This commit is contained in:
parent
8b73efc2ec
commit
2c2a45d9d9
4 changed files with 226 additions and 19 deletions
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue