Skip to content

Confusing error & warning message when importing a function and using it as if it were a module #81232

Closed
@joshuawarner32

Description

@joshuawarner32

When importing a function and using it (accidentally!) as if it were a module, rustc says the name doesn't exist. This lead me to quite a bit of head-scratching. I would humbly suggest either clarifying the error message in such a case, or adding a 'note:' with such a clarification.

I tried this code (playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e9602022b26521481d93c47608503185):

// Context: This is an attempt to distill down the essence of a confusing set of
// error messages I saw while using rust at my day job. Apologies if this is a little wordy,
// but I feel it's important to set context to understand my mindset when I hit this issue.
//
// My task of the day involved setting up some communication between threads.
// I decided to use crossbeam for this. I glanced at the docs briefly, as well
// as some existing uses laying around in our codebase.
//
// Somehow, not having looked in detail, I built up the faulty assumption
// that the relevant pieces of crossbeam_channel would be organized something like this:
//
// ```
// // crossbeam_channel/lib.rs
// pub mod bounded {
//     pub struct Sender { /*...*/ }
//     pub struct Receiver { /*...*/ }
//     pub fn channel() -> (Sender, Receiver) { /*...*/}
// }
// pub mod unbounded {
//     pub struct Sender { /*...*/ }
//     pub struct Receiver { /*...*/ }
//     pub fn channel() -> (Sender, Receiver) { /*...*/}
// }
// pub mod oneshot { // I know now this is not a thing in crossbeam ;)
//     pub struct Sender { /*...*/ }
//     pub struct Receiver { /*...*/ }
//     pub fn channel() -> (Sender, Receiver) { /*...*/}
// }
// ```
//
// This is of course _wrong_, and the real code is more like:
//
// ```
// // crossbeam_channel/lib.rs
// pub struct Sender { /*...*/ }
// pub struct Receiver { /*...*/ }
// pub fn bounded(bound: usize) -> (Sender, Receiver) { /*...*/}
// pub fn unbounded() -> (Sender, Receiver) { /*...*/}
// ```
//
// but setting that aside for the moment, I decided to import what I _thought_
// was a module (crossbeam_channel::unbounded), and start using types/functions from it.
//
// I thought I had an existing import of 'unbounded' elsewhere in the file, so I decided to
// rename the crossbeam import with `as`, like so:

use crossbeam_channel::unbounded as crossbeam_unbounded; // 0.8.0
// ^^^ warning: unused import: `crossbeam_channel::unbounded as crossbeam_unbounded`
//
// The fact that I see _both_ this warning and the undeclared error below made this more confusing.
// Note, in the real compiler output, both errors appear _before_ the warning. 

struct MyStruct {
    receiver: crossbeam_unbounded::Receiver<()>,
    // ^^^ 'error[E0433]: failed to resolve: use of undeclared crate or module `crossbeam_unbounded`'
    //
    // Suggestion: it'd be really helpful to either modify the error message itself
    // or else add a 'note:', to make it clear that crossbeam_unbounded _is_ in scope,
    // it's just a function rather than a module.
    //
    // e.g. 'note: there is a `crossbeam_unbounded` is in scope, but it's a function not a module'
}

fn my_fn(unimportant_param: usize) -> MyStruct {
    let (sender, receiver) = crossbeam_unbounded::channel();
    // ^^^ 'error[E0433]: failed to resolve: use of undeclared crate or module `crossbeam_unbounded`'
    // (same suggestion here as above)

    // do something with sender... or whatever
    MyStruct {
        receiver,
    }
}

// At this point, I was a bit flabargasted - the compiler clearly sees the import!
//
// I double-checked that I used the same name, copy-pasting one on top of the other.
//
// Then I thought, "oh maybe there's some intervening mod declaration so these aren't in the same scope"
// (the real file is much, _much_ longer)
//
// But nope, they're definitely in the same scope.
//
// I moved the first use of `crossbeam_unbounded` to directly after the import,
// and of course received the same error.

I expected to see this happen:

  • The compiler should let me know, somewhere in it's output, that the name is actually in scope, but it's not the right 'kind' of name (e.g. a function instead of a module).
  • This would be a great use-case for a 'note:' or a 'help:' output

Instead, this happened:

  • I scratched my head for ~30 minutes, thinking I was running into some sort of bizarre compiler bug where the compiler somehow wasn't tracking the imports correctly
  • I then figured out that the error was actually mine.

Meta

rustc --version --verbose:

rustc 1.49.0 (e1884a8e3 2020-12-29)
binary: rustc
commit-hash: e1884a8e3c3e813aada8254edfa120e85bf5ffca
commit-date: 2020-12-29
host: x86_64-apple-darwin
release: 1.49.0

(this also repros on the latest nightly in the playground, as of writing)

Not sure how difficult it would be to implement this, but if it's a reasonable 'beginner' issue, I'd be down to try to implement this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsC-bugCategory: This is a bug.D-confusingDiagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions