@@ -2,7 +2,7 @@ use super::FnCtxt;
2
2
use crate :: astconv:: AstConv ;
3
3
4
4
use rustc_ast:: util:: parser:: ExprPrecedence ;
5
- use rustc_span:: { self , Span } ;
5
+ use rustc_span:: { self , MultiSpan , Span } ;
6
6
7
7
use rustc_errors:: { Applicability , DiagnosticBuilder } ;
8
8
use rustc_hir as hir;
@@ -287,6 +287,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
287
287
}
288
288
}
289
289
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
+
290
322
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
291
323
pub ( in super :: super ) fn suggest_calling_boxed_future_when_appropriate (
292
324
& self ,
0 commit comments