Skip to content

Needless return with Err and question mark #10902

@nyurik

Description

@nyurik

What it does

I sometimes see return Err(MyError::SomeError(v))?; -- which seems redundant - it has both the return AND the question mark operator. So this can be rewritten as either

  • Err(MyError::SomeError(v))?; - without the return
  • return Err(MyError::SomeError(v)); - without the question operator

The second option only works if the error type is the same as in Result<..., MyError>, otherwise it only works with the question mark.

So question - does it make sense to suggest needless return in the case where it can be expressed with a question mark? Or should the question mark be suggested to be removed in the case where it can? Or neither?

Advantage

  • shorter code - no confusion over two "return" operators

Drawbacks

  • without return might be less readable, so perhaps only for same-result-errors and remove the question mark?

Example

use thiserror::Error;

#[derive(Error, Debug)]
enum MyTopError {
    #[error("Internal Error: {0}")]
    SubError(#[from] MySubError),
    #[error("Main Error")]
    MainError,
}

#[derive(Error, Debug)]
enum MySubError {
    #[error("Value {0} too small")]
    TooSmall(i32),
}

fn foo(v: i32) -> Result<(), MyTopError> {
    if v < 5 {
        return Err(MySubError::TooSmall(v))?;
        //    This is identical to the above, but too verbose:
        // return Err(MyTopError::SubError(MySubError::TooSmall(v)));
        //    This is identical to the above, but has no "return"
        // Err(MySubError::TooSmall(v))?;
        //    This causes an error: mismatched types
        // return Err(MySubError::TooSmall(v));
    }
    if v > 100 {
        return Err(MyTopError::MainError)?;
        // Err(MyTopError::MainError)?;        // This is identical to the above, but has no "return"
        // return Err(MyTopError::MainError);  // This is identical to the above, but has no question mark
    }
    println!("v: {v}");
    Ok(())
}

fn main() {
    let v = 3;
    let r = foo(v);
    println!("r: {:?}", r);
}

Metadata

Metadata

Assignees

Labels

A-lintArea: New lints

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions