@@ -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