mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
wip
This commit is contained in:
parent
2c2a45d9d9
commit
074161733e
5 changed files with 359 additions and 166 deletions
|
@ -106,8 +106,7 @@ impl MonoTypes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get(&self, id: MonoTypeId) -> &MonoType {
|
pub fn get(&self, id: MonoTypeId) -> &MonoType {
|
||||||
todo!("builtins are stored inline");
|
// Future strategy:
|
||||||
// Overall strategy:
|
|
||||||
// - Look at the three high bits to figure out which of the 8 MonoTypes we're dealing with
|
// - Look at the three high bits to figure out which of the 8 MonoTypes we're dealing with
|
||||||
// - The non-parameterized builtins have 000 as their high bits, and the whole MonoTypeId can be cast to a Primitive.
|
// - The non-parameterized builtins have 000 as their high bits, and the whole MonoTypeId can be cast to a Primitive.
|
||||||
// - The parameterized builtins don't need to store a length, just an index. We store that index inline.
|
// - The parameterized builtins don't need to store a length, just an index. We store that index inline.
|
||||||
|
@ -116,6 +115,18 @@ impl MonoTypes {
|
||||||
// - This means we use 2 bits for discriminant and another 2 bits for which parameterized type it is
|
// - This means we use 2 bits for discriminant and another 2 bits for which parameterized type it is
|
||||||
// - This means we get 29-bit indices, so a maximum of ~500M MonoTypes per module. Should be plenty.
|
// - This means we get 29-bit indices, so a maximum of ~500M MonoTypes per module. Should be plenty.
|
||||||
// - In the future, we can promote common collection types (e.g. List Str, List U8) to Primitives.
|
// - In the future, we can promote common collection types (e.g. List Str, List U8) to Primitives.
|
||||||
|
|
||||||
|
let opt = self.entries.get(id.inner.index());
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
opt.expect("A MonoTypeId corresponded to an index that wasn't in MonoTypes. This should never happen!")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
unsafe {
|
||||||
|
opt.unwrap_unchecked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_primitive(&mut self, primitive: Primitive) -> MonoTypeId {
|
pub(crate) fn add_primitive(&mut self, primitive: Primitive) -> MonoTypeId {
|
||||||
|
|
|
@ -244,17 +244,30 @@ fn lower_var<P: Push<Problem>>(
|
||||||
| Content::RecursionVar { .. } => Content::Structure(FlatType::EmptyTagUnion),
|
| Content::RecursionVar { .. } => Content::Structure(FlatType::EmptyTagUnion),
|
||||||
Content::LambdaSet(lambda_set) => Content::LambdaSet(lambda_set),
|
Content::LambdaSet(lambda_set) => Content::LambdaSet(lambda_set),
|
||||||
Content::ErasedLambda => Content::ErasedLambda,
|
Content::ErasedLambda => Content::ErasedLambda,
|
||||||
Content::Alias(symbol, args, real, kind) => {
|
|
||||||
let todo = (); // TODO we should unwrap this, but doing that probably means changing this from root_var to other stuff.
|
|
||||||
let new_real = lower_var(cache, subs, problems, *real);
|
|
||||||
Content::Alias(*symbol, *args, new_real, *kind)
|
|
||||||
}
|
|
||||||
Content::Error => Content::Error,
|
Content::Error => Content::Error,
|
||||||
*/
|
*/
|
||||||
},
|
},
|
||||||
_ => {
|
Content::RangedNumber(range) => {
|
||||||
|
use roc_types::num::NumericRange::*;
|
||||||
|
|
||||||
|
match range {
|
||||||
|
IntAtLeastSigned(int_lit_width) => int_lit_width_to_mono_type_id(int_lit_width),
|
||||||
|
IntAtLeastEitherSign(int_lit_width) => int_lit_width_to_mono_type_id(int_lit_width),
|
||||||
|
NumAtLeastSigned(int_lit_width) => int_lit_width_to_mono_type_id(int_lit_width),
|
||||||
|
NumAtLeastEitherSign(int_lit_width) => int_lit_width_to_mono_type_id(int_lit_width),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Content::Alias(_symbol, args, real, kind) => {
|
||||||
|
let mono_id = lower_var(env, subs, real)?;
|
||||||
|
// let mono_args = args
|
||||||
|
// .into_iter()
|
||||||
|
// .flat_map(|arg| lower_var(env, subs, subs[arg]));
|
||||||
|
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
content => {
|
||||||
|
todo!("specialize this Content: {content:?}");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This var is now known to be monomorphic, so we don't repeat this work again later.
|
// This var is now known to be monomorphic, so we don't repeat this work again later.
|
||||||
|
@ -264,6 +277,26 @@ fn lower_var<P: Push<Problem>>(
|
||||||
Some(mono_id)
|
Some(mono_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn int_lit_width_to_mono_type_id(int_lit_width: roc_can::num::IntLitWidth) -> MonoTypeId {
|
||||||
|
use roc_can::num::IntLitWidth;
|
||||||
|
|
||||||
|
match int_lit_width {
|
||||||
|
IntLitWidth::U8 => MonoTypeId::U8,
|
||||||
|
IntLitWidth::U16 => MonoTypeId::U16,
|
||||||
|
IntLitWidth::U32 => MonoTypeId::U32,
|
||||||
|
IntLitWidth::U64 => MonoTypeId::U64,
|
||||||
|
IntLitWidth::U128 => MonoTypeId::U128,
|
||||||
|
IntLitWidth::I8 => MonoTypeId::I8,
|
||||||
|
IntLitWidth::I16 => MonoTypeId::I16,
|
||||||
|
IntLitWidth::I32 => MonoTypeId::I32,
|
||||||
|
IntLitWidth::I64 => MonoTypeId::I64,
|
||||||
|
IntLitWidth::I128 => MonoTypeId::I128,
|
||||||
|
IntLitWidth::F32 => MonoTypeId::F32,
|
||||||
|
IntLitWidth::F64 => MonoTypeId::F64,
|
||||||
|
IntLitWidth::Dec => MonoTypeId::DEC,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn num_args_to_mono_id(
|
fn num_args_to_mono_id(
|
||||||
args: SubsSlice<Variable>,
|
args: SubsSlice<Variable>,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
|
|
126
crates/compiler/specialize_types/tests/helpers/mod.rs
Normal file
126
crates/compiler/specialize_types/tests/helpers/mod.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use roc_load::LoadedModule;
|
||||||
|
use roc_solve::FunctionKind;
|
||||||
|
use roc_specialize_types::{
|
||||||
|
DebugInfo, Env, Interns, MonoCache, MonoExpr, MonoExprs, MonoTypes, RecordFieldIds,
|
||||||
|
TupleElemIds,
|
||||||
|
};
|
||||||
|
use test_compile::{trim_and_deindent, SpecializedExprOut};
|
||||||
|
use test_solve_helpers::{format_problems, run_load_and_infer};
|
||||||
|
|
||||||
|
fn specialize_expr<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
src: &str,
|
||||||
|
string_interns: &mut Interns<'a>,
|
||||||
|
) -> SpecializedExprOut {
|
||||||
|
let (
|
||||||
|
LoadedModule {
|
||||||
|
module_id: home,
|
||||||
|
mut declarations_by_id,
|
||||||
|
mut can_problems,
|
||||||
|
mut type_problems,
|
||||||
|
interns,
|
||||||
|
mut solved,
|
||||||
|
mut exposed_to_host,
|
||||||
|
abilities_store,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
src,
|
||||||
|
) = run_load_and_infer(
|
||||||
|
trim_and_deindent(&arena, src),
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
FunctionKind::LambdaSet,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut can_problems = can_problems.remove(&home).unwrap_or_default();
|
||||||
|
let type_problems = type_problems.remove(&home).unwrap_or_default();
|
||||||
|
|
||||||
|
// Disregard UnusedDef problems, because those are unavoidable when
|
||||||
|
// returning a function from the test expression.
|
||||||
|
can_problems.retain(|prob| {
|
||||||
|
!matches!(
|
||||||
|
prob,
|
||||||
|
roc_problem::can::Problem::UnusedDef(_, _)
|
||||||
|
| roc_problem::can::Problem::UnusedBranchDef(..)
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let (can_problems, type_problems) =
|
||||||
|
format_problems(&src, home, &interns, can_problems, type_problems);
|
||||||
|
|
||||||
|
assert_eq!(can_problems, String::new());
|
||||||
|
assert_eq!(type_problems, String::new());
|
||||||
|
|
||||||
|
exposed_to_host.retain(|s, _| !abilities_store.is_specialization_name(*s));
|
||||||
|
|
||||||
|
let mut problems = Vec::new();
|
||||||
|
let mut debug_info: Option<DebugInfo> = None;
|
||||||
|
let mut types_cache = MonoCache::from_solved_subs(&solved);
|
||||||
|
let mut mono_types = MonoTypes::new();
|
||||||
|
let mut mono_exprs = MonoExprs::new();
|
||||||
|
|
||||||
|
let mut env = Env::new(
|
||||||
|
&arena,
|
||||||
|
&mut solved,
|
||||||
|
&mut types_cache,
|
||||||
|
&mut mono_types,
|
||||||
|
&mut mono_exprs,
|
||||||
|
RecordFieldIds::default(),
|
||||||
|
TupleElemIds::default(),
|
||||||
|
string_interns,
|
||||||
|
&mut debug_info,
|
||||||
|
&mut problems,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut home_decls = declarations_by_id.remove(&home).unwrap();
|
||||||
|
let main_expr = home_decls.expressions.pop().unwrap().value;
|
||||||
|
|
||||||
|
// This should be our only expr
|
||||||
|
assert_eq!(0, home_decls.expressions.len());
|
||||||
|
|
||||||
|
let mono_expr_id = env.to_mono_expr(main_expr);
|
||||||
|
|
||||||
|
SpecializedExprOut {
|
||||||
|
mono_expr_id,
|
||||||
|
problems,
|
||||||
|
mono_types,
|
||||||
|
mono_exprs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn expect_no_expr(input: impl AsRef<str>) {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let mut interns = Interns::new();
|
||||||
|
let out = specialize_expr(&arena, input.as_ref(), &mut interns);
|
||||||
|
let actual = out.mono_expr_id.map(|id| out.mono_exprs.get(id));
|
||||||
|
|
||||||
|
assert_eq!(None, actual, "This input expr should have specialized to being dicarded as zero-sized, but it didn't: {:?}", input.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn expect_mono_expr(input: impl AsRef<str>, mono_expr: MonoExpr) {
|
||||||
|
expect_mono_expr_with_interns(|_, _| {}, input, |_| mono_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn expect_mono_expr_with_interns<T>(
|
||||||
|
from_interns: impl for<'a> FnOnce(&'a Bump, &Interns<'a>) -> T,
|
||||||
|
input: impl AsRef<str>,
|
||||||
|
to_mono_expr: impl FnOnce(T) -> MonoExpr,
|
||||||
|
) {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let mut string_interns = Interns::new();
|
||||||
|
let out = specialize_expr(&arena, input.as_ref(), &mut string_interns);
|
||||||
|
let mono_expr_id = out
|
||||||
|
.mono_expr_id
|
||||||
|
.expect("This input expr should not have been discarded as zero-sized, but it was discarded: {input:?}");
|
||||||
|
|
||||||
|
let actual_expr = out.mono_exprs.get(mono_expr_id); // Must run first, to populate string interns!
|
||||||
|
|
||||||
|
let expected_expr = to_mono_expr(from_interns(&arena, &string_interns));
|
||||||
|
|
||||||
|
assert_eq!(&expected_expr, actual_expr);
|
||||||
|
}
|
181
crates/compiler/specialize_types/tests/specialize_primitives.rs
Normal file
181
crates/compiler/specialize_types/tests/specialize_primitives.rs
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pretty_assertions;
|
||||||
|
|
||||||
|
extern crate bumpalo;
|
||||||
|
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod specialize_primitives {
|
||||||
|
use roc_specialize_types::{MonoExpr, Number};
|
||||||
|
|
||||||
|
use super::helpers::{expect_mono_expr, expect_mono_expr_with_interns, expect_no_expr};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_record() {
|
||||||
|
expect_no_expr("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_literal() {
|
||||||
|
let string = "foo";
|
||||||
|
let expected = format!("\"{string}\"");
|
||||||
|
expect_mono_expr_with_interns(
|
||||||
|
|arena, interns| interns.try_get(arena, string).unwrap(),
|
||||||
|
expected,
|
||||||
|
|id| MonoExpr::Str(id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_zero() {
|
||||||
|
let expected = 0;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I8(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_negative_i8() {
|
||||||
|
let expected = -42;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I8(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_positive_i8() {
|
||||||
|
let expected = 42;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I8(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_u8() {
|
||||||
|
let expected = 128;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::U8(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_negative_i16() {
|
||||||
|
let expected = -5_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I16(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_positive_i16() {
|
||||||
|
let expected = 5_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I16(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_u16() {
|
||||||
|
let expected = 65_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::U16(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn unbound_negative_i32() {
|
||||||
|
let expected = -2_000_000_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I32(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_positive_i32() {
|
||||||
|
let expected = 2_000_000_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I32(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_u32() {
|
||||||
|
let expected = 4_000_000_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::U32(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_negative_i64() {
|
||||||
|
let expected = -9_000_000_000_000_000_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I64(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_positive_i64() {
|
||||||
|
let expected = 9_000_000_000_000_000_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I64(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_u64() {
|
||||||
|
let expected = 18_000_000_000_000_000_000;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::U64(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_negative_i128() {
|
||||||
|
let expected = -170_141_183_460_469_231_731_687_303_715_884_105_728;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I128(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_positive_i128() {
|
||||||
|
let expected = 170_141_183_460_469_231_731_687_303_715_884_105_727;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::I128(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_u128() {
|
||||||
|
let expected = 340_282_366_920_938_463_463_374_607_431_768_211_455;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::U128(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbound_f64() {
|
||||||
|
let expected = 3.14159265359;
|
||||||
|
expect_mono_expr(
|
||||||
|
format!("{expected}"),
|
||||||
|
MonoExpr::Number(Number::Dec(expected)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,158 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate pretty_assertions;
|
|
||||||
|
|
||||||
extern crate bumpalo;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod specialize_types {
|
|
||||||
use bumpalo::Bump;
|
|
||||||
use roc_load::LoadedModule;
|
|
||||||
use roc_solve::FunctionKind;
|
|
||||||
use roc_specialize_types::{
|
|
||||||
DebugInfo, Env, Interns, MonoCache, MonoExpr, MonoExprs, MonoTypes, Number, RecordFieldIds,
|
|
||||||
TupleElemIds,
|
|
||||||
};
|
|
||||||
use test_compile::{trim_and_deindent, SpecializedExprOut};
|
|
||||||
use test_solve_helpers::{format_problems, run_load_and_infer};
|
|
||||||
|
|
||||||
// HELPERS
|
|
||||||
|
|
||||||
fn specialize_expr<'a>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
src: &str,
|
|
||||||
string_interns: &mut Interns<'a>,
|
|
||||||
) -> SpecializedExprOut {
|
|
||||||
let (
|
|
||||||
LoadedModule {
|
|
||||||
module_id: home,
|
|
||||||
mut declarations_by_id,
|
|
||||||
mut can_problems,
|
|
||||||
mut type_problems,
|
|
||||||
interns,
|
|
||||||
mut solved,
|
|
||||||
mut exposed_to_host,
|
|
||||||
abilities_store,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
src,
|
|
||||||
) = run_load_and_infer(
|
|
||||||
trim_and_deindent(&arena, src),
|
|
||||||
[],
|
|
||||||
false,
|
|
||||||
FunctionKind::LambdaSet,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut can_problems = can_problems.remove(&home).unwrap_or_default();
|
|
||||||
let type_problems = type_problems.remove(&home).unwrap_or_default();
|
|
||||||
|
|
||||||
// Disregard UnusedDef problems, because those are unavoidable when
|
|
||||||
// returning a function from the test expression.
|
|
||||||
can_problems.retain(|prob| {
|
|
||||||
!matches!(
|
|
||||||
prob,
|
|
||||||
roc_problem::can::Problem::UnusedDef(_, _)
|
|
||||||
| roc_problem::can::Problem::UnusedBranchDef(..)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let (can_problems, type_problems) =
|
|
||||||
format_problems(&src, home, &interns, can_problems, type_problems);
|
|
||||||
|
|
||||||
assert_eq!(can_problems, String::new());
|
|
||||||
assert_eq!(type_problems, String::new());
|
|
||||||
|
|
||||||
exposed_to_host.retain(|s, _| !abilities_store.is_specialization_name(*s));
|
|
||||||
|
|
||||||
let mut problems = Vec::new();
|
|
||||||
let mut debug_info: Option<DebugInfo> = None;
|
|
||||||
let mut types_cache = MonoCache::from_solved_subs(&solved);
|
|
||||||
let mut mono_types = MonoTypes::new();
|
|
||||||
let mut mono_exprs = MonoExprs::new();
|
|
||||||
|
|
||||||
let mut env = Env::new(
|
|
||||||
&arena,
|
|
||||||
&mut solved,
|
|
||||||
&mut types_cache,
|
|
||||||
&mut mono_types,
|
|
||||||
&mut mono_exprs,
|
|
||||||
RecordFieldIds::default(),
|
|
||||||
TupleElemIds::default(),
|
|
||||||
string_interns,
|
|
||||||
&mut debug_info,
|
|
||||||
&mut problems,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut home_decls = declarations_by_id.remove(&home).unwrap();
|
|
||||||
let main_expr = home_decls.expressions.pop().unwrap().value;
|
|
||||||
|
|
||||||
// This should be our only expr
|
|
||||||
assert_eq!(0, home_decls.expressions.len());
|
|
||||||
|
|
||||||
let mono_expr_id = env.to_mono_expr(main_expr);
|
|
||||||
|
|
||||||
SpecializedExprOut {
|
|
||||||
mono_expr_id,
|
|
||||||
problems,
|
|
||||||
mono_types,
|
|
||||||
mono_exprs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expect_no_expr(input: impl AsRef<str>) {
|
|
||||||
let arena = Bump::new();
|
|
||||||
let mut interns = Interns::new();
|
|
||||||
let out = specialize_expr(&arena, input.as_ref(), &mut interns);
|
|
||||||
let actual = out.mono_expr_id.map(|id| out.mono_exprs.get(id));
|
|
||||||
|
|
||||||
assert_eq!(None, actual, "This input expr should have specialized to being dicarded as zero-sized, but it didn't: {:?}", input.as_ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expect_mono_expr(input: impl AsRef<str>, mono_expr: MonoExpr) {
|
|
||||||
expect_mono_expr_with_interns(|_, _| {}, input, |_| mono_expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expect_mono_expr_with_interns<T>(
|
|
||||||
from_interns: impl for<'a> FnOnce(&'a Bump, &Interns<'a>) -> T,
|
|
||||||
input: impl AsRef<str>,
|
|
||||||
to_mono_expr: impl FnOnce(T) -> MonoExpr,
|
|
||||||
) {
|
|
||||||
let arena = Bump::new();
|
|
||||||
let mut string_interns = Interns::new();
|
|
||||||
let out = specialize_expr(&arena, input.as_ref(), &mut string_interns);
|
|
||||||
let mono_expr_id = out
|
|
||||||
.mono_expr_id
|
|
||||||
.expect("This input expr should not have been discarded as zero-sized, but it was discarded: {input:?}");
|
|
||||||
|
|
||||||
let actual_expr = out.mono_exprs.get(mono_expr_id); // Must run first, to populate string interns!
|
|
||||||
|
|
||||||
let expected_expr = to_mono_expr(from_interns(&arena, &string_interns));
|
|
||||||
|
|
||||||
assert_eq!(&expected_expr, actual_expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_record() {
|
|
||||||
expect_no_expr("{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_literal() {
|
|
||||||
let string = "foo";
|
|
||||||
let expected = format!("\"{string}\"");
|
|
||||||
expect_mono_expr_with_interns(
|
|
||||||
|arena, interns| interns.try_get(arena, string).unwrap(),
|
|
||||||
expected,
|
|
||||||
|id| MonoExpr::Str(id),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unbound_num() {
|
|
||||||
let expected = 42;
|
|
||||||
expect_mono_expr(
|
|
||||||
format!("{expected}"),
|
|
||||||
MonoExpr::Number(Number::I64(expected)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue