shepmaster / snafu

Easily assign underlying errors into domain-specific errors while adding context
https://docs.rs/snafu/
Apache License 2.0
1.45k stars 61 forks source link

Compilation errors when Error is inside submodule #198

Closed ludiazv closed 4 years ago

ludiazv commented 4 years ago

Hi, I'm testing snafu and I'm trying to use it in submodule but I can't get it to compile. This is the test code:

mod error_module {
    pub use snafu::{ResultExt, Snafu};

    #[derive(Debug, Snafu)]
    pub enum Error {
        #[snafu(display("This is a test errror {}: {}", tests, source))]
        TestError {
            tests: String,
            source: std::io::Error,
        },
    }

    pub type Result<T, E = Error> = std::result::Result<T, E>;
}

use crate::error_module::*;
use std::fs;

fn test_error() -> Result<()> {
    let _ = fs::read("this will fail").context(TestError {
        tests: "some value".to_string(),
    })?;
    Ok(())
}

fn main() {
    println!("{:?}", test_error());
}

The output is the following:

error[E0422]: cannot find struct, variant or union type `TestError` in this scope
  --> src/main.rs:21:44
   |
21 |  let _=fs::read("this will fail").context( TestError { tests:"some value".to_string() })?;
   |                                            ^^^^^^^^^ not found in this scope
help: possible candidates are found in other modules, you can import them into scope
   |
16 | use crate::error_module::Error::TestError;
   |
16 | use crate::error_module::TestError;
   |

error: aborting due to previous error

Changing line with the error to:

let _=fs::read("this will fail").context( error_module::TestError { tests:"some value".to_string() })?;

I get this:

error[E0603]: struct `TestError` is private
  --> src/main.rs:21:58
   |
21 |  let _=fs::read("this will fail").context( error_module::TestError { tests:"some value".to_string() })?;
   |                                                          ^^^^^^^^^

error: aborting due to previous error

If I try this:

let _=fs::read("this will fail").context( error_module::Error::TestError { tests:"some value".to_string() })?;

I get:

   Compiling lua v0.1.0 (/home/ldiaz/experiments/rust/lua)
error[E0063]: missing field `source` in initializer of `error_module::Error`
  --> src/main.rs:21:44
   |
21 |  let _=fs::read("this will fail").context( error_module::Error::TestError { tests:"some value".to_string() })?;
   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `source`

error[E0277]: the trait bound `error_module::Error: snafu::IntoError<_>` is not satisfied
  --> src/main.rs:21:35
   |
21 |  let _=fs::read("this will fail").context( error_module::Error::TestError { tests:"some value".to_string() })?;
   |                                   ^^^^^^^ the trait `snafu::IntoError<_>` is not implemented for `error_module::Error`

error: aborting due to 2 previous errors

The code works fine if I remove the error_module What I'm doing wrong?. I'm using rust 2018, rustc 1.37 on linux.

Thanks

shepmaster commented 4 years ago

Does this section of the user's guide address your issue?

It looks like you need

#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum Error {
shepmaster commented 4 years ago

Opinion-wise, I don't think there's much benefit to placing your Error type in a module if you are going to be creating it from outside of that module.

ludiazv commented 4 years ago

Thanks!!!! It worked! I tried with visibility but somehow I wrote the directive wrong. I wnated to same same error across various module. It could an anti-pattern but for small programs will reduce the boilerplate and simplify error management at main program level as we have to deal with unique Result.

Thank you for your help.

shepmaster commented 4 years ago

I wnated to same same error across various module

That's fine, I'd just define the error type at the root of your hierarchy, instead of putting it in a module at all.