@@ -5,9 +5,9 @@ use rustc_infer::infer::{
55 error_reporting:: nice_region_error:: NiceRegionError ,
66 error_reporting:: unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin ,
77} ;
8- use rustc_middle:: mir:: ConstraintCategory ;
8+ use rustc_middle:: mir:: { ConstraintCategory , ReturnConstraint } ;
99use rustc_middle:: ty:: { self , RegionVid , Ty } ;
10- use rustc_span:: symbol:: kw ;
10+ use rustc_span:: symbol:: { kw , sym } ;
1111use rustc_span:: Span ;
1212
1313use crate :: util:: borrowck_errors;
@@ -26,7 +26,7 @@ impl ConstraintDescription for ConstraintCategory {
2626 // Must end with a space. Allows for empty names to be provided.
2727 match self {
2828 ConstraintCategory :: Assignment => "assignment " ,
29- ConstraintCategory :: Return => "returning this value " ,
29+ ConstraintCategory :: Return ( _ ) => "returning this value " ,
3030 ConstraintCategory :: Yield => "yielding this value " ,
3131 ConstraintCategory :: UseAsConst => "using this value as a constant " ,
3232 ConstraintCategory :: UseAsStatic => "using this value as a static " ,
@@ -37,6 +37,7 @@ impl ConstraintDescription for ConstraintCategory {
3737 ConstraintCategory :: SizedBound => "proving this value is `Sized` " ,
3838 ConstraintCategory :: CopyBound => "copying this value " ,
3939 ConstraintCategory :: OpaqueType => "opaque type " ,
40+ ConstraintCategory :: ClosureUpvar ( _) => "closure capture " ,
4041 ConstraintCategory :: Boring
4142 | ConstraintCategory :: BoringNoLocation
4243 | ConstraintCategory :: Internal => "" ,
@@ -306,8 +307,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
306307 } ;
307308
308309 let diag = match ( category, fr_is_local, outlived_fr_is_local) {
309- ( ConstraintCategory :: Return , true , false ) if self . is_closure_fn_mut ( fr) => {
310- self . report_fnmut_error ( & errci)
310+ ( ConstraintCategory :: Return ( kind ) , true , false ) if self . is_closure_fn_mut ( fr) => {
311+ self . report_fnmut_error ( & errci, kind )
311312 }
312313 ( ConstraintCategory :: Assignment , true , false )
313314 | ( ConstraintCategory :: CallArgument , true , false ) => {
@@ -347,7 +348,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
347348 /// executing...
348349 /// = note: ...therefore, returned references to captured variables will escape the closure
349350 /// ```
350- fn report_fnmut_error ( & self , errci : & ErrorConstraintInfo ) -> DiagnosticBuilder < ' tcx > {
351+ fn report_fnmut_error (
352+ & self ,
353+ errci : & ErrorConstraintInfo ,
354+ kind : ReturnConstraint ,
355+ ) -> DiagnosticBuilder < ' tcx > {
351356 let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
352357
353358 let mut diag = self
@@ -356,19 +361,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
356361 . sess
357362 . struct_span_err ( * span, "captured variable cannot escape `FnMut` closure body" ) ;
358363
359- // We should check if the return type of this closure is in fact a closure - in that
360- // case, we can special case the error further.
361- let return_type_is_closure =
362- self . regioncx . universal_regions ( ) . unnormalized_output_ty . is_closure ( ) ;
363- let message = if return_type_is_closure {
364- "returns a closure that contains a reference to a captured variable, which then \
365- escapes the closure body"
366- } else {
367- "returns a reference to a captured variable which escapes the closure body"
364+ let mut output_ty = self . regioncx . universal_regions ( ) . unnormalized_output_ty ;
365+ if let ty:: Opaque ( def_id, _) = output_ty. kind {
366+ output_ty = self . infcx . tcx . type_of ( def_id)
367+ } ;
368+
369+ debug ! ( "report_fnmut_error: output_ty={:?}" , output_ty) ;
370+
371+ let message = match output_ty. kind {
372+ ty:: Closure ( _, _) => {
373+ "returns a closure that contains a reference to a captured variable, which then \
374+ escapes the closure body"
375+ }
376+ ty:: Adt ( def, _) if self . infcx . tcx . is_diagnostic_item ( sym:: gen_future, def. did ) => {
377+ "returns an `async` block that contains a reference to a captured variable, which then \
378+ escapes the closure body"
379+ }
380+ _ => "returns a reference to a captured variable which escapes the closure body" ,
368381 } ;
369382
370383 diag. span_label ( * span, message) ;
371384
385+ if let ReturnConstraint :: ClosureUpvar ( upvar) = kind {
386+ let def_id = match self . regioncx . universal_regions ( ) . defining_ty {
387+ DefiningTy :: Closure ( def_id, _) => def_id,
388+ ty @ _ => bug ! ( "unexpected DefiningTy {:?}" , ty) ,
389+ } ;
390+
391+ let upvar_def_span = self . infcx . tcx . hir ( ) . span ( upvar) ;
392+ let upvar_span = self . infcx . tcx . upvars_mentioned ( def_id) . unwrap ( ) [ & upvar] . span ;
393+ diag. span_label ( upvar_def_span, "variable defined here" ) ;
394+ diag. span_label ( upvar_span, "variable captured here" ) ;
395+ }
396+
372397 match self . give_region_a_name ( * outlived_fr) . unwrap ( ) . source {
373398 RegionNameSource :: NamedEarlyBoundRegion ( fr_span)
374399 | RegionNameSource :: NamedFreeRegion ( fr_span)
@@ -506,7 +531,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
506531 outlived_fr_name. highlight_region_name ( & mut diag) ;
507532
508533 match ( category, outlived_fr_is_local, fr_is_local) {
509- ( ConstraintCategory :: Return , true , _) => {
534+ ( ConstraintCategory :: Return ( _ ) , true , _) => {
510535 diag. span_label (
511536 * span,
512537 format ! (
0 commit comments