Skip to content

Commit 6ce8d74

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Add Function.futureValueType and serialize Let.fileOffset
Serializing Let.fileOffset supports positions in stacktraces resulting from null aware expressions, like `if (o?.foo) ...` when `o` is `null`. Adding Function.futureValueType supports the proper backend implementation for the fix in https://dart-review.googlesource.com/c/sdk/+/181303 Closes #44654 TEST=existing Change-Id: Ie5939a248d3d8bf41388e8f435e4ba4195afeabd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/182269 Commit-Queue: Johnni Winther <[email protected]> Reviewed-by: Jens Johansen <[email protected]>
1 parent c88171c commit 6ce8d74

25 files changed

+771
-411
lines changed

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ import '../source/stack_listener_impl.dart' show offsetForToken;
111111

112112
import '../source/value_kinds.dart';
113113

114-
import '../type_inference/type_inferrer.dart' show TypeInferrer;
114+
import '../type_inference/type_inferrer.dart'
115+
show TypeInferrer, InferredFunctionBody;
115116

116117
import '../type_inference/type_promotion.dart'
117118
show TypePromoter, TypePromotionFact, TypePromotionScope;
@@ -992,9 +993,16 @@ class BodyBuilder extends ScopeListener<JumpTarget>
992993
builder.fileUri);
993994
}
994995

