mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Test monomorphizing string literals
This commit is contained in:
parent
7b80489772
commit
8b73efc2ec
7 changed files with 173 additions and 39 deletions
|
@ -12,7 +12,7 @@ use roc_collections::Push;
|
||||||
use roc_solve::module::Solved;
|
use roc_solve::module::Solved;
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
|
||||||
pub struct Env<'a, 'c, 'd, 's, 't, P> {
|
pub struct Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &'s mut Subs,
|
subs: &'s mut Subs,
|
||||||
types_cache: &'c mut MonoCache,
|
types_cache: &'c mut MonoCache,
|
||||||
|
@ -21,11 +21,11 @@ pub struct Env<'a, 'c, 'd, 's, 't, P> {
|
||||||
record_field_ids: RecordFieldIds,
|
record_field_ids: RecordFieldIds,
|
||||||
tuple_elem_ids: TupleElemIds,
|
tuple_elem_ids: TupleElemIds,
|
||||||
debug_info: &'d mut Option<DebugInfo>,
|
debug_info: &'d mut Option<DebugInfo>,
|
||||||
string_interns: &'a mut Interns<'a>,
|
string_interns: &'i mut Interns<'a>,
|
||||||
problems: P,
|
problems: P,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'c, 'd, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 's, 't, P> {
|
impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &'s mut Solved<Subs>,
|
subs: &'s mut Solved<Subs>,
|
||||||
|
@ -34,7 +34,7 @@ impl<'a, 'c, 'd, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 's, 't, P> {
|
||||||
mono_exprs: &'t mut MonoExprs,
|
mono_exprs: &'t mut MonoExprs,
|
||||||
record_field_ids: RecordFieldIds,
|
record_field_ids: RecordFieldIds,
|
||||||
tuple_elem_ids: TupleElemIds,
|
tuple_elem_ids: TupleElemIds,
|
||||||
string_interns: &'a mut Interns<'a>,
|
string_interns: &'i mut Interns<'a>,
|
||||||
debug_info: &'d mut Option<DebugInfo>,
|
debug_info: &'d mut Option<DebugInfo>,
|
||||||
problems: P,
|
problems: P,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -88,6 +88,7 @@ impl<'a, 'c, 'd, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 's, 't, P> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::Num(var, _str, int_value, _) | Expr::Int(var, _, _str, int_value, _) => {
|
Expr::Num(var, _str, int_value, _) | Expr::Int(var, _, _str, int_value, _) => {
|
||||||
|
// Numbers can specialize
|
||||||
match mono_from_var(var) {
|
match mono_from_var(var) {
|
||||||
Some(mono_id) => match mono_types.get(mono_id) {
|
Some(mono_id) => match mono_types.get(mono_id) {
|
||||||
MonoType::Primitive(primitive) => to_num(*primitive, int_value, problems),
|
MonoType::Primitive(primitive) => to_num(*primitive, int_value, problems),
|
||||||
|
@ -115,9 +116,10 @@ impl<'a, 'c, 'd, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 's, 't, P> {
|
||||||
return compiler_bug!(Problem::CharSpecializedToWrongType(None));
|
return compiler_bug!(Problem::CharSpecializedToWrongType(None));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::Str(contents) => {
|
Expr::Str(contents) => MonoExpr::Str(
|
||||||
MonoExpr::Str(self.string_interns.get(self.arena.alloc(contents)))
|
self.string_interns
|
||||||
}
|
.get(self.arena, self.arena.alloc(contents)),
|
||||||
|
),
|
||||||
Expr::EmptyRecord => {
|
Expr::EmptyRecord => {
|
||||||
// Empty records are zero-sized and should be discarded.
|
// Empty records are zero-sized and should be discarded.
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use bumpalo::Bump;
|
||||||
use roc_solve::module::Solved;
|
use roc_solve::module::Solved;
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ impl MonoModule {
|
||||||
pub struct InternedStrId(u32);
|
pub struct InternedStrId(u32);
|
||||||
|
|
||||||
/// TODO move this to its own crate
|
/// TODO move this to its own crate
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Interns<'a> {
|
pub struct Interns<'a> {
|
||||||
interned: Vec<&'a str>,
|
interned: Vec<&'a str>,
|
||||||
}
|
}
|
||||||
|
@ -37,7 +39,7 @@ impl<'a> Interns<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, string: &'a str) -> InternedStrId {
|
pub fn get(&mut self, _arena: &'a Bump, string: &'a str) -> InternedStrId {
|
||||||
match self
|
match self
|
||||||
.interned
|
.interned
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -53,4 +55,15 @@ impl<'a> Interns<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_get(&self, _arena: &'a Bump, string: &'a str) -> Option<InternedStrId> {
|
||||||
|
match self
|
||||||
|
.interned
|
||||||
|
.iter()
|
||||||
|
.position(|&interned| interned == string)
|
||||||
|
{
|
||||||
|
Some(index) => Some(InternedStrId(index as u32)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub struct MonoCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonoCache {
|
impl MonoCache {
|
||||||
pub fn from_subs(subs: &Solved<Subs>) -> Self {
|
pub fn from_solved_subs(subs: &Solved<Subs>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: VecMap::with_capacity(subs.inner().len()),
|
inner: VecMap::with_capacity(subs.inner().len()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,31 +5,148 @@ extern crate bumpalo;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod specialize_types {
|
mod specialize_types {
|
||||||
use roc_specialize_types::{MonoExpr, Number};
|
use bumpalo::Bump;
|
||||||
use test_compile::specialize_expr;
|
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>) {
|
fn expect_no_expr(input: impl AsRef<str>) {
|
||||||
let out = specialize_expr(input.as_ref());
|
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));
|
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());
|
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) {
|
fn expect_mono_expr(input: impl AsRef<str>, mono_expr: MonoExpr) {
|
||||||
let out = specialize_expr(input.as_ref());
|
expect_mono_expr_with_interns(|_, _| {}, input, |_| mono_expr);
|
||||||
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:?}");
|
|
||||||
|
|
||||||
assert_eq!(&mono_expr, out.mono_exprs.get(mono_expr_id));
|
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]
|
#[test]
|
||||||
fn empty_record() {
|
fn empty_record() {
|
||||||
let todo = (); // TODO need to get earlier stage working, specifically constraint + solve, by replicating existing solve tests.
|
|
||||||
expect_no_expr("{}");
|
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]
|
#[test]
|
||||||
fn unbound_num() {
|
fn unbound_num() {
|
||||||
let expected = 42;
|
let expected = 42;
|
||||||
|
|
|
@ -51,7 +51,7 @@ mod specialize_types {
|
||||||
|
|
||||||
debug_assert!(exposed_to_host.len() == 1, "{exposed_to_host:?}");
|
debug_assert!(exposed_to_host.len() == 1, "{exposed_to_host:?}");
|
||||||
let (_symbol, variable) = exposed_to_host.into_iter().next().unwrap();
|
let (_symbol, variable) = exposed_to_host.into_iter().next().unwrap();
|
||||||
let mut mono_cache = MonoCache::from_subs(&solved);
|
let mut mono_cache = MonoCache::from_solved_subs(&solved);
|
||||||
let mut mono_types = MonoTypes::new();
|
let mut mono_types = MonoTypes::new();
|
||||||
let debug_info = DebugInfo::new();
|
let debug_info = DebugInfo::new();
|
||||||
let mut record_field_ids = RecordFieldIds::new();
|
let mut record_field_ids = RecordFieldIds::new();
|
||||||
|
|
|
@ -19,29 +19,34 @@ pub struct SpecializedExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpecializedExpr {
|
impl SpecializedExpr {
|
||||||
pub fn specialize_expr<'a>(&'a self, input: &'a str) -> SpecializedExprOut {
|
pub fn specialize_expr<'a>(
|
||||||
|
&'a self,
|
||||||
|
input: &'a str,
|
||||||
|
string_interns: &'a mut Interns<'a>,
|
||||||
|
) -> SpecializedExprOut {
|
||||||
let mut solved_out = self.solved_expr.solve_expr(input);
|
let mut solved_out = self.solved_expr.solve_expr(input);
|
||||||
let mut problems = Vec::new();
|
let mut problems = Vec::new();
|
||||||
let mut debug_info: Option<DebugInfo> = None;
|
let mut debug_info: Option<DebugInfo> = None;
|
||||||
let mut types_cache = MonoCache::from_subs(&solved_out.subs);
|
let mut types_cache = MonoCache::from_solved_subs(&solved_out.subs);
|
||||||
let mut mono_types = MonoTypes::new();
|
let mut mono_types = MonoTypes::new();
|
||||||
let mut mono_exprs = MonoExprs::new();
|
let mut mono_exprs = MonoExprs::new();
|
||||||
let mut string_interns = Interns::new();
|
|
||||||
|
|
||||||
let mut env = Env::new(
|
let mono_expr_id = {
|
||||||
self.solved_expr.arena(),
|
let mut env = Env::new(
|
||||||
&mut solved_out.subs,
|
self.solved_expr.arena(),
|
||||||
&mut types_cache,
|
&mut solved_out.subs,
|
||||||
&mut mono_types,
|
&mut types_cache,
|
||||||
&mut mono_exprs,
|
&mut mono_types,
|
||||||
RecordFieldIds::default(),
|
&mut mono_exprs,
|
||||||
TupleElemIds::default(),
|
RecordFieldIds::default(),
|
||||||
&mut string_interns,
|
TupleElemIds::default(),
|
||||||
&mut debug_info,
|
string_interns,
|
||||||
&mut problems,
|
&mut debug_info,
|
||||||
);
|
&mut problems,
|
||||||
|
);
|
||||||
|
|
||||||
let mono_expr_id = env.to_mono_expr(solved_out.expr);
|
env.to_mono_expr(solved_out.expr)
|
||||||
|
};
|
||||||
|
|
||||||
SpecializedExprOut {
|
SpecializedExprOut {
|
||||||
mono_expr_id,
|
mono_expr_id,
|
||||||
|
|
|
@ -5,6 +5,7 @@ mod help_parse;
|
||||||
mod help_solve;
|
mod help_solve;
|
||||||
mod help_specialize;
|
mod help_specialize;
|
||||||
|
|
||||||
|
pub use deindent::trim_and_deindent;
|
||||||
pub use help_can::{CanExpr, CanExprOut};
|
pub use help_can::{CanExpr, CanExprOut};
|
||||||
pub use help_parse::ParseExpr;
|
pub use help_parse::ParseExpr;
|
||||||
pub use help_solve::{SolvedExpr, SolvedExprOut};
|
pub use help_solve::{SolvedExpr, SolvedExprOut};
|
||||||
|
@ -17,7 +18,3 @@ pub fn can_expr<'a>(input: &'a str) -> CanExprOut {
|
||||||
pub fn solve_expr<'a>(input: &'a str) -> SolvedExprOut {
|
pub fn solve_expr<'a>(input: &'a str) -> SolvedExprOut {
|
||||||
SolvedExpr::default().solve_expr(input)
|
SolvedExpr::default().solve_expr(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn specialize_expr<'a>(input: &'a str) -> SpecializedExprOut {
|
|
||||||
SpecializedExpr::default().specialize_expr(input)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue