@@ -38,10 +38,12 @@ use std::sync::Arc;
3838use chalk_ir:: {
3939 fold:: { Shift , TypeFoldable } ,
4040 interner:: HasInterner ,
41- NoSolution ,
41+ NoSolution , UniverseIndex ,
4242} ;
4343use hir_def:: { expr:: ExprId , type_ref:: Rawness , TypeOrConstParamId } ;
44+ use hir_expand:: name;
4445use itertools:: Either ;
46+ use traits:: FnTrait ;
4547use utils:: Generics ;
4648
4749use crate :: { consteval:: unknown_const, db:: HirDatabase , utils:: generics} ;
@@ -208,6 +210,7 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
208210pub struct CallableSig {
209211 params_and_return : Arc < [ Ty ] > ,
210212 is_varargs : bool ,
213+ safety : Safety ,
211214}
212215
213216has_interner ! ( CallableSig ) ;
@@ -216,9 +219,14 @@ has_interner!(CallableSig);
216219pub type PolyFnSig = Binders < CallableSig > ;
217220
218221impl CallableSig {
219- pub fn from_params_and_return ( mut params : Vec < Ty > , ret : Ty , is_varargs : bool ) -> CallableSig {
222+ pub fn from_params_and_return (
223+ mut params : Vec < Ty > ,
224+ ret : Ty ,
225+ is_varargs : bool ,
226+ safety : Safety ,
227+ ) -> CallableSig {
220228 params. push ( ret) ;
221- CallableSig { params_and_return : params. into ( ) , is_varargs }
229+ CallableSig { params_and_return : params. into ( ) , is_varargs, safety }
222230 }
223231
224232 pub fn from_fn_ptr ( fn_ptr : & FnPointer ) -> CallableSig {
@@ -235,13 +243,14 @@ impl CallableSig {
235243 . map ( |arg| arg. assert_ty_ref ( Interner ) . clone ( ) )
236244 . collect ( ) ,
237245 is_varargs : fn_ptr. sig . variadic ,
246+ safety : fn_ptr. sig . safety ,
238247 }
239248 }
240249
241250 pub fn to_fn_ptr ( & self ) -> FnPointer {
242251 FnPointer {
243252 num_binders : 0 ,
244- sig : FnSig { abi : ( ) , safety : Safety :: Safe , variadic : self . is_varargs } ,
253+ sig : FnSig { abi : ( ) , safety : self . safety , variadic : self . is_varargs } ,
245254 substitution : FnSubst ( Substitution :: from_iter (
246255 Interner ,
247256 self . params_and_return . iter ( ) . cloned ( ) ,
@@ -266,7 +275,11 @@ impl TypeFoldable<Interner> for CallableSig {
266275 ) -> Result < Self , E > {
267276 let vec = self . params_and_return . to_vec ( ) ;
268277 let folded = vec. try_fold_with ( folder, outer_binder) ?;
269- Ok ( CallableSig { params_and_return : folded. into ( ) , is_varargs : self . is_varargs } )
278+ Ok ( CallableSig {
279+ params_and_return : folded. into ( ) ,
280+ is_varargs : self . is_varargs ,
281+ safety : self . safety ,
282+ } )
270283 }
271284}
272285
@@ -508,3 +521,68 @@ where
508521 } ) ;
509522 Canonical { value, binders : chalk_ir:: CanonicalVarKinds :: from_iter ( Interner , kinds) }
510523}
524+
525+ pub fn callable_sig_from_fnonce (
526+ self_ty : & Canonical < Ty > ,
527+ env : Arc < TraitEnvironment > ,
528+ db : & dyn HirDatabase ,
529+ ) -> Option < CallableSig > {
530+ let krate = env. krate ;
531+ let fn_once_trait = FnTrait :: FnOnce . get_id ( db, krate) ?;
532+ let output_assoc_type = db. trait_data ( fn_once_trait) . associated_type_by_name ( & name ! [ Output ] ) ?;
533+
534+ let mut kinds = self_ty. binders . interned ( ) . to_vec ( ) ;
535+ let b = TyBuilder :: trait_ref ( db, fn_once_trait) ;
536+ if b. remaining ( ) != 2 {
537+ return None ;
538+ }
539+ let fn_once = b
540+ . push ( self_ty. value . clone ( ) )
541+ . fill_with_bound_vars ( DebruijnIndex :: INNERMOST , kinds. len ( ) )
542+ . build ( ) ;
543+ kinds. extend ( fn_once. substitution . iter ( Interner ) . skip ( 1 ) . map ( |x| {
544+ let vk = match x. data ( Interner ) {
545+ chalk_ir:: GenericArgData :: Ty ( _) => {
546+ chalk_ir:: VariableKind :: Ty ( chalk_ir:: TyVariableKind :: General )
547+ }
548+ chalk_ir:: GenericArgData :: Lifetime ( _) => chalk_ir:: VariableKind :: Lifetime ,
549+ chalk_ir:: GenericArgData :: Const ( c) => {
550+ chalk_ir:: VariableKind :: Const ( c. data ( Interner ) . ty . clone ( ) )
551+ }
552+ } ;
553+ chalk_ir:: WithKind :: new ( vk, UniverseIndex :: ROOT )
554+ } ) ) ;
555+
556+ // FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
557+ // `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
558+ let trait_env = env. env . clone ( ) ;
559+ let obligation = InEnvironment { goal : fn_once. cast ( Interner ) , environment : trait_env } ;
560+ let canonical =
561+ Canonical { binders : CanonicalVarKinds :: from_iter ( Interner , kinds) , value : obligation } ;
562+ let subst = match db. trait_solve ( krate, canonical) {
563+ Some ( Solution :: Unique ( vars) ) => vars. value . subst ,
564+ _ => return None ,
565+ } ;
566+ let args = subst. at ( Interner , self_ty. binders . interned ( ) . len ( ) ) . ty ( Interner ) ?;
567+ let params = match args. kind ( Interner ) {
568+ chalk_ir:: TyKind :: Tuple ( _, subst) => {
569+ subst. iter ( Interner ) . filter_map ( |arg| arg. ty ( Interner ) . cloned ( ) ) . collect :: < Vec < _ > > ( )
570+ }
571+ _ => return None ,
572+ } ;
573+ if params. iter ( ) . any ( |ty| ty. is_unknown ( ) ) {
574+ return None ;
575+ }
576+
577+ let fn_once = TyBuilder :: trait_ref ( db, fn_once_trait)
578+ . push ( self_ty. value . clone ( ) )
579+ . push ( args. clone ( ) )
580+ . build ( ) ;
581+ let projection =
582+ TyBuilder :: assoc_type_projection ( db, output_assoc_type, Some ( fn_once. substitution . clone ( ) ) )
583+ . build ( ) ;
584+
585+ let ret_ty = db. normalize_projection ( projection, env) ;
586+
587+ Some ( CallableSig :: from_params_and_return ( params, ret_ty. clone ( ) , false , Safety :: Safe ) )
588+ }
0 commit comments