Introduce polarity for extension variable printing

This commit is contained in:
Ayaz Hafiz 2022-10-25 13:58:52 -05:00
parent ae1a9e4dd6
commit d77080529a
No known key found for this signature in database
GPG Key ID: 0E2A37416A25EF58
6 changed files with 187 additions and 78 deletions

View File

@ -229,10 +229,7 @@ fn expect_types(mut loaded_module: LoadedModule, mut expected_types: HashMap<&st
.unwrap_or_default()
.is_empty());
let debug_print = DebugPrint {
print_lambda_sets: false,
print_only_under_alias: false,
};
let debug_print = DebugPrint::NOTHING;
let interns = &loaded_module.interns;
let declarations = loaded_module.declarations_by_id.remove(&home).unwrap();

View File

@ -316,6 +316,7 @@ mod solve_expr {
DebugPrint {
print_lambda_sets: true,
print_only_under_alias: options.print_only_under_alias,
ignore_polarity: true,
},
);
subs.rollback_to(snapshot);
@ -844,7 +845,7 @@ mod solve_expr {
List.map ["a", "b"] \elem -> Foo elem
"#
),
"List [Foo Str]*",
"List [Foo Str]",
)
}
@ -859,7 +860,7 @@ mod solve_expr {
foo "hi"
"#
),
"[Foo Str]*",
"[Foo Str]",
)
}
@ -872,7 +873,7 @@ mod solve_expr {
List.map ["a", "b"] Foo
"#
),
"List [Foo Str]*",
"List [Foo Str]",
)
}
@ -885,7 +886,7 @@ mod solve_expr {
[\x -> Bar x, Foo]
"#
),
"List (a -> [Bar a, Foo a]*)",
"List (a -> [Bar a, Foo a])",
)
}
@ -898,7 +899,7 @@ mod solve_expr {
[Foo, \x -> Bar x]
"#
),
"List (a -> [Bar a, Foo a]*)",
"List (a -> [Bar a, Foo a])",
)
}
@ -917,7 +918,7 @@ mod solve_expr {
}
"#
),
"{ x : List [Foo]*, y : List (a -> [Foo a]*), z : List (b, c -> [Foo b c]*) }",
"{ x : List [Foo], y : List (a -> [Foo a]), z : List (b, c -> [Foo b c]) }",
)
}
@ -1572,7 +1573,7 @@ mod solve_expr {
Foo
"#
),
"[Foo]*",
"[Foo]",
);
}
@ -1611,7 +1612,7 @@ mod solve_expr {
Foo "happy" 12
"#
),
"[Foo Str (Num *)]*",
"[Foo Str (Num *)]",
);
}
@ -1652,7 +1653,7 @@ mod solve_expr {
\Foo x -> Foo x
"#
),
"[Foo a] -> [Foo a]*",
"[Foo a] -> [Foo a]",
);
}
@ -1664,7 +1665,7 @@ mod solve_expr {
\Foo x _ -> Foo x "y"
"#
),
"[Foo a *] -> [Foo a Str]*",
"[Foo a *] -> [Foo a Str]",
);
}
@ -2672,7 +2673,7 @@ mod solve_expr {
fromBit
"#
),
"Num * -> [False, True]*",
"Num * -> [False, True]",
);
}
@ -2899,7 +2900,7 @@ mod solve_expr {
map
"#
),
"(a -> b), [Cons a c, Nil] as c -> [Cons b d, Nil]* as d",
"(a -> b), [Cons a c, Nil] as c -> [Cons b d, Nil] as d",
);
}
@ -3160,7 +3161,7 @@ mod solve_expr {
map
"#
),
"[S a, Z] as a -> [S b, Z]* as b",
"[S a, Z] as a -> [S b, Z] as b",
);
}
@ -3179,7 +3180,7 @@ mod solve_expr {
map
"#
),
"[S a, Z] as a -> [S b, Z]* as b",
"[S a, Z] as a -> [S b, Z] as b",
);
}
@ -3250,7 +3251,7 @@ mod solve_expr {
map
"#
),
"(a -> b), [Cons { x : a, xs : c }*, Nil] as c -> [Cons { x : b, xs : d }, Nil]* as d",
"(a -> b), [Cons { x : a, xs : c }*, Nil] as c -> [Cons { x : b, xs : d }, Nil] as d",
);
}
@ -3317,7 +3318,7 @@ mod solve_expr {
toAs
"#
),
"(a -> b), [Cons c [Cons a d, Nil], Nil] as d -> [Cons c [Cons b e]*, Nil]* as e",
"(a -> b), [Cons c [Cons a d, Nil], Nil] as d -> [Cons c [Cons b e], Nil] as e",
);
}
@ -4248,10 +4249,10 @@ mod solve_expr {
Foo Bar 1
"#
),
"[Foo [Bar]* (Num *)]*",
"[Foo [Bar] (Num *)]",
);
infer_eq_without_problem("Foo Bar 1", "[Foo [Bar]* (Num *)]*");
infer_eq_without_problem("Foo Bar 1", "[Foo [Bar] (Num *)]");
}
#[test]
@ -4979,7 +4980,7 @@ mod solve_expr {
canIGo
"#
),
"Str -> Result Str [SlowIt Str, StopIt Str, UnknownColor Str]*",
"Str -> Result Str [SlowIt Str, StopIt Str, UnknownColor Str]",
)
}
@ -5106,7 +5107,7 @@ mod solve_expr {
B -> Y
"#
),
"[A, B] -> [X, Y]*",
"[A, B] -> [X, Y]",
)
}
@ -5122,7 +5123,7 @@ mod solve_expr {
_ -> Z
"#
),
"[A, B]* -> [X, Y, Z]*",
"[A, B]* -> [X, Y, Z]",
)
}
@ -5137,7 +5138,7 @@ mod solve_expr {
A N -> Y
"#
),
"[A [M, N]] -> [X, Y]*",
"[A [M, N]] -> [X, Y]",
)
}
@ -5153,7 +5154,7 @@ mod solve_expr {
A _ -> Z
"#
),
"[A [M, N]*] -> [X, Y, Z]*",
"[A [M, N]*] -> [X, Y, Z]",
)
}
@ -5168,7 +5169,7 @@ mod solve_expr {
A (N K) -> X
"#
),
"[A [M [J], N [K]]] -> [X]*",
"[A [M [J], N [K]]] -> [X]",
)
}
@ -5184,7 +5185,7 @@ mod solve_expr {
A N -> X
"#
),
"[A [M, N], B] -> [X]*",
"[A [M, N], B] -> [X]",
)
}
@ -5199,9 +5200,6 @@ mod solve_expr {
t -> t
"#
),
// TODO: we could be a bit smarter by subtracting "A" as a possible
// tag in the union known by t, which would yield the principal type
// [A,]a -> [X]a
"[A, X]a -> [A, X]a",
)
}
@ -5528,7 +5526,7 @@ mod solve_expr {
Job lst s -> P lst s
"#
),
"[P (List ([Job (List a) Str] as a)) Str]*",
"[P (List ([Job (List a) Str] as a)) Str]",
)
}
@ -5646,7 +5644,7 @@ mod solve_expr {
else @Id (Id 21 (Z "felix"))
"#
),
r#"Id [Y Str, Z Str]*"#,
r#"Id [Y Str, Z Str]"#,
)
}
@ -5933,7 +5931,7 @@ mod solve_expr {
if Bool.true then List.first [] else Str.toI64 ""
"#
),
"Result I64 [InvalidNumStr, ListWasEmpty]*",
"Result I64 [InvalidNumStr, ListWasEmpty]",
)
}
@ -7853,7 +7851,7 @@ mod solve_expr {
g ""
"#
),
"[A Str, B Str]*",
"[A Str, B Str]",
);
}

