1
1
use std:: iter;
2
2
3
3
use rustc_ast:: util:: parser:: ExprPrecedence ;
4
- use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , StashKey } ;
4
+ use rustc_errors:: { Applicability , Diag , ErrorGuaranteed } ;
5
5
use rustc_hir:: def:: { self , CtorKind , Namespace , Res } ;
6
6
use rustc_hir:: def_id:: DefId ;
7
7
use rustc_hir:: { self as hir, HirId , LangItem } ;
@@ -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 _;
@@ -58,6 +58,7 @@ enum CallStep<'tcx> {
58
58
Overloaded ( MethodCallee < ' tcx > ) ,
59
59
}
60
60
61
+ #[ allow( unused) ] // TODO
61
62
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
62
63
pub ( crate ) fn check_expr_call (
63
64
& self ,
@@ -66,7 +67,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
66
67
arg_exprs : & ' tcx [ hir:: Expr < ' tcx > ] ,
67
68
expected : Expectation < ' tcx > ,
68
69
) -> Ty < ' tcx > {
69
- let original_callee_ty = match & callee_expr. kind {
70
+ let expr_ty = match & callee_expr. kind {
70
71
hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( ..) | hir:: QPath :: TypeRelative ( ..) ) => self
71
72
. check_expr_with_expectation_and_args (
72
73
callee_expr,
@@ -76,8 +77,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
76
77
_ => self . check_expr ( callee_expr) ,
77
78
} ;
78
79
79
- let expr_ty = self . structurally_resolve_type ( call_expr. span , original_callee_ty) ;
80
-
81
80
let mut autoderef = self . autoderef ( callee_expr. span , expr_ty) ;
82
81
let mut result = None ;
83
82
while result. is_none ( ) && autoderef. next ( ) . is_some ( ) {
@@ -87,29 +86,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
87
86
88
87
let output = match result {
89
88
None => {
90
- // Check all of the arg expressions, but with no expectations
91
- // since we don't have a signature to compare them to.
92
- for arg in arg_exprs {
93
- self . check_expr ( arg) ;
94
- }
89
+ // First report an ambiguity error if possible.
90
+ let expr_ty = self . structurally_resolve_type ( call_expr. span , expr_ty) ;
95
91
96
- if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = & callee_expr. kind
97
- && let [ segment] = path. segments
98
- {
99
- self . dcx ( ) . try_steal_modify_and_emit_err (
100
- segment. ident . span ,
101
- StashKey :: CallIntoMethod ,
102
- |err| {
103
- // Try suggesting `foo(a)` -> `a.foo()` if possible.
104
- self . suggest_call_as_method (
105
- err, segment, arg_exprs, call_expr, expected,
106
- ) ;
107
- } ,
108
- ) ;
109
- }
110
-
111
- let guar = self . report_invalid_callee ( call_expr, callee_expr, expr_ty, arg_exprs) ;
112
- Ty :: new_error ( self . tcx , guar)
92
+ // this will report an error since original_callee_ty is not a fn
93
+ self . confirm_builtin_call ( call_expr, callee_expr, expr_ty, arg_exprs, expected)
113
94
}
114
95
115
96
Some ( CallStep :: Builtin ( callee_ty) ) => {
@@ -144,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
144
125
autoderef : & Autoderef < ' a , ' tcx > ,
145
126
) -> Option < CallStep < ' tcx > > {
146
127
let adjusted_ty =
147
- self . structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
128
+ self . try_structurally_resolve_type ( autoderef. span ( ) , autoderef. final_ty ( false ) ) ;
148
129
149
130
// If the callee is a bare function or a closure, then we're all set.
150
131
match * adjusted_ty. kind ( ) {
@@ -241,6 +222,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
241
222
return None ;
242
223
}
243
224
225
+ // We only want to confirm a call step here if the infer var
226
+ // originated from the defining use of an opaque.
227
+ ty:: Infer ( ty:: TyVar ( vid) )
228
+ if let Some ( alias_ty) = self . find_sup_as_registered_opaque ( vid) =>
229
+ {
230
+ return self
231
+ . try_overloaded_call_traits_for_alias ( call_expr, alias_ty, arg_exprs)
232
+ . map ( |( autoref, method) | {
233
+ let mut adjustments = self . adjust_steps ( autoderef) ;
234
+ adjustments. extend ( autoref) ;
235
+ self . apply_adjustments ( callee_expr, adjustments) ;
236
+ CallStep :: Overloaded ( method)
237
+ } ) ;
238
+ }
239
+
240
+ ty:: Infer ( _) => {
241
+ return None ;
242
+ }
243
+
244
244
ty:: Error ( _) => {
245
245
return None ;
246
246
}
@@ -305,40 +305,111 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
305
305
306
306
// Try the options that are least restrictive on the caller first.
307
307
for ( opt_trait_def_id, method_name, borrow) in call_trait_choices {
308
- let Some ( trait_def_id) = opt_trait_def_id else { continue } ;
308
+ if let Some ( confirmed) = self . try_overloaded_call_trait (
309
+ call_expr,
310
+ adjusted_ty,
311
+ opt_arg_exprs,
312
+ opt_trait_def_id,
313
+ method_name,
314
+ borrow,
315
+ ) {
316
+ return Some ( confirmed) ;
317
+ }
318
+ }
309
319
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 ) ) )
320
+ None
321
+ }
322
+
323
+ fn try_overloaded_call_trait (
324
+ & self ,
325
+ call_expr : & hir:: Expr < ' _ > ,
326
+ call_ty : Ty < ' tcx > ,
327
+ opt_arg_exprs : Option < & ' tcx [ hir:: Expr < ' tcx > ] > ,
328
+ opt_trait_def_id : Option < DefId > ,
329
+ method_name : Symbol ,
330
+ borrow : bool ,
331
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
332
+ let Some ( trait_def_id) = opt_trait_def_id else {
333
+ return None ;
334
+ } ;
335
+
336
+ let opt_input_type = opt_arg_exprs. map ( |arg_exprs| {
337
+ Ty :: new_tup_from_iter ( self . tcx , arg_exprs. iter ( ) . map ( |e| self . next_ty_var ( e. span ) ) )
338
+ } ) ;
339
+
340
+ let Some ( ok) = self . lookup_method_for_operator (
341
+ self . misc ( call_expr. span ) ,
342
+ method_name,
343
+ trait_def_id,
344
+ call_ty,
345
+ opt_input_type,
346
+ ) else {
347
+ return None ;
348
+ } ;
349
+ let method = self . register_infer_ok_obligations ( ok) ;
350
+ let mut autoref = None ;
351
+ if borrow {
352
+ // Check for &self vs &mut self in the method signature. Since this is either
353
+ // the Fn or FnMut trait, it should be one of those.
354
+ let ty:: Ref ( _, _, mutbl) = method. sig . inputs ( ) [ 0 ] . kind ( ) else {
355
+ bug ! ( "Expected `FnMut`/`Fn` to take receiver by-ref/by-mut" )
356
+ } ;
357
+
358
+ // For initial two-phase borrow
359
+ // deployment, conservatively omit
360
+ // overloaded function call ops.
361
+ let mutbl = AutoBorrowMutability :: new ( * mutbl, AllowTwoPhase :: No ) ;
362
+
363
+ autoref = Some ( Adjustment {
364
+ kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutbl) ) ,
365
+ target : method. sig . inputs ( ) [ 0 ] ,
312
366
} ) ;
367
+ }
313
368
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
- }
369
+ Some ( ( autoref, method) )
370
+ }
371
+
372
+ fn try_overloaded_call_traits_for_alias (
373
+ & self ,
374
+ call_expr : & ' tcx hir:: Expr < ' tcx > ,
375
+ alias_ty : ty:: AliasTy < ' tcx > ,
376
+ arg_exprs : & ' tcx [ rustc_hir:: Expr < ' tcx > ] ,
377
+ ) -> Option < ( Option < Adjustment < ' tcx > > , MethodCallee < ' tcx > ) > {
378
+ let call_ty = alias_ty. to_ty ( self . tcx ) ;
379
+
380
+ let call_traits = [
381
+ ( self . tcx . lang_items ( ) . fn_trait ( ) , sym:: call, true ) ,
382
+ ( self . tcx . lang_items ( ) . fn_mut_trait ( ) , sym:: call_mut, true ) ,
383
+ ( self . tcx . lang_items ( ) . fn_once_trait ( ) , sym:: call_once, false ) ,
384
+ ( self . tcx . lang_items ( ) . async_fn_trait ( ) , sym:: async_call, true ) ,
385
+ ( self . tcx . lang_items ( ) . async_fn_mut_trait ( ) , sym:: async_call_mut, true ) ,
386
+ ( self . tcx . lang_items ( ) . async_fn_once_trait ( ) , sym:: async_call_once, false ) ,
387
+ ] ;
388
+ // We only want to try a call trait if it shows up in the bounds
389
+ // of the opaque. We confirm the first one that shows up in the
390
+ // bounds list, which can lead to inference weirdness but doesn't
391
+ // matter today.
392
+ for clause in
393
+ self . tcx . item_self_bounds ( alias_ty. def_id ) . iter_instantiated ( self . tcx , alias_ty. args )
394
+ {
395
+ let Some ( poly_trait_ref) = clause. as_trait_clause ( ) else {
396
+ continue ;
397
+ } ;
340
398
341
- return Some ( ( autoref, method) ) ;
399
+ if let Some ( & ( opt_trait_def_id, method_name, borrow) ) =
400
+ call_traits. iter ( ) . find ( |( trait_def_id, _, _) | {
401
+ trait_def_id. is_some_and ( |trait_def_id| trait_def_id == poly_trait_ref. def_id ( ) )
402
+ } )
403
+ && let Some ( confirmed) = self . try_overloaded_call_trait (
404
+ call_expr,
405
+ call_ty,
406
+ Some ( arg_exprs) ,
407
+ opt_trait_def_id,
408
+ method_name,
409
+ borrow,
410
+ )
411
+ {
412
+ return Some ( confirmed) ;
342
413
}
343
414
}
344
415
0 commit comments