@@ -62,9 +62,9 @@ use hir_ty::{
62
62
subst_prefix,
63
63
traits:: FnTrait ,
64
64
AliasEq , AliasTy , BoundVar , CallableDefId , CallableSig , Canonical , CanonicalVarKinds , Cast ,
65
- DebruijnIndex , GenericArgData , InEnvironment , Interner , ParamKind , QuantifiedWhereClause ,
66
- Scalar , Solution , Substitution , TraitEnvironment , TraitRefExt , Ty , TyBuilder , TyDefId , TyExt ,
67
- TyKind , TyVariableKind , WhereClause ,
65
+ ClosureId , DebruijnIndex , GenericArgData , InEnvironment , Interner , ParamKind ,
66
+ QuantifiedWhereClause , Scalar , Solution , Substitution , TraitEnvironment , TraitRefExt , Ty ,
67
+ TyBuilder , TyDefId , TyExt , TyKind , TyVariableKind , WhereClause ,
68
68
} ;
69
69
use itertools:: Itertools ;
70
70
use nameres:: diagnostics:: DefDiagnosticKind ;
@@ -2819,10 +2819,14 @@ impl Type {
2819
2819
}
2820
2820
2821
2821
pub fn as_callable ( & self , db : & dyn HirDatabase ) -> Option < Callable > {
2822
- let def = self . ty . callable_def ( db) ;
2822
+ let callee = match self . ty . kind ( Interner ) {
2823
+ TyKind :: Closure ( id, _) => Callee :: Closure ( * id) ,
2824
+ TyKind :: Function ( _) => Callee :: FnPtr ,
2825
+ _ => Callee :: Def ( self . ty . callable_def ( db) ?) ,
2826
+ } ;
2823
2827
2824
2828
let sig = self . ty . callable_sig ( db) ?;
2825
- Some ( Callable { ty : self . clone ( ) , sig, def , is_bound_method : false } )
2829
+ Some ( Callable { ty : self . clone ( ) , sig, callee , is_bound_method : false } )
2826
2830
}
2827
2831
2828
2832
pub fn is_closure ( & self ) -> bool {
@@ -3265,34 +3269,43 @@ impl Type {
3265
3269
}
3266
3270
}
3267
3271
3268
- // FIXME: closures
3269
3272
#[ derive( Debug ) ]
3270
3273
pub struct Callable {
3271
3274
ty : Type ,
3272
3275
sig : CallableSig ,
3273
- def : Option < CallableDefId > ,
3276
+ callee : Callee ,
3274
3277
pub ( crate ) is_bound_method : bool ,
3275
3278
}
3276
3279
3280
+ #[ derive( Debug ) ]
3281
+ enum Callee {
3282
+ Def ( CallableDefId ) ,
3283
+ Closure ( ClosureId ) ,
3284
+ FnPtr ,
3285
+ }
3286
+
3277
3287
pub enum CallableKind {
3278
3288
Function ( Function ) ,
3279
3289
TupleStruct ( Struct ) ,
3280
3290
TupleEnumVariant ( Variant ) ,
3281
3291
Closure ,
3292
+ FnPtr ,
3282
3293
}
3283
3294
3284
3295
impl Callable {
3285
3296
pub fn kind ( & self ) -> CallableKind {
3286
- match self . def {
3287
- Some ( CallableDefId :: FunctionId ( it) ) => CallableKind :: Function ( it. into ( ) ) ,
3288
- Some ( CallableDefId :: StructId ( it) ) => CallableKind :: TupleStruct ( it. into ( ) ) ,
3289
- Some ( CallableDefId :: EnumVariantId ( it) ) => CallableKind :: TupleEnumVariant ( it. into ( ) ) ,
3290
- None => CallableKind :: Closure ,
3297
+ use Callee :: * ;
3298
+ match self . callee {
3299
+ Def ( CallableDefId :: FunctionId ( it) ) => CallableKind :: Function ( it. into ( ) ) ,
3300
+ Def ( CallableDefId :: StructId ( it) ) => CallableKind :: TupleStruct ( it. into ( ) ) ,
3301
+ Def ( CallableDefId :: EnumVariantId ( it) ) => CallableKind :: TupleEnumVariant ( it. into ( ) ) ,
3302
+ Closure ( _) => CallableKind :: Closure ,
3303
+ FnPtr => CallableKind :: FnPtr ,
3291
3304
}
3292
3305
}
3293
3306
pub fn receiver_param ( & self , db : & dyn HirDatabase ) -> Option < ast:: SelfParam > {
3294
- let func = match self . def {
3295
- Some ( CallableDefId :: FunctionId ( it) ) if self . is_bound_method => it,
3307
+ let func = match self . callee {
3308
+ Callee :: Def ( CallableDefId :: FunctionId ( it) ) if self . is_bound_method => it,
3296
3309
_ => return None ,
3297
3310
} ;
3298
3311
let src = func. lookup ( db. upcast ( ) ) . source ( db. upcast ( ) ) ;
@@ -3312,18 +3325,30 @@ impl Callable {
3312
3325
. iter ( )
3313
3326
. skip ( if self . is_bound_method { 1 } else { 0 } )
3314
3327
. map ( |ty| self . ty . derived ( ty. clone ( ) ) ) ;
3315
- let patterns = match self . def {
3316
- Some ( CallableDefId :: FunctionId ( func) ) => {
3328
+ let map_param = |it : ast:: Param | it. pat ( ) . map ( Either :: Right ) ;
3329
+ let patterns = match self . callee {
3330
+ Callee :: Def ( CallableDefId :: FunctionId ( func) ) => {
3317
3331
let src = func. lookup ( db. upcast ( ) ) . source ( db. upcast ( ) ) ;
3318
3332
src. value . param_list ( ) . map ( |param_list| {
3319
3333
param_list
3320
3334
. self_param ( )
3321
3335
. map ( |it| Some ( Either :: Left ( it) ) )
3322
3336
. filter ( |_| !self . is_bound_method )
3323
3337
. into_iter ( )
3324
- . chain ( param_list. params ( ) . map ( |it| it . pat ( ) . map ( Either :: Right ) ) )
3338
+ . chain ( param_list. params ( ) . map ( map_param ) )
3325
3339
} )
3326
3340
}
3341
+ Callee :: Closure ( closure_id) => match closure_source ( db, closure_id) {
3342
+ Some ( src) => src. param_list ( ) . map ( |param_list| {
3343
+ param_list
3344
+ . self_param ( )
3345
+ . map ( |it| Some ( Either :: Left ( it) ) )
3346
+ . filter ( |_| !self . is_bound_method )
3347
+ . into_iter ( )
3348
+ . chain ( param_list. params ( ) . map ( map_param) )
3349
+ } ) ,
3350
+ None => None ,
3351
+ } ,
3327
3352
_ => None ,
3328
3353
} ;
3329
3354
patterns. into_iter ( ) . flatten ( ) . chain ( iter:: repeat ( None ) ) . zip ( types) . collect ( )
@@ -3333,6 +3358,18 @@ impl Callable {
3333
3358
}
3334
3359
}
3335
3360
3361
+ fn closure_source ( db : & dyn HirDatabase , closure : ClosureId ) -> Option < ast:: ClosureExpr > {
3362
+ let ( owner, expr_id) = db. lookup_intern_closure ( closure. into ( ) ) ;
3363
+ let ( _, source_map) = db. body_with_source_map ( owner) ;
3364
+ let ast = source_map. expr_syntax ( expr_id) . ok ( ) ?;
3365
+ let root = ast. file_syntax ( db. upcast ( ) ) ;
3366
+ let expr = ast. value . to_node ( & root) ;
3367
+ match expr {
3368
+ ast:: Expr :: ClosureExpr ( it) => Some ( it) ,
3369
+ _ => None ,
3370
+ }
3371
+ }
3372
+
3336
3373
#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
3337
3374
pub enum BindingMode {
3338
3375
Move ,
0 commit comments