@@ -1320,84 +1320,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13201320 ) -> Ty < ' tcx > {
13211321 let expected_ty = expected. coercion_target_type ( self , expr. span ) ;
13221322 if expected_ty == self . tcx . types . bool {
1323- // The expected type is `bool` but this will result in `()` so we can reasonably
1324- // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
1325- // The likely cause of this is `if foo = bar { .. }`.
1326- let actual_ty = self . tcx . types . unit ;
1327- let mut err = self . demand_suptype_diag ( expr. span , expected_ty, actual_ty) . unwrap_err ( ) ;
1328- let lhs_ty = self . check_expr ( lhs) ;
1329- let rhs_ty = self . check_expr ( rhs) ;
1330- let refs_can_coerce = |lhs : Ty < ' tcx > , rhs : Ty < ' tcx > | {
1331- let lhs = Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_erased , lhs. peel_refs ( ) ) ;
1332- let rhs = Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_erased , rhs. peel_refs ( ) ) ;
1333- self . may_coerce ( rhs, lhs)
1334- } ;
1335- let ( applicability, eq) = if self . may_coerce ( rhs_ty, lhs_ty) {
1336- ( Applicability :: MachineApplicable , true )
1337- } else if refs_can_coerce ( rhs_ty, lhs_ty) {
1338- // The lhs and rhs are likely missing some references in either side. Subsequent
1339- // suggestions will show up.
1340- ( Applicability :: MaybeIncorrect , true )
1341- } else if let ExprKind :: Binary (
1342- Spanned { node : hir:: BinOpKind :: And | hir:: BinOpKind :: Or , .. } ,
1343- _,
1344- rhs_expr,
1345- ) = lhs. kind
1346- {
1347- // if x == 1 && y == 2 { .. }
1348- // +
1349- let actual_lhs_ty = self . check_expr ( rhs_expr) ;
1350- (
1351- Applicability :: MaybeIncorrect ,
1352- self . may_coerce ( rhs_ty, actual_lhs_ty)
1353- || refs_can_coerce ( rhs_ty, actual_lhs_ty) ,
1354- )
1355- } else if let ExprKind :: Binary (
1356- Spanned { node : hir:: BinOpKind :: And | hir:: BinOpKind :: Or , .. } ,
1357- lhs_expr,
1358- _,
1359- ) = rhs. kind
1360- {
1361- // if x == 1 && y == 2 { .. }
1362- // +
1363- let actual_rhs_ty = self . check_expr ( lhs_expr) ;
1364- (
1365- Applicability :: MaybeIncorrect ,
1366- self . may_coerce ( actual_rhs_ty, lhs_ty)
1367- || refs_can_coerce ( actual_rhs_ty, lhs_ty) ,
1368- )
1369- } else {
1370- ( Applicability :: MaybeIncorrect , false )
1371- } ;
1372- if !lhs. is_syntactic_place_expr ( )
1373- && lhs. is_approximately_pattern ( )
1374- && !matches ! ( lhs. kind, hir:: ExprKind :: Lit ( _) )
1375- {
1376- // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
1377- if let hir:: Node :: Expr ( hir:: Expr { kind : ExprKind :: If { .. } , .. } ) =
1378- self . tcx . parent_hir_node ( expr. hir_id )
1379- {
1380- err. span_suggestion_verbose (
1381- expr. span . shrink_to_lo ( ) ,
1382- "you might have meant to use pattern matching" ,
1383- "let " ,
1384- applicability,
1385- ) ;
1386- } ;
1387- }
1388- if eq {
1389- err. span_suggestion_verbose (
1390- span. shrink_to_hi ( ) ,
1391- "you might have meant to compare for equality" ,
1392- '=' ,
1393- applicability,
1394- ) ;
1395- }
1396-
1397- // If the assignment expression itself is ill-formed, don't
1398- // bother emitting another error
1399- let reported = err. emit_unless ( lhs_ty. references_error ( ) || rhs_ty. references_error ( ) ) ;
1400- return Ty :: new_error ( self . tcx , reported) ;
1323+ let guar = self . expr_assign_expected_bool_error ( expr, lhs, rhs, span) ;
1324+ return Ty :: new_error ( self . tcx , guar) ;
14011325 }
14021326
14031327 let lhs_ty = self . check_expr_with_needs ( lhs, Needs :: MutPlace ) ;
@@ -1450,6 +1374,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14501374 }
14511375 }
14521376
1377+ /// The expected type is `bool` but this will result in `()` so we can reasonably
1378+ /// say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
1379+ /// The likely cause of this is `if foo = bar { .. }`.
1380+ fn expr_assign_expected_bool_error (
1381+ & self ,
1382+ expr : & ' tcx hir:: Expr < ' tcx > ,
1383+ lhs : & ' tcx hir:: Expr < ' tcx > ,
1384+ rhs : & ' tcx hir:: Expr < ' tcx > ,
1385+ span : Span ,
1386+ ) -> ErrorGuaranteed {
1387+ let actual_ty = self . tcx . types . unit ;
1388+ let expected_ty = self . tcx . types . bool ;
1389+ let mut err = self . demand_suptype_diag ( expr. span , expected_ty, actual_ty) . unwrap_err ( ) ;
1390+ let lhs_ty = self . check_expr ( lhs) ;
1391+ let rhs_ty = self . check_expr ( rhs) ;
1392+ let refs_can_coerce = |lhs : Ty < ' tcx > , rhs : Ty < ' tcx > | {
1393+ let lhs = Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_erased , lhs. peel_refs ( ) ) ;
1394+ let rhs = Ty :: new_imm_ref ( self . tcx , self . tcx . lifetimes . re_erased , rhs. peel_refs ( ) ) ;
1395+ self . may_coerce ( rhs, lhs)
1396+ } ;
1397+ let ( applicability, eq) = if self . may_coerce ( rhs_ty, lhs_ty) {
1398+ ( Applicability :: MachineApplicable , true )
1399+ } else if refs_can_coerce ( rhs_ty, lhs_ty) {
1400+ // The lhs and rhs are likely missing some references in either side. Subsequent
1401+ // suggestions will show up.
1402+ ( Applicability :: MaybeIncorrect , true )
1403+ } else if let ExprKind :: Binary (
1404+ Spanned { node : hir:: BinOpKind :: And | hir:: BinOpKind :: Or , .. } ,
1405+ _,
1406+ rhs_expr,
1407+ ) = lhs. kind
1408+ {
1409+ // if x == 1 && y == 2 { .. }
1410+ // +
1411+ let actual_lhs = self . check_expr ( rhs_expr) ;
1412+ let may_eq = self . may_coerce ( rhs_ty, actual_lhs) || refs_can_coerce ( rhs_ty, actual_lhs) ;
1413+ ( Applicability :: MaybeIncorrect , may_eq)
1414+ } else if let ExprKind :: Binary (
1415+ Spanned { node : hir:: BinOpKind :: And | hir:: BinOpKind :: Or , .. } ,
1416+ lhs_expr,
1417+ _,
1418+ ) = rhs. kind
1419+ {
1420+ // if x == 1 && y == 2 { .. }
1421+ // +
1422+ let actual_rhs = self . check_expr ( lhs_expr) ;
1423+ let may_eq = self . may_coerce ( actual_rhs, lhs_ty) || refs_can_coerce ( actual_rhs, lhs_ty) ;
1424+ ( Applicability :: MaybeIncorrect , may_eq)
1425+ } else {
1426+ ( Applicability :: MaybeIncorrect , false )
1427+ } ;
1428+
1429+ if !lhs. is_syntactic_place_expr ( )
1430+ && lhs. is_approximately_pattern ( )
1431+ && !matches ! ( lhs. kind, hir:: ExprKind :: Lit ( _) )
1432+ {
1433+ // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
1434+ if let hir:: Node :: Expr ( hir:: Expr { kind : ExprKind :: If { .. } , .. } ) =
1435+ self . tcx . parent_hir_node ( expr. hir_id )
1436+ {
1437+ err. span_suggestion_verbose (
1438+ expr. span . shrink_to_lo ( ) ,
1439+ "you might have meant to use pattern matching" ,
1440+ "let " ,
1441+ applicability,
1442+ ) ;
1443+ } ;
1444+ }
1445+ if eq {
1446+ err. span_suggestion_verbose (
1447+ span. shrink_to_hi ( ) ,
1448+ "you might have meant to compare for equality" ,
1449+ '=' ,
1450+ applicability,
1451+ ) ;
1452+ }
1453+
1454+ // If the assignment expression itself is ill-formed, don't
1455+ // bother emitting another error
1456+ err. emit_unless ( lhs_ty. references_error ( ) || rhs_ty. references_error ( ) )
1457+ }
1458+
14531459 pub ( super ) fn check_expr_let (
14541460 & self ,
14551461 let_expr : & ' tcx hir:: LetExpr < ' tcx > ,
0 commit comments