Trying to build my project and fix any errors - E0308 is clogging the log

Hello!
As you can probably tell from the title, rustc error E0308 is giving me a bit of a headache.
I've been writing an assembler, and as I just finished the lexer I wanted to build the program and fix any errors or typos I come across. However, there is one error - E0308 - that I have no idea how to fix (or, more bluntly, disable or work around). Essentially, in my code, if I come across an error during the lexical analysis / tokenization process I have whatever helper function that came across the error return a Result::Err. However, for some reason, in the places where I want to return with an error, rustc apparently isn't expecting it and so this triggers E0308.
As I said when I asked this same question on Stack Overflow, I do not care what the compiler is expecting. I'm trying to write an assembler here. Is there anything I can do about this?

There's no way to tell the compiler to ignore type mismatch errors like E0308. Could you post some code that illustrates how this error arises in your case? Otherwise it's hard to give you useful advice.

That looks like you're trying to return error from the function declared as non-fallible, like this:

fn nop_if_positive(x: i32) -> u32 {
    if x < 0 {
        return Err("Negative");
    }
    x as u32
}

I just ask you one question: what should the caller do, if you give him an error instead of the promised type (u32 in this example)?

1 Like

In case you weren't aware, handling returned errors (Result types) in Rust is an explicit process, not an implicit one (like throw/catch in some languages). If you want to return Err(whatever), your function needs to return a Result<NonErrorType, ErrorType> (you choose what NonErrorType and ErrorType are). And the caller of your function will have to deal with both the error and non-error cases in some way.

If you want to just bail on your entire program instead, you can panic!("Some error message") instead of return Error(...). Though this is generally considered bad design, especially if it's an error case you expect to encounter sometimes.

Here's the Rust Book chapter on error handling for more.

Here's the entire immediate function.

fn immediate(s: &str) -> Result<Token, String> {
    let bin_regex = Regex::new("[01]+").unwrap();
    let dec_regex = Regex::new("[0-9]+").unwrap();
    let hex_regex = Regex::new("[0-9a-fA-F]+").unwrap();
    let mut imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Word);
    let mut content = "";

    if s.starts_with("#") {
        // Numeric Immediate
        if s.starts_with("#%") {
            // Binary
            if bin_regex.is_match(&s[2..18]) {
                // 16-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Binary, ImmediateSize::Word);
                content = &s[0..18];
            } else if bin_regex.is_match(&s[2..10]) {
                // 8-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Binary, ImmediateSize::Byte);
                content = &s[0..10];
            } else {
                // INVALID
                Err(format!("Invalid binary immediate"))
            }
        } else if s.starts_with("#$") {
            // Hexadecimal
            if hex_regex.is_match(&s[2..6]) {
                // 16-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Hexadecimal, ImmediateSize::Word);
                content = &s[0..6];
            } else if hex_regex.is_match(&s[2..4]) {
                // 8-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Hexadecimal, ImmediateSize::Byte);
                content = &s[0..4];
            } else {
                // INVALID
                Err(format!("Invalid hexadecimal immediate"))
            }
        } else {
            // Decimal

            // Behold, the LENGTH-FINDER-INATOR!
            // it's just a loop though...
            let mut l = 1;
            loop {
                if s[l..l+1] == " " || s[l..l+1] == "," || s[l..l+2] == "\r\n" || s[l..l+1] == "\n" {
                    break;
                }
                l = l + 1;
            }

            let poss_dec = &s[1..l];
            if dec_regex.is_match(poss_dec) {
                // VALID
                if usize::from_str_radix(poss_dec, 10) <= 255 {
                    // 8-bit
                    imm_info = ImmediateInfo::new(ValueType::Decimal, ImmediateSize::Byte);
                    content = &s[0..l];
                } else if usize::from_str_radix(poss_dec, 10) <= 65535 {
                    // 16-bit
                    imm_info = ImmediateInfo::new(ValueType::Decimal, ImmediateSize::Word);
                    content = &s[0..l];
                } else {
                    // Out of bounds
                    Err(format!("Decimal immediate out of range"))
                }
            } else {
                // INVALID
              fn immediate(s: &str) -> Result<Token, String> {
    let bin_regex = Regex::new("[01]+").unwrap();
    let dec_regex = Regex::new("[0-9]+").unwrap();
    let hex_regex = Regex::new("[0-9a-fA-F]+").unwrap();
    let mut imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Word);
    let mut content = "";

    if s.starts_with("#") {
        // Numeric Immediate
        if s.starts_with("#%") {
            // Binary
            if bin_regex.is_match(&s[2..18]) {
                // 16-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Binary, ImmediateSize::Word);
                content = &s[0..18];
            } else if bin_regex.is_match(&s[2..10]) {
                // 8-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Binary, ImmediateSize::Byte);
                content = &s[0..10];
            } else {
                // INVALID
                Err(format!("Invalid binary immediate"))
            }
        } else if s.starts_with("#$") {
            // Hexadecimal
            if hex_regex.is_match(&s[2..6]) {
                // 16-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Hexadecimal, ImmediateSize::Word);
                content = &s[0..6];
            } else if hex_regex.is_match(&s[2..4]) {
                // 8-bit VALID
                imm_info = ImmediateInfo::new(ValueType::Hexadecimal, ImmediateSize::Byte);
                content = &s[0..4];
            } else {
                // INVALID
                Err(format!("Invalid hexadecimal immediate"))
            }
        } else {
            // Decimal

            // Behold, the LENGTH-FINDER-INATOR!
            // it's just a loop though...
            let mut l = 1;
            loop {
                if s[l..l+1] == " " || s[l..l+1] == "," || s[l..l+2] == "\r\n" || s[l..l+1] == "\n" {
                    break;
                }
                l = l + 1;
            }

            let poss_dec = &s[1..l];
            if dec_regex.is_match(poss_dec) {
                // VALID
                if usize::from_str_radix(poss_dec, 10) <= 255 {
                    // 8-bit
                    imm_info = ImmediateInfo::new(ValueType::Decimal, ImmediateSize::Byte);
                    content = &s[0..l];
                } else if usize::from_str_radix(poss_dec, 10) <= 65535 {
                    // 16-bit
                    imm_info = ImmediateInfo::new(ValueType::Decimal, ImmediateSize::Word);
                    content = &s[0..l];
                } else {
                    // Out of bounds
                    Err(format!("Decimal immediate out of range"))
                }
            } else {
                // INVALID
                Err(format!("Invalid decimal immediate"))
            }
        }
    } else if s.starts_with("'") {
        // ASCII Character Immediate
        if &s[1..2] == '\\' {
            // Escape
            if &s[2..3] == "x" {
                // ASCII character ID value
                if &s[5..6] == '\'' {
                    // character immediate is properly closed
                    imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Character);
                    content = &s[0..6]
                } else {
                    // error!
                    Err(format!("Character immediate not closed"))
                }
            }

            if &s[3..4] == '\'' {
                // character immediate is properly closed
                imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Character);
                content = &s[0..4]
            } else {
                // error!
                Err(format!("Character immediate not closed"))
            }
        } else {
            // Regular character
            if &s[2..3] == '\'' {
                // character immediate is properly closed
                imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Character);
                content = &s[0..3]
            } else {
                // error!
                Err(format!("Character immediate not closed"))
            }
        }
    } else if s.starts_with("\"") {
        // ASCII String Immediate

        // Behold, the LENGTH-FINDER-INATOR!
        // it's just a loop though...
        let mut l = 1;
        loop {
            if s[l..l+1] == "\"" {
                if s[l-1..l] == "\\" {
                    if s[l-2..l-1] == "\\" {
                        break;
                    }
                } else {
                    break;
                }
            }
            l = l + 1;
        }

        content = &s[0..l];
        imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::String);
    } else {
        // Not an immediate.
        Err(format!("e"))
    }

    match imm_info {
        Ok(i) => Ok(Token::new(content, TokenInfo::Immediate(i))),
        Err(e) => Err(format!("If you see this message, run."))
    }
}  Err(format!("Invalid decimal immediate"))
            }
        }
    } else if s.starts_with("'") {
        // ASCII Character Immediate
        if &s[1..2] == '\\' {
            // Escape
            if &s[2..3] == "x" {
                // ASCII character ID value
                if &s[5..6] == '\'' {
                    // character immediate is properly closed
                    imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Character);
                    content = &s[0..6]
                } else {
                    // error!
                    Err(format!("Character immediate not closed"))
                }
            }

            if &s[3..4] == '\'' {
                // character immediate is properly closed
                imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Character);
                content = &s[0..4]
            } else {
                // error!
                Err(format!("Character immediate not closed"))
            }
        } else {
            // Regular character
            if &s[2..3] == '\'' {
                // character immediate is properly closed
                imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::Character);
                content = &s[0..3]
            } else {
                // error!
                Err(format!("Character immediate not closed"))
            }
        }
    } else if s.starts_with("\"") {
        // ASCII String Immediate

        // Behold, the LENGTH-FINDER-INATOR!
        // it's just a loop though...
        let mut l = 1;
        loop {
            if s[l..l+1] == "\"" {
                if s[l-1..l] == "\\" {
                    if s[l-2..l-1] == "\\" {
                        break;
                    }
                } else {
                    break;
                }
            }
            l = l + 1;
        }

        content = &s[0..l];
        imm_info = ImmediateInfo::new(ValueType::ASCII, ImmediateSize::String);
    } else {
        // Not an immediate.
        Err(format!("e"))
    }

    match imm_info {
        Ok(i) => Ok(Token::new(content, TokenInfo::Immediate(i))),
        Err(e) => Err(format!("If you see this message, run."))
    }
}

