22
33use std:: iter;
44
5+ use crate :: traits:: TupleArgumentsFlag ;
6+
57use super :: assembly:: { self , AssemblyCtxt } ;
68use super :: { CanonicalGoal , Certainty , EvalCtxt , Goal , QueryResult } ;
79use rustc_hir:: def_id:: DefId ;
10+ use rustc_hir:: Unsafety ;
811use rustc_infer:: infer:: { InferCtxt , InferOk , LateBoundRegionConversionTime } ;
912use rustc_infer:: traits:: query:: NoSolution ;
1013use rustc_infer:: traits:: util:: supertraits;
@@ -13,6 +16,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
1316use rustc_middle:: ty:: TraitPredicate ;
1417use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1518use rustc_span:: DUMMY_SP ;
19+ use rustc_target:: spec:: abi:: Abi ;
1620
1721#[ allow( dead_code) ] // FIXME: implement and use all variants.
1822#[ derive( Debug , Clone , Copy ) ]
@@ -53,6 +57,9 @@ pub(super) enum CandidateSource {
5357 /// at the constituent types of the `self_ty` to check whether the auto trait
5458 /// is implemented for those.
5559 AutoImpl ,
60+ /// An automatic impl for `Fn`/`FnMut`/`FnOnce` for fn pointers, fn items,
61+ /// and closures.
62+ Fn ,
5663}
5764
5865type Candidate < ' tcx > = assembly:: Candidate < ' tcx , TraitPredicate < ' tcx > > ;
@@ -214,6 +221,39 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
214221 acx. try_insert_candidate ( CandidateSource :: AutoImpl , certainty) ;
215222 } )
216223 }
224+
225+ fn consider_fn_candidate (
226+ acx : & mut AssemblyCtxt < ' _ , ' tcx , Self > ,
227+ goal : Goal < ' tcx , Self > ,
228+ bound_sig : ty:: PolyFnSig < ' tcx > ,
229+ tuple_args_flag : TupleArgumentsFlag ,
230+ ) {
231+ if bound_sig. unsafety ( ) != Unsafety :: Normal || bound_sig. c_variadic ( ) {
232+ return ;
233+ }
234+
235+ // Binder skipped here (*)
236+ let ( arguments_tuple, expected_abi) = match tuple_args_flag {
237+ TupleArgumentsFlag :: No => ( bound_sig. skip_binder ( ) . inputs ( ) [ 0 ] , Abi :: RustCall ) ,
238+ TupleArgumentsFlag :: Yes => {
239+ ( acx. cx . tcx . intern_tup ( bound_sig. skip_binder ( ) . inputs ( ) ) , Abi :: Rust )
240+ }
241+ } ;
242+ if expected_abi != bound_sig. abi ( ) {
243+ return ;
244+ }
245+ // (*) Rebound here
246+ let found_trait_ref = bound_sig. rebind (
247+ acx. cx
248+ . tcx
249+ . mk_trait_ref ( goal. predicate . def_id ( ) , [ goal. predicate . self_ty ( ) , arguments_tuple] ) ,
250+ ) ;
251+
252+ acx. infcx . probe ( |_| {
253+ // FIXME: This needs to validate that `fn() -> TY` has `TY: Sized`.
254+ match_poly_trait_ref_against_goal ( acx, goal, found_trait_ref, CandidateSource :: Fn ) ;
255+ } )
256+ }
217257}
218258
219259fn match_poly_trait_ref_against_goal < ' tcx > (
@@ -379,7 +419,8 @@ impl<'tcx> EvalCtxt<'tcx> {
379419 | ( CandidateSource :: ObjectBound ( _) , _)
380420 | ( CandidateSource :: ObjectAutoBound , _)
381421 | ( CandidateSource :: Builtin , _)
382- | ( CandidateSource :: AutoImpl , _) => unimplemented ! ( ) ,
422+ | ( CandidateSource :: AutoImpl , _)
423+ | ( CandidateSource :: Fn , _) => unimplemented ! ( ) ,
383424 }
384425 }
385426
0 commit comments