Fix parenthesized spaces in tag unions

This commit is contained in:
Joshua Warner 2024-12-13 13:23:16 -08:00
parent 02e07f95e7
commit 3acc6940b4
No known key found for this signature in database
GPG key ID: 89AD497003F93FDD
5 changed files with 209 additions and 30 deletions

View file

@ -343,7 +343,7 @@ fn fmt_ty_ann(
} }
TypeAnnotation::TagUnion { tags, ext } => { TypeAnnotation::TagUnion { tags, ext } => {
fmt_collection(buf, indent, Braces::Square, *tags, newlines); fmt_tag_collection(buf, indent, *tags, newlines);
fmt_ext(ext, buf, indent); fmt_ext(ext, buf, indent);
} }
@ -403,6 +403,78 @@ fn fmt_ty_ann(
} }
} }
fn fmt_tag_collection<'a>(
buf: &mut Buf<'_>,
indent: u16,
tags: Collection<'a, Loc<Tag<'a>>>,
newlines: Newlines,
) {
let arena = buf.text.bump();
let mut new_items: Vec<'_, NodeSpaces<'_, Node<'_>>> = Vec::with_capacity_in(tags.len(), arena);
let mut last_after: &[CommentOrNewline<'_>] = &[];
for item in tags.items.iter() {
let lifted = tag_lift_to_node(arena, item.value);
let before = merge_spaces_conservative(arena, last_after, lifted.before);
last_after = lifted.after;
new_items.push(NodeSpaces {
before,
item: lifted.item,
after: &[],
});
}
let final_comments = merge_spaces_conservative(arena, last_after, tags.final_comments());
let new_items =
Collection::with_items_and_comments(arena, new_items.into_bump_slice(), final_comments);
fmt_collection(buf, indent, Braces::Square, new_items, newlines);
}
fn tag_lift_to_node<'a, 'b: 'a>(arena: &'a Bump, value: Tag<'b>) -> Spaces<'a, Node<'a>> {
match value {
Tag::Apply { name, args } => {
if args.is_empty() {
Spaces {
before: &[],
item: Node::Literal(name.value),
after: &[],
}
} else {
let first = Node::Literal(name.value);
let mut new_args: Vec<'a, (Sp<'a>, Node<'a>)> =
Vec::with_capacity_in(args.len(), arena);
let mut last_after: &[CommentOrNewline<'_>] = &[];
for arg in args.iter() {
let lifted = ann_lift_to_node(Parens::InApply, arena, &arg.value);
let before = merge_spaces_conservative(arena, last_after, lifted.before);
last_after = lifted.after;
new_args.push((before, lifted.item));
}
Spaces {
before: &[],
item: Node::Sequence(arena.alloc(first), new_args.into_bump_slice()),
after: last_after,
}
}
}
Tag::SpaceBefore(inner, sp) => {
let mut inner = tag_lift_to_node(arena, *inner);
inner.before = merge_spaces_conservative(arena, sp, inner.before);
inner
}
Tag::SpaceAfter(inner, sp) => {
let mut inner = tag_lift_to_node(arena, *inner);
inner.after = merge_spaces_conservative(arena, inner.after, sp);
inner
}
}
}
fn lower<'a, 'b: 'a>( fn lower<'a, 'b: 'a>(
arena: &'b Bump, arena: &'b Bump,
lifted: Spaces<'b, TypeAnnotation<'b>>, lifted: Spaces<'b, TypeAnnotation<'b>>,
@ -1070,6 +1142,8 @@ type Sp<'a> = &'a [CommentOrNewline<'a>];
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
enum Node<'a> { enum Node<'a> {
Literal(&'a str),
Sequence(&'a Node<'a>, &'a [(Sp<'a>, Node<'a>)]),
DelimitedSequence(Braces, &'a [(Sp<'a>, Node<'a>)], Sp<'a>), DelimitedSequence(Braces, &'a [(Sp<'a>, Node<'a>)], Sp<'a>),
TypeAnnotation(TypeAnnotation<'a>), TypeAnnotation(TypeAnnotation<'a>),
} }
@ -1078,17 +1152,19 @@ impl<'a> Formattable for Node<'a> {
fn is_multiline(&self) -> bool { fn is_multiline(&self) -> bool {
match self { match self {
Node::DelimitedSequence(_braces, lefts, right) => { Node::DelimitedSequence(_braces, lefts, right) => {
if !right.is_empty() { right.is_empty()
return true; && lefts
} .iter()
for (sp, l) in *lefts { .any(|(sp, l)| l.is_multiline() || !sp.is_empty())
if l.is_multiline() || !sp.is_empty() { }
return true; Node::Sequence(first, rest) => {
} first.is_multiline()
} || rest
false .iter()
.any(|(sp, l)| l.is_multiline() || !sp.is_empty())
} }
Node::TypeAnnotation(type_annotation) => type_annotation.is_multiline(), Node::TypeAnnotation(type_annotation) => type_annotation.is_multiline(),
Node::Literal(_) => false,
} }
} }
@ -1113,9 +1189,26 @@ impl<'a> Formattable for Node<'a> {
buf.indent(indent); buf.indent(indent);
buf.push(braces.end()); buf.push(braces.end());
} }
Node::Sequence(first, rest) => {
first.format_with_options(buf, parens, newlines, indent);
for (sp, l) in *rest {
if !sp.is_empty() {
fmt_spaces(buf, sp.iter(), indent);
} else {
buf.spaces(1);
}
l.format_with_options(buf, parens, newlines, indent);
}
}
Node::TypeAnnotation(type_annotation) => { Node::TypeAnnotation(type_annotation) => {
type_annotation.format_with_options(buf, parens, newlines, indent); type_annotation.format_with_options(buf, parens, newlines, indent);
} }
Node::Literal(text) => {
buf.indent(indent);
buf.push_str(text);
}
} }
} }
} }
@ -1158,14 +1251,27 @@ fn ann_lift_to_node<'a, 'b: 'a>(
&[] &[]
}; };
Spaces { let item = Node::TypeAnnotation(TypeAnnotation::Apply(
before: &[], module,
item: Node::TypeAnnotation(TypeAnnotation::Apply( func,
module, new_args.into_bump_slice(),
func, ));
new_args.into_bump_slice(),
)), if parens == Parens::InApply {
after, parens_around_node(
arena,
Spaces {
before: &[],
item,
after,
},
)
} else {
Spaces {
before: &[],
item,
after,
}
} }
} }
TypeAnnotation::SpaceBefore(expr, spaces) => { TypeAnnotation::SpaceBefore(expr, spaces) => {
@ -1198,18 +1304,8 @@ fn ann_lift_to_node<'a, 'b: 'a>(
item: Node::TypeAnnotation(new_ann), item: Node::TypeAnnotation(new_ann),
after: new_res.after, after: new_res.after,
}; };
if parens == Parens::InCollection { if parens == Parens::InCollection || parens == Parens::InApply {
let node = Node::DelimitedSequence( parens_around_node(arena, inner)
Braces::Round,
arena.alloc_slice_copy(&[(inner.before, inner.item)]),
inner.after,
);
Spaces {
before: &[],
item: node,
after: &[],
}
} else { } else {
inner inner
} }
@ -1225,6 +1321,21 @@ fn ann_lift_to_node<'a, 'b: 'a>(
} }
} }
fn parens_around_node<'a, 'b: 'a>(
arena: &'a Bump,
item: Spaces<'b, Node<'b>>,
) -> Spaces<'a, Node<'a>> {
Spaces {
before: &[],
item: Node::DelimitedSequence(
Braces::Round,
arena.alloc_slice_copy(&[(item.before, item.item)]),
item.after,
),
after: &[],
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct NodeSpaces<'a, T> { pub struct NodeSpaces<'a, T> {
pub before: &'a [CommentOrNewline<'a>], pub before: &'a [CommentOrNewline<'a>],

View file

@ -0,0 +1,60 @@
@0-12 SpaceAfter(
Defs(
Defs {
tags: [
EitherIndex(2147483648),
],
regions: [
@0-10,
],
space_before: [
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
],
space_after: [
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
],
spaces: [],
type_defs: [],
value_defs: [
Annotation(
@0-1 Identifier {
ident: "g",
},
@2-10 TagUnion {
ext: None,
tags: [
@3-9 Apply {
name: @3-4 "T",
args: [
@5-6 SpaceAfter(
Apply(
"",
"T",
[],
),
[
LineComment(
"",
),
],
),
],
},
],
},
),
],
},
@11-12 SpaceBefore(
Tag(
"D",
),
[
Newline,
],
),
),
[
Newline,
],
)

View file

@ -298,6 +298,7 @@ mod test_snapshots {
pass/annotated_tuple_destructure.expr, pass/annotated_tuple_destructure.expr,
pass/annotation_apply_newlines.expr, pass/annotation_apply_newlines.expr,
pass/annotation_comment_before_colon.expr, pass/annotation_comment_before_colon.expr,
pass/annotation_tag_parens_comment.expr,
pass/annotation_tuple_comment.expr, pass/annotation_tuple_comment.expr,
pass/annotation_tuple_newline.expr, pass/annotation_tuple_newline.expr,
pass/annotation_tuple_parens_newlines.expr, pass/annotation_tuple_parens_newlines.expr,