Reputation: 33
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
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
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