Obviously it still has some typos and errors, but I haven't finished correcting them and therefore haven't committed the fixes yet.

1 Like

On this line:

    } else {
        // INVALID
        Err(format!("Invalid binary immediate"))
    }

you need to use the return keyword if you want to return early with an error:

    } else {
        // INVALID
        return Err(format!("Invalid binary immediate"));
    }

Many of the errors in this file are similar to this, though it looks like there are also a lot of other errors. My biggest advice is to always correct the compilation errors in your existing code before writing new code. It might feel like it's slowing you down at first, but it will be much faster in the long run.

3 Likes

Yeah, as I said this came across in the "compile and fix errors that crop up if I can" process so there are definitely a bunch of errors in here. But I had no clue how to handle E0308 which is why I ended up here.

I'll try this out and see if it fixes it.

What I'm talking about is a lot more frequent: You should be compiling the program after writing, say, ten lines of code, not two thousand lines. Each time you create or modify any function, you should immediately compile the program and fix any errors. The fastest way to write a big program that works is to extend a slightly smaller program that works.

You can even use an IDE or editor like rust-analyzer or IntelliJ Rust that will highlight and fix errors, as you type!

2 Likes

I've actually been using IntelliJ Rust all this time, but there are certain errors it didn't catch (for example, pretty much any time I used from_str_radix() wrong it didn't catch any errors because for some reason it doesn't recognize it as a known function).

from_str_radix isn't a single function -- every primitive integer type has an associated function of that name:

You have to tell the compiler which of these you want by qualifying the name, e.g. u32::from_str_radix.

ETA: Ahh, sorry, I see you're calling usize::from_str_radix in the snippet you posted above, so you're aware of this already. If you can extract some example code that triggers the IntelliJ issue you mentioned we might be able to figure out what's going on.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.