mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Introduce string-based mono expr tests
This commit is contained in:
parent
03370da6d6
commit
219a0398a2
7 changed files with 207 additions and 24 deletions
|
@ -110,7 +110,7 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
},
|
||||
None => compiler_bug!(Problem::CharSpecializedToWrongType(None)),
|
||||
},
|
||||
Expr::Str(contents) => Some(MonoExpr::Str(self.string_interns.get(
|
||||
Expr::Str(contents) => Some(MonoExpr::Str(self.string_interns.get_id(
|
||||
self.arena,
|
||||
// TODO should be able to remove this alloc_str() once canonical Expr stores an arena-allocated string.
|
||||
self.arena.alloc_str(contents),
|
||||
|
|
|
@ -117,6 +117,18 @@ impl MonoExprs {
|
|||
*self.regions.get_unchecked_mut(index) = region;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_slice(&self, expr_ids: Slice<MonoExprId>) -> impl Iterator<Item = &MonoExpr> {
|
||||
expr_ids.indices().into_iter().map(|index| {
|
||||
debug_assert!(
|
||||
self.exprs.get(index).is_some(),
|
||||
"A Slice index was not found in MonoExprs. This should never happen!"
|
||||
);
|
||||
|
||||
// Safety: we should only ever hand out MonoExprId slices that are valid indices into here.
|
||||
unsafe { self.exprs.get_unchecked(index) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
|
|
@ -39,7 +39,19 @@ impl<'a> Interns<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get(&mut self, _arena: &'a Bump, string: &'a str) -> InternedStrId {
|
||||
pub fn get_str(&self, _arena: &'a Bump, id: InternedStrId) -> &'a str {
|
||||
let index = id.0 as usize;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert!(self.interned.get(index).is_some(), "Got an InternedStringId ({index}) that was outside the bounds of the backing array. This should never happen!");
|
||||
}
|
||||
|
||||
// Safety: We should only ever give out InternedStrId values that are in this range.
|
||||
unsafe { self.interned.get_unchecked(index) }
|
||||
}
|
||||
|
||||
pub fn get_id(&mut self, _arena: &'a Bump, string: &'a str) -> InternedStrId {
|
||||
match self
|
||||
.interned
|
||||
.iter()
|
||||
|
@ -56,7 +68,7 @@ impl<'a> Interns<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn try_get(&self, _arena: &'a Bump, string: &'a str) -> Option<InternedStrId> {
|
||||
pub fn try_get_id(&self, _arena: &'a Bump, string: &'a str) -> Option<InternedStrId> {
|
||||
match self
|
||||
.interned
|
||||
.iter()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use bumpalo::Bump;
|
||||
use core::fmt::Write;
|
||||
use roc_load::LoadedModule;
|
||||
use roc_region::all::Region;
|
||||
use roc_solve::FunctionKind;
|
||||
|
@ -107,14 +108,161 @@ pub fn expect_no_expr(input: impl AsRef<str>) {
|
|||
|
||||
#[track_caller]
|
||||
pub fn expect_mono_expr(input: impl AsRef<str>, mono_expr: MonoExpr) {
|
||||
expect_mono_expr_with_interns(|_, _| {}, input, |_| mono_expr);
|
||||
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,
|
||||
pub fn expect_mono_expr_str(input: impl AsRef<str>, expr_str: impl AsRef<str>) {
|
||||
expect_mono_expr_custom(
|
||||
input,
|
||||
|_, _, _| expr_str.as_ref().to_string(),
|
||||
|arena, mono_exprs, interns, expr| {
|
||||
dbg_mono_expr(arena, mono_exprs, interns, expr).to_string()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn dbg_mono_expr<'a>(
|
||||
arena: &'a Bump,
|
||||
mono_exprs: &MonoExprs,
|
||||
interns: &Interns<'a>,
|
||||
expr: &MonoExpr,
|
||||
) -> &'a str {
|
||||
let mut buf = bumpalo::collections::String::new_in(arena);
|
||||
|
||||
dbg_mono_expr_help(arena, mono_exprs, interns, expr, &mut buf);
|
||||
|
||||
buf.into_bump_str()
|
||||
}
|
||||
|
||||
fn dbg_mono_expr_help<'a>(
|
||||
arena: &'a Bump,
|
||||
mono_exprs: &MonoExprs,
|
||||
interns: &Interns<'a>,
|
||||
expr: &MonoExpr,
|
||||
buf: &mut impl Write,
|
||||
) {
|
||||
match expr {
|
||||
MonoExpr::Str(interned_str_id) => {
|
||||
write!(buf, "Str({:?})", interns.get_str(arena, *interned_str_id)).unwrap();
|
||||
}
|
||||
MonoExpr::Number(number) => {
|
||||
write!(buf, "Number({:?})", number).unwrap();
|
||||
}
|
||||
MonoExpr::Struct(expr_ids) => {
|
||||
write!(buf, "Struct([").unwrap();
|
||||
|
||||
for (index, expr) in mono_exprs.iter_slice(expr_ids.as_slice()).enumerate() {
|
||||
if index > 0 {
|
||||
write!(buf, ", ").unwrap();
|
||||
}
|
||||
|
||||
dbg_mono_expr_help(arena, mono_exprs, interns, expr, buf);
|
||||
}
|
||||
|
||||
write!(buf, "])").unwrap();
|
||||
}
|
||||
// MonoExpr::List { elem_type, elems } => todo!(),
|
||||
// MonoExpr::Lookup(symbol, mono_type_id) => todo!(),
|
||||
// MonoExpr::ParameterizedLookup {
|
||||
// name,
|
||||
// lookup_type,
|
||||
// params_name,
|
||||
// params_type,
|
||||
// } => todo!(),
|
||||
// MonoExpr::When {
|
||||
// cond,
|
||||
// cond_type,
|
||||
// branch_type,
|
||||
// branches,
|
||||
// } => todo!(),
|
||||
// MonoExpr::If {
|
||||
// branch_type,
|
||||
// branches,
|
||||
// final_else,
|
||||
// } => todo!(),
|
||||
// MonoExpr::LetRec { defs, ending_expr } => todo!(),
|
||||
// MonoExpr::LetNonRec { def, ending_expr } => todo!(),
|
||||
// MonoExpr::Call {
|
||||
// fn_type,
|
||||
// fn_expr,
|
||||
// args,
|
||||
// closure_type,
|
||||
// } => todo!(),
|
||||
// MonoExpr::RunLowLevel { op, args, ret_type } => todo!(),
|
||||
// MonoExpr::ForeignCall {
|
||||
// foreign_symbol,
|
||||
// args,
|
||||
// ret_type,
|
||||
// } => todo!(),
|
||||
// MonoExpr::Lambda {
|
||||
// fn_type,
|
||||
// arguments,
|
||||
// body,
|
||||
// captured_symbols,
|
||||
// recursive,
|
||||
// } => todo!(),
|
||||
// MonoExpr::Crash { msg, expr_type } => todo!(),
|
||||
// MonoExpr::StructAccess {
|
||||
// record_expr,
|
||||
// record_type,
|
||||
// field_type,
|
||||
// field_id,
|
||||
// } => todo!(),
|
||||
// MonoExpr::RecordUpdate {
|
||||
// record_type,
|
||||
// record_name,
|
||||
// updates,
|
||||
// } => todo!(),
|
||||
// MonoExpr::SmallTag {
|
||||
// discriminant,
|
||||
// tag_union_type,
|
||||
// args,
|
||||
// } => todo!(),
|
||||
// MonoExpr::BigTag {
|
||||
// discriminant,
|
||||
// tag_union_type,
|
||||
// args,
|
||||
// } => todo!(),
|
||||
// MonoExpr::Expect {
|
||||
// condition,
|
||||
// continuation,
|
||||
// lookups_in_cond,
|
||||
// } => todo!(),
|
||||
// MonoExpr::Dbg {
|
||||
// source_location,
|
||||
// source,
|
||||
// msg,
|
||||
// continuation,
|
||||
// expr_type,
|
||||
// name,
|
||||
// } => todo!(),
|
||||
MonoExpr::CompilerBug(problem) => {
|
||||
write!(buf, "CompilerBug({:?})", problem).unwrap();
|
||||
}
|
||||
other => {
|
||||
todo!("Implement dbg_mono_expr for {:?}", other)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn expect_mono_expr_with_interns(
|
||||
input: impl AsRef<str>,
|
||||
to_mono_expr: impl FnOnce(T) -> MonoExpr,
|
||||
from_interns: impl for<'a> Fn(&'a Bump, &Interns<'a>) -> MonoExpr,
|
||||
) {
|
||||
expect_mono_expr_custom(
|
||||
input,
|
||||
|arena, _exprs, interns| from_interns(arena, interns),
|
||||
|_, _, _, expr| *expr,
|
||||
);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn expect_mono_expr_custom<T: PartialEq + core::fmt::Debug>(
|
||||
input: impl AsRef<str>,
|
||||
to_expected: impl for<'a> Fn(&'a Bump, &MonoExprs, &Interns<'a>) -> T,
|
||||
to_actual: impl for<'a> Fn(&'a Bump, &MonoExprs, &Interns<'a>, &MonoExpr) -> T,
|
||||
) {
|
||||
let arena = Bump::new();
|
||||
let mut string_interns = Interns::new();
|
||||
|
@ -124,8 +272,8 @@ pub fn expect_mono_expr_with_interns<T>(
|
|||
.expect("This input expr should not have been discarded as zero-sized, but it was discarded: {input:?}");
|
||||
|
||||
let actual_expr = out.mono_exprs.get_expr(mono_expr_id); // Must run first, to populate string interns!
|
||||
let actual = to_actual(&arena, &out.mono_exprs, &string_interns, actual_expr);
|
||||
let expected = to_expected(&arena, &out.mono_exprs, &string_interns);
|
||||
|
||||
let expected_expr = to_mono_expr(from_interns(&arena, &string_interns));
|
||||
|
||||
assert_eq!(&expected_expr, actual_expr);
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
|
|
@ -9,17 +9,15 @@ mod helpers;
|
|||
mod specialize_primitives {
|
||||
use roc_specialize_types::{MonoExpr, Number};
|
||||
|
||||
use super::helpers::{expect_mono_expr, expect_mono_expr_with_interns, expect_no_expr};
|
||||
use super::helpers::{expect_mono_expr, expect_mono_expr_with_interns};
|
||||
|
||||
#[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),
|
||||
);
|
||||
expect_mono_expr_with_interns(expected, |arena, interns| {
|
||||
MonoExpr::Str(interns.try_get_id(arena, string).unwrap())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -9,6 +9,8 @@ mod helpers;
|
|||
mod specialize_structs {
|
||||
use roc_specialize_types::{MonoExpr, Number};
|
||||
|
||||
use crate::helpers::expect_mono_expr_str;
|
||||
|
||||
use super::helpers::{expect_mono_expr, expect_mono_expr_with_interns, expect_no_expr};
|
||||
|
||||
#[test]
|
||||
|
@ -25,11 +27,9 @@ mod specialize_structs {
|
|||
fn one_field_record_string_literal() {
|
||||
let string = "foo";
|
||||
let expected = format!("{{ discardedField: \"{string}\" }}");
|
||||
expect_mono_expr_with_interns(
|
||||
|arena, interns| interns.try_get(arena, string).unwrap(),
|
||||
expected,
|
||||
|id| MonoExpr::Str(id),
|
||||
);
|
||||
expect_mono_expr_with_interns(expected, |arena, interns| {
|
||||
MonoExpr::Str(interns.try_get_id(arena, string).unwrap())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -37,10 +37,19 @@ mod specialize_structs {
|
|||
let string = "foo";
|
||||
let expected =
|
||||
format!("{{ discarded: {{}}, discardedToo: \"{string}\", alsoDiscarded: {{}} }}");
|
||||
expect_mono_expr_with_interns(
|
||||
|arena, interns| interns.try_get(arena, string).unwrap(),
|
||||
expect_mono_expr_with_interns(expected, |arena, interns| {
|
||||
MonoExpr::Str(interns.try_get_id(arena, string).unwrap())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_fields() {
|
||||
let one = 42;
|
||||
let two = 50;
|
||||
let expected = format!("{{ one: {one}, two: {two} }}");
|
||||
expect_mono_expr_str(
|
||||
expected,
|
||||
|id| MonoExpr::Str(id),
|
||||
format!("Struct([Number(I8({one:?})), Number(I8({two:?}))])"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,6 +247,10 @@ impl<T> NonEmptySlice<T> {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> Slice<T> {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for NonEmptySlice<T> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue