@@ -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.
16261719 fn 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