Introduce string-based mono expr tests

This commit is contained in:
Richard Feldman 2024-11-16 18:31:32 -05:00
parent 03370da6d6
commit 219a0398a2
No known key found for this signature in database
GPG key ID: DAC334802F365236
7 changed files with 207 additions and 24 deletions

View file

@ -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),

View file

@ -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)]

View file

@ -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()

View file

@ -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);
}

View file

@ -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]

View file

@ -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:?}))])"),
);
}
}

View file

@ -247,6 +247,10 @@ impl<T> NonEmptySlice<T> {
},
}
}
pub fn as_slice(&self) -> Slice<T> {
self.inner
}
}
impl<T> IntoIterator for NonEmptySlice<T> {