@@ -10,7 +10,10 @@ use chalk_ir::{
10
10
cast:: Cast , fold:: Shift , DebruijnIndex , GenericArgData , Mutability , TyVariableKind ,
11
11
} ;
12
12
use 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
+ } ,
14
17
generics:: TypeOrConstParamData ,
15
18
path:: { GenericArg , GenericArgs } ,
16
19
resolver:: resolver_for_expr,
@@ -216,7 +219,7 @@ impl<'a> InferenceContext<'a> {
216
219
self . diverges = Diverges :: Maybe ;
217
220
TyBuilder :: unit ( )
218
221
}
219
- Expr :: Closure { body, args, ret_type, arg_types, closure_kind : _ } => {
222
+ Expr :: Closure { body, args, ret_type, arg_types, closure_kind } => {
220
223
assert_eq ! ( args. len( ) , arg_types. len( ) ) ;
221
224
222
225
let mut sig_tys = Vec :: new ( ) ;
@@ -244,20 +247,40 @@ impl<'a> InferenceContext<'a> {
244
247
) ,
245
248
} )
246
249
. 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
+ } ;
251
279
252
280
// Eagerly try to relate the closure type with the expected
253
281
// type, otherwise we often won't have enough information to
254
282
// 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) ;
261
284
262
285
// Now go through the argument patterns
263
286
for ( arg_pat, arg_ty) in args. iter ( ) . zip ( sig_tys) {
@@ -266,15 +289,18 @@ impl<'a> InferenceContext<'a> {
266
289
267
290
let prev_diverges = mem:: replace ( & mut self . diverges , Diverges :: Maybe ) ;
268
291
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) ;
269
294
270
295
self . with_breakable_ctx ( BreakableKind :: Border , self . err_ty ( ) , None , |this| {
271
296
this. infer_expr_coerce ( * body, & Expectation :: has_type ( ret_ty) ) ;
272
297
} ) ;
273
298
274
299
self . diverges = prev_diverges;
275
300
self . return_ty = prev_ret_ty;
301
+ self . resume_yield_tys = prev_resume_yield_tys;
276
302
277
- closure_ty
303
+ ty
278
304
}
279
305
Expr :: Call { callee, args, .. } => {
280
306
let callee_ty = self . infer_expr ( * callee, & Expectation :: none ( ) ) ;
@@ -423,11 +449,18 @@ impl<'a> InferenceContext<'a> {
423
449
TyKind :: Never . intern ( Interner )
424
450
}
425
451
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 )
429
463
}
430
- TyKind :: Never . intern ( Interner )
431
464
}
432
465
Expr :: RecordLit { path, fields, spread, .. } => {
433
466
let ( ty, def_id) = self . resolve_variant ( path. as_deref ( ) , false ) ;
0 commit comments