@@ -24,7 +24,7 @@ use crate::hir::def_id::DefId;
24
24
use crate :: infer:: { self , InferCtxt } ;
25
25
use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
26
26
use 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 } ;
28
28
use crate :: ty:: GenericParamDefKind ;
29
29
use crate :: ty:: error:: ExpectedFound ;
30
30
use crate :: ty:: fast_reject;
@@ -37,7 +37,7 @@ use errors::{Applicability, DiagnosticBuilder, pluralise};
37
37
use std:: fmt;
38
38
use syntax:: ast;
39
39
use syntax:: symbol:: { sym, kw} ;
40
- use syntax_pos:: { DUMMY_SP , Span , ExpnKind } ;
40
+ use syntax_pos:: { DUMMY_SP , Span , ExpnKind , MultiSpan } ;
41
41
42
42
impl < ' a , ' tcx > InferCtxt < ' a , ' tcx > {
43
43
pub fn report_fulfillment_errors (
@@ -550,7 +550,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
550
550
self . suggest_new_overflow_limit ( & mut err) ;
551
551
}
552
552
553
- self . note_obligation_cause ( & mut err, obligation) ;
553
+ self . note_obligation_cause_code ( & mut err, & obligation. predicate , & obligation. cause . code ,
554
+ & mut vec ! [ ] ) ;
554
555
555
556
err. emit ( ) ;
556
557
self . tcx . sess . abort_if_errors ( ) ;
@@ -940,7 +941,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
940
941
bug ! ( "overflow should be handled before the `report_selection_error` path" ) ;
941
942
}
942
943
} ;
944
+
943
945
self . note_obligation_cause ( & mut err, obligation) ;
946
+
944
947
err. emit ( ) ;
945
948
}
946
949
@@ -1604,15 +1607,165 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1604
1607
} )
1605
1608
}
1606
1609
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
+ }
1616
1769
}
1617
1770
1618
1771
fn note_obligation_cause_code < T > ( & self ,
0 commit comments