Change:
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:

Discussion:
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(),

else_ty) } None => { <del> check_block_no_value(fcx, then_blk); ty::mk_nil() </del> <ins> infer::common_supertype(fcx.infcx(), infer::IfExpressionWithNoElse(sp), false, then_ty, ty::mk_nil()) </ins> } };

infer::RelateOutputImplTypes(_) => "mismatched types", infer::MatchExpressionArm(_, _) => "match arms have incompatible types", infer::IfExpression(_) => "if and else have incompatible types", <ins> infer::IfExpressionWithNoElse(_) => "if may be missing an else clause", </ins> }; self.tcx.sess.span_err(

infer::IfExpression(_) => { format!("if and else have compatible types") } <ins> infer::IfExpressionWithNoElse(_) => { format!("if may be missing an else clause") } </ins> }; match self.values_str(&trace.values) {

// Computing common supertype in an if expression IfExpression(Span), <ins> // Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse(Span) </ins> } /// See `error_reporting.rs` for more details

RelateOutputImplTypes(span) => span, MatchExpressionArm(match_span, _) => match_span, IfExpression(span) => span, <ins> IfExpressionWithNoElse(span) => span </ins> } } }

IfExpression(a) => { format!("IfExpression({})", a.repr(tcx)) } <ins> IfExpressionWithNoElse(a) => { format!("IfExpressionWithNoElse({})", a.repr(tcx)) } </ins> } } }

// option. This file may not be copied, modified, or distributed // except according to those terms. <del> // error-pattern:mismatched types: expected `()`, found `bool` </del> extern crate debug; fn main() { let a = if true { true }; <ins> //~^ ERROR if may be missing an else clause: expected `()`, found `bool` (expected (), found bool) </ins> println!("{:?}", a); }

<ins> // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. fn main() { let a = if true { 0 } else if false { //~^ ERROR if may be missing an else clause: expected `()`, found `<generic integer #1>` 1 }; } </ins>