996+
InferredFunctionBody inferredFunctionBody;
995997
if (body != null) {
996-
body = typeInferrer?.inferFunctionBody(this, member.charOffset,
997-
_computeReturnTypeContext(member), asyncModifier, body);
998+
inferredFunctionBody = typeInferrer?.inferFunctionBody(
999+
this,
1000+
member.charOffset,
1001+
_computeReturnTypeContext(member),
1002+
asyncModifier,
1003+
body);
1004+
body = inferredFunctionBody.body;
1005+
builder.function.futureValueType = inferredFunctionBody.futureValueType;
9981006
libraryBuilder.loader.transformPostInference(body, transformSetLiterals,
9991007
transformCollections, libraryBuilder.library);
10001008
}
@@ -1426,10 +1434,10 @@ class BodyBuilder extends ScopeListener<JumpTarget>
14261434
typeInferrer?.flowAnalysis?.declare(formals[i].variable, true);
14271435
}
14281436
}
1429-
Statement inferredStatement = typeInferrer?.inferFunctionBody(
1437+
InferredFunctionBody inferredFunctionBody = typeInferrer?.inferFunctionBody(
14301438
this, fileOffset, const DynamicType(), AsyncMarker.Sync, fakeReturn);
14311439
assert(
1432-
fakeReturn == inferredStatement,
1440+
fakeReturn == inferredFunctionBody.body,
14331441
"Previously implicit assumption about inferFunctionBody "
14341442
"not returning anything different.");
14351443

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ abstract class ClosureContext {
3333
/// the unknown type.
3434
DartType get yieldContext;
3535

36+
DartType get futureValueType;
37+
3638
factory ClosureContext(TypeInferrerImpl inferrer, AsyncMarker asyncMarker,
3739
DartType returnContext, bool needToInferReturnType) {
3840
assert(returnContext != null);
@@ -55,15 +57,20 @@ abstract class ClosureContext {
5557
yieldContext, declaredReturnType, needToInferReturnType);
5658
}
5759
} else if (isAsync) {
60+
DartType futureValueType;
5861
if (inferrer.isNonNullableByDefault) {
5962
returnContext = inferrer.wrapFutureOrType(
6063
inferrer.computeFutureValueTypeSchema(returnContext));
64+
if (!needToInferReturnType) {
65+
futureValueType =
66+
computeFutureValueType(inferrer.coreTypes, declaredReturnType);
67+
}
6168
} else {
6269
returnContext = inferrer.wrapFutureOrType(
6370
inferrer.typeSchemaEnvironment.flatten(returnContext));
6471
}
65-
return new _AsyncClosureContext(
66-
returnContext, declaredReturnType, needToInferReturnType);
72+
return new _AsyncClosureContext(returnContext, declaredReturnType,
73+
needToInferReturnType, futureValueType);
6774
} else {
6875
return new _SyncClosureContext(
6976
returnContext, declaredReturnType, needToInferReturnType);
@@ -137,6 +144,9 @@ class _SyncClosureContext implements ClosureContext {
137144
/// being inferred.
138145
List<DartType> _returnExpressionTypes;
139146

147+
@override
148+
DartType get futureValueType => null;
149+
140150
_SyncClosureContext(this._returnContext, this._declaredReturnType,
141151
this._needToInferReturnType) {
142152
if (_needToInferReturnType) {
@@ -480,8 +490,10 @@ class _AsyncClosureContext implements ClosureContext {
480490
/// being inferred.
481491
List<DartType> _returnExpressionTypes;
482492

493+
DartType futureValueType;
494+
483495
_AsyncClosureContext(this._returnContext, this._declaredReturnType,
484-
this._needToInferReturnType) {
496+
this._needToInferReturnType, this.futureValueType) {
485497
if (_needToInferReturnType) {
486498
_returnStatements = [];
487499
_returnExpressionTypes = [];
@@ -491,8 +503,8 @@ class _AsyncClosureContext implements ClosureContext {
491503
void _checkValidReturn(TypeInferrerImpl inferrer, DartType returnType,
492504
ReturnStatement statement, DartType expressionType) {
493505
if (inferrer.isNonNullableByDefault) {
494-
DartType futureValueType =
495-
computeFutureValueType(inferrer.coreTypes, returnType);
506+
assert(
507+
futureValueType != null, "Future value type has not been computed.");
496508

497509
if (statement.expression == null) {
498510
// It is a compile-time error if s is `return;`, unless T_v is void,
@@ -788,6 +800,10 @@ class _AsyncClosureContext implements ClosureContext {
788800
}
789801
}
790802

803+
if (inferrer.isNonNullableByDefault) {
804+
futureValueType =
805+
computeFutureValueType(inferrer.coreTypes, inferredType);
806+
}
791807
for (int i = 0; i < _returnStatements.length; ++i) {
792808
_checkValidReturn(inferrer, inferredType, _returnStatements[i],
793809
_returnExpressionTypes[i]);
@@ -871,6 +887,9 @@ class _SyncStarClosureContext implements ClosureContext {
871887
/// being inferred.
872888
List<DartType> _yieldElementTypes;
873889

890+
@override
891+
DartType get futureValueType => null;
892+
874893
_SyncStarClosureContext(this._yieldElementContext, this._declaredReturnType,
875894
this._needToInferReturnType) {
876895
if (_needToInferReturnType) {
@@ -996,6 +1015,9 @@ class _AsyncStarClosureContext implements ClosureContext {
9961015
/// being inferred.
9971016
List<DartType> _yieldElementTypes;
9981017

1018+
@override
1019+
DartType get futureValueType => null;
1020+
9991021
_AsyncStarClosureContext(this._yieldElementContext, this._declaredReturnType,
10001022
this._needToInferReturnType) {
10011023
if (_needToInferReturnType) {

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ abstract class TypeInferrer {
149149
InferenceHelper helper, DartType declaredType, Expression initializer);
150150

151151
/// Performs type inference on the given function body.
152-
Statement inferFunctionBody(InferenceHelper helper, int fileOffset,
152+
InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
153153
DartType returnType, AsyncMarker asyncMarker, Statement body);
154154

155155
/// Performs type inference on the given constructor initializer.
@@ -1909,7 +1909,7 @@ class TypeInferrerImpl implements TypeInferrer {
19091909
}
19101910

19111911
@override
1912-
Statement inferFunctionBody(InferenceHelper helper, int fileOffset,
1912+
InferredFunctionBody inferFunctionBody(InferenceHelper helper, int fileOffset,
19131913
DartType returnType, AsyncMarker asyncMarker, Statement body) {
19141914
assert(body != null);
19151915
assert(closureContext == null);
@@ -1924,10 +1924,17 @@ class TypeInferrerImpl implements TypeInferrer {
19241924
}
19251925
result =
19261926
closureContext.handleImplicitReturn(this, body, result, fileOffset);
1927+
DartType futureValueType = closureContext.futureValueType;
1928+
assert(
1929+
!(isNonNullableByDefault &&
1930+
asyncMarker == AsyncMarker.Async &&
1931+
futureValueType == null),
1932+
"No future value type computed.");
19271933
closureContext = null;
19281934
this.helper = null;
19291935
flowAnalysis.finish();
1930-
return result.hasChanged ? result.statement : body;
1936+
return new InferredFunctionBody(
1937+
result.hasChanged ? result.statement : body, futureValueType);
19311938
}
19321939

19331940
InvocationInferenceResult inferInvocation(DartType typeContext, int offset,
@@ -2531,6 +2538,12 @@ class TypeInferrerImpl implements TypeInferrer {
25312538
}
25322539
bodyResult = closureContext.handleImplicitReturn(
25332540
this, function.body, bodyResult, fileOffset);
2541+
function.futureValueType = closureContext.futureValueType;
2542+
assert(
2543+
!(isNonNullableByDefault &&
2544+
function.asyncMarker == AsyncMarker.Async &&
2545+
function.futureValueType == null),
2546+
"No future value type computed.");
25342547

25352548
if (bodyResult.hasChanged) {
25362549
function.body = bodyResult.statement..parent = function;
@@ -4819,3 +4832,10 @@ FunctionType replaceReturnType(FunctionType functionType, DartType returnType) {
48194832
namedParameters: functionType.namedParameters,
48204833
typeParameters: functionType.typeParameters);
48214834
}
4835+
4836+
class InferredFunctionBody {
4837+
final Statement body;
4838+
final DartType futureValueType;
4839+
4840+
InferredFunctionBody(this.body, this.futureValueType);
4841+
}

pkg/front_end/test/static_types/data/for_in.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ forInIntToNum(List<int> list) {
4848
}
4949
}
5050

51+
/*cfe:nnbd.member: asyncForInDynamicStream:futureValueType=dynamic*/
5152
asyncForInDynamicStream(dynamic stream) async {
5253
/*current: dynamic*/
5354
await for (var e in
@@ -58,6 +59,7 @@ asyncForInDynamicStream(dynamic stream) async {
5859
}
5960
}
6061

62+
/*cfe:nnbd.member: asyncForInDynamic:futureValueType=dynamic*/
6163
asyncForInDynamic(Stream<dynamic> stream) async {
6264
/*current: dynamic*/
6365
await for (var e in
@@ -68,6 +70,7 @@ asyncForInDynamic(Stream<dynamic> stream) async {
6870
}
6971
}
7072

73+
/*cfe:nnbd.member: asyncForInInt:futureValueType=dynamic*/
7174
asyncForInInt(Stream<int> stream) async {
7275
/*cfe.current: int*/
7376
/*cfe:nnbd.current: int!*/
@@ -81,6 +84,7 @@ asyncForInInt(Stream<int> stream) async {
8184
}
8285
}
8386

87+
/*cfe:nnbd.member: asyncForInIntToNum:futureValueType=dynamic*/
8488
asyncForInIntToNum(Stream<int> stream) async {
8589
/*cfe.current: int*/
8690
/*cfe:nnbd.current: int!*/
@@ -115,6 +119,7 @@ abstract class CustomStream implements Stream<num> {
115119
Iterator<int> get iterator;
116120
}
117121

122+
/*cfe:nnbd.member: customStream:futureValueType=dynamic*/
118123
customStream(CustomStream stream) async {
119124
/*cfe.current: num*/
120125
/*cfe:nnbd.current: num!*/
@@ -153,6 +158,7 @@ abstract class StreamWithCustomIterator implements Stream<num> {
153158
CustomIterator get iterator;
154159
}
155160

161+
/*cfe:nnbd.member: customStreamIterator:futureValueType=dynamic*/
156162
customStreamIterator(StreamWithCustomIterator stream) async {
157163
/*cfe.current: num*/
158164
/*cfe:nnbd.current: num!*/
@@ -177,6 +183,7 @@ void genericIterable<T extends Iterable<T>>(T x) {
177183
}
178184
}
179185

186+
/*cfe:nnbd.member: genericStream:futureValueType=void*/
180187
void genericStream<T extends Stream<T>>(T x) async {
181188
/*cfe.current: T*/
182189
/*cfe:nnbd.current: T!*/
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/*cfe.library: nnbd=false*/
6+
7+
/*cfe:nnbd.library: nnbd=true*/
8+
9+
import 'dart:async';
10+
11+
/*cfe:nnbd.member: declaredFutureInt:futureValueType=int!*/
12+
Future<int> declaredFutureInt() async {
13+
return
14+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
15+
}
16+
17+
/*cfe:nnbd.member: declaredFutureOrInt:futureValueType=int!*/
18+
FutureOr<int> declaredFutureOrInt() async {
19+
return
20+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
21+
}
22+
23+
/*cfe:nnbd.member: declaredObject:futureValueType=Object?*/
24+
Object declaredObject() async {
25+
return
26+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
27+
}
28+
29+
/*cfe:nnbd.member: omitted:futureValueType=dynamic*/
30+
omitted() async {}
31+
32+
/*cfe:nnbd.member: method:futureValueType=dynamic*/
33+
method() async {
34+
/*cfe:nnbd.futureValueType=int!*/
35+
Future<int> declaredLocalFutureInt() async {
36+
return
37+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
38+
}
39+
40+
/*cfe:nnbd.futureValueType=int!*/
41+
FutureOr<int> declaredLocalFutureOrInt() async {
42+
return
43+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
44+
}
45+
46+
/*cfe:nnbd.futureValueType=Object?*/
47+
Object declaredLocalObject() async {
48+
return
49+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
50+
}
51+
52+
/*cfe:nnbd.futureValueType=Null*/ omittedLocal() async {}
53+
54+
Future<int> inferredCalledFutureInt =
55+
/*cfe.Future<int> Function()*/
56+
/*cfe:nnbd.Future<int!>! Function()!,futureValueType=int!*/
57+
() async {
58+
return
59+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
60+
}
61+
/*cfe.invoke: Future<int>*/
62+
/*cfe:nnbd.invoke: Future<int!>!*/
63+
();
64+
65+
FutureOr<int> inferredCalledFutureOrInt =
66+
/*cfe.Future<int> Function()*/
67+
/*cfe:nnbd.Future<int!>! Function()!,futureValueType=int!*/
68+
() async {
69+
return
70+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
71+
}
72+
/*cfe.invoke: Future<int>*/
73+
/*cfe:nnbd.invoke: Future<int!>!*/
74+
();
75+
76+
Future<int> Function() inferredFutureInt =
77+
/*cfe.Future<int> Function()*/
78+
/*cfe:nnbd.Future<int!>! Function()!,futureValueType=int!*/
79+
() async {
80+
return
81+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
82+
};
83+
84+
FutureOr<int> Function() inferredFutureOrInt =
85+
/*cfe.Future<int> Function()*/
86+
/*cfe:nnbd.Future<int!>! Function()!,futureValueType=int!*/
87+
() async {
88+
return
89+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
90+
};
91+
92+
Object Function() inferredInt =
93+
/*cfe.Future<int> Function()*/
94+
/*cfe:nnbd.Future<int!>! Function()!,futureValueType=int!*/
95+
() async {
96+
return
97+
/*cfe.int*/ /*cfe:nnbd.int!*/ 0;
98+
};
99+
100+
Object Function() inferredNull =
101+
/*cfe.Future<Null> Function()*/
102+
/*cfe:nnbd.Future<Null>! Function()!,futureValueType=Null*/
103+
() async {
104+
return
105+
/*Null*/ null;
106+
};
107+
108+
Object Function() inferredEmpty =
109+
/*cfe.Future<Null> Function()*/
110+
/*cfe:nnbd.Future<Null>! Function()!,futureValueType=Null*/
111+
() async {};
112+
}

0 commit comments

Comments
 (0)