@@ -14,7 +14,7 @@ use rustc_middle::ty::adjustment::{
1414use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt } ;
1515use rustc_middle:: { bug, span_bug} ;
1616use rustc_span:: def_id:: LocalDefId ;
17- use rustc_span:: { Ident , Span , sym} ;
17+ use rustc_span:: { Ident , Span , Symbol , sym} ;
1818use rustc_trait_selection:: error_reporting:: traits:: DefIdOrName ;
1919use rustc_trait_selection:: infer:: InferCtxtExt as _;
2020use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -66,7 +66,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6666 arg_exprs : & ' tcx [ hir:: Expr < ' tcx > ] ,
6767 expected : Expectation < ' tcx > ,
6868 ) -> Ty < ' tcx > {
69- let original_callee_ty = match & callee_expr. kind {
69+ let expr_ty = match & callee_expr. kind {
7070 hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( ..) | hir:: QPath :: TypeRelative ( ..) ) => self
7171 . check_expr_with_expectation_and_args (
7272 callee_expr,
@@ -76,8 +76,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7676 _ => self . check_expr ( callee_expr) ,
7777 } ;
7878
79- let expr_ty = self . structurally_resolve_type ( call_expr. span , original_callee_ty) ;
80-
8179 let mut autoderef = self . autoderef ( callee_expr. span , expr_ty) ;
8280 let mut result = None ;
8381 while result. is_none ( ) && autoderef. next ( ) . is_some ( ) {
@@ -87,14 +85,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8785
8886 let output = match result {
8987 None => {
88+ // First report an ambiguity error if possible.
89+ let expr_ty = self . structurally_resolve_type ( call_expr. span , expr_ty) ;
90+
9091 // 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)
9893 }
9994
10095 Some ( CallStep :: Builtin ( callee_ty) ) => {
@@ -129,7 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129124 autoderef : & Autoderef < ' a , ' tcx > ,
130125 ) -> Option < CallStep < ' tcx > > {
131126 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 ) ) ;
133128
134129 // If the callee is a bare function or a closure, then we're all set.
135130 match * adjusted_ty. kind ( ) {
@@ -226,6 +221,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
226221 return None ;
227222 }
228223
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+
229243 ty:: Error ( _) => {
230244 return None ;
231245 }
@@ -290,40 +304,111 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290304
291305 // Try the options that are least restrictive on the caller first.
292306 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+ }
294321
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 ] ,
297365 } ) ;
366+ }
298367
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+ }
325370
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) ;
327412 }
328413 }
329414
0 commit comments