mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
write more tests for reset/reuse
This commit is contained in:
parent
95365959f2
commit
eb793b2b44
5 changed files with 362 additions and 1 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2222,6 +2222,7 @@ dependencies = [
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
|
"ven_pretty",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -146,6 +146,17 @@ impl fmt::Debug for Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Symbol {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let module_id = self.module_id();
|
||||||
|
let ident_id = self.ident_id();
|
||||||
|
|
||||||
|
match ident_id {
|
||||||
|
IdentId(value) => write!(f, "{:?}.{:?}", module_id, value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fallback_debug_fmt(symbol: Symbol, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fallback_debug_fmt(symbol: Symbol, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let module_id = symbol.module_id();
|
let module_id = symbol.module_id();
|
||||||
let ident_id = symbol.ident_id();
|
let ident_id = symbol.ident_id();
|
||||||
|
|
|
@ -13,6 +13,7 @@ roc_types = { path = "../types" }
|
||||||
roc_can = { path = "../can" }
|
roc_can = { path = "../can" }
|
||||||
roc_unify = { path = "../unify" }
|
roc_unify = { path = "../unify" }
|
||||||
roc_problem = { path = "../problem" }
|
roc_problem = { path = "../problem" }
|
||||||
|
ven_pretty = { path = "../../vendor/pretty" }
|
||||||
bumpalo = { version = "3.2", features = ["collections"] }
|
bumpalo = { version = "3.2", features = ["collections"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -11,6 +11,7 @@ use roc_problem::can::RuntimeError;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_types::subs::{Content, FlatType, Subs, Variable};
|
use roc_types::subs::{Content, FlatType, Subs, Variable};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct PartialProc<'a> {
|
pub struct PartialProc<'a> {
|
||||||
|
@ -799,7 +800,6 @@ pub enum MonoProblem {
|
||||||
PatternProblem(crate::pattern::Error),
|
PatternProblem(crate::pattern::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
impl<'a> Expr<'a> {
|
impl<'a> Expr<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
|
@ -811,6 +811,156 @@ impl<'a> Expr<'a> {
|
||||||
let result = from_can(env, can_expr, procs, &mut layout_cache);
|
let result = from_can(env, can_expr, procs, &mut layout_cache);
|
||||||
function_r(env, env.arena.alloc(result))
|
function_r(env, env.arena.alloc(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, parens: bool) -> DocBuilder<'b, D, A>
|
||||||
|
where
|
||||||
|
D: DocAllocator<'b, A>,
|
||||||
|
D::Doc: Clone,
|
||||||
|
A: Clone,
|
||||||
|
{
|
||||||
|
use Expr::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Int(lit) => alloc.text(format!("{}i64", lit)),
|
||||||
|
Float(lit) => alloc.text(format!("{}f64", lit)),
|
||||||
|
Bool(lit) => alloc.text(format!("{}", lit)),
|
||||||
|
Byte(lit) => alloc.text(format!("{}u8", lit)),
|
||||||
|
Str(lit) => alloc.text(format!("{:?}", lit)),
|
||||||
|
Load(symbol) if parens => alloc.text(format!("(Load {})", symbol)),
|
||||||
|
Load(symbol) => alloc.text(format!("Load {}", symbol)),
|
||||||
|
|
||||||
|
DecAfter(symbol, expr) => expr
|
||||||
|
.to_doc(alloc, false)
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(alloc.text(format!("Dec {}", symbol))),
|
||||||
|
|
||||||
|
Reset(symbol, expr) => alloc
|
||||||
|
.text(format!("Reset {}", symbol))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(expr.to_doc(alloc, false)),
|
||||||
|
|
||||||
|
Reuse(symbol, expr) => alloc
|
||||||
|
.text(format!("Reuse {}", symbol))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(expr.to_doc(alloc, false)),
|
||||||
|
|
||||||
|
Store(stores, expr) => {
|
||||||
|
let doc_stores = stores
|
||||||
|
.iter()
|
||||||
|
.map(|(symbol, _, expr)| {
|
||||||
|
alloc
|
||||||
|
.text(format!("Store {}: ", symbol))
|
||||||
|
.append(expr.to_doc(alloc, false))
|
||||||
|
})
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
|
|
||||||
|
alloc
|
||||||
|
.intersperse(doc_stores, alloc.hardline())
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(expr.to_doc(alloc, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
Cond {
|
||||||
|
branching_symbol,
|
||||||
|
pass,
|
||||||
|
fail,
|
||||||
|
..
|
||||||
|
} => alloc
|
||||||
|
.text(format!("if {} then", branching_symbol))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(pass.1.to_doc(alloc, false).indent(4))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(alloc.text("else"))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(fail.1.to_doc(alloc, false).indent(4)),
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
cond_symbol,
|
||||||
|
branches,
|
||||||
|
default_branch,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let default_doc = alloc
|
||||||
|
.text("default:")
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(default_branch.1.to_doc(alloc, false).indent(4))
|
||||||
|
.indent(4);
|
||||||
|
|
||||||
|
let branches_docs = branches
|
||||||
|
.iter()
|
||||||
|
.map(|(tag, _, expr)| {
|
||||||
|
alloc
|
||||||
|
.text(format!("case {}:", tag))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(expr.to_doc(alloc, false).indent(4))
|
||||||
|
.indent(4)
|
||||||
|
})
|
||||||
|
.chain(std::iter::once(default_doc));
|
||||||
|
//
|
||||||
|
alloc
|
||||||
|
.text(format!("switch {}:", cond_symbol))
|
||||||
|
.append(alloc.hardline())
|
||||||
|
.append(
|
||||||
|
alloc.intersperse(branches_docs, alloc.hardline().append(alloc.hardline())),
|
||||||
|
)
|
||||||
|
.append(alloc.hardline())
|
||||||
|
}
|
||||||
|
|
||||||
|
Struct(fields) => alloc.text(format!("Struct {:?}", fields)),
|
||||||
|
|
||||||
|
Tag {
|
||||||
|
tag_name,
|
||||||
|
arguments,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let doc_tag = match tag_name {
|
||||||
|
TagName::Global(s) => alloc.text(s.as_str()),
|
||||||
|
TagName::Private(s) => alloc.text(format!("{}", s)),
|
||||||
|
};
|
||||||
|
let doc_args = arguments.iter().map(|(expr, _)| expr.to_doc(alloc, true));
|
||||||
|
|
||||||
|
let it = std::iter::once(doc_tag).chain(doc_args);
|
||||||
|
|
||||||
|
alloc.intersperse(it, alloc.space())
|
||||||
|
}
|
||||||
|
AccessAtIndex { index, expr, .. } if parens => alloc
|
||||||
|
.text(format!("(Access @{} ", index))
|
||||||
|
.append(expr.to_doc(alloc, false))
|
||||||
|
.append(alloc.text(")")),
|
||||||
|
|
||||||
|
AccessAtIndex { index, expr, .. } => alloc
|
||||||
|
.text(format!("Access @{} ", index))
|
||||||
|
.append(expr.to_doc(alloc, false)),
|
||||||
|
|
||||||
|
RunLowLevel(instr, arguments) => {
|
||||||
|
let doc_tag = alloc.text(format!("Lowlevel.{:?}", instr));
|
||||||
|
let doc_args = arguments.iter().map(|(expr, _)| expr.to_doc(alloc, true));
|
||||||
|
|
||||||
|
let it = std::iter::once(doc_tag).chain(doc_args);
|
||||||
|
|
||||||
|
if parens {
|
||||||
|
alloc
|
||||||
|
.text("(")
|
||||||
|
.append(alloc.intersperse(it, alloc.space()))
|
||||||
|
.append(alloc.text(")"))
|
||||||
|
} else {
|
||||||
|
alloc.intersperse(it, alloc.space())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CallByName { name, .. } => alloc.text("*magic*"),
|
||||||
|
_ => todo!("not yet implemented: {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn to_pretty(&self, width: usize) -> String {
|
||||||
|
let allocator = BoxAllocator;
|
||||||
|
let mut w = std::vec::Vec::new();
|
||||||
|
self.to_doc::<_, ()>(&allocator, false)
|
||||||
|
.1
|
||||||
|
.render(width, &mut w)
|
||||||
|
.unwrap();
|
||||||
|
w.push(b'\n');
|
||||||
|
String::from_utf8(w).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IntOrFloat {
|
enum IntOrFloat {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate pretty_assertions;
|
extern crate pretty_assertions;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate indoc;
|
||||||
|
|
||||||
extern crate bumpalo;
|
extern crate bumpalo;
|
||||||
extern crate roc_mono;
|
extern crate roc_mono;
|
||||||
|
|
||||||
|
@ -80,6 +83,57 @@ mod test_mono {
|
||||||
assert_eq!(get_expected(interns), mono_expr);
|
assert_eq!(get_expected(interns), mono_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compiles_to_string(src: &str, expected: &str) {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let CanExprOut {
|
||||||
|
loc_expr,
|
||||||
|
var_store,
|
||||||
|
var,
|
||||||
|
constraint,
|
||||||
|
home,
|
||||||
|
mut interns,
|
||||||
|
..
|
||||||
|
} = can_expr(src);
|
||||||
|
|
||||||
|
let subs = Subs::new(var_store.into());
|
||||||
|
let mut unify_problems = Vec::new();
|
||||||
|
let (_content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
|
|
||||||
|
// Compile and add all the Procs before adding main
|
||||||
|
let mut procs = Procs::default();
|
||||||
|
let mut ident_ids = interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
|
// assume 64-bit pointers
|
||||||
|
let pointer_size = std::mem::size_of::<u64>() as u32;
|
||||||
|
|
||||||
|
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||||
|
let mut mono_problems = Vec::new();
|
||||||
|
let mut mono_env = roc_mono::expr::Env {
|
||||||
|
arena: &arena,
|
||||||
|
subs: &mut subs,
|
||||||
|
problems: &mut mono_problems,
|
||||||
|
home,
|
||||||
|
ident_ids: &mut ident_ids,
|
||||||
|
pointer_size,
|
||||||
|
jump_counter: arena.alloc(0),
|
||||||
|
};
|
||||||
|
let mono_expr = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
let procs =
|
||||||
|
roc_mono::expr::specialize_all(&mut mono_env, procs, &mut LayoutCache::default());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
procs.runtime_errors,
|
||||||
|
roc_collections::all::MutMap::default()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns
|
||||||
|
interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
|
let result = mono_expr.to_pretty(200);
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn int_literal() {
|
fn int_literal() {
|
||||||
compiles_to("5", Int(5));
|
compiles_to("5", Int(5));
|
||||||
|
@ -748,4 +802,148 @@ mod test_mono {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_to_string() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
x = 3
|
||||||
|
|
||||||
|
x
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Store Test.0: 3i64
|
||||||
|
Load Test.0
|
||||||
|
Dec Test.0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_to_string() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
if True then 1 else 2
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Store Test.0: true
|
||||||
|
if Test.0 then
|
||||||
|
1i64
|
||||||
|
else
|
||||||
|
2i64
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_map_to_string() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
maybe : [ Nothing, Just Int ]
|
||||||
|
maybe = Just 3
|
||||||
|
|
||||||
|
when maybe is
|
||||||
|
Just x -> Just (x + 1)
|
||||||
|
Nothing -> Nothing
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Store Test.0: Just 0i64 3i64
|
||||||
|
Store Test.0: Load Test.0
|
||||||
|
Store Test.2: Lowlevel.And (Lowlevel.Eq 0i64 (Access @0 Load Test.0)) true
|
||||||
|
|
||||||
|
if Test.2 then
|
||||||
|
Reset Test.0
|
||||||
|
Reuse Test.0
|
||||||
|
Just 0i64 *magic*
|
||||||
|
else
|
||||||
|
Reset Test.0
|
||||||
|
Reuse Test.0
|
||||||
|
Nothing 1i64
|
||||||
|
Dec Test.0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn very_maybe_map_to_string() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Nothing, Just a ]
|
||||||
|
|
||||||
|
veryMaybe : Maybe (Maybe Int)
|
||||||
|
veryMaybe = Just (Just 3)
|
||||||
|
|
||||||
|
when veryMaybe is
|
||||||
|
Just (Just _) -> Just (Just 1)
|
||||||
|
Just Nothing -> Just Nothing
|
||||||
|
Nothing -> Nothing
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Store Test.1: Just 0i64 Just 0i64 3i64
|
||||||
|
Store Test.1: Load Test.1
|
||||||
|
Store Test.5: Lowlevel.And (Lowlevel.Eq 0i64 (Access @0 Load Test.1)) true
|
||||||
|
|
||||||
|
if Test.5 then
|
||||||
|
|
||||||
|
if Test.4 then
|
||||||
|
Just 0i64 Just 0i64 1i64
|
||||||
|
else
|
||||||
|
Just 0i64 Nothing 1i64
|
||||||
|
else
|
||||||
|
Reset Test.1
|
||||||
|
Reuse Test.1
|
||||||
|
Nothing 1i64
|
||||||
|
Dec Test.1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn these_map_to_string() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
These a b : [ This a, That b, These a b ]
|
||||||
|
|
||||||
|
these : These Int Int
|
||||||
|
these = These 1 2
|
||||||
|
|
||||||
|
when these is
|
||||||
|
This a -> This a
|
||||||
|
That b -> That b
|
||||||
|
These a b -> These b a
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Store Test.1: These 1i64 1i64 2i64
|
||||||
|
Store Test.1: Load Test.1
|
||||||
|
|
||||||
|
switch Test.1:
|
||||||
|
case 2:
|
||||||
|
Reset Test.1
|
||||||
|
Reuse Test.1
|
||||||
|
This 2i64 (Load Test.2)
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
Reset Test.1
|
||||||
|
Reuse Test.1
|
||||||
|
That 0i64 (Load Test.3)
|
||||||
|
|
||||||
|
default:
|
||||||
|
Reset Test.1
|
||||||
|
Reuse Test.1
|
||||||
|
These 1i64 (Load Test.5) (Load Test.4)
|
||||||
|
|
||||||
|
Dec Test.1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue