Skip to content

Commit 7c533bb

Browse files
committed
Update inference of closures with no context.
1 parent 6d50316 commit 7c533bb

File tree

1 file changed

+38
-18
lines changed

1 file changed

+38
-18
lines changed

resources/type-system/inference.md

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ Status: Draft
66

77
## CHANGELOG
88

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+
914
2022.05.12
1015
- Define the notions of "constraint solution for a set of type variables" and
1116
"Grounded constraint solution for a set of type variables". These
@@ -286,9 +291,9 @@ type schema `S` as follows:
286291
`Stream<S1>` for some `S1`, then the context type is `S1`.
287292
- If the function expression is declared `sync*` and `S` is of the form
288293
`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)`
290295
where `T` is the imposed return type schema; with null safety, the context
291-
type is `FutureOr<futureValueTypeSchema(S)>`.
296+
type is `futureValueTypeSchema(S)`.
292297

293298
The function **futureValueTypeSchema** is defined as follows:
294299

@@ -299,7 +304,7 @@ The function **futureValueTypeSchema** is defined as follows:
299304
- **futureValueTypeSchema**(`void`) = `void`.
300305
- **futureValueTypeSchema**(`dynamic`) = `dynamic`.
301306
- **futureValueTypeSchema**(`_`) = `_`.
302-
- Otherwise, for all `S`, **futureValueTypeSchema**(`S`) = `Object?`.
307+
- Otherwise, for all other `S`, **futureValueTypeSchema**(`S`) = `Object?`.
303308

304309
_Note that it is a compile-time error unless the return type of an asynchronous
305310
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.
315320
The actual returned type of a function literal with a block body is computed as
316321
follows. Let `T` be `Never` if every control path through the block exits the
317322
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
319326
path reaches the end of the block without exiting the block, as computed by the
320327
**definite completion** analysis specified elsewhere. Let `K` be the typing
321328
context for the function body as computed above from the imposed return type
322329
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)`.
328340
- For each `yield e;` statement in the block, let `S` be the inferred type of
329341
`e`, using the local type inference algorithm described below with typing
330342
context `K`, and update `T` to be `UP(S, T)`.
331343
- If the enclosing function is marked `sync*`, then for each `yield* e;`
332344
statement in the block, let `S` be the inferred type of `e`, using the
333345
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`._
336352
- If the enclosing function is marked `async*`, then for each `yield* e;`
337353
statement in the block, let `S` be the inferred type of `e`, using the
338354
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`._
341361

342362
The **actual returned type** of the function literal is the value of `T` after
343363
all `return` and `yield` statements in the block body have been considered.
344364

345365
Let `T` be the **actual returned type** of a function literal as computed above.
346366
Let `R` be the greatest closure of the typing context `K` as computed above.
347367

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`)_.
351370

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
353373
inferred return type of the function literal is then defined as follows:
354374

355375
- If the function literal is marked `async` then the inferred return type is
356-
`Future<flatten(S)>`.
376+
`Future<S>`.
357377
- If the function literal is marked `async*` then the inferred return type is
358378
`Stream<S>`.
359379
- If the function literal is marked `sync*` then the inferred return type is

0 commit comments

Comments
 (0)