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