@@ -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
}
@@ -3150,25 +3144,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3150
3144
}
3151
3145
3152
3146
if let Some ( mut err) = self . demand_suptype_diag ( expr. span , expected_ty, ty) {
3153
- // Add help to type error if this is an `if` condition with an assignment.
3154
- if let ( ExpectIfCondition , & ExprKind :: Assign ( ref lhs, ref rhs) )
3155
- = ( expected, & expr. node )
3156
- {
3157
- let msg = "try comparing for equality" ;
3158
- if let ( Ok ( left) , Ok ( right) ) = (
3159
- self . tcx . sess . source_map ( ) . span_to_snippet ( lhs. span ) ,
3160
- self . tcx . sess . source_map ( ) . span_to_snippet ( rhs. span ) )
3161
- {
3162
- err. span_suggestion (
3163
- expr. span ,
3164
- msg,
3165
- format ! ( "{} == {}" , left, right) ,
3166
- Applicability :: MaybeIncorrect ) ;
3167
- } else {
3168
- err. help ( msg) ;
3169
- }
3147
+ if self . is_assign_to_bool ( expr, expected_ty) {
3148
+ // Error reported in `check_assign` so avoid emitting error again.
3149
+ // FIXME(centril): Consider removing if/when `if` desugars to `match`.
3150
+ err. delay_as_bug ( ) ;
3151
+ } else {
3152
+ err. emit ( ) ;
3170
3153
}
3171
- err. emit ( ) ;
3172
3154
}
3173
3155
ty
3174
3156
}
@@ -3339,7 +3321,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3339
3321
opt_else_expr : Option < & ' gcx hir:: Expr > ,
3340
3322
sp : Span ,
3341
3323
expected : Expectation < ' tcx > ) -> Ty < ' tcx > {
3342
- let cond_ty = self . check_expr_meets_expectation_or_error ( cond_expr, ExpectIfCondition ) ;
3324
+ let cond_ty = self . check_expr_has_type_or_error ( cond_expr, self . tcx . types . bool ) ;
3343
3325
let cond_diverges = self . diverges . get ( ) ;
3344
3326
self . diverges . set ( Diverges :: Maybe ) ;
3345
3327
@@ -4424,34 +4406,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4424
4406
tcx. types . never
4425
4407
}
4426
4408
ExprKind :: Assign ( ref lhs, ref rhs) => {
4427
- let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
4428
-
4429
- let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
4430
-
4431
- match expected {
4432
- ExpectIfCondition => {
4433
- self . tcx . sess . delay_span_bug ( lhs. span , "invalid lhs expression in if;\
4434
- expected error elsehwere") ;
4435
- }
4436
- _ => {
4437
- // Only check this if not in an `if` condition, as the
4438
- // mistyped comparison help is more appropriate.
4439
- if !lhs. is_place_expr ( ) {
4440
- struct_span_err ! ( self . tcx. sess, expr. span, E0070 ,
4441
- "invalid left-hand side expression" )
4442
- . span_label ( expr. span , "left-hand of expression not valid" )
4443
- . emit ( ) ;
4444
- }
4445
- }
4446
- }
4447
-
4448
- self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
4449
-
4450
- if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
4451
- tcx. types . err
4452
- } else {
4453
- tcx. mk_unit ( )
4454
- }
4409
+ self . check_assign ( expr, expected, lhs, rhs)
4455
4410
}
4456
4411
ExprKind :: If ( ref cond, ref then_expr, ref opt_else_expr) => {
4457
4412
self . check_then_else ( & cond, then_expr, opt_else_expr. as_ref ( ) . map ( |e| & * * e) ,
@@ -4752,6 +4707,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4752
4707
}
4753
4708
}
4754
4709
4710
+ /// Type check assignment expression `expr` of form `lhs = rhs`.
4711
+ /// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
4712
+ fn check_assign (
4713
+ & self ,
4714
+ expr : & ' gcx hir:: Expr ,
4715
+ expected : Expectation < ' tcx > ,
4716
+ lhs : & ' gcx hir:: Expr ,
4717
+ rhs : & ' gcx hir:: Expr ,
4718
+ ) -> Ty < ' tcx > {
4719
+ let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
4720
+ let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty) ;
4721
+
4722
+ let expected_ty = expected. coercion_target_type ( self , expr. span ) ;
4723
+ if expected_ty == self . tcx . types . bool {
4724
+ // The expected type is `bool` but this will result in `()` so we can reasonably
4725
+ // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
4726
+ // The likely cause of this is `if foo = bar { .. }`.
4727
+ let actual_ty = self . tcx . mk_unit ( ) ;
4728
+ let mut err = self . demand_suptype_diag ( expr. span , expected_ty, actual_ty) . unwrap ( ) ;
4729
+ let msg = "try comparing for equality" ;
4730
+ let left = self . tcx . sess . source_map ( ) . span_to_snippet ( lhs. span ) ;
4731
+ let right = self . tcx . sess . source_map ( ) . span_to_snippet ( rhs. span ) ;
4732
+ if let ( Ok ( left) , Ok ( right) ) = ( left, right) {
4733
+ let help = format ! ( "{} == {}" , left, right) ;
4734
+ err. span_suggestion ( expr. span , msg, help, Applicability :: MaybeIncorrect ) ;
4735
+ } else {
4736
+ err. help ( msg) ;
4737
+ }
4738
+ err. emit ( ) ;
4739
+ } else if !lhs. is_place_expr ( ) {
4740
+ struct_span_err ! ( self . tcx. sess, expr. span, E0070 ,
4741
+ "invalid left-hand side expression" )
4742
+ . span_label ( expr. span , "left-hand of expression not valid" )
4743
+ . emit ( ) ;
4744
+ }
4745
+
4746
+ self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
4747
+
4748
+ if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
4749
+ self . tcx . types . err
4750
+ } else {
4751
+ self . tcx . mk_unit ( )
4752
+ }
4753
+ }
4754
+
4755
4755
// Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
4756
4756
// The newly resolved definition is written into `type_dependent_defs`.
4757
4757
fn finish_resolving_struct_path ( & self ,
0 commit comments