@@ -112,7 +112,13 @@ fn fn_sig_for_fn_abi<'tcx>(
112
112
let pin_did = tcx. require_lang_item ( LangItem :: Pin , None ) ;
113
113
let pin_adt_ref = tcx. adt_def ( pin_did) ;
114
114
let pin_args = tcx. mk_args ( & [ env_ty. into ( ) ] ) ;
115
- let env_ty = Ty :: new_adt ( tcx, pin_adt_ref, pin_args) ;
115
+ let env_ty = if tcx. coroutine_is_gen ( did) {
116
+ // Iterator::next doesn't accept a pinned argument,
117
+ // unlike for all other coroutine kinds.
118
+ env_ty
119
+ } else {
120
+ Ty :: new_adt ( tcx, pin_adt_ref, pin_args)
121
+ } ;
116
122
117
123
let sig = sig. skip_binder ( ) ;
118
124
// The `FnSig` and the `ret_ty` here is for a coroutines main
@@ -121,6 +127,8 @@ fn fn_sig_for_fn_abi<'tcx>(
121
127
// function in case this is a special coroutine backing an async construct.
122
128
let ( resume_ty, ret_ty) = if tcx. coroutine_is_async ( did) {
123
129
// The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
130
+ assert_eq ! ( sig. yield_ty, tcx. types. unit) ;
131
+
124
132
let poll_did = tcx. require_lang_item ( LangItem :: Poll , None ) ;
125
133
let poll_adt_ref = tcx. adt_def ( poll_did) ;
126
134
let poll_args = tcx. mk_args ( & [ sig. return_ty . into ( ) ] ) ;
@@ -140,27 +148,59 @@ fn fn_sig_for_fn_abi<'tcx>(
140
148
}
141
149
let context_mut_ref = Ty :: new_task_context ( tcx) ;
142
150
143
- ( context_mut_ref, ret_ty)
151
+ ( Some ( context_mut_ref) , ret_ty)
152
+ } else if tcx. coroutine_is_gen ( did) {
153
+ // The signature should be `Iterator::next(_) -> Option<Yield>`
154
+ let option_did = tcx. require_lang_item ( LangItem :: Option , None ) ;
155
+ let option_adt_ref = tcx. adt_def ( option_did) ;
156
+ let option_args = tcx. mk_args ( & [ sig. yield_ty . into ( ) ] ) ;
157
+ let ret_ty = Ty :: new_adt ( tcx, option_adt_ref, option_args) ;
158
+
159
+ assert_eq ! ( sig. return_ty, tcx. types. unit) ;
160
+
161
+ // We have to replace the `ResumeTy` that is used for type and borrow checking
162
+ // with `()` which is used in codegen.
163
+ #[ cfg( debug_assertions) ]
164
+ {
165
+ if let ty:: Adt ( resume_ty_adt, _) = sig. resume_ty . kind ( ) {
166
+ let expected_adt =
167
+ tcx. adt_def ( tcx. require_lang_item ( LangItem :: ResumeTy , None ) ) ;
168
+ assert_eq ! ( * resume_ty_adt, expected_adt) ;
169
+ } else {
170
+ panic ! ( "expected `ResumeTy`, found `{:?}`" , sig. resume_ty) ;
171
+ } ;
172
+ }
173
+
174
+ ( None , ret_ty)
144
175
} else {
145
176
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`
146
177
let state_did = tcx. require_lang_item ( LangItem :: CoroutineState , None ) ;
147
178
let state_adt_ref = tcx. adt_def ( state_did) ;
148
179
let state_args = tcx. mk_args ( & [ sig. yield_ty . into ( ) , sig. return_ty . into ( ) ] ) ;
149
180
let ret_ty = Ty :: new_adt ( tcx, state_adt_ref, state_args) ;
150
181
151
- ( sig. resume_ty , ret_ty)
182
+ ( Some ( sig. resume_ty ) , ret_ty)
152
183
} ;
153
184
154
- ty :: Binder :: bind_with_vars (
185
+ let fn_sig = if let Some ( resume_ty ) = resume_ty {
155
186
tcx. mk_fn_sig (
156
187
[ env_ty, resume_ty] ,
157
188
ret_ty,
158
189
false ,
159
190
hir:: Unsafety :: Normal ,
160
191
rustc_target:: spec:: abi:: Abi :: Rust ,
161
- ) ,
162
- bound_vars,
163
- )
192
+ )
193
+ } else {
194
+ // `Iterator::next` doesn't have a `resume` argument.
195
+ tcx. mk_fn_sig (
196
+ [ env_ty] ,
197
+ ret_ty,
198
+ false ,
199
+ hir:: Unsafety :: Normal ,
200
+ rustc_target:: spec:: abi:: Abi :: Rust ,
201
+ )
202
+ } ;
203
+ ty:: Binder :: bind_with_vars ( fn_sig, bound_vars)
164
204
}
165
205
_ => bug ! ( "unexpected type {:?} in Instance::fn_sig" , ty) ,
166
206
}
0 commit comments