@@ -246,9 +246,6 @@ pub enum Expectation<'tcx> {
246
246
/// We know nothing about what type this expression should have.
247
247
NoExpectation ,
248
248
249
- /// This expression is an `if` condition, it must resolve to `bool`.
250
- ExpectIfCondition ,
251
-
252
249
/// This expression should have the type given (or some subtype).
253
250
ExpectHasType ( Ty < ' tcx > ) ,
254
251
@@ -328,7 +325,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
328
325
fn resolve ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Expectation < ' tcx > {
329
326
match self {
330
327
NoExpectation => NoExpectation ,
331
- ExpectIfCondition => ExpectIfCondition ,
332
328
ExpectCastableToType ( t) => {
333
329
ExpectCastableToType ( fcx. resolve_type_vars_if_possible ( & t) )
334
330
}
@@ -344,7 +340,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
344
340
fn to_option ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
345
341
match self . resolve ( fcx) {
346
342
NoExpectation => None ,
347
- ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
348
343
ExpectCastableToType ( ty) |
349
344
ExpectHasType ( ty) |
350
345
ExpectRvalueLikeUnsized ( ty) => Some ( ty) ,
@@ -358,7 +353,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
358
353
fn only_has_type ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
359
354
match self . resolve ( fcx) {
360
355
ExpectHasType ( ty) => Some ( ty) ,
361
- ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
362
356
NoExpectation | ExpectCastableToType ( _) | ExpectRvalueLikeUnsized ( _) => None ,
363
357
}
364
358
}
@@ -3148,25 +3142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3148
3142
}
3149
3143
3150
3144
if let Some ( mut err) = self . demand_suptype_diag ( expr. span , expected_ty, ty) {
3151
- // Add help to type error if this is an `if` condition with an assignment.
3152
- if let ( ExpectIfCondition , & ExprKind :: Assign ( ref lhs, ref rhs) )
3153
- = ( expected, & expr. node )
3154
- {
3155
- let msg = "try comparing for equality" ;
3156
- if let ( Ok ( left) , Ok ( right) ) = (
3157
- self . tcx . sess . source_map ( ) . span_to_snippet ( lhs. span ) ,
3158
- self . tcx . sess . source_map ( ) . span_to_snippet ( rhs. span ) )
3159
- {
3160
- err. span_suggestion (
3161
- expr. span ,
3162
- msg,
3163
- format ! ( "{} == {}" , left, right) ,
3164
- Applicability :: MaybeIncorrect ) ;
3165
- } else {
3166
- err. help ( msg) ;
3167
- }
3145
+ if self . is_assign_to_bool ( expr, expected_ty) {
3146
+ // Error reported in `check_assign` so avoid emitting error again.
3147
+ // FIXME(centril): Consider removing if/when `if` desugars to `match`.
3148
+ err. delay_as_bug ( ) ;
3149
+ } else {
3150
+ err. emit ( ) ;
3168
3151
}
3169
- err. emit ( ) ;
3170
3152
}
3171
3153
ty
3172
3154
}
@@ -3337,7 +3319,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3337
3319
opt_else_expr : Option < & ' gcx hir:: Expr > ,
3338
3320
sp : Span ,
3339
3321
expected : Expectation < ' tcx > ) -> Ty < ' tcx > {
3340
- let cond_ty = self . check_expr_meets_expectation_or_error ( cond_expr, ExpectIfCondition ) ;
3322
+ let cond_ty = self . check_expr_has_type_or_error ( cond_expr, self . tcx . types . bool ) ;
3341
3323
let cond_diverges = self . diverges . get ( ) ;
3342
3324
self . diverges . set ( Diverges :: Maybe ) ;
3343
3325
@@ -4422,34 +4404,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4422
4404
tcx. types . never
4423
4405
}
4424
4406
ExprKind :: Assign ( ref lhs, ref rhs) => {
4425
- let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
4426
-
4427
- let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
4428
-
4429
- match expected {
4430
- ExpectIfCondition => {
4431
- self . tcx . sess . delay_span_bug ( lhs. span , "invalid lhs expression in if;\
4432
- expected error elsehwere") ;
4433
- }
4434
- _ => {
4435
- // Only check this if not in an `if` condition, as the
4436
- // mistyped comparison help is more appropriate.
4437
- if !lhs. is_place_expr ( ) {
4438
- struct_span_err ! ( self . tcx. sess, expr. span, E0070 ,
4439
- "invalid left-hand side expression" )
4440
- . span_label ( expr. span , "left-hand of expression not valid" )
4441
- . emit ( ) ;
4442
- }
4443
- }
4444
- }
4445
-
4446
- self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
4447
-
4448
- if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
4449
- tcx. types . err
4450
- } else {
4451
- tcx. mk_unit ( )
4452
- }
4407
+ self . check_assign ( expr, expected, lhs, rhs)
4453
4408
}
4454
4409
ExprKind :: If ( ref cond, ref then_expr, ref opt_else_expr) => {
4455
4410
self . check_then_else ( & cond, then_expr, opt_else_expr. as_ref ( ) . map ( |e| & * * e) ,
@@ -4750,6 +4705,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4750
4705
}
4751
4706
}
4752
4707
4708
+ /// Type check assignment expression `expr` of form `lhs = rhs`.
4709
+ /// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
4710
+ fn check_assign (
4711
+ & self ,
4712
+ expr : & ' gcx hir:: Expr ,
4713
+ expected : Expectation < ' tcx > ,
4714
+ lhs : & ' gcx hir:: Expr ,
4715
+ rhs : & ' gcx hir:: Expr ,
4716
+ ) -> Ty < ' tcx > {
4717
+ let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
4718
+ let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
4719
+
4720
+ let expected_ty = expected. coercion_target_type ( self , expr. span ) ;
4721
+ if expected_ty == self . tcx . types . bool {
4722
+ // The expected type is `bool` but this will result in `()` so we can reasonably
4723
+ // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
4724
+ // The likely cause of this is `if foo = bar { .. }`.
4725
+ let actual_ty = self . tcx . mk_unit ( ) ;
4726
+ let mut err = self . demand_suptype_diag ( expr. span , expected_ty, actual_ty) . unwrap ( ) ;
4727
+ let msg = "try comparing for equality" ;
4728
+ let left = self . tcx . sess . source_map ( ) . span_to_snippet ( lhs. span ) ;
4729
+ let right = self . tcx . sess . source_map ( ) . span_to_snippet ( rhs. span ) ;
4730
+ if let ( Ok ( left) , Ok ( right) ) = ( left, right) {
4731
+ let help = format ! ( "{} == {}" , left, right) ;
4732
+ err. span_suggestion ( expr. span , msg, help, Applicability :: MaybeIncorrect ) ;
4733
+ } else {
4734
+ err. help ( msg) ;
4735
+ }
4736
+ err. emit ( ) ;
4737
+ } else if !lhs. is_place_expr ( ) {
4738
+ struct_span_err ! ( self . tcx. sess, expr. span, E0070 ,
4739
+ "invalid left-hand side expression" )
4740
+ . span_label ( expr. span , "left-hand of expression not valid" )
4741
+ . emit ( ) ;
4742
+ }
4743
+
4744
+ self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
4745
+
4746
+ if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
4747
+ self . tcx . types . err
4748
+ } else {
4749
+ self . tcx . mk_unit ( )
4750
+ }
4751
+ }
4752
+
4753
4753
// Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
4754
4754
// The newly resolved definition is written into `type_dependent_defs`.
4755
4755
fn finish_resolving_struct_path ( & self ,
0 commit comments