diff --git a/crates/compiler/fmt/src/annotation.rs b/crates/compiler/fmt/src/annotation.rs index d2715aa057..cc48ce9fcb 100644 --- a/crates/compiler/fmt/src/annotation.rs +++ b/crates/compiler/fmt/src/annotation.rs @@ -1,7 +1,7 @@ use crate::{ collection::{fmt_collection, Braces}, expr::merge_spaces_conservative, - node::{parens_around_node, Item, Node, NodeSequenceBuilder, Nodify, Sp}, + node::{parens_around_node, Item, Node, NodeInfo, NodeSequenceBuilder, Nodify, Sp}, pattern::pattern_lift_spaces_after, pattern::snakify_camel_ident, spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT}, @@ -416,18 +416,14 @@ fn fmt_tag_collection<'a>( } impl<'a> Nodify<'a> for Tag<'a> { - fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> Spaces<'b, Node<'b>> + fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> NodeInfo<'b> where 'a: 'b, { match self { Tag::Apply { name, args } => { if args.is_empty() { - Spaces { - before: &[], - item: Node::Literal(name.value), - after: &[], - } + NodeInfo::item(Node::Literal(name.value)) } else { let first = Node::Literal(name.value); let mut new_args: Vec<'b, (Sp<'b>, Node<'b>)> = @@ -441,7 +437,7 @@ impl<'a> Nodify<'a> for Tag<'a> { new_args.push((Sp::with_space(before), lifted.item)); } - Spaces { + NodeInfo { before: &[], item: Node::Sequence { first: arena.alloc(first), @@ -449,6 +445,7 @@ impl<'a> Nodify<'a> for Tag<'a> { rest: new_args.into_bump_slice(), }, after: last_after, + needs_indent: true, } } } @@ -611,7 +608,7 @@ impl<'a> Formattable for AssignedField<'a, Expr<'a>> { } impl<'a> Nodify<'a> for AssignedField<'a, TypeAnnotation<'a>> { - fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> Spaces<'b, Node<'b>> + fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> NodeInfo<'b> where 'a: 'b, { @@ -628,10 +625,11 @@ impl<'a> Nodify<'a> for AssignedField<'a, TypeAnnotation<'a>> { AssignedField::OptionalValue(name, sp, value) => { assigned_field_value_to_node(name.value, arena, sp, &value.value, "?") } - AssignedField::LabelOnly(name) => Spaces { + AssignedField::LabelOnly(name) => NodeInfo { before: &[], item: Node::Literal(name.value), after: &[], + needs_indent: true, }, AssignedField::SpaceBefore(inner, sp) => { let mut inner = inner.to_node(arena, parens); @@ -653,7 +651,7 @@ fn assigned_field_value_to_node<'a, 'b>( sp: &'a [CommentOrNewline<'a>], value: &'a TypeAnnotation<'a>, sep: &'static str, -) -> Spaces<'b, Node<'b>> +) -> NodeInfo<'b> where 'a: 'b, { @@ -667,10 +665,11 @@ where b.push(Sp::with_space(value_lifted.before), value_lifted.item); - Spaces { + NodeInfo { before: &[], item: b.build(), after: value_lifted.after, + needs_indent: true, } } @@ -1206,7 +1205,7 @@ pub fn type_head_lift_spaces_after<'a, 'b: 'a>( } impl<'a> Nodify<'a> for TypeAnnotation<'a> { - fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> Spaces<'b, Node<'b>> + fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> NodeInfo<'b> where 'a: 'b, { @@ -1234,7 +1233,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { }); } - let item = Spaces { + let item = NodeInfo { before: &[], item: Node::CommaSequence { allow_blank_lines: false, @@ -1243,6 +1242,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { rest: rest.into_bump_slice(), }, after: last_after, + needs_indent: true, }; if parens == Parens::InApply && !args.is_empty() { @@ -1313,7 +1313,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { node: res_node.item, }); - let item = Spaces { + let item = NodeInfo { before: first_node.before, item: Node::CommaSequence { allow_blank_lines: false, @@ -1322,6 +1322,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { rest: rest_nodes.into_bump_slice(), }, after: res_node.after, + needs_indent: true, }; if parens == Parens::InCollection @@ -1342,10 +1343,11 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { b.push(Sp::with_space(before_as), Node::Literal("as")); b.push(Sp::with_space(right.before), right.item); - let item = Spaces { + let item = NodeInfo { before: left.before, item: b.build(), after: right.after, + needs_indent: true, }; if parens == Parens::InApply || parens == Parens::InAsPattern { @@ -1355,7 +1357,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { } } TypeAnnotation::BoundVariable(text) => { - let item = Spaces::item(Node::Literal(text)); + let item = NodeInfo::item(Node::Literal(text)); if *text == "implements" { parens_around_node(arena, item, false) @@ -1363,15 +1365,16 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> { item } } - TypeAnnotation::Inferred => Spaces::item(Node::Literal("_")), - TypeAnnotation::Wildcard => Spaces::item(Node::Literal("*")), - TypeAnnotation::Malformed(text) => Spaces::item(Node::Literal(text)), + TypeAnnotation::Inferred => NodeInfo::item(Node::Literal("_")), + TypeAnnotation::Wildcard => NodeInfo::item(Node::Literal("*")), + TypeAnnotation::Malformed(text) => NodeInfo::item(Node::Literal(text)), _ => { let lifted = ann_lift_spaces(arena, self); - Spaces { + NodeInfo { before: lifted.before, item: Node::TypeAnnotation(lifted.item), after: lifted.after, + needs_indent: true, } } } diff --git a/crates/compiler/fmt/src/def.rs b/crates/compiler/fmt/src/def.rs index 672a210ed9..21082fe57c 100644 --- a/crates/compiler/fmt/src/def.rs +++ b/crates/compiler/fmt/src/def.rs @@ -7,7 +7,7 @@ use crate::expr::{ expr_lift_and_lower, expr_lift_spaces, expr_lift_spaces_after, expr_lift_spaces_before, fmt_str_literal, is_str_multiline, sub_expr_requests_parens, }; -use crate::node::Nodify; +use crate::node::{NodeInfo, Nodify}; use crate::pattern::pattern_lift_spaces_before; use crate::pattern::{pattern_apply_to_node, pattern_fmt_apply}; use crate::spaces::{ @@ -542,7 +542,7 @@ impl<'a> Formattable for TypeHeader<'a> { } impl<'a> Nodify<'a> for TypeHeader<'a> { - fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> Spaces<'b, crate::node::Node<'b>> + fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> NodeInfo<'b> where 'a: 'b, { diff --git a/crates/compiler/fmt/src/node.rs b/crates/compiler/fmt/src/node.rs index fc315f8510..3b46a6416c 100644 --- a/crates/compiler/fmt/src/node.rs +++ b/crates/compiler/fmt/src/node.rs @@ -1,5 +1,5 @@ use bumpalo::{collections::Vec, Bump}; -use roc_parse::ast::{CommentOrNewline, Pattern, Spaces, TypeAnnotation}; +use roc_parse::ast::{CommentOrNewline, Pattern, TypeAnnotation}; use crate::{ annotation::{Formattable, Newlines, Parens}, @@ -98,12 +98,12 @@ impl<'a> Node<'a> { } } -pub fn parens_around_node<'a, 'b: 'a>( - arena: &'a Bump, - item: Spaces<'b, Node<'b>>, +pub fn parens_around_node<'b, 'a: 'b>( + arena: &'b Bump, + item: NodeInfo<'a>, allow_spaces_before: bool, -) -> Spaces<'a, Node<'a>> { - Spaces { +) -> NodeInfo<'b> { + NodeInfo { before: if allow_spaces_before { item.before } else { @@ -123,11 +123,29 @@ pub fn parens_around_node<'a, 'b: 'a>( ), // We move the comments/newlines to the outer scope, since they tend to migrate there when re-parsed after: item.after, + needs_indent: true, // Maybe want to make parens outdentable? + } +} + +pub struct NodeInfo<'b> { + pub before: &'b [CommentOrNewline<'b>], + pub item: Node<'b>, + pub after: &'b [CommentOrNewline<'b>], + pub needs_indent: bool, +} +impl<'b> NodeInfo<'b> { + pub fn item(text: Node<'b>) -> NodeInfo<'b> { + NodeInfo { + before: &[], + item: text, + after: &[], + needs_indent: true, + } } } pub trait Nodify<'a> { - fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> Spaces<'b, Node<'b>> + fn to_node<'b>(&'a self, arena: &'b Bump, parens: Parens) -> NodeInfo<'b> where 'a: 'b; } diff --git a/crates/compiler/fmt/src/pattern.rs b/crates/compiler/fmt/src/pattern.rs index 49d18ca243..45eaca7d85 100644 --- a/crates/compiler/fmt/src/pattern.rs +++ b/crates/compiler/fmt/src/pattern.rs @@ -2,7 +2,7 @@ use crate::annotation::{Formattable, Newlines, Parens}; use crate::expr::{ expr_is_multiline, expr_lift_spaces_after, fmt_str_literal, format_sq_literal, is_str_multiline, }; -use crate::node::{parens_around_node, Node, NodeSequenceBuilder, Sp}; +use crate::node::{parens_around_node, Node, NodeInfo, NodeSequenceBuilder, Sp}; use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT}; use crate::Buf; use bumpalo::Bump; @@ -552,7 +552,7 @@ pub fn pattern_apply_to_node<'b, 'a: 'b>( parens: Parens, func: Pattern<'a>, args: &[Loc>], -) -> Spaces<'b, Node<'b>> { +) -> NodeInfo<'b> { let func_lifted = pattern_lift_spaces(arena, &func); let mut b = NodeSequenceBuilder::new(arena, Node::Pattern(func_lifted.item), args.len(), true); @@ -567,10 +567,11 @@ pub fn pattern_apply_to_node<'b, 'a: 'b>( last_after = arg_lifted.after; } - let item = Spaces { + let item = NodeInfo { before: func_lifted.before, item: b.build(), after: last_after, + needs_indent: true, }; let parens = !args.is_empty() && parens == Parens::InApply;