From 7059257592a984a449e49a3914c92c63144d235a Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Thu, 11 Jun 2026 16:47:27 -0500 Subject: [PATCH] feat: add lowering fixtures --- crates/core/src/ir/lowerer.rs | 78 +++++++++++++++++++ ...14_project_compilation_and_dependencies.md | 2 +- .../dependency_module_overlap/gleam.toml | 7 ++ .../src/shared.gleam | 3 + .../duplicate_function_names/gleam.toml | 4 + .../duplicate_function_names/src/left.gleam | 3 + .../duplicate_function_names/src/main.gleam | 6 ++ .../duplicate_function_names/src/right.gleam | 3 + .../duplicate_module_basenames/gleam.toml | 4 + .../src/alpha/main.gleam | 3 + .../src/beta/main.gleam | 3 + .../lifted_closures/gleam.toml | 4 + .../lifted_closures/src/main.gleam | 8 ++ 13 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 fixtures/projects/generated_names/dependency_module_overlap/gleam.toml create mode 100644 fixtures/projects/generated_names/dependency_module_overlap/src/shared.gleam create mode 100644 fixtures/projects/generated_names/duplicate_function_names/gleam.toml create mode 100644 fixtures/projects/generated_names/duplicate_function_names/src/left.gleam create mode 100644 fixtures/projects/generated_names/duplicate_function_names/src/main.gleam create mode 100644 fixtures/projects/generated_names/duplicate_function_names/src/right.gleam create mode 100644 fixtures/projects/generated_names/duplicate_module_basenames/gleam.toml create mode 100644 fixtures/projects/generated_names/duplicate_module_basenames/src/alpha/main.gleam create mode 100644 fixtures/projects/generated_names/duplicate_module_basenames/src/beta/main.gleam create mode 100644 fixtures/projects/generated_names/lifted_closures/gleam.toml create mode 100644 fixtures/projects/generated_names/lifted_closures/src/main.gleam diff --git a/crates/core/src/ir/lowerer.rs b/crates/core/src/ir/lowerer.rs index a38a5f9..12826a2 100644 --- a/crates/core/src/ir/lowerer.rs +++ b/crates/core/src/ir/lowerer.rs @@ -2438,6 +2438,7 @@ mod tests { use crate::source::{SourceFile, SourceFileId}; use crate::{ast, parse, project, resolve, types}; use std::fs; + use std::path::{Path, PathBuf}; use tempfile::tempdir; fn lower_source(source: &str) -> Module { @@ -2458,6 +2459,19 @@ mod tests { lower(typed).expect_err("lowering should fail") } + fn fixture_project(path: &str) -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join("fixtures/projects") + .join(path) + } + + fn lower_project_fixture(path: &str) -> Module { + let project = project::load_project(fixture_project(path)).expect("load project fixture"); + let typed = types::check_project(&project).expect("type check project fixture"); + lower_project(typed).expect("lower project fixture") + } + #[test] fn lowers_project_functions_to_structured_backend_names() { let dir = tempdir().expect("tempdir"); @@ -2528,6 +2542,70 @@ mod tests { assert!(function_value.name.contains("$mod$x6d61696e$fn$x6964")); } + #[test] + fn fixture_duplicate_function_names_link_without_collision() { + let module = lower_project_fixture("generated_names/duplicate_function_names"); + + let id_names = module + .linked_names + .iter() + .filter(|name| name.source_name.ends_with(".id")) + .collect::>(); + assert_eq!(id_names.len(), 2); + assert!(id_names.iter().any(|name| name.source_name == "left.id")); + assert!(id_names.iter().any(|name| name.source_name == "right.id")); + assert_ne!(id_names[0].generated_name, id_names[1].generated_name); + assert_eq!(module.functions.len(), 3); + } + + #[test] + fn fixture_duplicate_module_basenames_link_without_collision() { + let module = lower_project_fixture("generated_names/duplicate_module_basenames"); + + let value_names = module + .linked_names + .iter() + .filter(|name| name.source_name.ends_with(".value")) + .collect::>(); + assert_eq!(value_names.len(), 2); + assert!(value_names.iter().any(|name| name.source_name == "alpha/main.value")); + assert!(value_names.iter().any(|name| name.source_name == "beta/main.value")); + assert_ne!(value_names[0].generated_name, value_names[1].generated_name); + } + + #[test] + fn fixture_dependency_module_name_overlap_keeps_root_package_names() { + let module = lower_project_fixture("generated_names/dependency_module_overlap"); + + assert_eq!(module.linked_names.len(), 1); + let name = &module.linked_names[0]; + assert_eq!(name.source_name, "shared.value"); + assert!( + name.generated_name + .contains("$pkg$x646570656e64656e63795f6d6f64756c655f6f7665726c6170$") + ); + assert!(name.generated_name.contains("$mod$x736861726564$")); + } + + #[test] + fn fixture_lifted_closures_receive_generated_helper_names() { + let module = lower_project_fixture("generated_names/lifted_closures"); + + let helper = module + .linked_names + .iter() + .find(|name| name.generated_name.contains("$helper$lifted$")) + .expect("lifted closure helper name"); + assert_eq!(helper.kind, LinkedNameKind::Helper); + assert_eq!(helper.source_name, "main.__anon_0"); + assert!( + module + .functions + .iter() + .any(|function| function.name == helper.generated_name) + ); + } + #[test] fn namespaces_project_host_import_wrappers_without_mangling_abi_names() { let dir = tempdir().expect("tempdir"); diff --git a/docs/internal/tasks/14_project_compilation_and_dependencies.md b/docs/internal/tasks/14_project_compilation_and_dependencies.md index 39b9e10..0b45741 100644 --- a/docs/internal/tasks/14_project_compilation_and_dependencies.md +++ b/docs/internal/tasks/14_project_compilation_and_dependencies.md @@ -42,7 +42,7 @@ The goal here is to make linked project names deterministic and collision-free. - [x] Detect generated-name collisions deterministically and report the source declarations that caused them. - [x] Show source names and generated names in linked IR debug dumps. -- [ ] Add fixtures for duplicate function names in different modules, duplicate +- [x] Add fixtures for duplicate function names in different modules, duplicate module basenames, dependency module name overlap, and lifted closures. ### Examples diff --git a/fixtures/projects/generated_names/dependency_module_overlap/gleam.toml b/fixtures/projects/generated_names/dependency_module_overlap/gleam.toml new file mode 100644 index 0000000..79c5948 --- /dev/null +++ b/fixtures/projects/generated_names/dependency_module_overlap/gleam.toml @@ -0,0 +1,7 @@ +name = "dependency_module_overlap" +version = "1.0.0" +description = "Generated-name fixture with project and dependency module-name overlap." +licences = ["Apache-2.0"] + +[dependencies] +overlap_dep = { path = "build/packages/overlap_dep" } diff --git a/fixtures/projects/generated_names/dependency_module_overlap/src/shared.gleam b/fixtures/projects/generated_names/dependency_module_overlap/src/shared.gleam new file mode 100644 index 0000000..54a2ca4 --- /dev/null +++ b/fixtures/projects/generated_names/dependency_module_overlap/src/shared.gleam @@ -0,0 +1,3 @@ +pub fn value() -> Int { + 1 +} diff --git a/fixtures/projects/generated_names/duplicate_function_names/gleam.toml b/fixtures/projects/generated_names/duplicate_function_names/gleam.toml new file mode 100644 index 0000000..2e56e38 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_function_names/gleam.toml @@ -0,0 +1,4 @@ +name = "duplicate_function_names" +version = "1.0.0" +description = "Generated-name fixture with the same function name in different modules." +licences = ["Apache-2.0"] diff --git a/fixtures/projects/generated_names/duplicate_function_names/src/left.gleam b/fixtures/projects/generated_names/duplicate_function_names/src/left.gleam new file mode 100644 index 0000000..b7d0608 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_function_names/src/left.gleam @@ -0,0 +1,3 @@ +pub fn id(value: Int) -> Int { + value +} diff --git a/fixtures/projects/generated_names/duplicate_function_names/src/main.gleam b/fixtures/projects/generated_names/duplicate_function_names/src/main.gleam new file mode 100644 index 0000000..e9f0824 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_function_names/src/main.gleam @@ -0,0 +1,6 @@ +import left +import right + +pub fn run() -> Int { + left.id(right.id(1)) +} diff --git a/fixtures/projects/generated_names/duplicate_function_names/src/right.gleam b/fixtures/projects/generated_names/duplicate_function_names/src/right.gleam new file mode 100644 index 0000000..366cda8 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_function_names/src/right.gleam @@ -0,0 +1,3 @@ +pub fn id(value: Int) -> Int { + value + 1 +} diff --git a/fixtures/projects/generated_names/duplicate_module_basenames/gleam.toml b/fixtures/projects/generated_names/duplicate_module_basenames/gleam.toml new file mode 100644 index 0000000..97e1db6 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_module_basenames/gleam.toml @@ -0,0 +1,4 @@ +name = "duplicate_module_basenames" +version = "1.0.0" +description = "Generated-name fixture with repeated file basenames in distinct modules." +licences = ["Apache-2.0"] diff --git a/fixtures/projects/generated_names/duplicate_module_basenames/src/alpha/main.gleam b/fixtures/projects/generated_names/duplicate_module_basenames/src/alpha/main.gleam new file mode 100644 index 0000000..54a2ca4 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_module_basenames/src/alpha/main.gleam @@ -0,0 +1,3 @@ +pub fn value() -> Int { + 1 +} diff --git a/fixtures/projects/generated_names/duplicate_module_basenames/src/beta/main.gleam b/fixtures/projects/generated_names/duplicate_module_basenames/src/beta/main.gleam new file mode 100644 index 0000000..a9c3165 --- /dev/null +++ b/fixtures/projects/generated_names/duplicate_module_basenames/src/beta/main.gleam @@ -0,0 +1,3 @@ +pub fn value() -> Int { + 2 +} diff --git a/fixtures/projects/generated_names/lifted_closures/gleam.toml b/fixtures/projects/generated_names/lifted_closures/gleam.toml new file mode 100644 index 0000000..a7010eb --- /dev/null +++ b/fixtures/projects/generated_names/lifted_closures/gleam.toml @@ -0,0 +1,4 @@ +name = "lifted_closures" +version = "1.0.0" +description = "Generated-name fixture with lifted anonymous closure helpers." +licences = ["Apache-2.0"] diff --git a/fixtures/projects/generated_names/lifted_closures/src/main.gleam b/fixtures/projects/generated_names/lifted_closures/src/main.gleam new file mode 100644 index 0000000..bb46700 --- /dev/null +++ b/fixtures/projects/generated_names/lifted_closures/src/main.gleam @@ -0,0 +1,8 @@ +fn call(value: Int, callback: fn(Int) -> Int) -> Int { + callback(value) +} + +pub fn run(seed: Int) -> Int { + let add_seed = fn(value) { value + seed } + call(1, add_seed) +} -- 2.51.2