@@ -232,6 +232,9 @@ pub enum Expectation<'tcx> {
232232 /// We know nothing about what type this expression should have.
233233 NoExpectation ,
234234
235+ /// This expression is an `if` condition, it must resolve to `bool`.
236+ ExpectIfCondition ,
237+
235238 /// This expression should have the type given (or some subtype)
236239 ExpectHasType ( Ty < ' tcx > ) ,
237240
@@ -310,9 +313,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
310313 // no constraints yet present), just returns `None`.
311314 fn resolve ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Expectation < ' tcx > {
312315 match self {
313- NoExpectation => {
314- NoExpectation
315- }
316+ NoExpectation => NoExpectation ,
317+ ExpectIfCondition => ExpectIfCondition ,
316318 ExpectCastableToType ( t) => {
317319 ExpectCastableToType ( fcx. resolve_type_vars_if_possible ( & t) )
318320 }
@@ -328,6 +330,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
328330 fn to_option ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
329331 match self . resolve ( fcx) {
330332 NoExpectation => None ,
333+ ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
331334 ExpectCastableToType ( ty) |
332335 ExpectHasType ( ty) |
333336 ExpectRvalueLikeUnsized ( ty) => Some ( ty) ,
@@ -341,7 +344,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
341344 fn only_has_type ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
342345 match self . resolve ( fcx) {
343346 ExpectHasType ( ty) => Some ( ty) ,
344- _ => None
347+ ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
348+ NoExpectation | ExpectCastableToType ( _) | ExpectRvalueLikeUnsized ( _) => None ,
345349 }
346350 }
347351
@@ -2644,10 +2648,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
26442648 self . demand_eqtype ( expr. span , expected, ty) ;
26452649 }
26462650
2647- pub fn check_expr_has_type ( & self ,
2648- expr : & ' gcx hir:: Expr ,
2649- expected : Ty < ' tcx > ) -> Ty < ' tcx > {
2650- let mut ty = self . check_expr_with_hint ( expr, expected) ;
2651+ pub fn check_expr_has_type_or_error ( & self ,
2652+ expr : & ' gcx hir:: Expr ,
2653+ expected : Ty < ' tcx > ) -> Ty < ' tcx > {
2654+ self . check_expr_meets_expectation_or_error ( expr, ExpectHasType ( expected) )
2655+ }
2656+
2657+ fn check_expr_meets_expectation_or_error ( & self ,
2658+ expr : & ' gcx hir:: Expr ,
2659+ expected : Expectation < ' tcx > ) -> Ty < ' tcx > {
2660+ let expected_ty = expected. to_option ( & self ) . unwrap_or ( self . tcx . types . bool ) ;
2661+ let mut ty = self . check_expr_with_expectation ( expr, expected) ;
26512662
26522663 // While we don't allow *arbitrary* coercions here, we *do* allow
26532664 // coercions from ! to `expected`.
@@ -2663,7 +2674,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
26632674 ty = adj_ty;
26642675 }
26652676
2666- self . demand_suptype ( expr. span , expected, ty) ;
2677+ if let Some ( mut err) = self . demand_suptype_diag ( expr. span , expected_ty, ty) {
2678+ // Add help to type error if this is an `if` condition with an assignment
2679+ match ( expected, & expr. node ) {
2680+ ( ExpectIfCondition , & hir:: ExprAssign ( ref lhs, ref rhs) ) => {
2681+ let msg = "did you mean to compare equality?" ;
2682+ if let ( Ok ( left) , Ok ( right) ) = (
2683+ self . tcx . sess . codemap ( ) . span_to_snippet ( lhs. span ) ,
2684+ self . tcx . sess . codemap ( ) . span_to_snippet ( rhs. span ) )
2685+ {
2686+ err. span_suggestion ( expr. span , msg, format ! ( "{} == {}" , left, right) ) ;
2687+ } else {
2688+ err. help ( msg) ;
2689+ }
2690+ }
2691+ _ => ( ) ,
2692+ }
2693+ err. emit ( ) ;
2694+ }
26672695 ty
26682696 }
26692697
@@ -2838,7 +2866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
28382866 opt_else_expr : Option < & ' gcx hir:: Expr > ,
28392867 sp : Span ,
28402868 expected : Expectation < ' tcx > ) -> Ty < ' tcx > {
2841- let cond_ty = self . check_expr_has_type ( cond_expr, self . tcx . types . bool ) ;
2869+ let cond_ty = self . check_expr_meets_expectation_or_error ( cond_expr, ExpectIfCondition ) ;
28422870 let cond_diverges = self . diverges . get ( ) ;
28432871 self . diverges . set ( Diverges :: Maybe ) ;
28442872
@@ -3325,7 +3353,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
33253353 self . check_expr_struct_fields ( struct_ty, expected, expr. id , path_span, variant, fields,
33263354 base_expr. is_none ( ) ) ;
33273355 if let & Some ( ref base_expr) = base_expr {
3328- self . check_expr_has_type ( base_expr, struct_ty) ;
3356+ self . check_expr_has_type_or_error ( base_expr, struct_ty) ;
33293357 match struct_ty. sty {
33303358 ty:: TyAdt ( adt, substs) if adt. is_struct ( ) => {
33313359 let fru_field_types = adt. struct_variant ( ) . fields . iter ( ) . map ( |f| {
@@ -3638,19 +3666,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
36383666 hir:: ExprAssign ( ref lhs, ref rhs) => {
36393667 let lhs_ty = self . check_expr_with_lvalue_pref ( & lhs, PreferMutLvalue ) ;
36403668
3641- let tcx = self . tcx ;
3642- if !tcx. expr_is_lval ( & lhs) {
3643- struct_span_err ! (
3644- tcx. sess, expr. span, E0070 ,
3645- "invalid left-hand side expression" )
3646- . span_label (
3647- expr. span ,
3648- "left-hand of expression not valid" )
3649- . emit ( ) ;
3650- }
3651-
36523669 let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
36533670
3671+ match expected {
3672+ ExpectIfCondition => {
3673+ self . tcx . sess . delay_span_bug ( lhs. span , "invalid lhs expression in if;\
3674+ expected error elsehwere") ;
3675+ }
3676+ _ => {
3677+ // Only check this if not in an `if` condition, as the
3678+ // mistyped comparison help is more appropriate.
3679+ if !self . tcx . expr_is_lval ( & lhs) {
3680+ struct_span_err ! (
3681+ self . tcx. sess, expr. span, E0070 ,
3682+ "invalid left-hand side expression" )
3683+ . span_label (
3684+ expr. span ,
3685+ "left-hand of expression not valid" )
3686+ . emit ( ) ;
3687+ }
3688+ }
3689+ }
3690+
36543691 self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
36553692
36563693 if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
@@ -3671,7 +3708,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
36713708 } ;
36723709
36733710 self . with_breakable_ctxt ( expr. id , ctxt, || {
3674- self . check_expr_has_type ( & cond, tcx. types . bool ) ;
3711+ self . check_expr_has_type_or_error ( & cond, tcx. types . bool ) ;
36753712 let cond_diverging = self . diverges . get ( ) ;
36763713 self . check_block_no_value ( & body) ;
36773714
@@ -3809,7 +3846,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38093846 }
38103847 None => {
38113848 let t: Ty = self . next_ty_var ( TypeVariableOrigin :: MiscVariable ( element. span ) ) ;
3812- let element_ty = self . check_expr_has_type ( & element, t) ;
3849+ let element_ty = self . check_expr_has_type_or_error ( & element, t) ;
38133850 ( element_ty, t)
38143851 }
38153852 } ;
@@ -4060,7 +4097,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
40604097 }
40614098 hir:: StmtExpr ( ref expr, _) => {
40624099 // Check with expected type of ()
4063- self . check_expr_has_type ( & expr, self . tcx . mk_nil ( ) ) ;
4100+ self . check_expr_has_type_or_error ( & expr, self . tcx . mk_nil ( ) ) ;
40644101 }
40654102 hir:: StmtSemi ( ref expr, _) => {
40664103 self . check_expr ( & expr) ;
0 commit comments