@@ -24,7 +24,7 @@ use crate::hir::def_id::DefId;
2424use crate :: infer:: { self , InferCtxt } ;
2525use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
2626use crate :: session:: DiagnosticMessageId ;
27- use crate :: ty:: { self , AdtKind , ToPredicate , ToPolyTraitRef , Ty , TyCtxt , TypeFoldable } ;
27+ use crate :: ty:: { self , AdtKind , DefIdTree , ToPredicate , ToPolyTraitRef , Ty , TyCtxt , TypeFoldable } ;
2828use crate :: ty:: GenericParamDefKind ;
2929use crate :: ty:: error:: ExpectedFound ;
3030use crate :: ty:: fast_reject;
@@ -37,7 +37,7 @@ use errors::{Applicability, DiagnosticBuilder, pluralise};
3737use std:: fmt;
3838use syntax:: ast;
3939use syntax:: symbol:: { sym, kw} ;
40- use syntax_pos:: { DUMMY_SP , Span , ExpnKind } ;
40+ use syntax_pos:: { DUMMY_SP , Span , ExpnKind , MultiSpan } ;
4141
4242impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
4343 pub fn report_fulfillment_errors (
@@ -550,7 +550,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
550550 self . suggest_new_overflow_limit ( & mut err) ;
551551 }
552552
553- self . note_obligation_cause ( & mut err, obligation) ;
553+ self . note_obligation_cause_code ( & mut err, & obligation. predicate , & obligation. cause . code ,
554+ & mut vec ! [ ] ) ;
554555
555556 err. emit ( ) ;
556557 self . tcx . sess . abort_if_errors ( ) ;
@@ -941,7 +942,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
941942 bug ! ( "overflow should be handled before the `report_selection_error` path" ) ;
942943 }
943944 } ;
945+
944946 self . note_obligation_cause ( & mut err, obligation) ;
947+
945948 err. emit ( ) ;
946949 }
947950
@@ -1593,15 +1596,165 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
15931596 } )
15941597 }
15951598
1596- fn note_obligation_cause < T > ( & self ,
1597- err : & mut DiagnosticBuilder < ' _ > ,
1598- obligation : & Obligation < ' tcx , T > )
1599- where T : fmt:: Display
1600- {
1601- self . note_obligation_cause_code ( err,
1602- & obligation. predicate ,
1603- & obligation. cause . code ,
1604- & mut vec ! [ ] ) ;
1599+ fn note_obligation_cause (
1600+ & self ,
1601+ err : & mut DiagnosticBuilder < ' _ > ,
1602+ obligation : & PredicateObligation < ' tcx > ,
1603+ ) {
1604+ // First, attempt to add note to this error with an async-await-specific
1605+ // message, and fall back to regular note otherwise.
1606+ if !self . note_obligation_cause_for_async_await ( err, obligation) {
1607+ self . note_obligation_cause_code ( err, & obligation. predicate , & obligation. cause . code ,
1608+ & mut vec ! [ ] ) ;
1609+ }
1610+ }
1611+
1612+ /// Adds an async-await specific note to the diagnostic:
1613+ ///
1614+ /// ```ignore (diagnostic)
1615+ /// note: future does not implement `std::marker::Send` because this value is used across an
1616+ /// await
1617+ /// --> $DIR/issue-64130-non-send-future-diags.rs:15:5
1618+ /// |
1619+ /// LL | let g = x.lock().unwrap();
1620+ /// | - has type `std::sync::MutexGuard<'_, u32>`
1621+ /// LL | baz().await;
1622+ /// | ^^^^^^^^^^^ await occurs here, with `g` maybe used later
1623+ /// LL | }
1624+ /// | - `g` is later dropped here
1625+ /// ```
1626+ ///
1627+ /// Returns `true` if an async-await specific note was added to the diagnostic.
1628+ fn note_obligation_cause_for_async_await (
1629+ & self ,
1630+ err : & mut DiagnosticBuilder < ' _ > ,
1631+ obligation : & PredicateObligation < ' tcx > ,
1632+ ) -> bool {
1633+ debug ! ( "note_obligation_cause_for_async_await: obligation.predicate={:?} \
1634+ obligation.cause.span={:?}", obligation. predicate, obligation. cause. span) ;
1635+ let source_map = self . tcx . sess . source_map ( ) ;
1636+
1637+ // Look into the obligation predicate to determine the type in the generator which meant
1638+ // that the predicate was not satisifed.
1639+ let ( trait_ref, target_ty) = match obligation. predicate {
1640+ ty:: Predicate :: Trait ( trait_predicate) =>
1641+ ( trait_predicate. skip_binder ( ) . trait_ref , trait_predicate. skip_binder ( ) . self_ty ( ) ) ,
1642+ _ => return false ,
1643+ } ;
1644+ debug ! ( "note_obligation_cause_for_async_await: target_ty={:?}" , target_ty) ;
1645+
1646+ // Attempt to detect an async-await error by looking at the obligation causes, looking
1647+ // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to
1648+ // be present.
1649+ //
1650+ // When a future does not implement a trait because of a captured type in one of the
1651+ // generators somewhere in the call stack, then the result is a chain of obligations.
1652+ // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
1653+ // future is passed as an argument to a function C which requires a `Send` type, then the
1654+ // chain looks something like this:
1655+ //
1656+ // - `BuiltinDerivedObligation` with a generator witness (B)
1657+ // - `BuiltinDerivedObligation` with a generator (B)
1658+ // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B)
1659+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
1660+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
1661+ // - `BuiltinDerivedObligation` with a generator witness (A)
1662+ // - `BuiltinDerivedObligation` with a generator (A)
1663+ // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A)
1664+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
1665+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
1666+ // - `BindingObligation` with `impl_send (Send requirement)
1667+ //
1668+ // The first obligations in the chain can be used to get the details of the type that is
1669+ // captured but the entire chain must be inspected to detect this case.
1670+ let mut generator = None ;
1671+ let mut next_code = Some ( & obligation. cause . code ) ;
1672+ while let Some ( code) = next_code {
1673+ debug ! ( "note_obligation_cause_for_async_await: code={:?}" , code) ;
1674+ match code {
1675+ ObligationCauseCode :: BuiltinDerivedObligation ( derived_obligation) |
1676+ ObligationCauseCode :: ImplDerivedObligation ( derived_obligation) => {
1677+ debug ! ( "note_obligation_cause_for_async_await: self_ty.kind={:?}" ,
1678+ derived_obligation. parent_trait_ref. self_ty( ) . kind) ;
1679+ match derived_obligation. parent_trait_ref . self_ty ( ) . kind {
1680+ ty:: Adt ( ty:: AdtDef { did, .. } , ..) if
1681+ self . tcx . is_diagnostic_item ( sym:: gen_future, * did) => { } ,
1682+ ty:: Generator ( did, ..) => generator = generator. or ( Some ( did) ) ,
1683+ ty:: GeneratorWitness ( _) | ty:: Opaque ( ..) => { } ,
1684+ _ => return false ,
1685+ }
1686+
1687+ next_code = Some ( derived_obligation. parent_code . as_ref ( ) ) ;
1688+ } ,
1689+ ObligationCauseCode :: ItemObligation ( _) | ObligationCauseCode :: BindingObligation ( ..)
1690+ if generator. is_some ( ) => break ,
1691+ _ => return false ,
1692+ }
1693+ }
1694+
1695+ let generator_did = generator. expect ( "can only reach this if there was a generator" ) ;
1696+
1697+ // Only continue to add a note if the generator is from an `async` function.
1698+ let parent_node = self . tcx . parent ( generator_did)
1699+ . and_then ( |parent_did| self . tcx . hir ( ) . get_if_local ( parent_did) ) ;
1700+ debug ! ( "note_obligation_cause_for_async_await: parent_node={:?}" , parent_node) ;
1701+ if let Some ( hir:: Node :: Item ( hir:: Item {
1702+ kind : hir:: ItemKind :: Fn ( _, header, _, _) ,
1703+ ..
1704+ } ) ) = parent_node {
1705+ debug ! ( "note_obligation_cause_for_async_await: header={:?}" , header) ;
1706+ if header. asyncness != hir:: IsAsync :: Async {
1707+ return false ;
1708+ }
1709+ }
1710+
1711+ let span = self . tcx . def_span ( generator_did) ;
1712+ let tables = self . tcx . typeck_tables_of ( generator_did) ;
1713+ debug ! ( "note_obligation_cause_for_async_await: generator_did={:?} span={:?} " ,
1714+ generator_did, span) ;
1715+
1716+ // Look for a type inside the generator interior that matches the target type to get
1717+ // a span.
1718+ let target_span = tables. generator_interior_types . iter ( )
1719+ . find ( |ty:: GeneratorInteriorTypeCause { ty, .. } | ty:: TyS :: same_type ( * ty, target_ty) )
1720+ . map ( |ty:: GeneratorInteriorTypeCause { span, scope_span, .. } |
1721+ ( span, source_map. span_to_snippet ( * span) , scope_span) ) ;
1722+ if let Some ( ( target_span, Ok ( snippet) , scope_span) ) = target_span {
1723+ // Look at the last interior type to get a span for the `.await`.
1724+ let await_span = tables. generator_interior_types . iter ( ) . map ( |i| i. span ) . last ( ) . unwrap ( ) ;
1725+ let mut span = MultiSpan :: from_span ( await_span) ;
1726+ span. push_span_label (
1727+ await_span, format ! ( "await occurs here, with `{}` maybe used later" , snippet) ) ;
1728+
1729+ span. push_span_label ( * target_span, format ! ( "has type `{}`" , target_ty) ) ;
1730+
1731+ // If available, use the scope span to annotate the drop location.
1732+ if let Some ( scope_span) = scope_span {
1733+ span. push_span_label (
1734+ source_map. end_point ( * scope_span) ,
1735+ format ! ( "`{}` is later dropped here" , snippet) ,
1736+ ) ;
1737+ }
1738+
1739+ err. span_note ( span, & format ! (
1740+ "future does not implement `{}` as this value is used across an await" ,
1741+ trait_ref,
1742+ ) ) ;
1743+
1744+ // Add a note for the item obligation that remains - normally a note pointing to the
1745+ // bound that introduced the obligation (e.g. `T: Send`).
1746+ debug ! ( "note_obligation_cause_for_async_await: next_code={:?}" , next_code) ;
1747+ self . note_obligation_cause_code (
1748+ err,
1749+ & obligation. predicate ,
1750+ next_code. unwrap ( ) ,
1751+ & mut Vec :: new ( ) ,
1752+ ) ;
1753+
1754+ true
1755+ } else {
1756+ false
1757+ }
16051758 }
16061759
16071760 fn note_obligation_cause_code < T > ( & self ,
0 commit comments