mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +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)),
|
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,
|
self.arena,
|
||||||
// TODO should be able to remove this alloc_str() once canonical Expr stores an arena-allocated string.
|
// TODO should be able to remove this alloc_str() once canonical Expr stores an arena-allocated string.
|
||||||
self.arena.alloc_str(contents),
|
self.arena.alloc_str(contents),
|
||||||
|
|
|
@ -117,6 +117,18 @@ impl MonoExprs {
|
||||||
*self.regions.get_unchecked_mut(index) = region;
|
*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)]
|
#[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
|
match self
|
||||||
.interned
|
.interned
|
||||||
.iter()
|
.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
|
match self
|
||||||
.interned
|
.interned
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use core::fmt::Write;
|
||||||
use roc_load::LoadedModule;
|
use roc_load::LoadedModule;
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
use roc_solve::FunctionKind;
|
use roc_solve::FunctionKind;
|
||||||
|
@ -107,14 +108,161 @@ pub fn expect_no_expr(input: impl AsRef<str>) {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn expect_mono_expr(input: impl AsRef<str>, mono_expr: MonoExpr) {
|
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]
|
#[track_caller]
|
||||||
pub fn expect_mono_expr_with_interns<T>(
|
pub fn expect_mono_expr_str(input: impl AsRef<str>, expr_str: impl AsRef<str>) {
|
||||||
from_interns: impl for<'a> FnOnce(&'a Bump, &Interns<'a>) -> T,
|
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>,
|
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 arena = Bump::new();
|
||||||
let mut string_interns = Interns::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:?}");
|
.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_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, actual);
|
||||||
|
|
||||||
assert_eq!(&expected_expr, actual_expr);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,15 @@ mod helpers;
|
||||||
mod specialize_primitives {
|
mod specialize_primitives {
|
||||||
use roc_specialize_types::{MonoExpr, Number};
|
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]
|
#[test]
|
||||||
fn string_literal() {
|
fn string_literal() {
|
||||||
let string = "foo";
|
let string = "foo";
|
||||||
let expected = format!("\"{string}\"");
|
let expected = format!("\"{string}\"");
|
||||||
expect_mono_expr_with_interns(
|
expect_mono_expr_with_interns(expected, |arena, interns| {
|
||||||
|arena, interns| interns.try_get(arena, string).unwrap(),
|
MonoExpr::Str(interns.try_get_id(arena, string).unwrap())
|
||||||
expected,
|
});
|
||||||
|id| MonoExpr::Str(id),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -9,6 +9,8 @@ mod helpers;
|
||||||
mod specialize_structs {
|
mod specialize_structs {
|
||||||
use roc_specialize_types::{MonoExpr, Number};
|
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};
|
use super::helpers::{expect_mono_expr, expect_mono_expr_with_interns, expect_no_expr};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -25,11 +27,9 @@ mod specialize_structs {
|
||||||
fn one_field_record_string_literal() {
|
fn one_field_record_string_literal() {
|
||||||
let string = "foo";
|
let string = "foo";
|
||||||
let expected = format!("{{ discardedField: \"{string}\" }}");
|
let expected = format!("{{ discardedField: \"{string}\" }}");
|
||||||
expect_mono_expr_with_interns(
|
expect_mono_expr_with_interns(expected, |arena, interns| {
|
||||||
|arena, interns| interns.try_get(arena, string).unwrap(),
|
MonoExpr::Str(interns.try_get_id(arena, string).unwrap())
|
||||||
expected,
|
});
|
||||||
|id| MonoExpr::Str(id),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -37,10 +37,19 @@ mod specialize_structs {
|
||||||
let string = "foo";
|
let string = "foo";
|
||||||
let expected =
|
let expected =
|
||||||
format!("{{ discarded: {{}}, discardedToo: \"{string}\", alsoDiscarded: {{}} }}");
|
format!("{{ discarded: {{}}, discardedToo: \"{string}\", alsoDiscarded: {{}} }}");
|
||||||
expect_mono_expr_with_interns(
|
expect_mono_expr_with_interns(expected, |arena, interns| {
|
||||||
|arena, interns| interns.try_get(arena, string).unwrap(),
|
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,
|
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> {
|
impl<T> IntoIterator for NonEmptySlice<T> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue