@@ -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,181 @@ 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 =
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+
17141890/// Checks that an opaque type does not contain cycles.
17151891fn check_opaque_for_cycles < ' tcx > (
17161892 tcx : TyCtxt < ' tcx > ,
@@ -1721,21 +1897,12 @@ fn check_opaque_for_cycles<'tcx>(
17211897) {
17221898 if let Err ( partially_expanded_type) = tcx. try_expand_impl_trait_type ( def_id. to_def_id ( ) , substs)
17231899 {
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)
17371904 }
1738- err . emit ( ) ;
1905+ _ => opaque_type_cycle_error ( tcx , def_id , span ) ,
17391906 }
17401907 }
17411908}
0 commit comments