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