mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 15:59:20 +03:00
Introduce polarity for extension variable printing
This commit is contained in:
parent
ae1a9e4dd6
commit
d77080529a
@ -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();
|
||||
|
@ -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]",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,7 @@ fn assemble_derived_golden(
|
||||
DebugPrint {
|
||||
print_lambda_sets: true,
|
||||
print_only_under_alias,
|
||||
..DebugPrint::NOTHING
|
||||
},
|
||||
);
|
||||
subs.rollback_to(snapshot);
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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]"#,
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user