@@ -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