@@ -246,9 +246,6 @@ pub enum Expectation<'tcx> {
246246 /// We know nothing about what type this expression should have.
247247 NoExpectation ,
248248
249- /// This expression is an `if` condition, it must resolve to `bool`.
250- ExpectIfCondition ,
251-
252249 /// This expression should have the type given (or some subtype).
253250 ExpectHasType ( Ty < ' tcx > ) ,
254251
@@ -328,7 +325,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
328325 fn resolve ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Expectation < ' tcx > {
329326 match self {
330327 NoExpectation => NoExpectation ,
331- ExpectIfCondition => ExpectIfCondition ,
332328 ExpectCastableToType ( t) => {
333329 ExpectCastableToType ( fcx. resolve_type_vars_if_possible ( & t) )
334330 }
@@ -344,7 +340,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
344340 fn to_option ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
345341 match self . resolve ( fcx) {
346342 NoExpectation => None ,
347- ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
348343 ExpectCastableToType ( ty) |
349344 ExpectHasType ( ty) |
350345 ExpectRvalueLikeUnsized ( ty) => Some ( ty) ,
@@ -358,7 +353,6 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
358353 fn only_has_type ( self , fcx : & FnCtxt < ' a , ' gcx , ' tcx > ) -> Option < Ty < ' tcx > > {
359354 match self . resolve ( fcx) {
360355 ExpectHasType ( ty) => Some ( ty) ,
361- ExpectIfCondition => Some ( fcx. tcx . types . bool ) ,
362356 NoExpectation | ExpectCastableToType ( _) | ExpectRvalueLikeUnsized ( _) => None ,
363357 }
364358 }
@@ -3148,25 +3142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
31483142 }
31493143
31503144 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 ( ) ;
31683151 }
3169- err. emit ( ) ;
31703152 }
31713153 ty
31723154 }
@@ -3337,7 +3319,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
33373319 opt_else_expr : Option < & ' gcx hir:: Expr > ,
33383320 sp : Span ,
33393321 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 ) ;
33413323 let cond_diverges = self . diverges . get ( ) ;
33423324 self . diverges . set ( Diverges :: Maybe ) ;
33433325
@@ -4422,34 +4404,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44224404 tcx. types . never
44234405 }
44244406 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)
44534408 }
44544409 ExprKind :: If ( ref cond, ref then_expr, ref opt_else_expr) => {
44554410 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> {
47504705 }
47514706 }
47524707
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+
47534753 // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
47544754 // The newly resolved definition is written into `type_dependent_defs`.
47554755 fn finish_resolving_struct_path ( & self ,
0 commit comments