@@ -138,6 +138,7 @@ use rustc_target::spec::abi::Abi;
138138use  rustc_trait_selection:: infer:: InferCtxtExt  as  _; 
139139use  rustc_trait_selection:: opaque_types:: { InferCtxtExt  as  _,  OpaqueTypeDecl } ; 
140140use  rustc_trait_selection:: traits:: error_reporting:: recursive_type_with_infinite_size_error; 
141+ use  rustc_trait_selection:: traits:: error_reporting:: suggestions:: ReturnsVisitor ; 
141142use  rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt  as  _; 
142143use  rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt  as  _; 
143144use  rustc_trait_selection:: traits:: { 
@@ -1710,6 +1711,173 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
17101711    } 
17111712} 
17121713
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+ 
17131881/// Checks that an opaque type does not contain cycles. 
17141882fn  check_opaque_for_cycles < ' tcx > ( 
17151883    tcx :  TyCtxt < ' tcx > , 
@@ -1720,21 +1888,12 @@ fn check_opaque_for_cycles<'tcx>(
17201888)  { 
17211889    if  let  Err ( partially_expanded_type)  = tcx. try_expand_impl_trait_type ( def_id. to_def_id ( ) ,  substs) 
17221890    { 
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) 
17361895            } 
1737-             err . emit ( ) ; 
1896+             _ =>  opaque_type_cycle_error ( tcx ,  def_id ,  span ) , 
17381897        } 
17391898    } 
17401899} 
0 commit comments