@@ -2,7 +2,7 @@ use super::FnCtxt;
22use crate :: astconv:: AstConv ;
33
44use rustc_ast:: util:: parser:: ExprPrecedence ;
5- use rustc_span:: { self , Span } ;
5+ use rustc_span:: { self , MultiSpan , Span } ;
66
77use rustc_errors:: { Applicability , DiagnosticBuilder } ;
88use rustc_hir as hir;
@@ -287,6 +287,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
287287 }
288288 }
289289
290+ /// When encountering a closure that captures variables, where a FnPtr is expected,
291+ /// suggest a non-capturing closure
292+ pub ( in super :: super ) fn suggest_no_capture_closure (
293+ & self ,
294+ err : & mut DiagnosticBuilder < ' _ > ,
295+ expected : Ty < ' tcx > ,
296+ found : Ty < ' tcx > ,
297+ ) {
298+ if let ( ty:: FnPtr ( _) , ty:: Closure ( def_id, _) ) = ( expected. kind ( ) , found. kind ( ) ) {
299+ if let Some ( upvars) = self . tcx . upvars_mentioned ( * def_id) {
300+ // Report upto four upvars being captured to reduce the amount error messages
301+ // reported back to the user.
302+ let spans_and_labels = upvars
303+ . iter ( )
304+ . take ( 4 )
305+ . map ( |( var_hir_id, upvar) | {
306+ let var_name = self . tcx . hir ( ) . name ( * var_hir_id) . to_string ( ) ;
307+ let msg = format ! ( "`{}` captured here" , var_name) ;
308+ ( upvar. span , msg)
309+ } )
310+ . collect :: < Vec < _ > > ( ) ;
311+
312+ let mut multi_span: MultiSpan =
313+ spans_and_labels. iter ( ) . map ( |( sp, _) | * sp) . collect :: < Vec < _ > > ( ) . into ( ) ;
314+ for ( sp, label) in spans_and_labels {
315+ multi_span. push_span_label ( sp, label) ;
316+ }
317+ err. span_note ( multi_span, "closures can only be coerced to `fn` types if they do not capture any variables" ) ;
318+ }
319+ }
320+ }
321+
290322 /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
291323 pub ( in super :: super ) fn suggest_calling_boxed_future_when_appropriate (
292324 & self ,
0 commit comments