@@ -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:: { Ident , Span , sym} ;
17
+ use rustc_span:: { Ident , 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 ( ) {
@@ -87,14 +85,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
87
85
88
86
let output = match result {
89
87
None => {
88
+ // First report an ambiguity error if possible.
89
+ let expr_ty = self . structurally_resolve_type ( call_expr. span , expr_ty) ;
90
+
90
91
// this will report an error since original_callee_ty is not a fn
91
- self . confirm_builtin_call (
92
- call_expr,
93
- callee_expr,
94
- original_callee_ty,
95
- arg_exprs,
96
- expected,
97
- )
92
+ self . confirm_builtin_call ( call_expr, callee_expr, expr_ty, arg_exprs, expected)
98
93
}
99
94
100
95
Some ( CallStep :: Builtin ( callee_ty) ) => {
@@ -129,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129
124
autoderef : & Autoderef < ' a , ' tcx > ,
130
125
) -> Option < CallStep < ' tcx > > {
131
126
let adjusted_ty =
132
- self . structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
127
+ self . try_structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
133
128
134
129
// If the callee is a bare function or a closure, then we're all set.
135
130
match * adjusted_ty. kind ( ) {
@@ -226,6 +221,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
226
221
return None ;
227
222
}
228
223
224
+ // We only want to confirm a call step here if the infer var
225
+ // originated from the defining use of an opaque.
226
+ ty:: Infer ( ty:: TyVar ( vid) )
227
+ if let Some ( alias_ty) = self . find_sup_as_registered_opaque ( vid) =>
228
+ {
229
+ return self
230
+ . try_overloaded_call_traits_for_alias ( call_expr, alias_ty, arg_exprs)
231
+ . map ( |( autoref, method) | {
232
+ let mut adjustments = self . adjust_steps ( autoderef) ;
233
+ adjustments. extend ( autoref) ;
234
+ self . apply_adjustments ( callee_expr, adjustments) ;
235
+ CallStep :: Overloaded ( method)
236
+ } ) ;
237
+ }
238
+
239
+ ty:: Infer ( _) => {
240
+ return None ;
241
+ }
242
+
229
243
ty:: Error ( _) => {
230
244
return None ;
231
245
}
@@ -290,40 +304,111 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290
304
291
305
// Try the options that are least restrictive on the caller first.
292
306
for ( opt_trait_def_id, method_name, borrow) in call_trait_choices {
293
- let Some ( trait_def_id) = opt_trait_def_id else { continue } ;
307
+ if let Some ( confirmed) = self . try_overloaded_call_trait (
308
+ call_expr,
309
+ adjusted_ty,
310
+ opt_arg_exprs,
311
+ opt_trait_def_id,
312
+ method_name,
313
+ borrow,
314
+ ) {
315
+ return Some ( confirmed) ;
316
+ }
317
+ }
318
+
319
+ None
320
+ }
294
321
295
- let opt_input_type = opt_arg_exprs. map ( |arg_exprs| {
296
- Ty :: new_tup_from_iter ( self . tcx , arg_exprs. iter ( ) . map ( |e| self . next_ty_var ( e. span ) ) )
322
+ fn try_overloaded_call_trait (
323
+ & self ,
324
+ call_expr : & hir:: Expr < ' _ > ,
325
+ call_ty : Ty < ' tcx > ,
326
+ opt_arg_exprs : Option < & ' tcx [ hir:: Expr < ' tcx > ] > ,
327
+ opt_trait_def_id : Option < DefId > ,
328
+ method_name : Symbol ,
329
+ borrow : bool ,
330
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
331
+ let Some ( trait_def_id) = opt_trait_def_id else {
332
+ return None ;
333
+ } ;
334
+
335
+ let opt_input_type = opt_arg_exprs. map ( |arg_exprs| {
336
+ Ty :: new_tup_from_iter ( self . tcx , arg_exprs. iter ( ) . map ( |e| self . next_ty_var ( e. span ) ) )
337
+ } ) ;
338
+
339
+ let Some ( ok) = self . lookup_method_in_trait (
340
+ self . misc ( call_expr. span ) ,
341
+ Ident :: with_dummy_span ( method_name) ,
342
+ trait_def_id,
343
+ call_ty,
344
+ opt_input_type,
345
+ ) else {
346
+ return None ;
347
+ } ;
348
+ let method = self . register_infer_ok_obligations ( ok) ;
349
+ let mut autoref = None ;
350
+ if borrow {
351
+ // Check for &self vs &mut self in the method signature. Since this is either
352
+ // the Fn or FnMut trait, it should be one of those.
353
+ let ty:: Ref ( _, _, mutbl) = method. sig . inputs ( ) [ 0 ] . kind ( ) else {
354
+ bug ! ( "Expected `FnMut`/`Fn` to take receiver by-ref/by-mut" )
355
+ } ;
356
+
357
+ // For initial two-phase borrow
358
+ // deployment, conservatively omit
359
+ // overloaded function call ops.
360
+ let mutbl = AutoBorrowMutability :: new ( * mutbl, AllowTwoPhase :: No ) ;
361
+
362
+ autoref = Some ( Adjustment {
363
+ kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
364
+ target : method. sig . inputs ( ) [ 0 ] ,
297
365
} ) ;
366
+ }
298
367
299
- if let Some ( ok) = self . lookup_method_in_trait (
300
- self . misc ( call_expr. span ) ,
301
- Ident :: with_dummy_span ( method_name) ,
302
- trait_def_id,
303
- adjusted_ty,
304
- opt_input_type,
305
- ) {
306
- let method = self . register_infer_ok_obligations ( ok) ;
307
- let mut autoref = None ;
308
- if borrow {
309
- // Check for &self vs &mut self in the method signature. Since this is either
310
- // the Fn or FnMut trait, it should be one of those.
311
- let ty:: Ref ( _, _, mutbl) = method. sig . inputs ( ) [ 0 ] . kind ( ) else {
312
- bug ! ( "Expected `FnMut`/`Fn` to take receiver by-ref/by-mut" )
313
- } ;
314
-
315
- // For initial two-phase borrow
316
- // deployment, conservatively omit
317
- // overloaded function call ops.
318
- let mutbl = AutoBorrowMutability :: new ( * mutbl, AllowTwoPhase :: No ) ;
319
-
320
- autoref = Some ( Adjustment {
321
- kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
322
- target : method. sig . inputs ( ) [ 0 ] ,
323
- } ) ;
324
- }
368
+ Some ( ( autoref, method) )
369
+ }
325
370
326
- return Some ( ( autoref, method) ) ;
371
+ fn try_overloaded_call_traits_for_alias (
372
+ & self ,
373
+ call_expr : & ' tcx hir:: Expr < ' tcx > ,
374
+ alias_ty : ty:: AliasTy < ' tcx > ,
375
+ arg_exprs : & ' tcx [ rustc_hir:: Expr < ' tcx > ] ,
376
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
377
+ let call_ty = alias_ty. to_ty ( self . tcx ) ;
378
+
379
+ let call_traits = [
380
+ ( self . tcx . lang_items ( ) . fn_trait ( ) , sym:: call, true ) ,
381
+ ( self . tcx . lang_items ( ) . fn_mut_trait ( ) , sym:: call_mut, true ) ,
382
+ ( self . tcx . lang_items ( ) . fn_once_trait ( ) , sym:: call_once, false ) ,
383
+ ( self . tcx . lang_items ( ) . async_fn_trait ( ) , sym:: async_call, true ) ,
384
+ ( self . tcx . lang_items ( ) . async_fn_mut_trait ( ) , sym:: async_call_mut, true ) ,
385
+ ( self . tcx . lang_items ( ) . async_fn_once_trait ( ) , sym:: async_call_once, false ) ,
386
+ ] ;
387
+ // We only want to try a call trait if it shows up in the bounds
388
+ // of the opaque. We confirm the first one that shows up in the
389
+ // bounds list, which can lead to inference weirdness but doesn't
390
+ // matter today.
391
+ for clause in
392
+ self . tcx . item_self_bounds ( alias_ty. def_id ) . iter_instantiated ( self . tcx , alias_ty. args )
393
+ {
394
+ let Some ( poly_trait_ref) = clause. as_trait_clause ( ) else {
395
+ continue ;
396
+ } ;
397
+
398
+ if let Some ( & ( opt_trait_def_id, method_name, borrow) ) =
399
+ call_traits. iter ( ) . find ( |( trait_def_id, _, _) | {
400
+ trait_def_id. is_some_and ( |trait_def_id| trait_def_id == poly_trait_ref. def_id ( ) )
401
+ } )
402
+ && let Some ( confirmed) = self . try_overloaded_call_trait (
403
+ call_expr,
404
+ call_ty,
405
+ Some ( arg_exprs) ,
406
+ opt_trait_def_id,
407
+ method_name,
408
+ borrow,
409
+ )
410
+ {
411
+ return Some ( confirmed) ;
327
412
}
328
413
}
329
414
0 commit comments