@@ -50,7 +50,6 @@ 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 ,
@@ -65,7 +64,6 @@ use rustc_hir::def_id::DefId;
6564use rustc_hir:: lang_items:: LangItem ;
6665use rustc_hir:: { Item , ItemKind , Node } ;
6766use rustc_middle:: ty:: error:: TypeError ;
68- use rustc_middle:: ty:: ParamEnvAnd ;
6967use rustc_middle:: ty:: {
7068 self ,
7169 subst:: { Subst , SubstsRef } ,
@@ -1621,6 +1619,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16211619 Mismatch :: Variable ( exp_found) => Some ( exp_found) ,
16221620 Mismatch :: Fixed ( _) => None ,
16231621 } ;
1622+ let exp_found = match terr {
1623+ // `terr` has more accurate type information than `exp_found` in match expressions.
1624+ ty:: error:: TypeError :: Sorts ( terr)
1625+ if exp_found. map_or ( false , |ef| terr. found == ef. found ) =>
1626+ {
1627+ Some ( * terr)
1628+ }
1629+ _ => exp_found,
1630+ } ;
1631+ debug ! ( "exp_found {:?} terr {:?}" , exp_found, terr) ;
16241632 if let Some ( exp_found) = exp_found {
16251633 self . suggest_as_ref_where_appropriate ( span, & exp_found, diag) ;
16261634 self . suggest_await_on_expect_found ( cause, span, & exp_found, diag) ;
@@ -1642,6 +1650,53 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16421650 self . note_error_origin ( diag, cause, exp_found) ;
16431651 }
16441652
1653+ fn get_impl_future_output_ty ( & self , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
1654+ if let ty:: Opaque ( def_id, substs) = ty. kind ( ) {
1655+ let future_trait = self . tcx . require_lang_item ( LangItem :: Future , None ) ;
1656+ // Future::Output
1657+ let item_def_id = self
1658+ . tcx
1659+ . associated_items ( future_trait)
1660+ . in_definition_order ( )
1661+ . next ( )
1662+ . unwrap ( )
1663+ . def_id ;
1664+
1665+ let bounds = self . tcx . explicit_item_bounds ( * def_id) ;
1666+
1667+ for ( predicate, _) in bounds {
1668+ let predicate = predicate. subst ( self . tcx , substs) ;
1669+ if let ty:: PredicateAtom :: Projection ( projection_predicate) =
1670+ predicate. skip_binders ( )
1671+ {
1672+ if projection_predicate. projection_ty . item_def_id == item_def_id {
1673+ // We don't account for multiple `Future::Output = Ty` contraints.
1674+ return Some ( projection_predicate. ty ) ;
1675+ }
1676+ }
1677+ }
1678+ }
1679+ None
1680+ }
1681+
1682+ /// A possible error is to forget to add `.await` when using futures:
1683+ ///
1684+ /// ```
1685+ /// async fn make_u32() -> u32 {
1686+ /// 22
1687+ /// }
1688+ ///
1689+ /// fn take_u32(x: u32) {}
1690+ ///
1691+ /// async fn foo() {
1692+ /// let x = make_u32();
1693+ /// take_u32(x);
1694+ /// }
1695+ /// ```
1696+ ///
1697+ /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
1698+ /// expected type. If this is the case, and we are inside of an async body, it suggests adding
1699+ /// `.await` to the tail of the expression.
16451700 fn suggest_await_on_expect_found (
16461701 & self ,
16471702 cause : & ObligationCause < ' tcx > ,
@@ -1651,50 +1706,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16511706 ) {
16521707 debug ! (
16531708 "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}" ,
1654- exp_span, exp_found. expected, exp_found. found
1709+ exp_span, exp_found. expected, exp_found. found,
16551710 ) ;
16561711
1657- if let ty:: Opaque ( def_id, _) = * exp_found. expected . kind ( ) {
1658- let future_trait = self . tcx . require_lang_item ( LangItem :: Future , None ) ;
1659- // Future::Output
1660- let item_def_id = self
1661- . tcx
1662- . associated_items ( future_trait)
1663- . in_definition_order ( )
1664- . next ( )
1665- . unwrap ( )
1666- . def_id ;
1712+ if let ObligationCauseCode :: CompareImplMethodObligation { .. } = & cause. code {
1713+ return ;
1714+ }
16671715
1668- let projection_ty = self . tcx . projection_ty_from_predicates ( ( def_id, item_def_id) ) ;
1669- if let Some ( projection_ty) = projection_ty {
1670- let projection_query = self . canonicalize_query (
1671- & ParamEnvAnd { param_env : self . tcx . param_env ( def_id) , value : projection_ty } ,
1672- & mut OriginalQueryValues :: default ( ) ,
1673- ) ;
1674- if let Ok ( resp) = self . tcx . normalize_projection_ty ( projection_query) {
1675- let normalized_ty = resp. value . value . normalized_ty ;
1676- debug ! ( "suggest_await_on_expect_found: normalized={:?}" , normalized_ty) ;
1677- if ty:: TyS :: same_type ( normalized_ty, exp_found. found ) {
1678- let span = if let ObligationCauseCode :: Pattern {
1679- span,
1680- origin_expr : _,
1681- root_ty : _,
1682- } = cause. code
1683- {
1684- // scrutinee's span
1685- span. unwrap_or ( exp_span)
1686- } else {
1687- exp_span
1688- } ;
1689- diag. span_suggestion_verbose (
1690- span. shrink_to_hi ( ) ,
1691- "consider awaiting on the future" ,
1692- ".await" . to_string ( ) ,
1716+ match (
1717+ self . get_impl_future_output_ty ( exp_found. expected ) ,
1718+ self . get_impl_future_output_ty ( exp_found. found ) ,
1719+ ) {
1720+ ( Some ( exp) , Some ( found) ) if ty:: TyS :: same_type ( exp, found) => match & cause. code {
1721+ ObligationCauseCode :: IfExpression ( box IfExpressionCause { then, .. } ) => {
1722+ diag. multipart_suggestion (
1723+ "consider `await`ing on both `Future`s" ,
1724+ vec ! [
1725+ ( then. shrink_to_hi( ) , ".await" . to_string( ) ) ,
1726+ ( exp_span. shrink_to_hi( ) , ".await" . to_string( ) ) ,
1727+ ] ,
1728+ Applicability :: MaybeIncorrect ,
1729+ ) ;
1730+ }
1731+ ObligationCauseCode :: MatchExpressionArm ( box MatchExpressionArmCause {
1732+ prior_arms,
1733+ ..
1734+ } ) => {
1735+ if let [ .., arm_span] = & prior_arms[ ..] {
1736+ diag. multipart_suggestion (
1737+ "consider `await`ing on both `Future`s" ,
1738+ vec ! [
1739+ ( arm_span. shrink_to_hi( ) , ".await" . to_string( ) ) ,
1740+ ( exp_span. shrink_to_hi( ) , ".await" . to_string( ) ) ,
1741+ ] ,
16931742 Applicability :: MaybeIncorrect ,
16941743 ) ;
1744+ } else {
1745+ diag. help ( "consider `await`ing on both `Future`s" ) ;
16951746 }
16961747 }
1748+ _ => {
1749+ diag. help ( "consider `await`ing on both `Future`s" ) ;
1750+ }
1751+ } ,
1752+ ( _, Some ( ty) ) if ty:: TyS :: same_type ( exp_found. expected , ty) => {
1753+ let span = match cause. code {
1754+ // scrutinee's span
1755+ ObligationCauseCode :: Pattern { span : Some ( span) , .. } => span,
1756+ _ => exp_span,
1757+ } ;
1758+ diag. span_suggestion_verbose (
1759+ span. shrink_to_hi ( ) ,
1760+ "consider `await`ing on the `Future`" ,
1761+ ".await" . to_string ( ) ,
1762+ Applicability :: MaybeIncorrect ,
1763+ ) ;
1764+ }
1765+ ( Some ( ty) , _) if ty:: TyS :: same_type ( ty, exp_found. found ) => {
1766+ let span = match cause. code {
1767+ // scrutinee's span
1768+ ObligationCauseCode :: Pattern { span : Some ( span) , .. } => span,
1769+ _ => exp_span,
1770+ } ;
1771+ diag. span_suggestion_verbose (
1772+ span. shrink_to_hi ( ) ,
1773+ "consider `await`ing on the `Future`" ,
1774+ ".await" . to_string ( ) ,
1775+ Applicability :: MaybeIncorrect ,
1776+ ) ;
16971777 }
1778+ _ => { }
16981779 }
16991780 }
17001781
0 commit comments