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