Code change:
expected: Expectation) { check_expr_has_type(fcx, cond_expr, ty::mk_bool()); <ins> // Disregard "castable to" expectations because they // can lead us astray. Consider for example `if cond // {22} else {c} as u8` -- if we propagate the // "castable to u8" constraint to 22, it will pick the // type 22u8, which is overly constrained (c might not // be a u8). In effect, the problem is that the // "castable to" expectation is not the tightest thing // we can say, so we want to drop it in this case. // The tightest thing we can say is "must unify with // else branch". Note that in the case of a "has type" // constraint, this limitation does not hold. // If the expected type is just a type variable, then don't use // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. let expected = match expected.only_has_type() { ExpectHasType(ety) => { match infer::resolve_type(fcx.infcx(), Some(sp), ety, force_tvar) { Ok(rty) if !ty::type_is_ty_var(rty) => ExpectHasType(rty), _ => NoExpectation } } _ => NoExpectation }; check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); </ins> let branches_ty = match opt_else_expr { Some(ref else_expr) => { <del> // Disregard "castable to" expectations because they // can lead us astray. Consider for example `if cond // {22} else {c} as u8` -- if we propagate the // "castable to u8" constraint to 22, it will pick the // type 22u8, which is overly constrained (c might not // be a u8). In effect, the problem is that the // "castable to" expectation is not the tightest thing // we can say, so we want to drop it in this case. // The tightest thing we can say is "must unify with // else branch". Note that in the case of a "has type" // constraint, this limitation does not hold. // If the expected type is just a type variable, then don't use // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. let expected = match expected.only_has_type() { ExpectHasType(ety) => { match infer::resolve_type(fcx.infcx(), Some(sp), ety, force_tvar) { Ok(rty) if !ty::type_is_ty_var(rty) => ExpectHasType(rty), _ => NoExpectation } } _ => NoExpectation }; check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); </del> check_expr_with_expectation(fcx, &**else_expr, expected); let else_ty = fcx.expr_ty(&**else_expr); infer::common_supertype(fcx.infcx(),

Related discussion:
text: I apologize in advance if this is a separate issue. With the map() generic function from the tutorial: That code gives a nice error message: However, remove the assignment and what should be the same error message becomes:
Yes, that is unrelated to this issue. You're seeing an expected type mismatch error since the return type of main() is () and your samples result in two different non-() results.
Thanks I was one hour into learning Rust when I came across this. I understand what is going on now. I still think the error message could be improved to mention that "expected " is referring to the return type of main(). That simple clue could help people not as familiar with Rust to remember the semicolon rule to turn a statement into an expression.
Not critical for 0.7, but improving error messages is always good. Nominating for milestone 5.
declined. this is bad but it's not a blocker.
Confirmed that the situation is unchanged.
This is still an issue.
Bug triage. Still an issue.
Very, very small change: