13
13
*/
14
14
15
15
use super :: check_fn;
16
- use super :: Expectation ;
16
+ use super :: { Expectation , ExpectCastableToType , ExpectHasType , NoExpectation } ;
17
17
use super :: FnCtxt ;
18
18
19
- use middle:: ty;
19
+ use middle:: subst;
20
+ use middle:: ty:: { mod, Ty } ;
20
21
use middle:: typeck:: astconv;
21
22
use middle:: typeck:: infer;
22
23
use middle:: typeck:: rscope:: RegionScope ;
@@ -25,13 +26,40 @@ use syntax::ast;
25
26
use syntax:: ast_util;
26
27
use util:: ppaux:: Repr ;
27
28
28
- pub fn check_unboxed_closure ( fcx : & FnCtxt ,
29
- expr : & ast:: Expr ,
30
- kind : ast:: UnboxedClosureKind ,
31
- decl : & ast:: FnDecl ,
32
- body : & ast:: Block ) {
29
+ pub fn check_unboxed_closure < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
30
+ expr : & ast:: Expr ,
31
+ kind : ast:: UnboxedClosureKind ,
32
+ decl : & ast:: FnDecl ,
33
+ body : & ast:: Block ,
34
+ expected : Expectation < ' tcx > ) {
33
35
let expr_def_id = ast_util:: local_def ( expr. id ) ;
34
36
37
+ let expected_sig_and_kind = match expected. resolve ( fcx) {
38
+ NoExpectation => None ,
39
+ ExpectCastableToType ( t) | ExpectHasType ( t) => {
40
+ deduce_unboxed_closure_expectations_from_expected_type ( fcx, t)
41
+ }
42
+ } ;
43
+
44
+ let ( expected_sig, expected_kind) = match expected_sig_and_kind {
45
+ None => ( None , None ) ,
46
+ Some ( ( sig, kind) ) => {
47
+ // Avoid accidental capture of bound regions by renaming
48
+ // them to fresh names, basically.
49
+ let sig =
50
+ ty:: replace_late_bound_regions (
51
+ fcx. tcx ( ) ,
52
+ & sig,
53
+ |_, debruijn| fcx. inh . infcx . fresh_bound_region ( debruijn) ) . 0 ;
54
+ ( Some ( sig) , Some ( kind) )
55
+ }
56
+ } ;
57
+
58
+ debug ! ( "check_unboxed_closure expected={} expected_sig={} expected_kind={}" ,
59
+ expected. repr( fcx. tcx( ) ) ,
60
+ expected_sig. repr( fcx. tcx( ) ) ,
61
+ expected_kind) ;
62
+
35
63
let mut fn_ty = astconv:: ty_of_closure (
36
64
fcx,
37
65
ast:: NormalFn ,
@@ -46,7 +74,7 @@ pub fn check_unboxed_closure(fcx: &FnCtxt,
46
74
47
75
decl,
48
76
abi:: RustCall ,
49
- None ) ;
77
+ expected_sig ) ;
50
78
51
79
let region = match fcx. infcx ( ) . anon_regions ( expr. span , 1 ) {
52
80
Err ( _) => {
@@ -98,6 +126,95 @@ pub fn check_unboxed_closure(fcx: &FnCtxt,
98
126
. insert ( expr_def_id, unboxed_closure) ;
99
127
}
100
128
129
+ fn deduce_unboxed_closure_expectations_from_expected_type < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
130
+ expected_ty : Ty < ' tcx > )
131
+ -> Option < ( ty:: FnSig < ' tcx > ,
132
+ ty:: UnboxedClosureKind ) >
133
+ {
134
+ match expected_ty. sty {
135
+ ty:: ty_trait( ref object_type) => {
136
+ deduce_unboxed_closure_expectations_from_trait_ref ( fcx, & object_type. principal )
137
+ }
138
+ ty:: ty_infer( ty:: TyVar ( vid) ) => {
139
+ deduce_unboxed_closure_expectations_from_obligations ( fcx, vid)
140
+ }
141
+ _ => {
142
+ None
143
+ }
144
+ }
145
+ }
146
+
147
+ fn deduce_unboxed_closure_expectations_from_trait_ref < ' a , ' tcx > (
148
+ fcx : & FnCtxt < ' a , ' tcx > ,
149
+ trait_ref : & ty:: TraitRef < ' tcx > )
150
+ -> Option < ( ty:: FnSig < ' tcx > , ty:: UnboxedClosureKind ) >
151
+ {
152
+ let tcx = fcx. tcx ( ) ;
153
+
154
+ debug ! ( "deduce_unboxed_closure_expectations_from_object_type({})" ,
155
+ trait_ref. repr( tcx) ) ;
156
+
157
+ let def_id_kinds = [
158
+ ( tcx. lang_items . fn_trait ( ) , ty:: FnUnboxedClosureKind ) ,
159
+ ( tcx. lang_items . fn_mut_trait ( ) , ty:: FnMutUnboxedClosureKind ) ,
160
+ ( tcx. lang_items . fn_once_trait ( ) , ty:: FnOnceUnboxedClosureKind ) ,
161
+ ] ;
162
+
163
+ for & ( def_id, kind) in def_id_kinds. iter ( ) {
164
+ if Some ( trait_ref. def_id ) == def_id {
165
+ debug ! ( "found object type {}" , kind) ;
166
+
167
+ let arg_param_ty = * trait_ref. substs . types . get ( subst:: TypeSpace , 0 ) ;
168
+ let arg_param_ty = fcx. infcx ( ) . resolve_type_vars_if_possible ( arg_param_ty) ;
169
+ debug ! ( "arg_param_ty {}" , arg_param_ty. repr( tcx) ) ;
170
+
171
+ let input_tys = match arg_param_ty. sty {
172
+ ty:: ty_tup( ref tys) => { ( * tys) . clone ( ) }
173
+ _ => { continue ; }
174
+ } ;
175
+ debug ! ( "input_tys {}" , input_tys. repr( tcx) ) ;
176
+
177
+ let ret_param_ty = * trait_ref. substs . types . get ( subst:: TypeSpace , 1 ) ;
178
+ let ret_param_ty = fcx. infcx ( ) . resolve_type_vars_if_possible ( ret_param_ty) ;
179
+ debug ! ( "ret_param_ty {}" , ret_param_ty. repr( tcx) ) ;
180
+
181
+ let fn_sig = ty:: FnSig {
182
+ inputs : input_tys,
183
+ output : ty:: FnConverging ( ret_param_ty) ,
184
+ variadic : false
185
+ } ;
186
+ debug ! ( "fn_sig {}" , fn_sig. repr( tcx) ) ;
187
+
188
+ return Some ( ( fn_sig, kind) ) ;
189
+ }
190
+ }
191
+
192
+ None
193
+ }
194
+
195
+ fn deduce_unboxed_closure_expectations_from_obligations < ' a , ' tcx > (
196
+ fcx : & FnCtxt < ' a , ' tcx > ,
197
+ expected_vid : ty:: TyVid )
198
+ -> Option < ( ty:: FnSig < ' tcx > , ty:: UnboxedClosureKind ) >
199
+ {
200
+ // Here `expected_ty` is known to be a type inference variable.
201
+ for obligation in fcx. inh . fulfillment_cx . borrow ( ) . pending_trait_obligations ( ) . iter ( ) {
202
+ let obligation_self_ty = fcx. infcx ( ) . shallow_resolve ( obligation. self_ty ( ) ) ;
203
+ match obligation_self_ty. sty {
204
+ ty:: ty_infer( ty:: TyVar ( v) ) if expected_vid == v => { }
205
+ _ => { continue ; }
206
+ }
207
+
208
+ match deduce_unboxed_closure_expectations_from_trait_ref ( fcx, & * obligation. trait_ref ) {
209
+ Some ( e) => { return Some ( e) ; }
210
+ None => { }
211
+ }
212
+ }
213
+
214
+ None
215
+ }
216
+
217
+
101
218
pub fn check_expr_fn < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
102
219
expr : & ast:: Expr ,
103
220
store : ty:: TraitStore ,
0 commit comments