@@ -10,7 +10,10 @@ use chalk_ir::{
1010 cast:: Cast , fold:: Shift , DebruijnIndex , GenericArgData , Mutability , TyVariableKind ,
1111} ;
1212use hir_def:: {
13- expr:: { ArithOp , Array , BinaryOp , CmpOp , Expr , ExprId , LabelId , Literal , Statement , UnaryOp } ,
13+ expr:: {
14+ ArithOp , Array , BinaryOp , ClosureKind , CmpOp , Expr , ExprId , LabelId , Literal , Statement ,
15+ UnaryOp ,
16+ } ,
1417 generics:: TypeOrConstParamData ,
1518 path:: { GenericArg , GenericArgs } ,
1619 resolver:: resolver_for_expr,
@@ -216,7 +219,7 @@ impl<'a> InferenceContext<'a> {
216219 self . diverges = Diverges :: Maybe ;
217220 TyBuilder :: unit ( )
218221 }
219- Expr :: Closure { body, args, ret_type, arg_types, closure_kind : _ } => {
222+ Expr :: Closure { body, args, ret_type, arg_types, closure_kind } => {
220223 assert_eq ! ( args. len( ) , arg_types. len( ) ) ;
221224
222225 let mut sig_tys = Vec :: new ( ) ;
@@ -244,20 +247,40 @@ impl<'a> InferenceContext<'a> {
244247 ) ,
245248 } )
246249 . intern ( Interner ) ;
247- let closure_id = self . db . intern_closure ( ( self . owner , tgt_expr) ) . into ( ) ;
248- let closure_ty =
249- TyKind :: Closure ( closure_id, Substitution :: from1 ( Interner , sig_ty. clone ( ) ) )
250- . intern ( Interner ) ;
250+
251+ let ( ty, resume_yield_tys) = if matches ! ( closure_kind, ClosureKind :: Generator ( _) ) {
252+ // FIXME: report error when there are more than 1 parameter.
253+ let resume_ty = match sig_tys. first ( ) {
254+ // When `sig_tys.len() == 1` the first type is the return type, not the
255+ // first parameter type.
256+ Some ( ty) if sig_tys. len ( ) > 1 => ty. clone ( ) ,
257+ _ => self . result . standard_types . unit . clone ( ) ,
258+ } ;
259+ let yield_ty = self . table . new_type_var ( ) ;
260+
261+ let subst = TyBuilder :: subst_for_generator ( self . db , self . owner )
262+ . push ( resume_ty. clone ( ) )
263+ . push ( yield_ty. clone ( ) )
264+ . push ( ret_ty. clone ( ) )
265+ . build ( ) ;
266+
267+ let generator_id = self . db . intern_generator ( ( self . owner , tgt_expr) ) . into ( ) ;
268+ let generator_ty = TyKind :: Generator ( generator_id, subst) . intern ( Interner ) ;
269+
270+ ( generator_ty, Some ( ( resume_ty, yield_ty) ) )
271+ } else {
272+ let closure_id = self . db . intern_closure ( ( self . owner , tgt_expr) ) . into ( ) ;
273+ let closure_ty =
274+ TyKind :: Closure ( closure_id, Substitution :: from1 ( Interner , sig_ty. clone ( ) ) )
275+ . intern ( Interner ) ;
276+
277+ ( closure_ty, None )
278+ } ;
251279
252280 // Eagerly try to relate the closure type with the expected
253281 // type, otherwise we often won't have enough information to
254282 // infer the body.
255- self . deduce_closure_type_from_expectations (
256- tgt_expr,
257- & closure_ty,
258- & sig_ty,
259- expected,
260- ) ;
283+ self . deduce_closure_type_from_expectations ( tgt_expr, & ty, & sig_ty, expected) ;
261284
262285 // Now go through the argument patterns
263286 for ( arg_pat, arg_ty) in args. iter ( ) . zip ( sig_tys) {
@@ -266,15 +289,18 @@ impl<'a> InferenceContext<'a> {
266289
267290 let prev_diverges = mem:: replace ( & mut self . diverges , Diverges :: Maybe ) ;
268291 let prev_ret_ty = mem:: replace ( & mut self . return_ty , ret_ty. clone ( ) ) ;
292+ let prev_resume_yield_tys =
293+ mem:: replace ( & mut self . resume_yield_tys , resume_yield_tys) ;
269294
270295 self . with_breakable_ctx ( BreakableKind :: Border , self . err_ty ( ) , None , |this| {
271296 this. infer_expr_coerce ( * body, & Expectation :: has_type ( ret_ty) ) ;
272297 } ) ;
273298
274299 self . diverges = prev_diverges;
275300 self . return_ty = prev_ret_ty;
301+ self . resume_yield_tys = prev_resume_yield_tys;
276302
277- closure_ty
303+ ty
278304 }
279305 Expr :: Call { callee, args, .. } => {
280306 let callee_ty = self . infer_expr ( * callee, & Expectation :: none ( ) ) ;
@@ -423,11 +449,18 @@ impl<'a> InferenceContext<'a> {
423449 TyKind :: Never . intern ( Interner )
424450 }
425451 Expr :: Yield { expr } => {
426- // FIXME: track yield type for coercion
427- if let Some ( expr) = expr {
428- self . infer_expr ( * expr, & Expectation :: none ( ) ) ;
452+ if let Some ( ( resume_ty, yield_ty) ) = self . resume_yield_tys . clone ( ) {
453+ if let Some ( expr) = expr {
454+ self . infer_expr_coerce ( * expr, & Expectation :: has_type ( yield_ty) ) ;
455+ } else {
456+ let unit = self . result . standard_types . unit . clone ( ) ;
457+ let _ = self . coerce ( Some ( tgt_expr) , & unit, & yield_ty) ;
458+ }
459+ resume_ty
460+ } else {
461+ // FIXME: report error (yield expr in non-generator)
462+ TyKind :: Error . intern ( Interner )
429463 }
430- TyKind :: Never . intern ( Interner )
431464 }
432465 Expr :: RecordLit { path, fields, spread, .. } => {
433466 let ( ty, def_id) = self . resolve_variant ( path. as_deref ( ) , false ) ;
0 commit comments