@@ -14,7 +14,7 @@ use rustc_middle::ty::adjustment::{
14
14
use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt } ;
15
15
use rustc_middle:: { bug, span_bug} ;
16
16
use rustc_span:: def_id:: LocalDefId ;
17
- use rustc_span:: { Span , sym} ;
17
+ use rustc_span:: { Span , Symbol , sym} ;
18
18
use rustc_trait_selection:: error_reporting:: traits:: DefIdOrName ;
19
19
use rustc_trait_selection:: infer:: InferCtxtExt as _;
20
20
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -66,7 +66,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
66
66
arg_exprs : & ' tcx [ hir:: Expr < ' tcx > ] ,
67
67
expected : Expectation < ' tcx > ,
68
68
) -> Ty < ' tcx > {
69
- let original_callee_ty = match & callee_expr. kind {
69
+ let expr_ty = match & callee_expr. kind {
70
70
hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( ..) | hir:: QPath :: TypeRelative ( ..) ) => self
71
71
. check_expr_with_expectation_and_args (
72
72
callee_expr,
@@ -76,8 +76,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
76
76
_ => self . check_expr ( callee_expr) ,
77
77
} ;
78
78
79
- let expr_ty = self . structurally_resolve_type ( call_expr. span , original_callee_ty) ;
80
-
81
79
let mut autoderef = self . autoderef ( callee_expr. span , expr_ty) ;
82
80
let mut result = None ;
83
81
while result. is_none ( ) && autoderef. next ( ) . is_some ( ) {
@@ -144,7 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
144
142
autoderef : & Autoderef < ' a , ' tcx > ,
145
143
) -> Option < CallStep < ' tcx > > {
146
144
let adjusted_ty =
147
- self . structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
145
+ self . try_structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
148
146
149
147
// If the callee is a bare function or a closure, then we're all set.
150
148
match * adjusted_ty. kind ( ) {
@@ -241,6 +239,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
241
239
return None ;
242
240
}
243
241
242
+ // We only want to confirm a call step here if the infer var
243
+ // originated from the defining use of an opaque.
244
+ ty:: Infer ( ty:: TyVar ( vid) )
245
+ if let Some ( alias_ty) = self . find_sup_as_registered_opaque ( vid) =>
246
+ {
247
+ return self
248
+ . try_overloaded_call_traits_for_alias ( call_expr, alias_ty, arg_exprs)
249
+ . map ( |( autoref, method) | {
250
+ let mut adjustments = self . adjust_steps ( autoderef) ;
251
+ adjustments. extend ( autoref) ;
252
+ self . apply_adjustments ( callee_expr, adjustments) ;
253
+ CallStep :: Overloaded ( method)
254
+ } ) ;
255
+ }
256
+
257
+ ty:: Infer ( _) => {
258
+ return None ;
259
+ }
260
+
244
261
ty:: Error ( _) => {
245
262
return None ;
246
263
}
@@ -305,40 +322,111 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
305
322
306
323
// Try the options that are least restrictive on the caller first.
307
324
for ( opt_trait_def_id, method_name, borrow) in call_trait_choices {
308
- let Some ( trait_def_id) = opt_trait_def_id else { continue } ;
325
+ if let Some ( confirmed) = self . try_overloaded_call_trait (
326
+ call_expr,
327
+ adjusted_ty,
328
+ opt_arg_exprs,
329
+ opt_trait_def_id,
330
+ method_name,
331
+ borrow,
332
+ ) {
333
+ return Some ( confirmed) ;
334
+ }
335
+ }
336
+
337
+ None
338
+ }
339
+
340
+ fn try_overloaded_call_trait (
341
+ & self ,
342
+ call_expr : & hir:: Expr < ' _ > ,
343
+ call_ty : Ty < ' tcx > ,
344
+ opt_arg_exprs : Option < & ' tcx [ hir:: Expr < ' tcx > ] > ,
345
+ opt_trait_def_id : Option < DefId > ,
346
+ method_name : Symbol ,
347
+ borrow : bool ,
348
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
349
+ let Some ( trait_def_id) = opt_trait_def_id else {
350
+ return None ;
351
+ } ;
352
+
353
+ let opt_input_type = opt_arg_exprs. map ( |arg_exprs| {
354
+ Ty :: new_tup_from_iter ( self . tcx , arg_exprs. iter ( ) . map ( |e| self . next_ty_var ( e. span ) ) )
355
+ } ) ;
356
+
357
+ let Some ( ok) = self . lookup_method_for_operator (
358
+ self . misc ( call_expr. span ) ,
359
+ method_name,
360
+ trait_def_id,
361
+ call_ty,
362
+ opt_input_type,
363
+ ) else {
364
+ return None ;
365
+ } ;
366
+ let method = self . register_infer_ok_obligations ( ok) ;
367
+ let mut autoref = None ;
368
+ if borrow {
369
+ // Check for &self vs &mut self in the method signature. Since this is either
370
+ // the Fn or FnMut trait, it should be one of those.
371
+ let ty:: Ref ( _, _, mutbl) = * method. sig . inputs ( ) [ 0 ] . kind ( ) else {
372
+ bug ! ( "Expected `FnMut`/`Fn` to take receiver by-ref/by-mut" )
373
+ } ;
309
374
310
- let opt_input_type = opt_arg_exprs. map ( |arg_exprs| {
311
- Ty :: new_tup_from_iter ( self . tcx , arg_exprs. iter ( ) . map ( |e| self . next_ty_var ( e. span ) ) )
375
+ // For initial two-phase borrow
376
+ // deployment, conservatively omit
377
+ // overloaded function call ops.
378
+ let mutbl = AutoBorrowMutability :: new ( mutbl, AllowTwoPhase :: No ) ;
379
+
380
+ autoref = Some ( Adjustment {
381
+ kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
382
+ target : method. sig . inputs ( ) [ 0 ] ,
312
383
} ) ;
384
+ }
313
385
314
- if let Some ( ok) = self . lookup_method_for_operator (
315
- self . misc ( call_expr. span ) ,
316
- method_name,
317
- trait_def_id,
318
- adjusted_ty,
319
- opt_input_type,
320
- ) {
321
- let method = self . register_infer_ok_obligations ( ok) ;
322
- let mut autoref = None ;
323
- if borrow {
324
- // Check for &self vs &mut self in the method signature. Since this is either
325
- // the Fn or FnMut trait, it should be one of those.
326
- let ty:: Ref ( _, _, mutbl) = method. sig . inputs ( ) [ 0 ] . kind ( ) else {
327
- bug ! ( "Expected `FnMut`/`Fn` to take receiver by-ref/by-mut" )
328
- } ;
329
-
330
- // For initial two-phase borrow
331
- // deployment, conservatively omit
332
- // overloaded function call ops.
333
- let mutbl = AutoBorrowMutability :: new ( * mutbl, AllowTwoPhase :: No ) ;
334
-
335
- autoref = Some ( Adjustment {
336
- kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
337
- target : method. sig . inputs ( ) [ 0 ] ,
338
- } ) ;
339
- }
386
+ Some ( ( autoref, method) )
387
+ }
340
388
341
- return Some ( ( autoref, method) ) ;
389
+ fn try_overloaded_call_traits_for_alias (
390
+ & self ,
391
+ call_expr : & ' tcx hir:: Expr < ' tcx > ,
392
+ alias_ty : ty:: AliasTy < ' tcx > ,
393
+ arg_exprs : & ' tcx [ rustc_hir:: Expr < ' tcx > ] ,
394
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
395
+ let call_ty = alias_ty. to_ty ( self . tcx ) ;
396
+
397
+ let call_traits = [
398
+ ( self . tcx . lang_items ( ) . fn_trait ( ) , sym:: call, true ) ,
399
+ ( self . tcx . lang_items ( ) . fn_mut_trait ( ) , sym:: call_mut, true ) ,
400
+ ( self . tcx . lang_items ( ) . fn_once_trait ( ) , sym:: call_once, false ) ,
401
+ ( self . tcx . lang_items ( ) . async_fn_trait ( ) , sym:: async_call, true ) ,
402
+ ( self . tcx . lang_items ( ) . async_fn_mut_trait ( ) , sym:: async_call_mut, true ) ,
403
+ ( self . tcx . lang_items ( ) . async_fn_once_trait ( ) , sym:: async_call_once, false ) ,
404
+ ] ;
405
+ // We only want to try a call trait if it shows up in the bounds
406
+ // of the opaque. We confirm the first one that shows up in the
407
+ // bounds list, which can lead to inference weirdness but doesn't
408
+ // matter today.
409
+ for clause in
410
+ self . tcx . item_self_bounds ( alias_ty. def_id ) . iter_instantiated ( self . tcx , alias_ty. args )
411
+ {
412
+ let Some ( poly_trait_ref) = clause. as_trait_clause ( ) else {
413
+ continue ;
414
+ } ;
415
+
416
+ if let Some ( & ( opt_trait_def_id, method_name, borrow) ) =
417
+ call_traits. iter ( ) . find ( |( trait_def_id, _, _) | {
418
+ trait_def_id. is_some_and ( |trait_def_id| trait_def_id == poly_trait_ref. def_id ( ) )
419
+ } )
420
+ && let Some ( confirmed) = self . try_overloaded_call_trait (
421
+ call_expr,
422
+ call_ty,
423
+ Some ( arg_exprs) ,
424
+ opt_trait_def_id,
425
+ method_name,
426
+ borrow,
427
+ )
428
+ {
429
+ return Some ( confirmed) ;
342
430
}
343
431
}
344
432
0 commit comments