@@ -98,6 +98,7 @@ fn fn_sig_for_fn_abi<'tcx>(
9898 )
9999 }
100100 ty:: Coroutine ( did, args, _) => {
101+ let coroutine_kind = tcx. coroutine_kind ( did) . unwrap ( ) ;
101102 let sig = args. as_coroutine ( ) . poly_sig ( ) ;
102103
103104 let bound_vars = tcx. mk_bound_variable_kinds_from_iter (
@@ -112,55 +113,92 @@ fn fn_sig_for_fn_abi<'tcx>(
112113 let pin_did = tcx. require_lang_item ( LangItem :: Pin , None ) ;
113114 let pin_adt_ref = tcx. adt_def ( pin_did) ;
114115 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+ } ;
116126
117127 let sig = sig. skip_binder ( ) ;
118128 // The `FnSig` and the `ret_ty` here is for a coroutines main
119129 // `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)
140159 }
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) ;
142166
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) ;
150169
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+ }
152181 } ;
153182
154- ty :: Binder :: bind_with_vars (
183+ let fn_sig = if let Some ( resume_ty ) = resume_ty {
155184 tcx. mk_fn_sig (
156185 [ env_ty, resume_ty] ,
157186 ret_ty,
158187 false ,
159188 hir:: Unsafety :: Normal ,
160189 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)
164202 }
165203 _ => bug ! ( "unexpected type {:?} in Instance::fn_sig" , ty) ,
166204 }
0 commit comments