Skip to content

Commit 77fcb33

Browse files
committed
[cfe] Update local function return type inference
Closes #42721 Change-Id: Ia962c8ff3b6d469a0884b8983994de5c5c2286f4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155760 Reviewed-by: Dmitry Stefantsov <[email protected]>
1 parent 4c210e8 commit 77fcb33

9 files changed

+53
-53
lines changed

pkg/front_end/lib/src/fasta/type_inference/closure_context.dart

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,8 @@ abstract class ClosureContext {
106106
class _SyncClosureContext implements ClosureContext {
107107
bool get isAsync => false;
108108

109-
/// The typing expectation for the subexpression of a `return` or `yield`
110-
/// statement inside the function.
111-
///
112-
/// For non-generator async functions, this will be a "FutureOr" type (since
113-
/// it is permissible for such a function to return either a direct value or
114-
/// a future).
115-
///
116-
/// For generator functions containing a `yield*` statement, the expected type
117-
/// for the subexpression of the `yield*` statement is the result of wrapping
118-
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
109+
/// The typing expectation for the subexpression of a `return` statement
110+
/// inside the function.
119111
final DartType _returnContext;
120112

121113
@override
@@ -423,16 +415,11 @@ class _SyncClosureContext implements ClosureContext {
423415
class _AsyncClosureContext implements ClosureContext {
424416
bool get isAsync => true;
425417

426-
/// The typing expectation for the subexpression of a `return` or `yield`
427-
/// statement inside the function.
428-
///
429-
/// For non-generator async functions, this will be a "FutureOr" type (since
430-
/// it is permissible for such a function to return either a direct value or
431-
/// a future).
418+
/// The typing expectation for the subexpression of a `return` statement
419+
/// inside the function.
432420
///
433-
/// For generator functions containing a `yield*` statement, the expected type
434-
/// for the subexpression of the `yield*` statement is the result of wrapping
435-
/// this typing expectation in `Stream` or `Iterator`, as appropriate.
421+
/// This will be a "FutureOr" type (since it is permissible for such a
422+
/// function to return either a direct value or a future).
436423
final DartType _returnContext;
437424

438425
@override
@@ -696,11 +683,24 @@ class _AsyncClosureContext implements ClosureContext {
696683
inferredType, unwrappedType, inferrer.library.library);
697684
}
698685
}
699-
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(
700-
inferredType, _returnContext, SubtypeCheckMode.withNullabilities)) {
686+
687+
// Let `T` be the **actual returned type** of a function literal as
688+
// computed above.
689+
690+
// Let `R` be the greatest closure of the typing context `K` as computed
691+
// above. If `R` is `void`, or the function literal is marked `async` and
692+
// `R` is `FutureOr<void>`, let `S` be `void`. Otherwise, if `T <: R` then
693+
// let `S` be `T`. Otherwise, let `S` be `R`.
694+
DartType returnContext = inferrer.computeGreatestClosure2(_returnContext);
695+
if (returnContext is VoidType ||
696+
returnContext is FutureOrType &&
697+
returnContext.typeArgument is VoidType) {
698+
inferredType = const VoidType();
699+
} else if (!inferrer.typeSchemaEnvironment.isSubtypeOf(
700+
inferredType, returnContext, SubtypeCheckMode.withNullabilities)) {
701701
// If the inferred return type isn't a subtype of the context, we use
702702
// the context.
703-
inferredType = inferrer.computeGreatestClosure2(_declaredReturnType);
703+
inferredType = returnContext;
704704
}
705705
inferredType = inferrer.wrapFutureType(
706706
inferrer.typeSchemaEnvironment.flatten(inferredType),

pkg/front_end/testcases/nnbd/issue41697.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
import 'dart:async';
66

7-
typedef G<T> = void Function<S extends T>(S);
8-
typedef H<T> = void Function<S extends FutureOr<T>>(S, FutureOr<T>);
7+
typedef G<T> = dynamic Function<S extends T>(S);
8+
typedef H<T> = dynamic Function<S extends FutureOr<T>>(S, FutureOr<T>);
99
// TODO(johnniwinther): Enable and use these when #41951 is fixed to test that
1010
// updating self referencing type parameters works.
1111
//typedef I<T> = void Function<S extends FutureOr<S>>(S, T);

pkg/front_end/testcases/nnbd/issue41697.dart.outline.expect

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import "dart:core" as core;
44

55
import "dart:async";
66

7-
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
8-
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → void;
7+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → dynamic;
8+
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → dynamic;
99
class C<T extends core::Object? = dynamic> extends core::Object {
10-
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
11-
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2;
12-
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
10+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → dynamic field1;
11+
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2;
12+
constructor •(<S extends self::C::T% = dynamic>(S%) → dynamic field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2) → self::C<self::C::T%>
1313
;
1414
}
1515
static method test1(self::C<core::num> c) → dynamic

pkg/front_end/testcases/nnbd/issue41697.dart.strong.expect

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ import "dart:async" as asy;
2020

2121
import "dart:async";
2222

23-
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
24-
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → void;
23+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → dynamic;
24+
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → dynamic;
2525
class C<T extends core::Object? = dynamic> extends core::Object {
26-
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
27-
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2;
28-
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
26+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → dynamic field1;
27+
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2;
28+
constructor •(<S extends self::C::T% = dynamic>(S%) → dynamic field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2) → self::C<self::C::T%>
2929
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
3030
;
3131
}

pkg/front_end/testcases/nnbd/issue41697.dart.strong.transformed.expect

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ import "dart:_internal" as _in;
2121

2222
import "dart:async";
2323

24-
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
25-
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → void;
24+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → dynamic;
25+
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → dynamic;
2626
class C<T extends core::Object? = dynamic> extends core::Object {
27-
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
28-
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2;
29-
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
27+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → dynamic field1;
28+
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2;
29+
constructor •(<S extends self::C::T% = dynamic>(S%) → dynamic field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2) → self::C<self::C::T%>
3030
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
3131
;
3232
}

pkg/front_end/testcases/nnbd/issue41697.dart.textual_outline.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'dart:async';
22

3-
typedef G<T> = void Function<S extends T>(S);
4-
typedef H<T> = void Function<S extends FutureOr<T>>(S, FutureOr<T>);
3+
typedef G<T> = dynamic Function<S extends T>(S);
4+
typedef H<T> = dynamic Function<S extends FutureOr<T>>(S, FutureOr<T>);
55

66
class C<T> {
77
G<T> field1;

pkg/front_end/testcases/nnbd/issue41697.dart.textual_outline_modelled.expect

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ main() {}
1010
test1(C<num> c) {}
1111
test2(C<num?> c) {}
1212
test3<S extends num?>(S s) => s + 1;
13-
typedef G<T> = void Function<S extends T>(S);
14-
typedef H<T> = void Function<S extends FutureOr<T>>(S, FutureOr<T>);
13+
typedef G<T> = dynamic Function<S extends T>(S);
14+
typedef H<T> = dynamic Function<S extends FutureOr<T>>(S, FutureOr<T>);

pkg/front_end/testcases/nnbd/issue41697.dart.weak.expect

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ import "dart:async" as asy;
2020

2121
import "dart:async";
2222

23-
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
24-
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → void;
23+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → dynamic;
24+
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → dynamic;
2525
class C<T extends core::Object? = dynamic> extends core::Object {
26-
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
27-
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2;
28-
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
26+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → dynamic field1;
27+
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2;
28+
constructor •(<S extends self::C::T% = dynamic>(S%) → dynamic field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2) → self::C<self::C::T%>
2929
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
3030
;
3131
}

pkg/front_end/testcases/nnbd/issue41697.dart.weak.transformed.expect

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ import "dart:_internal" as _in;
2121

2222
import "dart:async";
2323

24-
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
25-
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → void;
24+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → dynamic;
25+
typedef H<invariant T extends core::Object? = dynamic> = <S extends FutureOr<T%> = dynamic>(S%, FutureOr<T%>) → dynamic;
2626
class C<T extends core::Object? = dynamic> extends core::Object {
27-
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
28-
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2;
29-
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
27+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → dynamic field1;
28+
generic-covariant-impl field <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2;
29+
constructor •(<S extends self::C::T% = dynamic>(S%) → dynamic field1, <S extends FutureOr<self::C::T%> = dynamic>(S%, FutureOr<self::C::T%>) → dynamic field2) → self::C<self::C::T%>
3030
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
3131
;
3232
}

0 commit comments

Comments
 (0)