Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a distinct error code for "if may be missing an else clause" #36915

Merged
merged 4 commits into from
Oct 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,23 @@ fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) {
```
"##,

E0317: r##"
This error occurs when an `if` expression without an `else` block is used in a
context where a type other than `()` is expected, for example a `let`
expression:

```compile_fail,E0317
fn main() {
let x = 5;
let a = if x == 5 { 1 };
Copy link
Member

@nagisa nagisa Oct 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example can be made more relatable if written as such:

if condition {
    some_value
}

Missing semicolon after last expression in an if is likely the most common reason for this error by a large degree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That example produces the generic "mismatched types" variant of E0308 though, not "if may be missing an else clause".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it? That’s weird. I would expect else-less if as a last expression in a function body/block to produce the “if may be missing an else clause” error instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be dependent on the expected type in the expression's context:

fn foo() -> i32 {
    if true {
        5
    }
}

produces:

error[E0308]: if may be missing an else clause
 --> <anon>:2:5
  |
2 |     if true {
  |     ^ expected (), found i32
  |

However, change i32 to () and it's:

error[E0308]: mismatched types
 --> <anon>:3:9
  |
3 |         5
  |         ^ expected (), found integral variable
  |

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me -- even if you added an else, given that the expected type of this expression is (), the body would have to be changed. That is, the body and the fn signature are in conflict. We choose to blame the body. You could make a case the other way, but blaming the if seems wrong, since there is nothing you can change about the if itself (without changing something else) that would make this code compile.

Not that the compiler thinks this hard when selecting what to blame; it's semi-random. Just saying that in this case the span makes sense. It'd be nice if we could give a better error message though, explaining where the () came from.

I think that Elm does some nice tracking here. We should copy them. =)

}
```

An `if` expression without an `else` block has the type `()`, so this is a type
error. To resolve it, add an `else` block having the same type as the `if`
block.
"##,

E0398: r##"
In Rust 1.3, the default object lifetime bounds are expected to change, as
described in RFC #1156 [1]. You are getting a warning because the compiler
Expand Down
15 changes: 10 additions & 5 deletions src/librustc/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,11 +577,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
terr: &TypeError<'tcx>)
-> DiagnosticBuilder<'tcx>
{
// FIXME: do we want to use a different error code for each origin?
let mut diag = struct_span_err!(
self.tcx.sess, trace.origin.span(), E0308,
"{}", trace.origin.as_failure_str()
);
let span = trace.origin.span();
let failure_str = trace.origin.as_failure_str();
let mut diag = match trace.origin {
TypeOrigin::IfExpressionWithNoElse(_) => {
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
},
_ => {
struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
},
};
self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
diag
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/if-without-else-result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

fn main() {
let a = if true { true };
//~^ ERROR if may be missing an else clause
//~^ ERROR if may be missing an else clause [E0317]
//~| expected type `()`
//~| found type `bool`
//~| expected (), found bool
Expand Down