Several migration fixes and make some zig parser improvements based on migrated code in the wild (#7716)

This commit is contained in:
Joshua Warner 2025-04-08 04:46:44 -07:00 committed by GitHub
parent 68af4b9a06
commit 6d22c4dd7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
329 changed files with 1663 additions and 833 deletions

View file

@ -9,6 +9,7 @@ use roc_can::expr::{DeclarationTag, Declarations, Expr};
use roc_error_macros::{internal_error, user_error};
use roc_fmt::def::fmt_defs;
use roc_fmt::header::fmt_header;
use roc_fmt::migrate::MigrateError;
use roc_fmt::Buf;
use roc_fmt::MigrationFlags;
use roc_load::{ExecutionMode, FunctionKind, LoadConfig, LoadedModule, LoadingProblem, Threading};
@ -78,7 +79,7 @@ fn is_roc_file(path: &Path) -> bool {
pub fn format_files(
files: std::vec::Vec<PathBuf>,
mode: FormatMode,
flags: MigrationFlags,
migrate: bool,
) -> Result<(), String> {
let arena = Bump::new();
let mut files_to_reformat = Vec::new(); // to track which files failed `roc format --check`
@ -86,7 +87,7 @@ pub fn format_files(
for file in flatten_directories(files) {
let src = std::fs::read_to_string(&file).unwrap();
match format_src(&arena, &src, flags) {
match format_src(&arena, &src, migrate) {
Ok(buf) => {
match mode {
FormatMode::CheckOnly => {
@ -168,6 +169,11 @@ pub fn format_files(
unstable_2_file.display()
);
}
FormatProblem::UnsupportedMigration(e) => internal_error!(
"Formatting bug; unsupported migration\n\n\
Migration error was: {:?}\n\n",
e
),
},
}
}
@ -197,13 +203,28 @@ pub enum FormatProblem {
formatted_src: String,
reformatted_src: String,
},
UnsupportedMigration(MigrateError),
}
pub fn format_src(arena: &Bump, src: &str, flags: MigrationFlags) -> Result<String, FormatProblem> {
pub fn format_src(arena: &Bump, src: &str, migrate: bool) -> Result<String, FormatProblem> {
let ast = arena.alloc(parse_all(arena, src).unwrap_or_else(|e| {
user_error!("Unexpected parse failure when parsing this formatting:\n\n{src}\n\nParse error was:\n\n{:#?}\n\n", e)
}));
let flags = MigrationFlags {
snakify: migrate,
parens_and_commas: migrate,
};
let mut buf = Buf::new_in(arena, flags);
if migrate {
roc_fmt::migrate::fmt_header(&mut buf, &ast.header)
.map_err(FormatProblem::UnsupportedMigration)?;
roc_fmt::migrate::fmt_defs(&mut buf, &ast.defs)
.map_err(FormatProblem::UnsupportedMigration)?;
buf.fmt_end_of_file();
return Ok(buf.as_str().to_string());
}
fmt_all(&mut buf, ast);
let reparsed_ast = match arena.alloc(parse_all(arena, buf.as_str())) {
@ -224,9 +245,7 @@ pub fn format_src(arena: &Bump, src: &str, flags: MigrationFlags) -> Result<Stri
// the PartialEq implementation is returning `false` even when the Debug-formatted impl is exactly the same.
// I don't have the patience to debug this right now, so let's leave it for another day...
// TODO: fix PartialEq impl on ast types
if !flags.at_least_one_active()
&& format!("{ast_normalized:?}") != format!("{reparsed_ast_normalized:?}")
{
if format!("{ast_normalized:?}") != format!("{reparsed_ast_normalized:?}") {
return Err(FormatProblem::ReformattingChangedAst {
formatted_src: buf.as_str().to_string(),
ast_before: format!("{ast_normalized:#?}\n"),
@ -235,7 +254,7 @@ pub fn format_src(arena: &Bump, src: &str, flags: MigrationFlags) -> Result<Stri
}
// Now verify that the resultant formatting is _stable_ - i.e. that it doesn't change again if re-formatted
let mut reformatted_buf = Buf::new_in(arena, flags);
let mut reformatted_buf = Buf::new_in(arena, MigrationFlags::default());
fmt_all(&mut reformatted_buf, reparsed_ast);
@ -483,12 +502,7 @@ main =
fn test_single_file_needs_reformatting() {
let dir = tempdir().unwrap();
let file_path = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
let flags = MigrationFlags {
snakify: false,
parens_and_commas: false,
};
let result = format_files(vec![file_path.clone()], FormatMode::CheckOnly, flags);
let result = format_files(vec![file_path.clone()], FormatMode::CheckOnly, false);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
@ -506,12 +520,7 @@ main =
let dir = tempdir().unwrap();
let file1 = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
let file2 = setup_test_file(dir.path(), "test2.roc", UNFORMATTED_ROC);
let flags = MigrationFlags {
snakify: false,
parens_and_commas: false,
};
let result = format_files(vec![file1, file2], FormatMode::CheckOnly, flags);
let result = format_files(vec![file1, file2], FormatMode::CheckOnly, false);
assert!(result.is_err());
let error_message = result.unwrap_err();
assert!(error_message.contains("test1.roc") && error_message.contains("test2.roc"));
@ -523,12 +532,7 @@ main =
fn test_no_files_need_reformatting() {
let dir = tempdir().unwrap();
let file_path = setup_test_file(dir.path(), "formatted.roc", FORMATTED_ROC);
let flags = MigrationFlags {
snakify: false,
parens_and_commas: false,
};
let result = format_files(vec![file_path], FormatMode::CheckOnly, flags);
let result = format_files(vec![file_path], FormatMode::CheckOnly, false);
assert!(result.is_ok());
cleanup_temp_dir(dir);
@ -540,15 +544,10 @@ main =
let file_formatted = setup_test_file(dir.path(), "formatted.roc", FORMATTED_ROC);
let file1_unformated = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
let file2_unformated = setup_test_file(dir.path(), "test2.roc", UNFORMATTED_ROC);
let flags = MigrationFlags {
snakify: false,
parens_and_commas: false,
};
let result = format_files(
vec![file_formatted, file1_unformated, file2_unformated],
FormatMode::CheckOnly,
flags,
false,
);
assert!(result.is_err());
let error_message = result.unwrap_err();

View file

@ -13,7 +13,6 @@ use roc_cli::{
};
use roc_docs::generate_docs_html;
use roc_error_macros::{internal_error, user_error};
use roc_fmt::MigrationFlags;
use roc_gen_dev::AssemblyBackendMode;
use roc_gen_llvm::llvm::build::LlvmBackendMode;
use roc_load::{LoadingProblem, Threading};
@ -395,10 +394,6 @@ fn main() -> io::Result<()> {
false => FormatMode::WriteToFile,
}
};
let flags = MigrationFlags {
snakify: migrate,
parens_and_commas: migrate,
};
if from_stdin && matches!(format_mode, FormatMode::WriteToFile) {
eprintln!("When using the --stdin flag, either the --check or the --stdout flag must also be specified. (Otherwise, it's unclear what filename to write to!)");
@ -451,7 +446,7 @@ fn main() -> io::Result<()> {
std::process::exit(1);
});
match format_src(&arena, src, flags) {
match format_src(&arena, src, migrate) {
Ok(formatted_src) => {
match format_mode {
FormatMode::CheckOnly => {
@ -483,7 +478,7 @@ fn main() -> io::Result<()> {
}
}
} else {
match format_files(roc_files, format_mode, flags) {
match format_files(roc_files, format_mode, migrate) {
Ok(()) => 0,
Err(message) => {
eprintln!("{message}");