Merge pull request #7468 from joshuawarner32/fuzzing-bugs-9

And... more fuzzing bugs!
This commit is contained in:
Luke Boswell 2025-01-06 14:28:18 +11:00 committed by GitHub
commit 89ef225f5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 499 additions and 279 deletions

View file

@ -703,36 +703,37 @@ impl<'a> Formattable for ImplementsAbility<'a> {
impl<'a> Formattable for ImplementsAbilities<'a> {
fn is_multiline(&self) -> bool {
match self {
ImplementsAbilities::SpaceAfter(..) | ImplementsAbilities::SpaceBefore(..) => true,
ImplementsAbilities::Implements(has_abilities) => {
is_collection_multiline(has_abilities)
}
}
self.before_implements_kw.iter().any(|s| s.is_comment())
|| self.after_implements_kw.iter().any(|s| s.is_comment())
|| is_collection_multiline(&self.item.value)
}
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
match self {
ImplementsAbilities::Implements(has_abilities) => {
if newlines == Newlines::Yes {
buf.newline();
}
buf.indent(indent);
buf.push_str(roc_parse::keyword::IMPLEMENTS);
buf.spaces(1);
fmt_collection(buf, indent, Braces::Square, *has_abilities, Newlines::No);
}
ImplementsAbilities::SpaceBefore(has_abilities, spaces) => {
buf.newline();
buf.indent(indent);
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
has_abilities.format_with_options(buf, parens, Newlines::No, indent)
}
ImplementsAbilities::SpaceAfter(has_abilities, spaces) => {
has_abilities.format_with_options(buf, parens, newlines, indent);
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
}
fn format_with_options(&self, buf: &mut Buf, _parens: Parens, newlines: Newlines, indent: u16) {
if !self.before_implements_kw.is_empty() {
buf.newline();
buf.indent(indent);
fmt_comments_only(
buf,
self.before_implements_kw.iter(),
NewlineAt::Bottom,
indent,
);
}
if newlines == Newlines::Yes {
buf.ensure_ends_with_newline();
}
buf.indent(indent);
buf.push_str(roc_parse::keyword::IMPLEMENTS);
if !self.after_implements_kw.is_empty() {
fmt_comments_only(
buf,
self.after_implements_kw.iter(),
NewlineAt::Bottom,
indent,
);
}
buf.ensure_ends_with_whitespace();
fmt_collection(buf, indent, Braces::Square, self.item.value, Newlines::No);
}
}
@ -1217,7 +1218,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> {
},
after: last_after,
needs_indent,
prec: Prec::AsType,
prec: Prec::FunctionType,
}
}
}

View file

@ -19,8 +19,8 @@ use roc_error_macros::internal_error;
use roc_parse::ast::{
AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
ModuleImportParams, Pattern, PatternApplyStyle, Spaceable, Spaces, SpacesAfter, SpacesBefore,
StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
ModuleImportParams, Pattern, PatternApplyStyle, Spaces, SpacesBefore, StrLiteral,
TypeAnnotation, TypeDef, TypeHeader, ValueDef,
};
use roc_parse::expr::merge_spaces;
use roc_parse::header::Keyword;
@ -94,21 +94,6 @@ pub fn def_lift_spaces<'a, 'b: 'a>(
}
}
fn lift_spaces_after<'a, 'b: 'a, T: 'b + ExtractSpaces<'a> + Spaceable<'a>>(
arena: &'a Bump,
item: T,
) -> SpacesAfter<'a, <T as ExtractSpaces<'a>>::Item>
where
<T as ExtractSpaces<'a>>::Item: Spaceable<'a>,
{
let spaces = item.extract_spaces();
SpacesAfter {
item: spaces.item.maybe_before(arena, spaces.before),
after: spaces.after,
}
}
pub fn tydef_lift_spaces<'a, 'b: 'a>(arena: &'a Bump, def: TypeDef<'b>) -> Spaces<'a, TypeDef<'a>> {
match def {
TypeDef::Alias { header, ann } => {
@ -128,17 +113,12 @@ pub fn tydef_lift_spaces<'a, 'b: 'a>(arena: &'a Bump, def: TypeDef<'b>) -> Space
typ,
derived,
} => {
if let Some(derived) = derived {
let derived_lifted = lift_spaces_after(arena, derived.value);
if derived.is_some() {
// It's structurally impossible for a derived clause to have spaces after
Spaces {
before: &[],
item: TypeDef::Opaque {
header,
typ,
derived: Some(Loc::at(derived.region, derived_lifted.item)),
},
after: derived_lifted.after,
item: def,
after: &[],
}
} else {
let typ_lifted = ann_lift_spaces_after(arena, &typ.value);
@ -461,7 +441,7 @@ impl<'a> Formattable for TypeDef<'a> {
// Always put the has-abilities clause on a newline if the opaque annotation
// contains a where-has clause.
let has_abilities_multiline = if let Some(has_abilities) = has_abilities {
!has_abilities.value.is_empty() && ann_is_where_clause
!has_abilities.item.value.is_empty() && ann_is_where_clause
} else {
false
};
@ -481,7 +461,7 @@ impl<'a> Formattable for TypeDef<'a> {
if let Some(has_abilities) = has_abilities {
buf.spaces(1);
has_abilities.format_with_options(
(*has_abilities).format_with_options(
buf,
Parens::NotNeeded,
Newlines::from_bool(make_multiline),

View file

@ -1814,14 +1814,17 @@ fn fmt_return<'a>(
buf.indent(indent);
buf.push_str(keyword::RETURN);
let return_indent = if return_value.is_multiline() {
let value = expr_lift_spaces(parens, buf.text.bump(), &return_value.value);
let return_indent = if value.item.is_multiline()
|| (newlines == Newlines::Yes && !value.before.is_empty())
|| value.before.iter().any(|s| s.is_comment())
{
indent + INDENT
} else {
indent
};
let value = expr_lift_spaces(parens, buf.text.bump(), &return_value.value);
if !value.before.is_empty() {
format_spaces(buf, value.before, newlines, return_indent);
}
@ -2057,15 +2060,17 @@ fn fmt_record_like<'a, 'b: 'a, Field, ToSpacesAround>(
// doesnt make sense.
Some(RecordPrefix::Update(record_var)) => {
buf.spaces(1);
record_var.format(buf, indent);
buf.indent(indent);
buf.push_str(" &");
record_var.format(buf, indent + INDENT);
buf.indent(indent + INDENT);
buf.ensure_ends_with_whitespace();
buf.push_str("&");
}
Some(RecordPrefix::Mapper(mapper_var)) => {
buf.spaces(1);
mapper_var.format(buf, indent);
buf.indent(indent);
buf.push_str(" <-");
mapper_var.format(buf, indent + INDENT);
buf.indent(indent + INDENT);
buf.ensure_ends_with_whitespace();
buf.push_str("<-");
}
}