Skip to content

Commit 4c210e8

Browse files
committed
[cfe] Infer Null from implicit return in function literal type inference
Closes #42743 Change-Id: I7aca374894704cdc002d927aef9ea72cbabd12e6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155606 Reviewed-by: Dmitry Stefantsov <[email protected]>
1 parent 4517362 commit 4c210e8

18 files changed

+315
-124
lines changed

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

Lines changed: 74 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,15 @@ class _SyncClosureContext implements ClosureContext {
303303
assert(_needToInferReturnType);
304304
assert(hasImplicitReturn != null);
305305
DartType inferredType;
306-
if (_returnStatements.isNotEmpty) {
306+
if (inferrer.isNonNullableByDefault) {
307+
if (hasImplicitReturn) {
308+
// No explicit returns we have an implicit `return null`.
309+
inferredType = inferrer.typeSchemaEnvironment.nullType;
310+
} else {
311+
// No explicit return and the function doesn't complete normally; that
312+
// is, it throws.
313+
inferredType = new NeverType(inferrer.library.nonNullable);
314+
}
307315
// Use the types seen from the explicit return statements.
308316
for (int i = 0; i < _returnStatements.length; i++) {
309317
ReturnStatement statement = _returnStatements[i];
@@ -322,15 +330,32 @@ class _SyncClosureContext implements ClosureContext {
322330
inferredType, type, inferrer.library.library);
323331
}
324332
}
325-
} else if (hasImplicitReturn) {
326-
// No explicit returns we have an implicit `return null`.
327-
inferredType = inferrer.typeSchemaEnvironment.nullType;
328333
} else {
329-
// No explicit return and the function doesn't complete normally; that is,
330-
// it throws.
331-
if (inferrer.isNonNullableByDefault) {
332-
inferredType = new NeverType(inferrer.library.nonNullable);
334+
if (_returnStatements.isNotEmpty) {
335+
// Use the types seen from the explicit return statements.
336+
for (int i = 0; i < _returnStatements.length; i++) {
337+
ReturnStatement statement = _returnStatements[i];
338+
DartType type = _returnExpressionTypes[i];
339+
// The return expression has to be assignable to the return type
340+
// expectation from the downwards inference context.
341+
if (statement.expression != null) {
342+
if (!inferrer.isAssignable(_returnContext, type)) {
343+
type = inferrer.computeGreatestClosure(_returnContext);
344+
}
345+
}
346+
if (inferredType == null) {
347+
inferredType = type;
348+
} else {
349+
inferredType = inferrer.typeSchemaEnvironment.getStandardUpperBound(
350+
inferredType, type, inferrer.library.library);
351+
}
352+
}
353+
} else if (hasImplicitReturn) {
354+
// No explicit returns we have an implicit `return null`.
355+
inferredType = inferrer.typeSchemaEnvironment.nullType;
333356
} else {
357+
// No explicit return and the function doesn't complete normally; that
358+
// is, it throws.
334359
inferredType = inferrer.typeSchemaEnvironment.nullType;
335360
}
336361
}
@@ -649,23 +674,20 @@ class _AsyncClosureContext implements ClosureContext {
649674
assert(_needToInferReturnType);
650675
assert(hasImplicitReturn != null);
651676
DartType inferredType;
652-
if (_returnStatements.isNotEmpty) {
677+
678+
if (inferrer.isNonNullableByDefault) {
679+
if (hasImplicitReturn) {
680+
// No explicit returns we have an implicit `return null`.
681+
inferredType = inferrer.typeSchemaEnvironment.nullType;
682+
} else {
683+
// No explicit return and the function doesn't complete normally; that
684+
// is, it throws.
685+
inferredType = new NeverType(inferrer.library.nonNullable);
686+
}
653687
// Use the types seen from the explicit return statements.
654688
for (int i = 0; i < _returnStatements.length; i++) {
655-
ReturnStatement statement = _returnStatements[i];
656689
DartType type = _returnExpressionTypes[i];
657690

658-
// The return expression has to be assignable to the return type
659-
// expectation from the downwards inference context.
660-
if (!inferrer.isNonNullableByDefault) {
661-
if (statement.expression != null) {
662-
if (!inferrer.isAssignable(
663-
computeAssignableType(inferrer, _returnContext, type), type)) {
664-
// Not assignable, use the expectation.
665-
type = inferrer.computeGreatestClosure(_returnContext);
666-
}
667-
}
668-
}
669691
DartType unwrappedType = inferrer.typeSchemaEnvironment.flatten(type);
670692
if (inferredType == null) {
671693
inferredType = unwrappedType;
@@ -674,20 +696,6 @@ class _AsyncClosureContext implements ClosureContext {
674696
inferredType, unwrappedType, inferrer.library.library);
675697
}
676698
}
677-
} else if (hasImplicitReturn) {
678-
// No explicit returns we have an implicit `return null`.
679-
inferredType = inferrer.typeSchemaEnvironment.nullType;
680-
} else {
681-
// No explicit return and the function doesn't complete normally; that is,
682-
// it throws.
683-
if (inferrer.isNonNullableByDefault) {
684-
inferredType = new NeverType(inferrer.library.nonNullable);
685-
} else {
686-
inferredType = inferrer.typeSchemaEnvironment.nullType;
687-
}
688-
}
689-
690-
if (inferrer.isNonNullableByDefault) {
691699
if (!inferrer.typeSchemaEnvironment.isSubtypeOf(
692700
inferredType, _returnContext, SubtypeCheckMode.withNullabilities)) {
693701
// If the inferred return type isn't a subtype of the context, we use
@@ -698,6 +706,37 @@ class _AsyncClosureContext implements ClosureContext {
698706
inferrer.typeSchemaEnvironment.flatten(inferredType),
699707
inferrer.library.nonNullable);
700708
} else {
709+
if (_returnStatements.isNotEmpty) {
710+
// Use the types seen from the explicit return statements.
711+
for (int i = 0; i < _returnStatements.length; i++) {
712+
ReturnStatement statement = _returnStatements[i];
713+
DartType type = _returnExpressionTypes[i];
714+
715+
// The return expression has to be assignable to the return type
716+
// expectation from the downwards inference context.
717+
if (statement.expression != null) {
718+
if (!inferrer.isAssignable(
719+
computeAssignableType(inferrer, _returnContext, type), type)) {
720+
// Not assignable, use the expectation.
721+
type = inferrer.computeGreatestClosure(_returnContext);
722+
}
723+
}
724+
DartType unwrappedType = inferrer.typeSchemaEnvironment.flatten(type);
725+
if (inferredType == null) {
726+
inferredType = unwrappedType;
727+
} else {
728+
inferredType = inferrer.typeSchemaEnvironment.getStandardUpperBound(
729+
inferredType, unwrappedType, inferrer.library.library);
730+
}
731+
}
732+
} else if (hasImplicitReturn) {
733+
// No explicit returns we have an implicit `return null`.
734+
inferredType = inferrer.typeSchemaEnvironment.nullType;
735+
} else {
736+
// No explicit return and the function doesn't complete normally;
737+
// that is, it throws.
738+
inferredType = inferrer.typeSchemaEnvironment.nullType;
739+
}
701740
inferredType =
702741
inferrer.wrapFutureType(inferredType, inferrer.library.nonNullable);
703742

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,31 @@ library /*isNonNullableByDefault*/;
66
// String Function(int) x2 = (int v) /* error */ {
77
// ^
88
//
9-
// pkg/front_end/testcases/nnbd/issue41156.dart:44:29: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
9+
// pkg/front_end/testcases/nnbd/issue41156.dart:44:29: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
1010
// String Function(int) x3 = (int v) /* error */ {
1111
// ^
1212
//
1313
// pkg/front_end/testcases/nnbd/issue41156.dart:49:29: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
1414
// String Function(int) x5 = (int v) /* error */ {
1515
// ^
1616
//
17-
// pkg/front_end/testcases/nnbd/issue41156.dart:54:29: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
17+
// pkg/front_end/testcases/nnbd/issue41156.dart:54:29: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
1818
// String Function(int) x6 = (int v) /* error */ {
1919
// ^
2020
//
2121
// pkg/front_end/testcases/nnbd/issue41156.dart:59:37: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
2222
// Future<String> Function(int) y2 = (int v) async /* error */ {
2323
// ^
2424
//
25-
// pkg/front_end/testcases/nnbd/issue41156.dart:64:37: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
25+
// pkg/front_end/testcases/nnbd/issue41156.dart:64:37: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
2626
// Future<String> Function(int) y3 = (int v) async /* error */ {
2727
// ^
2828
//
2929
// pkg/front_end/testcases/nnbd/issue41156.dart:69:37: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
3030
// Future<String> Function(int) y5 = (int v) async /* error */ {
3131
// ^
3232
//
33-
// pkg/front_end/testcases/nnbd/issue41156.dart:74:37: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
33+
// pkg/front_end/testcases/nnbd/issue41156.dart:74:37: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
3434
// Future<String> Function(int) y6 = (int v) async /* error */ {
3535
// ^
3636
//
@@ -81,13 +81,13 @@ static method errors() → void async {
8181
String Function(int) x2 = (int v) /* error */ {
8282
^" in null;
8383
};
84-
(core::int) → core::String x3 = (core::int v) → Never {
84+
(core::int) → core::String x3 = (core::int v) → core::String {
8585
try {
8686
return throw v;
8787
}
8888
on core::Object catch(final core::Object _) {
8989
}
90-
return let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:44:29: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
90+
return let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:44:29: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
9191
String Function(int) x3 = (int v) /* error */ {
9292
^" in null;
9393
};
@@ -101,13 +101,13 @@ static method errors() → void async {
101101
String Function(int) x5 = (int v) /* error */ {
102102
^" in null;
103103
};
104-
(core::int) → core::String x6 = (core::int v) → Never {
104+
(core::int) → core::String x6 = (core::int v) → core::String {
105105
try {
106106
return self::throwing();
107107
}
108108
on core::Object catch(final core::Object _) {
109109
}
110-
return let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:54:29: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
110+
return let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:54:29: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
111111
String Function(int) x6 = (int v) /* error */ {
112112
^" in null;
113113
};
@@ -121,13 +121,13 @@ static method errors() → void async {
121121
Future<String> Function(int) y2 = (int v) async /* error */ {
122122
^" in null;
123123
};
124-
(core::int) → asy::Future<core::String> y3 = (core::int v) → asy::Future<Never> async {
124+
(core::int) → asy::Future<core::String> y3 = (core::int v) → asy::Future<core::String> async {
125125
try {
126126
return throw v;
127127
}
128128
on core::Object catch(final core::Object _) {
129129
}
130-
return let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:64:37: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
130+
return let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:64:37: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
131131
Future<String> Function(int) y3 = (int v) async /* error */ {
132132
^" in null;
133133
};
@@ -141,13 +141,13 @@ static method errors() → void async {
141141
Future<String> Function(int) y5 = (int v) async /* error */ {
142142
^" in null;
143143
};
144-
(core::int) → asy::Future<core::String> y6 = (core::int v) → asy::Future<Never> async {
144+
(core::int) → asy::Future<core::String> y6 = (core::int v) → asy::Future<core::String> async {
145145
try {
146146
return self::throwing();
147147
}
148148
on core::Object catch(final core::Object _) {
149149
}
150-
return let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:74:37: Error: A non-null value must be returned since the return type 'Never' doesn't allow null.
150+
return let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/issue41156.dart:74:37: Error: A non-null value must be returned since the return type 'String' doesn't allow null.
151151
Future<String> Function(int) y6 = (int v) async /* error */ {
152152
^" in null;
153153
};

0 commit comments

Comments
 (0)