Ashton Scott Snapp
Ashton Scott Snapp

Reputation: 33

Returning a Result::Err() causes E0308 and its clogging my error log

I'm trying to program an assembler for an as-of-yet unimplemented processor architecture using Rust. I just finished the lexer and am trying to build it and fix any typos and errors I have made along the way.

However, one error that keeps clogging the build log is error E0308: mismatched types. Essentially, every time I try to return a Result::Err (because the source file contained an error) somewhere the rust compiler isn't expecting me to, I get this error. I do not care what the rust compiler expects. I'm trying to write an assembler here. What can I do to stop E0308 from occurring?

Example: Here's a bit of my program where this error was triggered.

if bin_regex.is_match(&s[1..25]) {
    // Absolute Memory
    add_info = AddressInfo::new(ValueType::Binary, AddressMode::AbsoluteMemory);
    content = &s[0..25];
} else if bin_regex.is_match(&s[1..17]) {
    if &s[17..18] == "p" {
        // Absolute Port
        add_info = AddressInfo::new(ValueType::Binary, AddressMode::AbsolutePort);
        content = &s[0..18];
    } else {
        // Zero Bank
        add_info = AddressInfo:new(ValueType::Binary, AddressMode::ZeroBank);
        content = &s[0..17];
} else if bin_regex.is_match(&s[1..9]) {
    // Zero Page
    add_info = AddressInfo::new(ValueType::Hexadecimal, AddressMode::ZeroPage);
    content = &s[0..9];
} else {
    // Error
    Err(format!("Invalid Binary address or Binary address out of range"))
}

And here's what the error looks like:

...

 error[E0308]: mismatched types
    --> src/lex.rs:407:17
     |
 401 |               } else if bin_regex.is_match(&s[1..9]) {
     |  ____________________-
 402 | |                 // Zero Page
 403 | |                 add_info = AddressInfo::new(ValueType::Binary, AddressMode::ZeroPage);
 404 | |                 content = &s[0..9];
 ... | |
 407 | |                 Err(format!("Invalid Binary address or Binary address out of range"))
     | |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `std::result::Result`
 408 | |             }
     | |_____________- expected this to be `()`
     |
     = note: expected unit type `()`
                     found enum `std::result::Result<_, std::string::String>`
...

Upvotes: 1

Views: 248

Answers (2)

Michael Anderson
Michael Anderson

Reputation: 73480

If you just want your application to exit when your error case occurs, then you should use panic! rather than Err(...) (as Err is a constructor that just creates a Result object and does nothing with it)


pub fn doit() {
  if ... {
    // ...
  } else {
    // Error
    panic!("Invalid Binary address or Binary address out of range"))
  }
}

Generally using panic! is frowned upon to some degree. But for initial work, it is often OK. Later you may want to change the function to return a Result so you can do better error handling. In that case you return an Err.

pub fn doit() -> Result<(), String> {
  if ... {
    // ...
  } else {
    // Error
    return Err(format!("Invalid Binary address or Binary address out of range"));
  }
  Ok(())
}

The next step is to use a specific error type to encode the errors

#[derive(Debug, Clone)]
pub enum Error {
   InvalidAddressError,
   ...
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Invalid Binary address or Binary address out of range")
    }
}

pub fn doit() -> Result<(), Error> {
  if ... {
    // ...
  } else {
    // Error
    return Err(Error::InvalidAddressError);
  }
  Ok(())
}

Upvotes: 0

orlp
orlp

Reputation: 117681

Errors aren't special in Rust. If you wish to return an error from a function, that function must have the Result return type. Suppose we have this function:

fn divide(a: i64, b: i64) -> i64 {
    a / b
}

But there's a problem in case b == 0, so we'd like to report an error instead:

fn divide(a: i64, b: i64) -> i64 {
    if b == 0 {
        Err("divide by zero")
    } else {
        a / b
    }
}

But this runs into your error:

error[E0308]: mismatched types
 --> src/main.rs:3:13
  |
1 |     fn divide(a: i64, b: i64) -> i64 {
  |                                  --- expected `i64` because of return type
2 |         if b == 0 {
3 |             Err("divide by zero")
  |             ^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found enum `std::result::Result`
  |
  = note: expected type `i64`
             found enum `std::result::Result<_, &str>`

What we must do is give the function the appropriate type, that allows us to return results that can have errors. We must also wrap any result that isn't an error in Ok(...):

fn divide(a: i64, b: i64) -> Result<i64, &'static str> {
    if b == 0 {
        Err("divide by zero")
    } else {
        Ok(a / b)
    }
}

Note that it's not a good practice to use raw strings as error types - this is just for a quick example.

Upvotes: 4

Related Questions