@@ -50,10 +50,10 @@ use super::region_constraints::GenericKind;
5050use  super :: { InferCtxt ,  RegionVariableOrigin ,  SubregionOrigin ,  TypeTrace ,  ValuePairs } ; 
5151
5252use  crate :: infer; 
53- use  crate :: infer:: OriginalQueryValues ; 
5453use  crate :: traits:: error_reporting:: report_object_safety_error; 
5554use  crate :: traits:: { 
5655    IfExpressionCause ,  MatchExpressionArmCause ,  ObligationCause ,  ObligationCauseCode , 
56+     StatementAsExpression , 
5757} ; 
5858
5959use  rustc_data_structures:: fx:: { FxHashMap ,  FxHashSet } ; 
@@ -64,7 +64,6 @@ use rustc_hir::def_id::DefId;
6464use  rustc_hir:: lang_items:: LangItem ; 
6565use  rustc_hir:: { Item ,  ItemKind ,  Node } ; 
6666use  rustc_middle:: ty:: error:: TypeError ; 
67- use  rustc_middle:: ty:: ParamEnvAnd ; 
6867use  rustc_middle:: ty:: { 
6968    self , 
7069    subst:: { Subst ,  SubstsRef } , 
@@ -688,13 +687,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
688687                    } ; 
689688                    let  msg = "`match` arms have incompatible types" ; 
690689                    err. span_label ( outer_error_span,  msg) ; 
691-                     if  let  Some ( sp)  = semi_span { 
692-                         err. span_suggestion_short ( 
693-                             sp, 
694-                             "consider removing this semicolon" , 
695-                             String :: new ( ) , 
696-                             Applicability :: MachineApplicable , 
697-                         ) ; 
690+                     if  let  Some ( ( sp,  boxed) )  = semi_span { 
691+                         if  let  ( StatementAsExpression :: NeedsBoxing ,  [ ..,  prior_arm] )  =
692+                             ( boxed,  & prior_arms[ ..] ) 
693+                         { 
694+                             err. multipart_suggestion ( 
695+                                 "consider removing this semicolon and boxing the expressions" , 
696+                                 vec ! [ 
697+                                     ( prior_arm. shrink_to_lo( ) ,  "Box::new(" . to_string( ) ) , 
698+                                     ( prior_arm. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
699+                                     ( arm_span. shrink_to_lo( ) ,  "Box::new(" . to_string( ) ) , 
700+                                     ( arm_span. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
701+                                     ( sp,  String :: new( ) ) , 
702+                                 ] , 
703+                                 Applicability :: HasPlaceholders , 
704+                             ) ; 
705+                         }  else  if  matches ! ( boxed,  StatementAsExpression :: NeedsBoxing )  { 
706+                             err. span_suggestion_short ( 
707+                                 sp, 
708+                                 "consider removing this semicolon and boxing the expressions" , 
709+                                 String :: new ( ) , 
710+                                 Applicability :: MachineApplicable , 
711+                             ) ; 
712+                         }  else  { 
713+                             err. span_suggestion_short ( 
714+                                 sp, 
715+                                 "consider removing this semicolon" , 
716+                                 String :: new ( ) , 
717+                                 Applicability :: MachineApplicable , 
718+                             ) ; 
719+                         } 
698720                    } 
699721                    if  let  Some ( ret_sp)  = opt_suggest_box_span { 
700722                        // Get return type span and point to it. 
@@ -717,13 +739,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
717739                if  let  Some ( sp)  = outer { 
718740                    err. span_label ( sp,  "`if` and `else` have incompatible types" ) ; 
719741                } 
720-                 if  let  Some ( sp)  = semicolon { 
721-                     err. span_suggestion_short ( 
722-                         sp, 
723-                         "consider removing this semicolon" , 
724-                         String :: new ( ) , 
725-                         Applicability :: MachineApplicable , 
726-                     ) ; 
742+                 if  let  Some ( ( sp,  boxed) )  = semicolon { 
743+                     if  matches ! ( boxed,  StatementAsExpression :: NeedsBoxing )  { 
744+                         err. multipart_suggestion ( 
745+                             "consider removing this semicolon and boxing the expression" , 
746+                             vec ! [ 
747+                                 ( then. shrink_to_lo( ) ,  "Box::new(" . to_string( ) ) , 
748+                                 ( then. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
749+                                 ( else_sp. shrink_to_lo( ) ,  "Box::new(" . to_string( ) ) , 
750+                                 ( else_sp. shrink_to_hi( ) ,  ")" . to_string( ) ) , 
751+                                 ( sp,  String :: new( ) ) , 
752+                             ] , 
753+                             Applicability :: MachineApplicable , 
754+                         ) ; 
755+                     }  else  { 
756+                         err. span_suggestion_short ( 
757+                             sp, 
758+                             "consider removing this semicolon" , 
759+                             String :: new ( ) , 
760+                             Applicability :: MachineApplicable , 
761+                         ) ; 
762+                     } 
727763                } 
728764                if  let  Some ( ret_sp)  = opt_suggest_box_span { 
729765                    self . suggest_boxing_for_return_impl_trait ( 
@@ -1602,6 +1638,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16021638            Mismatch :: Variable ( exp_found)  => Some ( exp_found) , 
16031639            Mismatch :: Fixed ( _)  => None , 
16041640        } ; 
1641+         let  exp_found = match  terr { 
1642+             // `terr` has more accurate type information than `exp_found` in match expressions. 
1643+             ty:: error:: TypeError :: Sorts ( terr) 
1644+                 if  exp_found. map_or ( false ,  |ef| terr. found  == ef. found )  =>
1645+             { 
1646+                 Some ( * terr) 
1647+             } 
1648+             _ => exp_found, 
1649+         } ; 
1650+         debug ! ( "exp_found {:?} terr {:?}" ,  exp_found,  terr) ; 
16051651        if  let  Some ( exp_found)  = exp_found { 
16061652            self . suggest_as_ref_where_appropriate ( span,  & exp_found,  diag) ; 
16071653            self . suggest_await_on_expect_found ( cause,  span,  & exp_found,  diag) ; 
@@ -1623,6 +1669,53 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16231669        self . note_error_origin ( diag,  cause,  exp_found) ; 
16241670    } 
16251671
1672+     fn  get_impl_future_output_ty ( & self ,  ty :  Ty < ' tcx > )  -> Option < Ty < ' tcx > >  { 
1673+         if  let  ty:: Opaque ( def_id,  substs)  = ty. kind ( )  { 
1674+             let  future_trait = self . tcx . require_lang_item ( LangItem :: Future ,  None ) ; 
1675+             // Future::Output 
1676+             let  item_def_id = self 
1677+                 . tcx 
1678+                 . associated_items ( future_trait) 
1679+                 . in_definition_order ( ) 
1680+                 . next ( ) 
1681+                 . unwrap ( ) 
1682+                 . def_id ; 
1683+ 
1684+             let  bounds = self . tcx . explicit_item_bounds ( * def_id) ; 
1685+ 
1686+             for  ( predicate,  _)  in  bounds { 
1687+                 let  predicate = predicate. subst ( self . tcx ,  substs) ; 
1688+                 if  let  ty:: PredicateAtom :: Projection ( projection_predicate)  =
1689+                     predicate. skip_binders ( ) 
1690+                 { 
1691+                     if  projection_predicate. projection_ty . item_def_id  == item_def_id { 
1692+                         // We don't account for multiple `Future::Output = Ty` contraints. 
1693+                         return  Some ( projection_predicate. ty ) ; 
1694+                     } 
1695+                 } 
1696+             } 
1697+         } 
1698+         None 
1699+     } 
1700+ 
1701+     /// A possible error is to forget to add `.await` when using futures: 
1702+ /// 
1703+ /// ``` 
1704+ /// async fn make_u32() -> u32 { 
1705+ ///     22 
1706+ /// } 
1707+ /// 
1708+ /// fn take_u32(x: u32) {} 
1709+ /// 
1710+ /// async fn foo() { 
1711+ ///     let x = make_u32(); 
1712+ ///     take_u32(x); 
1713+ /// } 
1714+ /// ``` 
1715+ /// 
1716+ /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the 
1717+ /// expected type. If this is the case, and we are inside of an async body, it suggests adding 
1718+ /// `.await` to the tail of the expression. 
16261719fn  suggest_await_on_expect_found ( 
16271720        & self , 
16281721        cause :  & ObligationCause < ' tcx > , 
@@ -1632,50 +1725,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16321725    )  { 
16331726        debug ! ( 
16341727            "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}" , 
1635-             exp_span,  exp_found. expected,  exp_found. found
1728+             exp_span,  exp_found. expected,  exp_found. found, 
16361729        ) ; 
16371730
1638-         if  let  ty:: Opaque ( def_id,  _)  = * exp_found. expected . kind ( )  { 
1639-             let  future_trait = self . tcx . require_lang_item ( LangItem :: Future ,  None ) ; 
1640-             // Future::Output 
1641-             let  item_def_id = self 
1642-                 . tcx 
1643-                 . associated_items ( future_trait) 
1644-                 . in_definition_order ( ) 
1645-                 . next ( ) 
1646-                 . unwrap ( ) 
1647-                 . def_id ; 
1731+         if  let  ObligationCauseCode :: CompareImplMethodObligation  {  .. }  = & cause. code  { 
1732+             return ; 
1733+         } 
16481734
1649-             let  projection_ty = self . tcx . projection_ty_from_predicates ( ( def_id,  item_def_id) ) ; 
1650-             if  let  Some ( projection_ty)  = projection_ty { 
1651-                 let  projection_query = self . canonicalize_query ( 
1652-                     & ParamEnvAnd  {  param_env :  self . tcx . param_env ( def_id) ,  value :  projection_ty } , 
1653-                     & mut  OriginalQueryValues :: default ( ) , 
1654-                 ) ; 
1655-                 if  let  Ok ( resp)  = self . tcx . normalize_projection_ty ( projection_query)  { 
1656-                     let  normalized_ty = resp. value . value . normalized_ty ; 
1657-                     debug ! ( "suggest_await_on_expect_found: normalized={:?}" ,  normalized_ty) ; 
1658-                     if  ty:: TyS :: same_type ( normalized_ty,  exp_found. found )  { 
1659-                         let  span = if  let  ObligationCauseCode :: Pattern  { 
1660-                             span, 
1661-                             origin_expr :  _, 
1662-                             root_ty :  _, 
1663-                         }  = cause. code 
1664-                         { 
1665-                             // scrutinee's span 
1666-                             span. unwrap_or ( exp_span) 
1667-                         }  else  { 
1668-                             exp_span
1669-                         } ; 
1670-                         diag. span_suggestion_verbose ( 
1671-                             span. shrink_to_hi ( ) , 
1672-                             "consider awaiting on the future" , 
1673-                             ".await" . to_string ( ) , 
1735+         match  ( 
1736+             self . get_impl_future_output_ty ( exp_found. expected ) , 
1737+             self . get_impl_future_output_ty ( exp_found. found ) , 
1738+         )  { 
1739+             ( Some ( exp) ,  Some ( found) )  if  ty:: TyS :: same_type ( exp,  found)  => match  & cause. code  { 
1740+                 ObligationCauseCode :: IfExpression ( box IfExpressionCause  {  then,  .. } )  => { 
1741+                     diag. multipart_suggestion ( 
1742+                         "consider `await`ing on both `Future`s" , 
1743+                         vec ! [ 
1744+                             ( then. shrink_to_hi( ) ,  ".await" . to_string( ) ) , 
1745+                             ( exp_span. shrink_to_hi( ) ,  ".await" . to_string( ) ) , 
1746+                         ] , 
1747+                         Applicability :: MaybeIncorrect , 
1748+                     ) ; 
1749+                 } 
1750+                 ObligationCauseCode :: MatchExpressionArm ( box MatchExpressionArmCause  { 
1751+                     prior_arms, 
1752+                     ..
1753+                 } )  => { 
1754+                     if  let  [ ..,  arm_span]  = & prior_arms[ ..]  { 
1755+                         diag. multipart_suggestion ( 
1756+                             "consider `await`ing on both `Future`s" , 
1757+                             vec ! [ 
1758+                                 ( arm_span. shrink_to_hi( ) ,  ".await" . to_string( ) ) , 
1759+                                 ( exp_span. shrink_to_hi( ) ,  ".await" . to_string( ) ) , 
1760+                             ] , 
16741761                            Applicability :: MaybeIncorrect , 
16751762                        ) ; 
1763+                     }  else  { 
1764+                         diag. help ( "consider `await`ing on both `Future`s" ) ; 
16761765                    } 
16771766                } 
1767+                 _ => { 
1768+                     diag. help ( "consider `await`ing on both `Future`s" ) ; 
1769+                 } 
1770+             } , 
1771+             ( _,  Some ( ty) )  if  ty:: TyS :: same_type ( exp_found. expected ,  ty)  => { 
1772+                 let  span = match  cause. code  { 
1773+                     // scrutinee's span 
1774+                     ObligationCauseCode :: Pattern  {  span :  Some ( span) ,  .. }  => span, 
1775+                     _ => exp_span, 
1776+                 } ; 
1777+                 diag. span_suggestion_verbose ( 
1778+                     span. shrink_to_hi ( ) , 
1779+                     "consider `await`ing on the `Future`" , 
1780+                     ".await" . to_string ( ) , 
1781+                     Applicability :: MaybeIncorrect , 
1782+                 ) ; 
1783+             } 
1784+             ( Some ( ty) ,  _)  if  ty:: TyS :: same_type ( ty,  exp_found. found )  => { 
1785+                 let  span = match  cause. code  { 
1786+                     // scrutinee's span 
1787+                     ObligationCauseCode :: Pattern  {  span :  Some ( span) ,  .. }  => span, 
1788+                     _ => exp_span, 
1789+                 } ; 
1790+                 diag. span_suggestion_verbose ( 
1791+                     span. shrink_to_hi ( ) , 
1792+                     "consider `await`ing on the `Future`" , 
1793+                     ".await" . to_string ( ) , 
1794+                     Applicability :: MaybeIncorrect , 
1795+                 ) ; 
16781796            } 
1797+             _ => { } 
16791798        } 
16801799    } 
16811800
0 commit comments