@@ -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:: {
@@ -1711,6 +1712,173 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
17111712 }
17121713}
17131714
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+
17141882/// Checks that an opaque type does not contain cycles.
17151883fn check_opaque_for_cycles < ' tcx > (
17161884 tcx : TyCtxt < ' tcx > ,
@@ -1721,21 +1889,12 @@ fn check_opaque_for_cycles<'tcx>(
17211889) {
17221890 if let Err ( partially_expanded_type) = tcx. try_expand_impl_trait_type ( def_id. to_def_id ( ) , substs)
17231891 {
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)
17371896 }
1738- err . emit ( ) ;
1897+ _ => opaque_type_cycle_error ( tcx , def_id , span ) ,
17391898 }
17401899 }
17411900}
0 commit comments