@@ -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,181 @@ 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 =
1745
+ struct_span_err ! ( tcx. sess, span, E0720 , "cannot resolve opaque type to a concrete type" ) ;
1746
+
1747
+ let mut label = false ;
1748
+ if let Some ( ( hir_id, visitor) ) = get_owner_return_paths ( tcx, def_id) {
1749
+ let tables = tcx. typeck_tables_of ( tcx. hir ( ) . local_def_id ( hir_id) ) ;
1750
+ if visitor
1751
+ . returns
1752
+ . iter ( )
1753
+ . filter_map ( |expr| tables. node_type_opt ( expr. hir_id ) )
1754
+ . map ( |ty| tcx. infer_ctxt ( ) . enter ( |infcx| infcx. resolve_vars_if_possible ( & ty) ) )
1755
+ . all ( |ty| matches ! ( ty. kind, ty:: Never ) )
1756
+ {
1757
+ let spans = visitor
1758
+ . returns
1759
+ . iter ( )
1760
+ . filter ( |expr| tables. node_type_opt ( expr. hir_id ) . is_some ( ) )
1761
+ . map ( |expr| expr. span )
1762
+ . collect :: < Vec < Span > > ( ) ;
1763
+ let span_len = spans. len ( ) ;
1764
+ if span_len == 1 {
1765
+ err. span_label ( spans[ 0 ] , "this returned value is of `!` type" ) ;
1766
+ } else {
1767
+ let mut multispan: MultiSpan = spans. clone ( ) . into ( ) ;
1768
+ for span in spans {
1769
+ multispan
1770
+ . push_span_label ( span, "this returned value is of `!` type" . to_string ( ) ) ;
1771
+ }
1772
+ err. span_note ( multispan, "these returned values have a concrete \" never\" type" ) ;
1773
+ }
1774
+ err. help ( "this error will resolve once the item's body returns a concrete type" ) ;
1775
+ } else {
1776
+ let mut seen = FxHashSet :: default ( ) ;
1777
+ seen. insert ( span) ;
1778
+ err. span_label ( span, "recursive opaque type" ) ;
1779
+ label = true ;
1780
+ for ( sp, ty) in visitor
1781
+ . returns
1782
+ . iter ( )
1783
+ . filter_map ( |e| tables. node_type_opt ( e. hir_id ) . map ( |t| ( e. span , t) ) )
1784
+ . filter ( |( _, ty) | !matches ! ( ty. kind, ty:: Never ) )
1785
+ . map ( |( sp, ty) | {
1786
+ ( sp, tcx. infer_ctxt ( ) . enter ( |infcx| infcx. resolve_vars_if_possible ( & ty) ) )
1787
+ } )
1788
+ {
1789
+ struct VisitTypes ( Vec < DefId > ) ;
1790
+ impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for VisitTypes {
1791
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> bool {
1792
+ match t. kind {
1793
+ ty:: Opaque ( def, _) => {
1794
+ self . 0 . push ( def) ;
1795
+ false
1796
+ }
1797
+ _ => t. super_visit_with ( self ) ,
1798
+ }
1799
+ }
1800
+ }
1801
+ let mut visitor = VisitTypes ( vec ! [ ] ) ;
1802
+ ty. visit_with ( & mut visitor) ;
1803
+ for def_id in visitor. 0 {
1804
+ let ty_span = tcx. def_span ( def_id) ;
1805
+ if !seen. contains ( & ty_span) {
1806
+ err. span_label ( ty_span, & format ! ( "returning this opaque type `{}`" , ty) ) ;
1807
+ seen. insert ( ty_span) ;
1808
+ }
1809
+ err. span_label ( sp, & format ! ( "returning here with type `{}`" , ty) ) ;
1810
+ }
1811
+ }
1812
+ }
1813
+ }
1814
+ if !label {
1815
+ err. span_label ( span, "cannot resolve to a concrete type" ) ;
1816
+ }
1817
+ err. emit ( ) ;
1818
+ }
1819
+
1820
+ /// Emit an error for recursive opaque types in a `let` binding.
1821
+ fn binding_opaque_type_cycle_error (
1822
+ tcx : TyCtxt < ' tcx > ,
1823
+ def_id : LocalDefId ,
1824
+ span : Span ,
1825
+ partially_expanded_type : Ty < ' tcx > ,
1826
+ ) {
1827
+ let mut err =
1828
+ struct_span_err ! ( tcx. sess, span, E0720 , "cannot resolve opaque type to a concrete type" ) ;
1829
+ err. span_label ( span, "cannot resolve to a concrete type" ) ;
1830
+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) ;
1831
+ let mut prev_hir_id = hir_id;
1832
+ let mut hir_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
1833
+ while let Some ( node) = tcx. hir ( ) . find ( hir_id) {
1834
+ match node {
1835
+ hir:: Node :: Local ( hir:: Local {
1836
+ pat,
1837
+ init : None ,
1838
+ ty : Some ( ty) ,
1839
+ source : hir:: LocalSource :: Normal ,
1840
+ ..
1841
+ } ) => {
1842
+ err. span_label ( pat. span , "this binding might not have a concrete type" ) ;
1843
+ err. span_suggestion_verbose (
1844
+ ty. span . shrink_to_hi ( ) ,
1845
+ "set the binding to a value for a concrete type to be resolved" ,
1846
+ " = /* value */" . to_string ( ) ,
1847
+ Applicability :: HasPlaceholders ,
1848
+ ) ;
1849
+ }
1850
+ hir:: Node :: Local ( hir:: Local {
1851
+ init : Some ( expr) ,
1852
+ source : hir:: LocalSource :: Normal ,
1853
+ ..
1854
+ } ) => {
1855
+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) ;
1856
+ let tables =
1857
+ tcx. typeck_tables_of ( tcx. hir ( ) . local_def_id ( tcx. hir ( ) . get_parent_item ( hir_id) ) ) ;
1858
+ let ty = tables. node_type_opt ( expr. hir_id ) ;
1859
+ if let Some ( ty) =
1860
+ tcx. infer_ctxt ( ) . enter ( |infcx| infcx. resolve_vars_if_possible ( & ty) )
1861
+ {
1862
+ err. span_label (
1863
+ expr. span ,
1864
+ & format ! (
1865
+ "this is of type `{}`, which doesn't constrain \
1866
+ `{}` enough to arrive to a concrete type",
1867
+ ty, partially_expanded_type
1868
+ ) ,
1869
+ ) ;
1870
+ }
1871
+ }
1872
+ _ => { }
1873
+ }
1874
+ if prev_hir_id == hir_id {
1875
+ break ;
1876
+ }
1877
+ prev_hir_id = hir_id;
1878
+ hir_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
1879
+ }
1880
+ err. emit ( ) ;
1881
+ }
1882
+
1883
+ fn async_opaque_type_cycle_error ( tcx : TyCtxt < ' tcx > , span : Span ) {
1884
+ struct_span_err ! ( tcx. sess, span, E0733 , "recursion in an `async fn` requires boxing" )
1885
+ . span_label ( span, "recursive `async fn`" )
1886
+ . note ( "a recursive `async fn` must be rewritten to return a boxed `dyn Future`" )
1887
+ . emit ( ) ;
1888
+ }
1889
+
1714
1890
/// Checks that an opaque type does not contain cycles.
1715
1891
fn check_opaque_for_cycles < ' tcx > (
1716
1892
tcx : TyCtxt < ' tcx > ,
@@ -1721,21 +1897,12 @@ fn check_opaque_for_cycles<'tcx>(
1721
1897
) {
1722
1898
if let Err ( partially_expanded_type) = tcx. try_expand_impl_trait_type ( def_id. to_def_id ( ) , substs)
1723
1899
{
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) ) ;
1900
+ match origin {
1901
+ hir:: OpaqueTyOrigin :: AsyncFn => async_opaque_type_cycle_error ( tcx, span) ,
1902
+ hir:: OpaqueTyOrigin :: Binding => {
1903
+ binding_opaque_type_cycle_error ( tcx, def_id, span, partially_expanded_type)
1737
1904
}
1738
- err . emit ( ) ;
1905
+ _ => opaque_type_cycle_error ( tcx , def_id , span ) ,
1739
1906
}
1740
1907
}
1741
1908
}
0 commit comments