@@ -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 }
@@ -3150,25 +3144,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
31503144 }
31513145
31523146 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 ( ) ;
31703153 }
3171- err. emit ( ) ;
31723154 }
31733155 ty
31743156 }
@@ -3339,7 +3321,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
33393321 opt_else_expr : Option < & ' gcx hir:: Expr > ,
33403322 sp : Span ,
33413323 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 ) ;
33433325 let cond_diverges = self . diverges . get ( ) ;
33443326 self . diverges . set ( Diverges :: Maybe ) ;
33453327
@@ -4424,34 +4406,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44244406 tcx. types . never
44254407 }
44264408 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)
44554410 }
44564411 ExprKind :: If ( ref cond, ref then_expr, ref opt_else_expr) => {
44574412 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> {
47524707 }
47534708 }
47544709
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+
47554755 // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
47564756 // The newly resolved definition is written into `type_dependent_defs`.
47574757 fn finish_resolving_struct_path ( & self ,
0 commit comments