Reputation: 16013
I started grouping code for one of my projects into module files. I encountered a lot of warnings about unused code for functions in those modules, but the functions are actually used (privately within the module).
An example from my project:
// ...
// Line 46:
fn calc_p(word: &str, dict: &Dictionary) -> f32
{
if !dict.contains_key(word) {
return 0.0;
}
let total: u32 = dict.values().sum();
dict[word] as f32 / total as f32
}
...
But at line 13 in the same file, same module the function is clearly used:
// ...
pub fn suggest_corrections(to_be_corrected: &str, dict: &Dictionary) -> Vec<(f32, String)>
{
let candidates = create_candidates(to_be_corrected, dict);
let mut weighted_candidates = candidates
.into_iter()
.map(|w| (calc_p(&w, dict), w)) // Line 13 - calc_p used here
.collect::<Vec<_>>();
weighted_candidates.sort_by(|a, b| b.partial_cmp(a).unwrap());
weighted_candidates
}
// ...
Yet I get the compiler warning:
warning: function is never used: `calc_p`, #[warn(dead_code)] on by default
--> src/spellcheck/corrections.rs:46:1
|
46 | fn calc_p(word: &str, dict: &Dictionary) -> f32
| _^ starting here...
47 | | {
48 | | if !dict.contains_key(word) {
49 | | return 0.0;
50 | | }
51 | |
52 | | let total: u32 = dict.values().sum();
53 | | dict[word] as f32 / total as f32
54 | | }
| |_^ ...ending here
I thought maybe it's because the module corrections
is not public, but I also marked the module as public and still get the same warning.
I tried to reproduce the behaviour using the playground, but if the module is defined in the same file it seems to work. The warnings also happen for me during a TravisCI build.
Why is the function marked as unused although it's actually used in the same file in the same module?
I'm using Rust 1.15 / 1.16.
Upvotes: 3
Views: 2125
Reputation: 430961
Why is the function marked as unused although it's actually used in the same file in the same module?
Because unused code is a transitive calculation, and the code that calls that function cannot be called from outside the crate. The compiler is correct here.
The first error I see is:
warning: static item is never used: `ALPHABET`, #[warn(dead_code)] on by default
--> src/spellcheck/edits.rs:3:1
That's defined as:
src/spellcheck/edits.rs
static ALPHABET : &'static str = "abcdefghijklmnopqrstuvwxyz";
So it's not public, and can only be used from inside the module.
It's called from replaces
and inserts
. Both of those are used from edits1
, a public function. Is the module containing it (edits
) public?
src/spellcheck/mod.rs
mod edits;
pub mod corrections;
pub mod dictionary;
Nope, it is not. So where is edits1
called from? kodecheck_spellcheck::spellcheck::corrections::create_candidates
, a non-public function. This is called by suggest_corrections
, a public function, inside the public module corrections
.
Let's look up the tree...
src/lib-spellcheck.rs
// @FIXME do we really need this here or move to sub-modules?
#[macro_use]
extern crate nom;
extern crate regex;
mod spellcheck;
Ah. For whatever reason, you've decided to introduce a completely nested private module spellcheck
inside the crate (which is why the full path earlier is kodecheck_spellcheck::spellcheck::corrections::create_candidates
).
From this, we can see that kodecheck_spellcheck::spellcheck
cannot be accessed from outside the crate; it's not pub
.
Let's create an example that uses the crate. This the the best way to see if it's true and would have been easy for you to test yourself:
examples/foo.rs
extern crate kodecheck_spellcheck;
fn main() {
kodecheck_spellcheck::spellcheck::corrections::create_candidates();
}
Compiling this has the error:
error: module `spellcheck` is private
--> examples/foo.rs:4:5
|
4 | kodecheck_spellcheck::spellcheck::corrections::create_candidates();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We could also create a MCVE:
mod spellcheck {
mod edits {
static ALPHABET: &'static str = "";
pub fn edits1() {
println!("{}", ALPHABET);
}
}
pub mod corrections {
pub fn create_candidates() {
::spellcheck::edits::edits1();
}
}
}
fn main() {}
Note that this differs from your example because main
is empty. Your library crate doesn't have a main
method that calls anything. You could also explicitly specify that it's a library crate, but this is less well-known:
#![crate_type="lib"]
mod spellcheck {
mod edits {
static ALPHABET: &'static str = "";
pub fn edits1() {
println!("{}", ALPHABET);
}
}
pub mod corrections {
pub fn create_candidates() {
::spellcheck::edits::edits1();
}
}
}
Because there's a private module where all the code is, nothing outside this crate can call anything inside the crate. Therefore every method is unreachable.
To fix it, I'd suggest combining src/spellcheck/mod.rs into src/lib-spellcheck.rs. You could also just make the module public, but I see no reason to have the extra module.
I also see no reason to rename src/lib.rs to src/lib-spellcheck.rs; it's far more idiomatic to just leave it lib.rs.
Additionally, you should go ahead and become comfortable with Rust style. Braces go on the same line as the signature:
fn calc_p(word: &str, dict: &Dictionary) -> f32 {
// ...
Tools like rustfmt will help you apply the proper style.
Upvotes: 5