Apply tag union diffs to recursive tag unions

This commit is contained in:
Richard Feldman 2023-03-26 23:16:55 -04:00
parent 389ec09451
commit d391982c33
No known key found for this signature in database
GPG Key ID: F1F21AA5B1D9E43B
2 changed files with 68 additions and 66 deletions

View File

@ -2495,6 +2495,7 @@ fn to_doc_help<'b>(
.collect(),
tag_ext_to_doc(alloc, pol, gen_usages, ext),
0, // zero tags omitted, since this isn't a diff
None,
)
}
@ -2514,13 +2515,16 @@ fn to_doc_help<'b>(
.collect::<Vec<_>>();
tags.sort_by(|(a, _), (b, _)| a.cmp(b));
report_text::recursive_tag_union(
let rec_doc = to_doc_help(ctx, gen_usages, alloc, Parens::Unnecessary, *rec_var);
report_text::tag_union(
alloc,
to_doc_help(ctx, gen_usages, alloc, Parens::Unnecessary, *rec_var),
tags.into_iter()
.map(|(k, v)| (alloc.tag_name(k), v))
.collect(),
tag_ext_to_doc(alloc, pol, gen_usages, ext),
0, // zero tags omitted, since this isn't a diff
Some(rec_doc),
)
}
@ -2888,21 +2892,11 @@ fn to_diff<'b>(
}
(TagUnion(tags1, ext1, pol), TagUnion(tags2, ext2, _)) => {
diff_tag_union(alloc, pol, tags1, ext1, tags2, ext2)
diff_tag_union(alloc, pol, tags1, ext1, None, tags2, ext2, None)
}
(RecursiveTagUnion(_rec1, _tags1, _ext1, _), RecursiveTagUnion(_rec2, _tags2, _ext2, _)) => {
// TODO do a better job here
let (left, left_able) = to_doc(alloc, Parens::Unnecessary, type1);
let (right, right_able) = to_doc(alloc, Parens::Unnecessary, type2);
Diff {
left,
right,
status: Status::Similar,
left_able,
right_able,
}
(RecursiveTagUnion(rec1, tags1, ext1, pol), RecursiveTagUnion(rec2, tags2, ext2, _)) => {
diff_tag_union(alloc, pol, tags1, ext1, Some(*rec1), tags2, ext2, Some(*rec2))
}
pair => {
@ -3539,8 +3533,10 @@ fn diff_tag_union<'b>(
pol: Polarity,
tags1: SendMap<TagName, Vec<ErrorType>>,
ext1: TypeExt,
rec1: Option<ErrorType>,
mut tags2: SendMap<TagName, Vec<ErrorType>>,
ext2: TypeExt,
rec2: Option<ErrorType>,
) -> Diff<RocDocBuilder<'b>> {
let gen_usages1 = {
let mut usages = VecMap::default();
@ -3733,8 +3729,38 @@ fn diff_tag_union<'b>(
.map(|(_, a, b)| (a, b))
.collect();
let doc1 = report_text::tag_union(alloc, lefts, ext_diff.left, left_tags_omitted);
let doc2 = report_text::tag_union(alloc, rights, ext_diff.right, right_tags_omitted);
let doc1 = match rec1 {
None => report_text::tag_union(alloc, lefts, ext_diff.left, left_tags_omitted, None),
Some(rec) => {
let (rec_doc, able) = to_doc(alloc, Parens::Unnecessary, rec);
tags_diff.left_able.extend(able);
report_text::tag_union(
alloc,
lefts,
ext_diff.left,
left_tags_omitted,
Some(rec_doc),
)
}
};
let doc2 = match rec2 {
None => report_text::tag_union(alloc, rights, ext_diff.right, right_tags_omitted, None),
Some(rec) => {
let (rec_doc, able) = to_doc(alloc, Parens::Unnecessary, rec);
tags_diff.right_able.extend(able);
report_text::tag_union(
alloc,
rights,
ext_diff.right,
right_tags_omitted,
Some(rec_doc),
)
}
};
tags_diff.status.merge(status);
@ -4105,6 +4131,7 @@ mod report_text {
entries: Vec<(RocDocBuilder<'b>, Vec<RocDocBuilder<'b>>)>,
opt_ext: Option<RocDocBuilder<'b>>,
tags_omitted: usize,
opt_rec: Option<RocDocBuilder<'b>>,
) -> RocDocBuilder<'b> {
let ext_doc = if let Some(t) = opt_ext {
t
@ -4122,7 +4149,7 @@ mod report_text {
}
};
if entries.is_empty() {
let without_rec = if entries.is_empty() {
if tags_omitted == 0 {
alloc.text("[]")
} else {
@ -4168,50 +4195,11 @@ mod report_text {
),
)
.append(ext_doc)
}
}
pub fn recursive_tag_union<'b>(
alloc: &'b RocDocAllocator<'b>,
rec_var: RocDocBuilder<'b>,
entries: Vec<(RocDocBuilder<'b>, Vec<RocDocBuilder<'b>>)>,
opt_ext: Option<RocDocBuilder<'b>>,
) -> RocDocBuilder<'b> {
// TODO
let ext_doc = if let Some(t) = opt_ext {
t
} else {
alloc.nil()
};
if entries.is_empty() {
alloc.text("[]")
} else {
let entry_to_doc = |(tag_name, arguments): (RocDocBuilder<'b>, Vec<_>)| {
if arguments.is_empty() {
tag_name
} else {
tag_name
.append(alloc.space())
.append(alloc.intersperse(arguments, alloc.space()))
}
};
let starts =
std::iter::once(alloc.reflow("[")).chain(std::iter::repeat(alloc.reflow(", ")));
let entries_doc = alloc.concat(
entries
.into_iter()
.zip(starts)
.map(|(entry, start)| start.append(entry_to_doc(entry))),
);
entries_doc
.append(alloc.reflow("]"))
.append(ext_doc)
.append(alloc.text(" as "))
.append(rec_var)
match opt_rec {
Some(rec) => without_rec.append(alloc.text(" as ")).append(rec),
None => without_rec,
}
}

View File

@ -3392,7 +3392,10 @@ mod test_reporting {
[
Cons {} [
Cons Str [Cons {} a, Nil]b as a,
Cons Str [
Cons {} a,
Nil,
]b as a,
Nil,
]b,
Nil,
@ -3400,7 +3403,10 @@ mod test_reporting {
But the type annotation on `x` says it should be:
[Cons {} a, Nil] as a
[
Cons {} a,
Nil,
] as a
"###
);
@ -3437,8 +3443,10 @@ mod test_reporting {
ACons (Int Signed64) [
BCons (Int Signed64) [
ACons Str [
BCons I64 [ACons I64 (BList I64 I64),
ANil]b as ,
BCons I64 [
ACons I64 (BList I64 I64),
ANil,
]b as ,
BNil,
]c,
ANil,
@ -3450,7 +3458,10 @@ mod test_reporting {
But the type annotation on `x` says it should be:
[ACons I64 (BList I64 I64), ANil] as a
[
ACons I64 (BList I64 I64),
ANil,
] as a
"###
);
@ -10008,7 +10019,10 @@ In roc, functions are always written as a lambda, like{}
This `lst` value is a:
[Cons {} , Nil] as
[
Cons {} ,
Nil,
] as
But the type annotation on `olist` says it should be: