Skip to content

Commit

Permalink
Merge pull request #39 from FrankBro/keep-variants-open
Browse files Browse the repository at this point in the history
Keep variants open
  • Loading branch information
FrankBro authored Jan 27, 2024
2 parents 893babd + 6c874ed commit 5daff2f
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 27 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[workspace]
resolver = "2"
members = ["cli", "ordo"]
exclude = ["web"]
6 changes: 3 additions & 3 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
}
</style>

<link rel="preload" href="./web-78a67224672b0005_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="./web-78a67224672b0005.js"></head>
<link rel="preload" href="./web-3e88601d133d91f8_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="./web-3e88601d133d91f8.js"></head>
<body>

<script type="module">import init from './web-78a67224672b0005.js';init('./web-78a67224672b0005_bg.wasm');</script></body></html>
<script type="module">import init from './web-3e88601d133d91f8.js';init('./web-3e88601d133d91f8_bg.wasm');</script></body></html>
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ async function __wbg_init(input) {
if (wasm !== undefined) return wasm;

if (typeof input === 'undefined') {
input = new URL('web-78a67224672b0005_bg.wasm', import.meta.url);
input = new URL('web-3e88601d133d91f8_bg.wasm', import.meta.url);
}
const imports = __wbg_get_imports();

Expand Down
Binary file not shown.
21 changes: 6 additions & 15 deletions ordo/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,9 @@ impl Env {
return Ok(expr);
}
labels.insert(OK_LABEL.to_owned(), expr.ty().clone());
let rest = Type::RowEmpty;
let constraints = labels.keys().cloned().collect();
// TODO: I shouldn't need to do an unbound row and then generalize here, right?
let rest = self.new_generic_row(constraints);
let ty = Type::Variant(Type::RowExtend(labels, rest.into()).into());
expr.context.ty.ty = ty;
Ok(expr)
Expand Down Expand Up @@ -909,6 +911,7 @@ impl Env {
let value = self.infer_inner(level, value)?;
match value.ty() {
Type::Variant(rows) => {
// TODO: Should I use this rest or I can make a new one
let (mut labels, _) = self.match_row_ty(rows)?;
match labels.remove(OK_LABEL) {
None => {
Expand Down Expand Up @@ -942,20 +945,8 @@ impl Env {
}
let else_body = self.infer_inner(level, else_body)?;
self.unify(if_body.ty(), else_body.ty())?;
// TODO: if calling a function with an open variant should keep it open
match if_body.ty().clone() {
Type::Variant(row) => {
let (labels, _rest) = self.match_row_ty(&row)?;
let ty =
Type::Variant(Type::RowExtend(labels, Type::RowEmpty.into()).into());
Ok(Expr::If(if_expr, if_body, typed_elifs, else_body)
.with(expr.context, ty))
}
ty => {
Ok(Expr::If(if_expr, if_body, typed_elifs, else_body)
.with(expr.context, ty))
}
}
let ty = if_body.ty().clone();
Ok(Expr::If(if_expr, if_body, typed_elifs, else_body).with(expr.context, ty))
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions ordo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ mod typed_exprs;
#[cfg(test)]
#[path = "tests/emit_tests.rs"]
mod emit_tests;

#[cfg(test)]
#[path = "tests/variant_tests.rs"]
mod variant_tests;
2 changes: 1 addition & 1 deletion ordo/src/tests/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn ifs() {
);
pass(
"if 1 == 1 then :one {} else :zero {}",
"[one: {}, zero: {}]",
"forall ra. (ra\\one\\zero) => [one: {}, zero: {} | ra]",
Value::Variant("one".to_owned(), Value::Record(BTreeMap::new()).into()),
);
pass(
Expand Down
14 changes: 7 additions & 7 deletions ordo/src/tests/unwraps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ impl Env {
let mut env = Self { infer, eval };
env.add(
"let safe_div(n, d) = if d == 0 then :div_by_zero {} else :ok (n / d)",
"(int, int) -> [div_by_zero: {}, ok: int]",
"forall ra. (ra\\div_by_zero\\ok) => (int, int) -> [div_by_zero: {}, ok: int | ra]",
);
env.add(
"let safe_minus(x, y) = if y < 0 then :would_add {} else :ok (x - y)",
"(int, int) -> [ok: int, would_add: {}]",
"forall ra. (ra\\ok\\would_add) => (int, int) -> [ok: int, would_add: {} | ra]",
);
env
}
Expand Down Expand Up @@ -59,30 +59,30 @@ fn pass(source: &str, source_ty: &str, expected_val: Value) {
fn unwrap_ok() {
pass(
"safe_div(2, 2)?",
"[div_by_zero: {}, ok: int]",
"forall ra. (ra\\div_by_zero\\ok) => [div_by_zero: {}, ok: int | ra]",
Value::Int(1),
);
pass(
"safe_div(2, 0)?",
"[div_by_zero: {}, ok: int]",
"forall ra. (ra\\div_by_zero\\ok) => [div_by_zero: {}, ok: int | ra]",
Value::Variant(
"div_by_zero".to_owned(),
Value::Record(BTreeMap::new()).into(),
),
);
pass(
"let x = safe_div(2, 2)? in x",
"[div_by_zero: {}, ok: int]",
"forall ra. (ra\\div_by_zero\\ok) => [div_by_zero: {}, ok: int | ra]",
Value::Int(1),
);
pass(
"let x = safe_div(2, 0)? in x",
"[div_by_zero: {}, ok: int]",
"forall ra. (ra\\div_by_zero\\ok) => [div_by_zero: {}, ok: int | ra]",
Value::Variant("div_by_zero".to_owned(), Value::record(Vec::new()).into()),
);
pass(
"let x = safe_div(2, 2)? in let y = safe_minus(x, 1)? in y",
"[div_by_zero: {}, ok: int, would_add: {}]",
"forall ra. (ra\\div_by_zero\\ok\\would_add) => [div_by_zero: {}, ok: int, would_add: {} | ra]",
Value::Int(0),
);
}
42 changes: 42 additions & 0 deletions ordo/src/tests/variant_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::{core::make_env, infer::Error, parser::Parser};

#[track_caller]
fn pass(expr_str: &str, expected: &str) {
let (forall, ty) = Parser::ty(expected).unwrap();
let mut env = make_env();
let expected = env.replace_ty_constants_with_vars(forall, ty);
let expr = Parser::expr(expr_str).unwrap();
let typed_expr = env.infer(expr).unwrap();
let actual = typed_expr.context.ty.ty;
let expected = env.ty_to_string(&expected).unwrap();
let actual = env.ty_to_string(&actual).unwrap();
assert_eq!(expected, actual, "for {}", expr_str);
}

#[track_caller]
fn fail(expr_str: &str, expected: Error) {
let mut env = make_env();
let expr = Parser::expr(expr_str).unwrap();
let actual = env.infer(expr).unwrap_err();
assert_eq!(expected, actual, "for {}", expr_str);
}

#[test]
fn variant_tests() {
pass(
"let f(v) = match v { :a a -> 0, :b b -> 1 } in f(:a 1)",
"int",
);
pass(
"let f(v) = match v { :a a -> 0, :b b -> 1, otherwise -> 2 } in f(:a 1)",
"int",
);
fail(
"let f(v) = match v { :a a -> 0, :b b -> 1 } in f(:c 1)",
Error::MissingLabel("c".to_owned()),
);
pass(
"let f(v) = match v { :a a -> 0, :b b -> 1, otherwise -> 2 } in f(:c 1)",
"int",
);
}

0 comments on commit 5daff2f

Please sign in to comment.