@@ -15,7 +15,7 @@ use rustc_middle::ty::adjustment::{
15
15
use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt } ;
16
16
use rustc_middle:: { bug, span_bug} ;
17
17
use rustc_span:: def_id:: LocalDefId ;
18
- use rustc_span:: { Span , sym} ;
18
+ use rustc_span:: { Span , Symbol , sym} ;
19
19
use rustc_target:: spec:: { AbiMap , AbiMapping } ;
20
20
use rustc_trait_selection:: error_reporting:: traits:: DefIdOrName ;
21
21
use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
78
78
_ => self . check_expr ( callee_expr) ,
79
79
} ;
80
80
81
- let expr_ty = self . structurally_resolve_type ( call_expr. span , original_callee_ty) ;
81
+ let expr_ty = self . try_structurally_resolve_type ( call_expr. span , original_callee_ty) ;
82
82
83
83
let mut autoderef = self . autoderef ( callee_expr. span , expr_ty) ;
84
84
let mut result = None ;
@@ -200,7 +200,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200
200
arg_exprs : & ' tcx [ hir:: Expr < ' tcx > ] ,
201
201
autoderef : & Autoderef < ' a , ' tcx > ,
202
202
) -> Option < CallStep < ' tcx > > {
203
- let adjusted_ty = self . structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( ) ) ;
203
+ let adjusted_ty =
204
+ self . try_structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( ) ) ;
204
205
205
206
// If the callee is a function pointer or a closure, then we're all set.
206
207
match * adjusted_ty. kind ( ) {
@@ -297,6 +298,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
297
298
return None ;
298
299
}
299
300
301
+ ty:: Infer ( ty:: TyVar ( vid) ) => {
302
+ // If we end up with an inference variable which is not the hidden type of
303
+ // an opaque, emit an error.
304
+ if let Some ( alias_ty) = self . find_opaque_type_related_to_vid ( vid) {
305
+ return self
306
+ . try_overloaded_call_traits_for_alias ( call_expr, alias_ty, arg_exprs)
307
+ . map ( |( autoref, method) | {
308
+ let mut adjustments = self . adjust_steps ( autoderef) ;
309
+ adjustments. extend ( autoref) ;
310
+ self . apply_adjustments ( callee_expr, adjustments) ;
311
+ CallStep :: Overloaded ( method)
312
+ } ) ;
313
+ } else {
314
+ self . type_must_be_known_at_this_point ( autoderef. span ( ) , adjusted_ty) ;
315
+ return None ;
316
+ }
317
+ }
318
+
300
319
ty:: Error ( _) => {
301
320
return None ;
302
321
}
@@ -401,6 +420,102 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
401
420
None
402
421
}
403
422
423
+ fn try_overloaded_call_trait (
424
+ & self ,
425
+ call_expr : & hir:: Expr < ' _ > ,
426
+ call_ty : Ty < ' tcx > ,
427
+ opt_arg_exprs : Option < & ' tcx [ hir:: Expr < ' tcx > ] > ,
428
+ opt_trait_def_id : Option < DefId > ,
429
+ method_name : Symbol ,
430
+ borrow : bool ,
431
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
432
+ let Some ( trait_def_id) = opt_trait_def_id else {
433
+ return None ;
434
+ } ;
435
+
436
+ let opt_input_type = opt_arg_exprs. map ( |arg_exprs| {
437
+ Ty :: new_tup_from_iter ( self . tcx , arg_exprs. iter ( ) . map ( |e| self . next_ty_var ( e. span ) ) )
438
+ } ) ;
439
+
440
+ let Some ( ok) = self . lookup_method_for_operator (
441
+ self . misc ( call_expr. span ) ,
442
+ method_name,
443
+ trait_def_id,
444
+ call_ty,
445
+ opt_input_type,
446
+ ) else {
447
+ return None ;
448
+ } ;
449
+ let method = self . register_infer_ok_obligations ( ok) ;
450
+ let mut autoref = None ;
451
+ if borrow {
452
+ // Check for &self vs &mut self in the method signature. Since this is either
453
+ // the Fn or FnMut trait, it should be one of those.
454
+ let ty:: Ref ( _, _, mutbl) = * method. sig . inputs ( ) [ 0 ] . kind ( ) else {
455
+ bug ! ( "Expected `FnMut`/`Fn` to take receiver by-ref/by-mut" )
456
+ } ;
457
+
458
+ // For initial two-phase borrow
459
+ // deployment, conservatively omit
460
+ // overloaded function call ops.
461
+ let mutbl = AutoBorrowMutability :: new ( mutbl, AllowTwoPhase :: No ) ;
462
+
463
+ autoref = Some ( Adjustment {
464
+ kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
465
+ target : method. sig . inputs ( ) [ 0 ] ,
466
+ } ) ;
467
+ }
468
+
469
+ Some ( ( autoref, method) )
470
+ }
471
+
472
+ fn try_overloaded_call_traits_for_alias (
473
+ & self ,
474
+ call_expr : & ' tcx hir:: Expr < ' tcx > ,
475
+ alias_ty : ty:: AliasTy < ' tcx > ,
476
+ arg_exprs : & ' tcx [ rustc_hir:: Expr < ' tcx > ] ,
477
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
478
+ let call_ty = alias_ty. to_ty ( self . tcx ) ;
479
+
480
+ let call_traits = [
481
+ ( self . tcx . lang_items ( ) . fn_trait ( ) , sym:: call, true ) ,
482
+ ( self . tcx . lang_items ( ) . fn_mut_trait ( ) , sym:: call_mut, true ) ,
483
+ ( self . tcx . lang_items ( ) . fn_once_trait ( ) , sym:: call_once, false ) ,
484
+ ( self . tcx . lang_items ( ) . async_fn_trait ( ) , sym:: async_call, true ) ,
485
+ ( self . tcx . lang_items ( ) . async_fn_mut_trait ( ) , sym:: async_call_mut, true ) ,
486
+ ( self . tcx . lang_items ( ) . async_fn_once_trait ( ) , sym:: async_call_once, false ) ,
487
+ ] ;
488
+ // We only want to try a call trait if it shows up in the bounds
489
+ // of the opaque. We confirm the first one that shows up in the
490
+ // bounds list, which can lead to inference weirdness but doesn't
491
+ // matter today.
492
+ for clause in
493
+ self . tcx . item_self_bounds ( alias_ty. def_id ) . iter_instantiated ( self . tcx , alias_ty. args )
494
+ {
495
+ let Some ( poly_trait_ref) = clause. as_trait_clause ( ) else {
496
+ continue ;
497
+ } ;
498
+
499
+ if let Some ( & ( opt_trait_def_id, method_name, borrow) ) =
500
+ call_traits. iter ( ) . find ( |( trait_def_id, _, _) | {
501
+ trait_def_id. is_some_and ( |trait_def_id| trait_def_id == poly_trait_ref. def_id ( ) )
502
+ } )
503
+ && let Some ( confirmed) = self . try_overloaded_call_trait (
504
+ call_expr,
505
+ call_ty,
506
+ Some ( arg_exprs) ,
507
+ opt_trait_def_id,
508
+ method_name,
509
+ borrow,
510
+ )
511
+ {
512
+ return Some ( confirmed) ;
513
+ }
514
+ }
515
+
516
+ None
517
+ }
518
+
404
519
/// Give appropriate suggestion when encountering `||{/* not callable */}()`, where the
405
520
/// likely intention is to call the closure, suggest `(||{})()`. (#55851)
406
521
fn identify_bad_closure_def_and_call (
0 commit comments