Skip to content

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

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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