@@ -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 ( ) ;
@@ -941,7 +942,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
941
942
bug ! ( "overflow should be handled before the `report_selection_error` path" ) ;
942
943
}
943
944
} ;
945
+
944
946
self . note_obligation_cause ( & mut err, obligation) ;
947
+
945
948
err. emit ( ) ;
946
949
}
947
950
@@ -1593,15 +1596,165 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1593
1596
} )
1594
1597
}
1595
1598
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
+ }
1605
1758
}
1606
1759
1607
1760
fn note_obligation_cause_code < T > ( & self ,
0 commit comments