@@ -38,10 +38,12 @@ use std::sync::Arc;
38
38
use chalk_ir:: {
39
39
fold:: { Shift , TypeFoldable } ,
40
40
interner:: HasInterner ,
41
- NoSolution ,
41
+ NoSolution , UniverseIndex ,
42
42
} ;
43
43
use hir_def:: { expr:: ExprId , type_ref:: Rawness , TypeOrConstParamId } ;
44
+ use hir_expand:: name;
44
45
use itertools:: Either ;
46
+ use traits:: FnTrait ;
45
47
use utils:: Generics ;
46
48
47
49
use crate :: { consteval:: unknown_const, db:: HirDatabase , utils:: generics} ;
@@ -208,6 +210,7 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
208
210
pub struct CallableSig {
209
211
params_and_return : Arc < [ Ty ] > ,
210
212
is_varargs : bool ,
213
+ safety : Safety ,
211
214
}
212
215
213
216
has_interner ! ( CallableSig ) ;
@@ -216,9 +219,14 @@ has_interner!(CallableSig);
216
219
pub type PolyFnSig = Binders < CallableSig > ;
217
220
218
221
impl 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 {
220
228
params. push ( ret) ;
221
- CallableSig { params_and_return : params. into ( ) , is_varargs }
229
+ CallableSig { params_and_return : params. into ( ) , is_varargs, safety }
222
230
}
223
231
224
232
pub fn from_fn_ptr ( fn_ptr : & FnPointer ) -> CallableSig {
@@ -235,13 +243,14 @@ impl CallableSig {
235
243
. map ( |arg| arg. assert_ty_ref ( Interner ) . clone ( ) )
236
244
. collect ( ) ,
237
245
is_varargs : fn_ptr. sig . variadic ,
246
+ safety : fn_ptr. sig . safety ,
238
247
}
239
248
}
240
249
241
250
pub fn to_fn_ptr ( & self ) -> FnPointer {
242
251
FnPointer {
243
252
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 } ,
245
254
substitution : FnSubst ( Substitution :: from_iter (
246
255
Interner ,
247
256
self . params_and_return . iter ( ) . cloned ( ) ,
@@ -266,7 +275,11 @@ impl TypeFoldable<Interner> for CallableSig {
266
275
) -> Result < Self , E > {
267
276
let vec = self . params_and_return . to_vec ( ) ;
268
277
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
+ } )
270
283
}
271
284
}
272
285
@@ -508,3 +521,68 @@ where
508
521
} ) ;
509
522
Canonical { value, binders : chalk_ir:: CanonicalVarKinds :: from_iter ( Interner , kinds) }
510
523
}
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