View File

@ -291,6 +291,7 @@ fn assemble_derived_golden(
DebugPrint {
print_lambda_sets: true,
print_only_under_alias,
..DebugPrint::NOTHING
},
);
subs.rollback_to(snapshot);

View File

@ -2,7 +2,9 @@ use crate::subs::{
self, AliasVariables, Content, FlatType, GetSubsSlice, Label, Subs, SubsIndex, UnionLabels,
UnionTags, UnsortedUnionLabels, Variable,
};
use crate::types::{name_type_var, name_type_var_with_hint, AbilitySet, RecordField, Uls};
use crate::types::{
name_type_var, name_type_var_with_hint, AbilitySet, Polarity, RecordField, Uls,
};
use roc_collections::all::MutMap;
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, ModuleId, Symbol};
@ -52,12 +54,14 @@ macro_rules! write_parens {
pub struct DebugPrint {
pub print_lambda_sets: bool,
pub print_only_under_alias: bool,
pub ignore_polarity: bool,
}
impl DebugPrint {
pub const NOTHING: DebugPrint = DebugPrint {
print_lambda_sets: false,
print_only_under_alias: false,
ignore_polarity: false,
};
}
@ -552,6 +556,7 @@ fn content_to_string(
interns: &Interns,
named_result: NamedResult,
debug_print: DebugPrint,
pol: Polarity,
) -> String {
let mut buf = String::new();
let env = Env {
@ -564,7 +569,15 @@ fn content_to_string(
recursion_structs_to_expand: named_result.recursion_structs_to_expand,
};
write_content(&env, &mut ctx, content, subs, &mut buf, Parens::Unnecessary);
write_content(
&env,
&mut ctx,
content,
subs,
&mut buf,
Parens::Unnecessary,
pol,
);
ctx.able_variables.sort();
ctx.able_variables.dedup();
@ -593,7 +606,15 @@ pub fn name_and_print_var(
) -> String {
let named_result = name_all_type_vars(var, subs, debug_print.print_only_under_alias);
let content = subs.get_content_without_compacting(var);
content_to_string(content, subs, home, interns, named_result, debug_print)
content_to_string(
content,
subs,
home,
interns,
named_result,
debug_print,
Polarity::Pos,
)
}
pub fn get_single_arg<'a>(subs: &'a Subs, args: &'a AliasVariables) -> &'a Content {
@ -614,6 +635,7 @@ fn write_content<'a>(
subs: &'a Subs,
buf: &mut String,
parens: Parens,
pol: Polarity,
) {
use crate::subs::Content::*;
@ -660,6 +682,7 @@ fn write_content<'a>(
subs,
buf,
parens,
pol,
);
} else {
let name = &subs.field_names[name_index.index as usize];
@ -670,7 +693,7 @@ fn write_content<'a>(
unreachable!("This should always be filled in!")
}
},
Structure(flat_type) => write_flat_type(env, ctx, flat_type, subs, buf, parens),
Structure(flat_type) => write_flat_type(env, ctx, flat_type, subs, buf, parens, pol),
Alias(symbol, args, actual, _kind) => {
let write_parens = parens == Parens::InTypeParam && !args.is_empty();
@ -688,6 +711,7 @@ fn write_content<'a>(
buf,
parens,
write_parens,
pol,
);
}
Symbol::NUM_FLOATINGPOINT => write_float(
@ -698,17 +722,18 @@ fn write_content<'a>(
buf,
parens,
write_parens,
pol,
),
_ => write_parens!(write_parens, buf, {
buf.push_str("Num ");
write_content(env, ctx, content, subs, buf, parens);
write_content(env, ctx, content, subs, buf, parens, pol);
}),
},
_ => write_parens!(write_parens, buf, {
buf.push_str("Num ");
write_content(env, ctx, content, subs, buf, parens);
write_content(env, ctx, content, subs, buf, parens, pol);
}),
}
}
@ -716,7 +741,7 @@ fn write_content<'a>(
Symbol::NUM_INT => {
let content = get_single_arg(subs, args);
write_integer(env, ctx, content, subs, buf, parens, write_parens)
write_integer(env, ctx, content, subs, buf, parens, write_parens, pol)
}
Symbol::NUM_FRAC => write_float(
@ -727,11 +752,12 @@ fn write_content<'a>(
buf,
parens,
write_parens,
pol,
),
_ if env.debug.print_only_under_alias => write_parens!(write_parens, buf, {
let content = subs.get_content_without_compacting(*actual);
write_content(env, ctx, content, subs, buf, parens)
write_content(env, ctx, content, subs, buf, parens, pol)
}),
_ => write_parens!(write_parens, buf, {
@ -747,13 +773,14 @@ fn write_content<'a>(
subs,
buf,
Parens::InTypeParam,
pol,
);
}
roc_debug_flags::dbg_do!(roc_debug_flags::ROC_PRETTY_PRINT_ALIAS_CONTENTS, {
buf.push_str("[[ but really ");
let content = subs.get_content_without_compacting(*actual);
write_content(env, ctx, content, subs, buf, parens);
write_content(env, ctx, content, subs, buf, parens, pol);
buf.push_str("]]");
});
}),
@ -793,6 +820,7 @@ fn write_content<'a>(
buf,
solved.unsorted_lambdas(subs),
print_symbol,
pol,
);
buf.push(']');
@ -806,6 +834,7 @@ fn write_content<'a>(
subs,
buf,
parens,
pol,
)
}
@ -818,6 +847,7 @@ fn write_content<'a>(
subs,
buf,
Parens::Unnecessary,
pol,
);
buf.push(':');
buf.push_str(&print_symbol(member));
@ -840,6 +870,7 @@ fn write_content<'a>(
subs,
buf,
Parens::Unnecessary,
pol,
);
}
buf.push(')');
@ -856,6 +887,7 @@ fn write_float<'a>(
buf: &mut String,
parens: Parens,
write_parens: bool,
pol: Polarity,
) {
use crate::subs::Content::*;
match content {
@ -864,7 +896,7 @@ fn write_float<'a>(
Alias(Symbol::NUM_DECIMAL, _, _, _) => buf.push_str("Dec"),
_ => write_parens!(write_parens, buf, {
buf.push_str("Float ");
write_content(env, ctx, content, subs, buf, parens);
write_content(env, ctx, content, subs, buf, parens, pol);
}),
}
}
@ -877,6 +909,7 @@ fn write_integer<'a>(
buf: &mut String,
parens: Parens,
write_parens: bool,
pol: Polarity,
) {
use crate::subs::Content::*;
@ -894,7 +927,7 @@ fn write_integer<'a>(
buf,
{
buf.push_str("Int ");
write_content(env, ctx, actual, subs, buf, parens);
write_content(env, ctx, actual, subs, buf, parens, pol);
}
)
}
@ -923,12 +956,20 @@ enum ExtContent<'a> {
}
impl<'a> ExtContent<'a> {
fn from_var(subs: &'a Subs, ext: Variable) -> Self {
fn for_tag(subs: &'a Subs, ext: Variable, pol: Polarity, debug_flags: &DebugPrint) -> Self {
let content = subs.get_content_without_compacting(ext);
match content {
Content::Structure(FlatType::EmptyTagUnion) => ExtContent::Empty,
Content::Structure(FlatType::EmptyRecord) => ExtContent::Empty,
Content::FlexVar(None) | Content::FlexAbleVar(None, _)
if pol.is_pos() && !debug_flags.ignore_polarity =>
{
// This is a wildcard `[...]*`, which is elided in positive positions!
ExtContent::Empty
}
// All other vars are named, and must appear regardless of their position.
Content::FlexVar(_)
| Content::FlexAbleVar(..)
| Content::RigidVar(_)
@ -946,6 +987,7 @@ fn write_ext_content<'a>(
buf: &mut String,
ext_content: ExtContent<'a>,
parens: Parens,
pol: Polarity,
) {
if let ExtContent::Content(_, content) = ext_content {
// This is an open record or tag union, so print the variable
@ -953,7 +995,7 @@ fn write_ext_content<'a>(
//
// e.g. the "*" at the end of `{ x: I64 }*`
// or the "r" at the end of `{ x: I64 }r`
write_content(env, ctx, content, subs, buf, parens)
write_content(env, ctx, content, subs, buf, parens, pol)
}
}
@ -964,6 +1006,7 @@ fn write_sorted_tags2<'a, L>(
buf: &mut String,
tags: UnsortedUnionLabels<L>,
label_to_string: impl Fn(&L) -> String,
pol: Polarity,
) where
L: Label + Ord,
{
@ -991,6 +1034,7 @@ fn write_sorted_tags2<'a, L>(
subs,
buf,
Parens::InTypeParam,
pol,
);
}
}
@ -1003,6 +1047,7 @@ fn write_sorted_tags<'a>(
buf: &mut String,
tags: &MutMap<TagName, Vec<Variable>>,
ext_var: Variable,
pol: Polarity,
) -> ExtContent<'a> {
// Sort the fields so they always end up in the same order.
let mut sorted_fields = Vec::with_capacity(tags.len());
@ -1042,11 +1087,12 @@ fn write_sorted_tags<'a>(
subs,
buf,
Parens::InTypeParam,
pol,
);
}
}
ExtContent::from_var(subs, ext_var)
ExtContent::for_tag(subs, ext_var, pol, &env.debug)
}
fn write_flat_type<'a>(
@ -1056,6 +1102,7 @@ fn write_flat_type<'a>(
subs: &'a Subs,
buf: &mut String,
parens: Parens,
pol: Polarity,
) {
use crate::subs::FlatType::*;
@ -1068,6 +1115,7 @@ fn write_flat_type<'a>(
subs,
buf,
parens,
pol,
),
EmptyRecord => buf.push_str(EMPTY_RECORD),
EmptyTagUnion => buf.push_str(EMPTY_TAG_UNION),
@ -1080,6 +1128,7 @@ fn write_flat_type<'a>(
subs,
buf,
parens,
pol,
),
Record(fields, ext_var) => {
use crate::types::{gather_fields, RecordStructure};
@ -1123,6 +1172,7 @@ fn write_flat_type<'a>(
subs,
buf,
Parens::Unnecessary,
pol,
);
}
@ -1139,7 +1189,7 @@ fn write_flat_type<'a>(
//
// e.g. the "*" at the end of `{ x: I64 }*`
// or the "r" at the end of `{ x: I64 }r`
write_content(env, ctx, content, subs, buf, parens)
write_content(env, ctx, content, subs, buf, parens, pol)
}
}
}
@ -1148,7 +1198,15 @@ fn write_flat_type<'a>(
// Sort the fields so they always end up in the same order.
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, *ext_var);
write_sorted_tags2(env, ctx, subs, buf, tags, |tag| tag.0.as_str().to_string());
write_sorted_tags2(
env,
ctx,
subs,
buf,
tags,
|tag| tag.0.as_str().to_string(),
pol,
);
buf.push(']');
@ -1157,8 +1215,9 @@ fn write_flat_type<'a>(
ctx,
subs,
buf,
ExtContent::from_var(subs, new_ext_var),
ExtContent::for_tag(subs, new_ext_var, pol, &env.debug),
parens,
pol,
)
}
@ -1171,11 +1230,11 @@ fn write_flat_type<'a>(
.iter()
.map(|t| (t.clone(), vec![])),
);
let ext_content = write_sorted_tags(env, ctx, subs, buf, &tags, *ext_var);
let ext_content = write_sorted_tags(env, ctx, subs, buf, &tags, *ext_var, pol);
buf.push(']');
write_ext_content(env, ctx, subs, buf, ext_content, parens)
write_ext_content(env, ctx, subs, buf, ext_content, parens, pol)
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
@ -1183,7 +1242,15 @@ fn write_flat_type<'a>(
buf.push('[');
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, *ext_var);
write_sorted_tags2(env, ctx, subs, buf, tags, |tag| tag.0.as_str().to_string());
write_sorted_tags2(
env,
ctx,
subs,
buf,
tags,
|tag| tag.0.as_str().to_string(),
pol,
);
buf.push(']');
@ -1192,8 +1259,9 @@ fn write_flat_type<'a>(
ctx,
subs,
buf,
ExtContent::from_var(subs, new_ext_var),
ExtContent::for_tag(subs, new_ext_var, pol, &env.debug),
parens,
pol,
);
buf.push_str(" as ");
@ -1204,6 +1272,7 @@ fn write_flat_type<'a>(
subs,
buf,
parens,
pol,
)
})
}
@ -1278,6 +1347,7 @@ fn write_apply<'a>(
subs: &'a Subs,
buf: &mut String,
parens: Parens,
pol: Polarity,
) {
let write_parens = parens == Parens::InTypeParam && !args.is_empty();
@ -1299,7 +1369,15 @@ fn write_apply<'a>(
buf.push('(');
}
write_content(env, ctx, content, subs, &mut arg_param, Parens::InTypeParam);
write_content(
env,
ctx,
content,
subs,
&mut arg_param,
Parens::InTypeParam,
pol,
);
buf.push_str("Num ");
buf.push_str(&arg_param);
@ -1337,6 +1415,7 @@ fn write_apply<'a>(
subs,
buf,
Parens::InTypeParam,
pol,
);
}
@ -1357,6 +1436,7 @@ fn write_fn<'a>(
subs: &'a Subs,
buf: &mut String,
parens: Parens,
pol: Polarity,
) {
let mut needs_comma = false;
let use_parens = parens != Parens::Unnecessary;
@ -1379,6 +1459,7 @@ fn write_fn<'a>(
subs,
buf,
Parens::InFn,
Polarity::Neg,
);
}
@ -1393,6 +1474,7 @@ fn write_fn<'a>(
subs,
buf,
parens,
pol,
);
buf.push_str("-> ");
}
@ -1404,6 +1486,7 @@ fn write_fn<'a>(
subs,
buf,
Parens::InFn,
Polarity::Pos,
);
if use_parens {

View File

@ -333,6 +333,36 @@ impl OptAbleType {
}
}
/// Polarity of a type, or roughly, what side of an arrow it appears on.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Polarity {
/// A type that appears in negative/input position
Neg,
/// A type that appears in positive/output position
Pos,
}
impl std::ops::Neg for Polarity {
type Output = Self;
fn neg(self) -> Self::Output {
match self {
Polarity::Neg => todo!(),
Polarity::Pos => todo!(),
}
}
}
impl Polarity {
pub fn is_neg(&self) -> bool {
matches!(self, Self::Neg)
}
pub fn is_pos(&self) -> bool {
matches!(self, Self::Pos)
}
}
#[derive(PartialEq, Eq)]
pub enum Type {
EmptyRec,

View File

@ -144,26 +144,26 @@ fn bool_false() {
#[test]
fn arbitrary_tag_unions() {
expect_success("if 1 == 1 then Red else Green", "Red : [Green, Red]*");
expect_success("if 1 != 1 then Red else Green", "Green : [Green, Red]*");
expect_success("if 1 == 1 then Red else Green", "Red : [Green, Red]");
expect_success("if 1 != 1 then Red else Green", "Green : [Green, Red]");
}
#[test]
fn tag_without_arguments() {
expect_success("True", "True : [True]*");
expect_success("False", "False : [False]*");
expect_success("True", "True : [True]");
expect_success("False", "False : [False]");
}
#[test]
fn byte_tag_union() {
expect_success(
"if 1 == 1 then Red else if 1 == 1 then Green else Blue",
"Red : [Blue, Green, Red]*",
"Red : [Blue, Green, Red]",
);
expect_success(
"{ y: { x: if 1 == 1 then Red else if 1 == 1 then Green else Blue } }",
"{ y: { x: Red } } : { y : { x : [Blue, Green, Red]* } }",
"{ y: { x: Red } } : { y : { x : [Blue, Green, Red] } }",
);
}
@ -171,24 +171,24 @@ fn byte_tag_union() {
fn tag_in_record() {
expect_success(
"{ x: Foo 1 2 3, y : 4 }",
"{ x: Foo 1 2 3, y: 4 } : { x : [Foo (Num *) (Num *) (Num *)]*, y : Num * }",
"{ x: Foo 1 2 3, y: 4 } : { x : [Foo (Num *) (Num *) (Num *)], y : Num * }",
);
expect_success(
"{ x: Foo 1 2 3 }",
"{ x: Foo 1 2 3 } : { x : [Foo (Num *) (Num *) (Num *)]* }",
"{ x: Foo 1 2 3 } : { x : [Foo (Num *) (Num *) (Num *)] }",
);
expect_success("{ x: Unit }", "{ x: Unit } : { x : [Unit]* }");
expect_success("{ x: Unit }", "{ x: Unit } : { x : [Unit] }");
}
#[test]
fn single_element_tag_union() {
expect_success("True 1", "True 1 : [True (Num *)]*");
expect_success("Foo 1 3.14", "Foo 1 3.14 : [Foo (Num *) (Float *)]*");
expect_success("True 1", "True 1 : [True (Num *)]");
expect_success("Foo 1 3.14", "Foo 1 3.14 : [Foo (Num *) (Float *)]");
}
#[test]
fn newtype_of_unit() {
expect_success("Foo Bar", "Foo Bar : [Foo [Bar]*]*");
expect_success("Foo Bar", "Foo Bar : [Foo [Bar]]");
}
#[test]
@ -202,7 +202,7 @@ fn newtype_of_big_data() {
A lefty
"#
),
r#"A (Left "loosey") : [A (Either Str Str)]*"#,
r#"A (Left "loosey") : [A (Either Str Str)]"#,
)
}
@ -217,7 +217,7 @@ fn newtype_nested() {
A (B (C lefty))
"#
),
r#"A (B (C (Left "loosey"))) : [A [B [C (Either Str Str)]*]*]*"#,
r#"A (B (C (Left "loosey"))) : [A [B [C (Either Str Str)]]]"#,
)
}
@ -232,17 +232,17 @@ fn newtype_of_big_of_newtype() {
A big
"#
),
r#"A (Big "s" (Wrapper (Newtype "t"))) : [A (Big Str)]*"#,
r#"A (Big "s" (Wrapper (Newtype "t"))) : [A (Big Str)]"#,
)
}
#[test]
fn tag_with_arguments() {
expect_success("True 1", "True 1 : [True (Num *)]*");
expect_success("True 1", "True 1 : [True (Num *)]");
expect_success(
"if 1 == 1 then True 3 else False 3.14",
"True 3 : [False (Float *), True (Num *)]*",
"True 3 : [False (Float *), True (Num *)]",
)
}
@ -886,7 +886,7 @@ fn function_in_unwrapped_record() {
fn function_in_tag() {
expect_success(
r#"Adder (\x -> x + 1)"#,
r#"Adder <function> : [Adder (Num a -> Num a)]*"#,
r#"Adder <function> : [Adder (Num a -> Num a)]"#,
)
}
@ -894,7 +894,7 @@ fn function_in_tag() {
fn newtype_of_record_of_tag_of_record_of_tag() {
expect_success(
r#"A {b: C {d: 1}}"#,
r#"A { b: C { d: 1 } } : [A { b : [C { d : Num * }]* }]*"#,
r#"A { b: C { d: 1 } } : [A { b : [C { d : Num * }] }]"#,
)
}
@ -1089,7 +1089,7 @@ fn opaque_pattern_and_call() {
f (@F (Package A {}))
"#
),
r#"@F (Package {} A) : F {} [A]*"#,
r#"@F (Package {} A) : F {} [A]"#,
)
}