@@ -232,6 +232,9 @@ pub enum Expectation<'tcx> {
232
232
/// We know nothing about what type this expression should have.
233
233
NoExpectation ,
234
234
235
+ /// This expression is an `if` condition, it must resolve to `bool`.
236
+ ExpectIfCondition ,
237
+
235
238
/// This expression should have the type given (or some subtype)
236
239
ExpectHasType ( Ty < ' tcx > ) ,
237
240
@@ -310,9 +313,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
310
313
// no constraints yet present), just returns `None`.
311
314
fn resolve ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Expectation < ' tcx > {
312
315
match self {
313
- NoExpectation => {
314
- NoExpectation
315
- }
316
+ NoExpectation => NoExpectation ,
317
+ ExpectIfCondition => ExpectIfCondition ,
316
318
ExpectCastableToType ( t) => {
317
319
ExpectCastableToType ( fcx. resolve_type_vars_if_possible ( & t) )
318
320
}
@@ -328,6 +330,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
328
330
fn to_option ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
329
331
match self . resolve ( fcx) {
330
332
NoExpectation => None ,
333
+ ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
331
334
ExpectCastableToType ( ty) |
332
335
ExpectHasType ( ty) |
333
336
ExpectRvalueLikeUnsized ( ty) => Some ( ty) ,
@@ -341,7 +344,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
341
344
fn only_has_type ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
342
345
match self . resolve ( fcx) {
343
346
ExpectHasType ( ty) => Some ( ty) ,
344
- _ => None
347
+ ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
348
+ NoExpectation | ExpectCastableToType ( _) | ExpectRvalueLikeUnsized ( _) => None ,
345
349
}
346
350
}
347
351
@@ -2644,10 +2648,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2644
2648
self . demand_eqtype ( expr. span , expected, ty) ;
2645
2649
}
2646
2650
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) ;
2651
2662
2652
2663
// While we don't allow *arbitrary* coercions here, we *do* allow
2653
2664
// coercions from ! to `expected`.
@@ -2663,7 +2674,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2663
2674
ty = adj_ty;
2664
2675
}
2665
2676
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
+ }
2667
2695
ty
2668
2696
}
2669
2697
@@ -2838,7 +2866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2838
2866
opt_else_expr : Option < & ' gcx hir:: Expr > ,
2839
2867
sp : Span ,
2840
2868
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 ) ;
2842
2870
let cond_diverges = self . diverges . get ( ) ;
2843
2871
self . diverges . set ( Diverges :: Maybe ) ;
2844
2872
@@ -3325,7 +3353,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3325
3353
self . check_expr_struct_fields ( struct_ty, expected, expr. id , path_span, variant, fields,
3326
3354
base_expr. is_none ( ) ) ;
3327
3355
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) ;
3329
3357
match struct_ty. sty {
3330
3358
ty:: TyAdt ( adt, substs) if adt. is_struct ( ) => {
3331
3359
let fru_field_types = adt. struct_variant ( ) . fields . iter ( ) . map ( |f| {
@@ -3638,19 +3666,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3638
3666
hir:: ExprAssign ( ref lhs, ref rhs) => {
3639
3667
let lhs_ty = self . check_expr_with_lvalue_pref ( & lhs, PreferMutLvalue ) ;
3640
3668
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
-
3652
3669
let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
3653
3670
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
+
3654
3691
self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
3655
3692
3656
3693
if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
@@ -3671,7 +3708,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3671
3708
} ;
3672
3709
3673
3710
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 ) ;
3675
3712
let cond_diverging = self . diverges . get ( ) ;
3676
3713
self . check_block_no_value ( & body) ;
3677
3714
@@ -3809,7 +3846,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3809
3846
}
3810
3847
None => {
3811
3848
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) ;
3813
3850
( element_ty, t)
3814
3851
}
3815
3852
} ;
@@ -4060,7 +4097,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4060
4097
}
4061
4098
hir:: StmtExpr ( ref expr, _) => {
4062
4099
// 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 ( ) ) ;
4064
4101
}
4065
4102
hir:: StmtSemi ( ref expr, _) => {
4066
4103
self . check_expr ( & expr) ;
0 commit comments