1
1
use crate :: clauses:: ClauseBuilder ;
2
2
use crate :: infer:: instantiate:: IntoBindersAndValue ;
3
- use crate :: rust_ir:: WellKnownTrait ;
3
+ use crate :: rust_ir:: { ClosureKind , WellKnownTrait } ;
4
4
use crate :: { Interner , RustIrDatabase , TraitRef } ;
5
+ use chalk_ir:: cast:: Cast ;
5
6
use chalk_ir:: {
6
7
AliasTy , ApplicationTy , Binders , Floundered , Normalize , ProjectionTy , Substitution , TraitId ,
7
8
Ty , TyData , TypeName , VariableKinds ,
@@ -19,11 +20,116 @@ use chalk_ir::{
19
20
pub fn add_fn_trait_program_clauses < I : Interner > (
20
21
db : & dyn RustIrDatabase < I > ,
21
22
builder : & mut ClauseBuilder < ' _ , I > ,
22
- trait_id : TraitId < I > ,
23
+ well_known : WellKnownTrait ,
23
24
self_ty : Ty < I > ,
24
25
) -> Result < ( ) , Floundered > {
25
26
let interner = db. interner ( ) ;
27
+ let trait_id = db. well_known_trait_id ( well_known) . unwrap ( ) ;
26
28
match self_ty. data ( interner) {
29
+ TyData :: Apply ( apply) => match apply. name {
30
+ TypeName :: FnDef ( fn_def_id) => {
31
+ let fn_def_datum = builder. db . fn_def_datum ( fn_def_id) ;
32
+ let bound = fn_def_datum
33
+ . binders
34
+ . substitute ( builder. interner ( ) , & apply. substitution ) ;
35
+ builder. push_binders ( & bound. inputs_and_output , |builder, inputs_and_output| {
36
+ let interner = builder. interner ( ) ;
37
+ let ty = ApplicationTy {
38
+ name : apply. name ,
39
+ substitution : builder. substitution_in_scope ( ) ,
40
+ }
41
+ . intern ( interner) ;
42
+
43
+ let substitution = {
44
+ let self_ty = ty. cast ( interner) ;
45
+ let arguments = ApplicationTy {
46
+ name : TypeName :: Tuple ( inputs_and_output. argument_types . len ( ) ) ,
47
+ substitution : Substitution :: from (
48
+ interner,
49
+ inputs_and_output
50
+ . argument_types
51
+ . iter ( )
52
+ . cloned ( )
53
+ . map ( |ty| ty. cast ( interner) ) ,
54
+ ) ,
55
+ }
56
+ . intern ( interner)
57
+ . cast ( interner) ;
58
+ Substitution :: from ( interner, & [ self_ty, arguments] )
59
+ } ;
60
+ builder. push_fact ( TraitRef {
61
+ trait_id,
62
+ substitution : substitution. clone ( ) ,
63
+ } ) ;
64
+
65
+ if let WellKnownTrait :: FnOnce = well_known {
66
+ let trait_datum = db. trait_datum ( trait_id) ;
67
+ let output_id = trait_datum. associated_ty_ids [ 0 ] ;
68
+ let alias = AliasTy :: Projection ( ProjectionTy {
69
+ associated_ty_id : output_id,
70
+ substitution,
71
+ } ) ;
72
+ let return_type = inputs_and_output. return_type ;
73
+ builder. push_fact ( Normalize {
74
+ alias,
75
+ ty : return_type,
76
+ } ) ;
77
+ }
78
+ } ) ;
79
+ Ok ( ( ) )
80
+ }
81
+ TypeName :: Closure ( closure_id) => {
82
+ let closure_datum = db. closure_datum ( closure_id, apply. substitution . clone ( ) ) ;
83
+ let trait_matches = match well_known {
84
+ WellKnownTrait :: Fn => matches ! ( closure_datum. kind, ClosureKind :: Fn ) ,
85
+ WellKnownTrait :: FnMut => {
86
+ matches ! ( closure_datum. kind, ClosureKind :: FnMut | ClosureKind :: Fn )
87
+ }
88
+ WellKnownTrait :: FnOnce => matches ! (
89
+ closure_datum. kind,
90
+ ClosureKind :: FnOnce | ClosureKind :: FnMut | ClosureKind :: Fn
91
+ ) ,
92
+ _ => false ,
93
+ } ;
94
+ if trait_matches {
95
+ builder. push_binders (
96
+ & closure_datum. inputs_and_output ,
97
+ |builder, inputs_and_output| {
98
+ let substitution = Substitution :: from (
99
+ interner,
100
+ Some ( self_ty. cast ( interner) ) . into_iter ( ) . chain (
101
+ inputs_and_output
102
+ . argument_types
103
+ . iter ( )
104
+ . cloned ( )
105
+ . map ( |ty| ty. cast ( interner) ) ,
106
+ ) ,
107
+ ) ;
108
+ builder. push_fact ( TraitRef {
109
+ trait_id,
110
+ substitution : substitution. clone ( ) ,
111
+ } ) ;
112
+
113
+ if let WellKnownTrait :: FnOnce = well_known {
114
+ let trait_datum = db. trait_datum ( trait_id) ;
115
+ let output_id = trait_datum. associated_ty_ids [ 0 ] ;
116
+ let alias = AliasTy :: Projection ( ProjectionTy {
117
+ associated_ty_id : output_id,
118
+ substitution,
119
+ } ) ;
120
+ let return_type = inputs_and_output. return_type . clone ( ) ;
121
+ builder. push_fact ( Normalize {
122
+ alias,
123
+ ty : return_type,
124
+ } ) ;
125
+ }
126
+ } ,
127
+ ) ;
128
+ }
129
+ Ok ( ( ) )
130
+ }
131
+ _ => Ok ( ( ) ) ,
132
+ } ,
27
133
TyData :: Function ( fn_val) => {
28
134
let ( binders, orig_sub) = fn_val. into_binders_and_value ( interner) ;
29
135
let bound_ref = Binders :: new ( VariableKinds :: from ( interner, binders) , orig_sub) ;
0 commit comments