@@ -6,6 +6,11 @@ Status: Draft
6
6
7
7
## CHANGELOG
8
8
9
+ 2023.06.15
10
+ - Adjust function literal return type inference to avoid spurious application
11
+ of ` flatten ` , and make sure return statements do not affect generator
12
+ functions.
13
+
9
14
2022.05.12
10
15
- Define the notions of "constraint solution for a set of type variables" and
11
16
"Grounded constraint solution for a set of type variables". These
@@ -286,9 +291,9 @@ type schema `S` as follows:
286
291
` Stream<S1> ` for some ` S1 ` , then the context type is ` S1 ` .
287
292
- If the function expression is declared ` sync* ` and ` S ` is of the form
288
293
` Iterable<S1> ` for some ` S1 ` , then the context type is ` S1 ` .
289
- - Otherwise, without null safety, the context type is ` FutureOr< flatten(T)> `
294
+ - Otherwise, without null safety, the context type is ` flatten(T) `
290
295
where ` T ` is the imposed return type schema; with null safety, the context
291
- type is ` FutureOr< futureValueTypeSchema(S)> ` .
296
+ type is ` futureValueTypeSchema(S) ` .
292
297
293
298
The function ** futureValueTypeSchema** is defined as follows:
294
299
@@ -299,7 +304,7 @@ The function **futureValueTypeSchema** is defined as follows:
299
304
- ** futureValueTypeSchema** (` void ` ) = ` void ` .
300
305
- ** futureValueTypeSchema** (` dynamic ` ) = ` dynamic ` .
301
306
- ** futureValueTypeSchema** (` _ ` ) = ` _ ` .
302
- - Otherwise, for all ` S ` , ** futureValueTypeSchema** (` S ` ) = ` Object? ` .
307
+ - Otherwise, for all other ` S ` , ** futureValueTypeSchema** (` S ` ) = ` Object? ` .
303
308
304
309
_ Note that it is a compile-time error unless the return type of an asynchronous
305
310
non-generator function is a supertype of ` Future<Never> ` , which means that
@@ -315,45 +320,60 @@ described below with a typing context as computed above.
315
320
The actual returned type of a function literal with a block body is computed as
316
321
follows. Let ` T ` be ` Never ` if every control path through the block exits the
317
322
block without reaching the end of the block, as computed by the ** definite
318
- completion** analysis specified elsewhere. Let ` T ` be ` Null ` if any control
323
+ completion** analysis specified elsewhere, or if the function is a generator
324
+ function.
325
+ Let ` T ` be ` Null ` if the function is a non-generator function and any control
319
326
path reaches the end of the block without exiting the block, as computed by the
320
327
** definite completion** analysis specified elsewhere. Let ` K ` be the typing
321
328
context for the function body as computed above from the imposed return type
322
329
schema.
323
- - For each ` return e; ` statement in the block, let ` S ` be the inferred type of
324
- ` e ` , using the local type inference algorithm described below with typing
325
- context ` K ` , and update ` T ` to be ` UP(flatten(S), T) ` if the enclosing
326
- function is ` async ` , or ` UP(S, T) ` otherwise.
327
- - For each ` return; ` statement in the block, update ` T ` to be ` UP(Null, T) ` .
330
+ - If the enclosing function is a non-` async ` non-generator function,
331
+ for each ` return e; ` statement in the block, let ` S ` be the inferred type
332
+ of ` e ` , using the local type inference algorithm described below with typing
333
+ context ` K ` , and update ` T ` to be ` UP(S, T) ` .
334
+ - If the enclosing function is marekd ` async ` , for each ` return e; ` statement
335
+ in the block, let ` S ` be the inferred type of ` e ` , using the local type
336
+ inference algorithm described below with typing context ` FutureOr<K> ` ,
337
+ and update ` T ` to be ` UP(flatten(S), T) ` .
338
+ - If the enclosing function is a non-generator function, for each ` return; `
339
+ statement in the block, update ` T ` to be ` UP(Null, T) ` .
328
340
- For each ` yield e; ` statement in the block, let ` S ` be the inferred type of
329
341
` e ` , using the local type inference algorithm described below with typing
330
342
context ` K ` , and update ` T ` to be ` UP(S, T) ` .
331
343
- If the enclosing function is marked ` sync* ` , then for each ` yield* e; `
332
344
statement in the block, let ` S ` be the inferred type of ` e ` , using the
333
345
local type inference algorithm described below with a typing context of
334
- ` Iterable<K> ` ; let ` E ` be the type such that ` Iterable<E> ` is a
335
- super-interface of ` S ` ; and update ` T ` to be ` UP(E, T) ` .
346
+ ` Iterable<K> ` . If there exists a type ` E ` such that ` Iterable<E> ` is a
347
+ super-interface of ` S ` , update ` T ` to be ` UP(E, T) ` . Otherwise update
348
+ ` T ` to be ` UP(S, T) ` .
349
+ _ It is a compile-time error if * S* is not a assignable to
350
+ ` Iterable<Object?> ` , so either * S* implements ` Iterable ` , or it is one of
351
+ ` dynamic ` or ` Never ` ._
336
352
- If the enclosing function is marked ` async* ` , then for each ` yield* e; `
337
353
statement in the block, let ` S ` be the inferred type of ` e ` , using the
338
354
local type inference algorithm described below with a typing context of
339
- ` Stream<K> ` ; let ` E ` be the type such that ` Stream<E> ` is a super-interface
340
- of ` S ` ; and update ` T ` to be ` UP(E, T) ` .
355
+ ` Stream<K> ` . If there exists a type ` E ` such that ` Stream<E> ` is a
356
+ super-interface of ` S ` , update ` T ` to be ` UP(E, T) ` . Otherwise update
357
+ ` T ` to be ` UP(S, T) ` .
358
+ _ It is a compile-time error if * S* is not a assignable to
359
+ ` Stream<Object?> ` , so either * S* implements ` Iterable ` , or it is one of
360
+ ` dynamic ` or ` Never ` ._
341
361
342
362
The ** actual returned type** of the function literal is the value of ` T ` after
343
363
all ` return ` and ` yield ` statements in the block body have been considered.
344
364
345
365
Let ` T ` be the ** actual returned type** of a function literal as computed above.
346
366
Let ` R ` be the greatest closure of the typing context ` K ` as computed above.
347
367
348
- With null safety: if ` R ` is ` void ` , or the function literal is marked ` async `
349
- and ` R ` is ` FutureOr<void> ` , let ` S ` be ` void ` (without null-safety: no special
350
- treatment is applicable to ` void ` ).
368
+ With null safety, if ` R ` is ` void ` , let ` S ` be ` void `
369
+ _ (without null-safety: no special treatment is applicable to ` void ` )_ .
351
370
352
- Otherwise, if ` T <: R ` then let ` S ` be ` T ` . Otherwise, let ` S ` be ` R ` . The
371
+ Otherwise (_ without null safety or if ` R ` is not ` void ` _ ),
372
+ if ` T <: R ` then let ` S ` be ` T ` . Otherwise, let ` S ` be ` R ` . The
353
373
inferred return type of the function literal is then defined as follows:
354
374
355
375
- If the function literal is marked ` async ` then the inferred return type is
356
- ` Future<flatten(S) > ` .
376
+ ` Future<S > ` .
357
377
- If the function literal is marked ` async* ` then the inferred return type is
358
378
` Stream<S> ` .
359
379
- If the function literal is marked ` sync* ` then the inferred return type is
0 commit comments