Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

stop warning for modules that are used only by private functions

author
Giacomo Cavalieri
committer
Louis Pilfold
date (Sep 7, 2025, 2:32 PM +0100) commit 064d8948 parent f7dc3b67 change-id xuzpvokp
+139 -36
+9 -4
CHANGELOG.md
··· 304 304 305 305 ([Surya Rose](https://github.com/GearsDatapacks)) 306 306 307 - - The "Add type annotations" and "Generate function" code actions now ignore type 308 - variables defined in other functions, improving the generated code. For example: 307 + - The "Add type annotations" and "Generate function" code actions now ignore 308 + type variables defined in other functions, improving the generated code. 309 + For example: 309 310 310 311 ```gleam 311 312 fn something(a: a, b: b, c: c) -> d { todo } ··· 369 370 370 371 ### Bug fixes 371 372 372 - - Fixed a bug where literals using `\u{XXXX}` syntax in bit array pattern segments were not 373 - translated to Erlang's `\x{XXXX}` syntax correctly. 373 + - Fixed a bug where literals using `\u{XXXX}` syntax in bit array pattern 374 + segments were not translated to Erlang's `\x{XXXX}` syntax correctly. 374 375 ([Benjamin Peinhardt](https://github.com/bcpeinhardt)) 375 376 376 377 - Fixed a bug where `echo` could crash on JavaScript if the module contains ··· 433 434 - Fixed a bug where the compiler would reference a redeclared variable in a let 434 435 assert message, instead of the original variable, on the Erlang target. 435 436 ([Danielle Maywood](https://github.com/DanielleMaywood)) 437 + 438 + - Fixed a bug where the compiler would report an imported module as unused if it 439 + were used by private functions only. 440 + ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
+60 -5
compiler-core/src/reference.rs
··· 1 - use std::collections::HashMap; 1 + use std::collections::{HashMap, HashSet}; 2 2 3 3 use crate::ast::{Publicity, SrcSpan}; 4 4 use bimap::{BiMap, Overwritten}; ··· 84 84 graph: StableGraph<(), (), Directed>, 85 85 entities: BiMap<Entity, NodeIndex>, 86 86 current_node: NodeIndex, 87 - public_entities: Vec<Entity>, 87 + public_entities: HashSet<Entity>, 88 88 entity_information: HashMap<Entity, EntityInformation>, 89 89 90 90 /// The locations of the references to each value in this module, used for ··· 193 193 self.create_node_and_maybe_shadow(entity.clone(), self.current_node); 194 194 match publicity { 195 195 Publicity::Public | Publicity::Internal { .. } => { 196 - self.public_entities.push(entity.clone()); 196 + let _ = self.public_entities.insert(entity.clone()); 197 197 } 198 198 Publicity::Private => {} 199 199 } ··· 223 223 }; 224 224 match publicity { 225 225 Publicity::Public | Publicity::Internal { .. } => { 226 - self.public_entities.push(entity.clone()); 226 + let _ = self.public_entities.insert(entity.clone()); 227 227 } 228 228 Publicity::Private => {} 229 229 } ··· 257 257 }; 258 258 match publicity { 259 259 Publicity::Public | Publicity::Internal { .. } => { 260 - self.public_entities.push(entity.clone()); 260 + let _ = self.public_entities.insert(entity.clone()); 261 261 } 262 262 Publicity::Private => {} 263 263 } ··· 423 423 } 424 424 } 425 425 426 + for (entity, _) in self.entities.iter() { 427 + let Some(index) = self.entities.get_by_left(entity) else { 428 + continue; 429 + }; 430 + 431 + if self.public_entities.contains(entity) { 432 + self.mark_entity_as_used(&mut unused_values, entity, *index); 433 + } else { 434 + // If the entity is not public, we still want to mark referenced 435 + // imports as used. 436 + self.mark_referenced_imports_as_used(&mut unused_values, entity, *index); 437 + } 438 + } 439 + 426 440 unused_values 427 441 } 428 442 ··· 437 451 if let Some(entity) = self.entities.get_by_right(&node) { 438 452 self.mark_entity_as_used(unused, entity, node); 439 453 } 454 + } 455 + } 456 + } 457 + 458 + fn mark_referenced_imports_as_used( 459 + &self, 460 + unused: &mut HashMap<Entity, EntityInformation>, 461 + entity: &Entity, 462 + index: NodeIndex, 463 + ) { 464 + // If the entity is a module there's no way it can reference other 465 + // modules so we just ignore it. 466 + // This also means that module aliases do not count as using a module! 467 + if entity.layer == EntityLayer::Module { 468 + return; 469 + } 470 + 471 + for node in self.graph.neighbors_directed(index, Direction::Outgoing) { 472 + // We only want to mark referenced modules as used, so if the node 473 + // is not a module we just skip it. 474 + let Some( 475 + module @ Entity { 476 + layer: EntityLayer::Module, 477 + .. 478 + }, 479 + ) = self.entities.get_by_right(&node) 480 + else { 481 + continue; 482 + }; 483 + 484 + // If the value appears in the module import list, it doesn't count 485 + // as using it! 486 + let is_imported_type = self 487 + .type_references 488 + .contains_key(&(module.name.clone(), entity.name.clone())); 489 + let is_imported_value = self 490 + .value_references 491 + .contains_key(&(module.name.clone(), entity.name.clone())); 492 + let appears_in_module_import_list = is_imported_type || is_imported_value; 493 + if !(appears_in_module_import_list) { 494 + self.mark_entity_as_used(unused, module, node); 440 495 } 441 496 } 442 497 }
-8
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_alias_only_referenced_by_unused_function.snap
··· 20 20 21 21 22 22 ----- WARNING 23 - warning: Unused imported module 24 - ┌─ /src/warning/wrn.gleam:2:1 25 - 26 - 2 │ import wibble as wobble 27 - │ ^^^^^^^^^^^^^^^^^^^^^^^ This imported module is never used 28 - 29 - Hint: You can safely remove it. 30 - 31 23 warning: Unused private function 32 24 ┌─ /src/warning/wrn.gleam:4:1 33 25
-11
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_alias_only_referenced_by_unused_function_with_unqualified.snap
··· 24 24 25 25 26 26 ----- WARNING 27 - warning: Unused imported module alias 28 - ┌─ /src/warning/wrn.gleam:2:29 29 - 30 - 2 │ import wibble.{type Wibble} as wobble 31 - │ ^^^^^^^^^ This alias is never used 32 - 33 - Hint: You can safely remove it. 34 - 35 - import wibble as _ 36 - 37 - 38 27 warning: Unused private function 39 28 ┌─ /src/warning/wrn.gleam:4:1 40 29
-8
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__dead_code_detection__imported_module_only_referenced_by_unused_function.snap
··· 20 20 21 21 22 22 ----- WARNING 23 - warning: Unused imported module 24 - ┌─ /src/warning/wrn.gleam:2:1 25 - 26 - 2 │ import wibble 27 - │ ^^^^^^^^^^^^^ This imported module is never used 28 - 29 - Hint: You can safely remove it. 30 - 31 23 warning: Unused private function 32 24 ┌─ /src/warning/wrn.gleam:4:1 33 25
+23
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__aliased_module_used_by_unused_function_is_not_marked_as_unused.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "import wibble as woo\nfn wobble() {\n woo.a\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + -- wibble.gleam 7 + pub const a = 1 8 + 9 + -- main.gleam 10 + import wibble as woo 11 + fn wobble() { 12 + woo.a 13 + } 14 + 15 + 16 + ----- WARNING 17 + warning: Unused private function 18 + ┌─ /src/warning/wrn.gleam:2:1 19 + 20 + 2 │ fn wobble() { 21 + │ ^^^^^^^^^^^ This private function is never used 22 + 23 + Hint: You can safely remove it.
+23
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__module_used_by_unused_function_is_not_marked_as_unused.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "import wibble\nfn wobble() {\n wibble.a\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + -- wibble.gleam 7 + pub const a = 1 8 + 9 + -- main.gleam 10 + import wibble 11 + fn wobble() { 12 + wibble.a 13 + } 14 + 15 + 16 + ----- WARNING 17 + warning: Unused private function 18 + ┌─ /src/warning/wrn.gleam:2:1 19 + 20 + 2 │ fn wobble() { 21 + │ ^^^^^^^^^^^ This private function is never used 22 + 23 + Hint: You can safely remove it.
+24
compiler-core/src/type_/tests/warnings.rs
··· 1517 1517 } 1518 1518 1519 1519 #[test] 1520 + fn module_used_by_unused_function_is_not_marked_as_unused() { 1521 + assert_warning!( 1522 + ("wibble", "pub const a = 1"), 1523 + "import wibble 1524 + fn wobble() { 1525 + wibble.a 1526 + } 1527 + " 1528 + ); 1529 + } 1530 + 1531 + #[test] 1532 + fn aliased_module_used_by_unused_function_is_not_marked_as_unused() { 1533 + assert_warning!( 1534 + ("wibble", "pub const a = 1"), 1535 + "import wibble as woo 1536 + fn wobble() { 1537 + woo.a 1538 + } 1539 + " 1540 + ); 1541 + } 1542 + 1543 + #[test] 1520 1544 fn calling_function_from_other_module_is_not_marked_unused() { 1521 1545 assert_no_warnings!( 1522 1546 ("wibble", "wibble", "pub fn println(a) { panic }"),