@@ -138,6 +138,7 @@ use rustc_target::spec::abi::Abi;
138
138
use rustc_trait_selection:: infer:: InferCtxtExt as _;
139
139
use rustc_trait_selection:: opaque_types:: { InferCtxtExt as _, OpaqueTypeDecl } ;
140
140
use rustc_trait_selection:: traits:: error_reporting:: recursive_type_with_infinite_size_error;
141
+ use rustc_trait_selection:: traits:: error_reporting:: suggestions:: ReturnsVisitor ;
141
142
use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt as _;
142
143
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
143
144
use rustc_trait_selection:: traits:: {
@@ -1711,6 +1712,173 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
1711
1712
}
1712
1713
}
1713
1714
1715
+ /// Given a `DefId` for an opaque type in return position, find its parent item's return
1716
+ /// expressions.
1717
+ fn get_owner_return_paths (
1718
+ tcx : TyCtxt < ' tcx > ,
1719
+ def_id : LocalDefId ,
1720
+ ) -> Option < ( hir:: HirId , ReturnsVisitor < ' tcx > ) > {
1721
+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) ;
1722
+ let id = tcx. hir ( ) . get_parent_item ( hir_id) ;
1723
+ tcx. hir ( )
1724
+ . find ( id)
1725
+ . map ( |n| ( id, n) )
1726
+ . and_then ( |( hir_id, node) | node. body_id ( ) . map ( |b| ( hir_id, b) ) )
1727
+ . map ( |( hir_id, body_id) | {
1728
+ let body = tcx. hir ( ) . body ( body_id) ;
1729
+ let mut visitor = ReturnsVisitor :: default ( ) ;
1730
+ visitor. visit_body ( body) ;
1731
+ ( hir_id, visitor)
1732
+ } )
1733
+ }
1734
+
1735
+ /// Emit an error for recursive opaque types.
1736
+ ///
1737
+ /// If this is a return `impl Trait`, find the item's return expressions and point at them. For
1738
+ /// direct recursion this is enough, but for indirect recursion also point at the last intermediary
1739
+ /// `impl Trait`.
1740
+ ///
1741
+ /// If all the return expressions evaluate to `!`, then we explain that the error will go away
1742
+ /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
1743
+ fn opaque_type_cycle_error ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId , span : Span ) {
1744
+ let mut err = struct_span_err ! ( tcx. sess, span, E0720 , "cannot resolve opaque type" ) ;
1745
+
1746
+ let mut label = false ;
1747
+ if let Some ( ( hir_id, visitor) ) = get_owner_return_paths ( tcx, def_id) {
1748
+ let tables = tcx. typeck_tables_of ( tcx. hir ( ) . local_def_id ( hir_id) ) ;
1749
+ if visitor
1750
+ . returns
1751
+ . iter ( )
1752
+ . filter_map ( |expr| tables. node_type_opt ( expr. hir_id ) )
1753
+ . all ( |ty| matches ! ( ty. kind, ty:: Never ) )
1754
+ {
1755
+ let spans = visitor
1756
+ . returns
1757
+ . iter ( )
1758
+ . filter ( |expr| tables. node_type_opt ( expr. hir_id ) . is_some ( ) )
1759
+ . map ( |expr| expr. span )
1760
+ . collect :: < Vec < Span > > ( ) ;
1761
+ let span_len = spans. len ( ) ;
1762
+ if span_len == 1 {
1763
+ err. span_label ( spans[ 0 ] , "this returned value is of `!` type" ) ;
1764
+ } else {
1765
+ let mut multispan: MultiSpan = spans. clone ( ) . into ( ) ;
1766
+ for span in spans {
1767
+ multispan
1768
+ . push_span_label ( span, "this returned value is of `!` type" . to_string ( ) ) ;
1769
+ }
1770
+ err. span_note ( multispan, "these returned values have a concrete \" never\" type" ) ;
1771
+ }
1772
+ err. help ( "this error will resolve once the item's body returns a concrete type" ) ;
1773
+ } else {
1774
+ let mut seen = FxHashSet :: default ( ) ;
1775
+ seen. insert ( span) ;
1776
+ err. span_label ( span, "recursive opaque type" ) ;
1777
+ label = true ;
1778
+ for ( sp, ty) in visitor
1779
+ . returns
1780
+ . iter ( )
1781
+ . filter_map ( |e| tables. node_type_opt ( e. hir_id ) . map ( |t| ( e. span , t) ) )
1782
+ . filter ( |( _, ty) | !matches ! ( ty. kind, ty:: Never ) )
1783
+ {
1784
+ struct VisitTypes ( Vec < DefId > ) ;
1785
+ impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for VisitTypes {
1786
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> bool {
1787
+ match t. kind {
1788
+ ty:: Opaque ( def, _) => {
1789
+ self . 0 . push ( def) ;
1790
+ false
1791
+ }
1792
+ _ => t. super_visit_with ( self ) ,
1793
+ }
1794
+ }
1795
+ }
1796
+ let mut visitor = VisitTypes ( vec ! [ ] ) ;
1797
+ ty. visit_with ( & mut visitor) ;
1798
+ for def_id in visitor. 0 {
1799
+ let ty_span = tcx. def_span ( def_id) ;
1800
+ if !seen. contains ( & ty_span) {
1801
+ err. span_label ( ty_span, & format ! ( "returning this opaque type `{}`" , ty) ) ;
1802
+ seen. insert ( ty_span) ;
1803
+ }
1804
+ err. span_label ( sp, & format ! ( "returning here with type `{}`" , ty) ) ;
1805
+ }
1806
+ }
1807
+ }
1808
+ }
1809
+ if !label {
1810
+ err. span_label ( span, "cannot resolve opaque type" ) ;
1811
+ }
1812
+ err. emit ( ) ;
1813
+ }
1814
+
1815
+ /// Emit an error for recursive opaque types in a `let` binding.
1816
+ fn binding_opaque_type_cycle_error (
1817
+ tcx : TyCtxt < ' tcx > ,
1818
+ def_id : LocalDefId ,
1819
+ span : Span ,
1820
+ partially_expanded_type : Ty < ' tcx > ,
1821
+ ) {
1822
+ let mut err = struct_span_err ! ( tcx. sess, span, E0720 , "cannot resolve opaque type" ) ;
1823
+ err. span_label ( span, "cannot resolve opaque type" ) ;
1824
+ // Find the the owner that declared this `impl Trait` type.
1825
+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) ;
1826
+ let mut prev_hir_id = hir_id;
1827
+ let mut hir_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
1828
+ while let Some ( node) = tcx. hir ( ) . find ( hir_id) {
1829
+ match node {
1830
+ hir:: Node :: Local ( hir:: Local {
1831
+ pat,
1832
+ init : None ,
1833
+ ty : Some ( ty) ,
1834
+ source : hir:: LocalSource :: Normal ,
1835
+ ..
1836
+ } ) => {
1837
+ err. span_label ( pat. span , "this binding might not have a concrete type" ) ;
1838
+ err. span_suggestion_verbose (
1839
+ ty. span . shrink_to_hi ( ) ,
1840
+ "set the binding to a value for a concrete type to be resolved" ,
1841
+ " = /* value */" . to_string ( ) ,
1842
+ Applicability :: HasPlaceholders ,
1843
+ ) ;
1844
+ }
1845
+ hir:: Node :: Local ( hir:: Local {
1846
+ init : Some ( expr) ,
1847
+ source : hir:: LocalSource :: Normal ,
1848
+ ..
1849
+ } ) => {
1850
+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) ;
1851
+ let tables =
1852
+ tcx. typeck_tables_of ( tcx. hir ( ) . local_def_id ( tcx. hir ( ) . get_parent_item ( hir_id) ) ) ;
1853
+ if let Some ( ty) = tables. node_type_opt ( expr. hir_id ) {
1854
+ err. span_label (
1855
+ expr. span ,
1856
+ & format ! (
1857
+ "this is of type `{}`, which doesn't constrain \
1858
+ `{}` enough to arrive to a concrete type",
1859
+ ty, partially_expanded_type
1860
+ ) ,
1861
+ ) ;
1862
+ }
1863
+ }
1864
+ _ => { }
1865
+ }
1866
+ if prev_hir_id == hir_id {
1867
+ break ;
1868
+ }
1869
+ prev_hir_id = hir_id;
1870
+ hir_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
1871
+ }
1872
+ err. emit ( ) ;
1873
+ }
1874
+
1875
+ fn async_opaque_type_cycle_error ( tcx : TyCtxt < ' tcx > , span : Span ) {
1876
+ struct_span_err ! ( tcx. sess, span, E0733 , "recursion in an `async fn` requires boxing" )
1877
+ . span_label ( span, "recursive `async fn`" )
1878
+ . note ( "a recursive `async fn` must be rewritten to return a boxed `dyn Future`" )
1879
+ . emit ( ) ;
1880
+ }
1881
+
1714
1882
/// Checks that an opaque type does not contain cycles.
1715
1883
fn check_opaque_for_cycles < ' tcx > (
1716
1884
tcx : TyCtxt < ' tcx > ,
@@ -1721,21 +1889,12 @@ fn check_opaque_for_cycles<'tcx>(
1721
1889
) {
1722
1890
if let Err ( partially_expanded_type) = tcx. try_expand_impl_trait_type ( def_id. to_def_id ( ) , substs)
1723
1891
{
1724
- if let hir:: OpaqueTyOrigin :: AsyncFn = origin {
1725
- struct_span_err ! ( tcx. sess, span, E0733 , "recursion in an `async fn` requires boxing" , )
1726
- . span_label ( span, "recursive `async fn`" )
1727
- . note ( "a recursive `async fn` must be rewritten to return a boxed `dyn Future`" )
1728
- . emit ( ) ;
1729
- } else {
1730
- let mut err =
1731
- struct_span_err ! ( tcx. sess, span, E0720 , "opaque type expands to a recursive type" , ) ;
1732
- err. span_label ( span, "expands to a recursive type" ) ;
1733
- if let ty:: Opaque ( ..) = partially_expanded_type. kind {
1734
- err. note ( "type resolves to itself" ) ;
1735
- } else {
1736
- err. note ( & format ! ( "expanded type is `{}`" , partially_expanded_type) ) ;
1892
+ match origin {
1893
+ hir:: OpaqueTyOrigin :: AsyncFn => async_opaque_type_cycle_error ( tcx, span) ,
1894
+ hir:: OpaqueTyOrigin :: Binding => {
1895
+ binding_opaque_type_cycle_error ( tcx, def_id, span, partially_expanded_type)
1737
1896
}
1738
- err . emit ( ) ;
1897
+ _ => opaque_type_cycle_error ( tcx , def_id , span ) ,
1739
1898
}
1740
1899
}
1741
1900
}
0 commit comments