Version 2.8.0-dev.15.0
Merge commit 'eb9c26bd378fbe3a0ebd00ce91973b49814d32be' into dev
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 20db2ee..8c08a77 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2020-02-27T09:12:42.886102",
+ "generated": "2020-03-11T09:16:09.767708",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -57,12 +57,6 @@
"languageVersion": "2.7"
},
{
- "name": "analyzer_fe_comparison",
- "rootUri": "../pkg/analyzer_fe_comparison",
- "packageUri": "lib/",
- "languageVersion": "2.0"
- },
- {
"name": "analyzer_plugin",
"rootUri": "../pkg/analyzer_plugin",
"packageUri": "lib/",
diff --git a/.packages b/.packages
index b6c666c..a5ab646 100644
--- a/.packages
+++ b/.packages
@@ -13,7 +13,6 @@
analysis_tool:pkg/analysis_tool/lib
analyzer:pkg/analyzer/lib
analyzer_cli:pkg/analyzer_cli/lib
-analyzer_fe_comparison:pkg/analyzer_fe_comparison/lib
analyzer_plugin:pkg/analyzer_plugin/lib
args:third_party/pkg/args/lib
async:third_party/pkg/async/lib
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9146f83..8b44589 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -61,6 +61,11 @@
`ProcessStartMode.inheritStdio`) upon accessing the `stdin`, `stdout`, and
`stderr` getters. Previously these getters would all return `null`.
+* **Breaking change** [#40706](https://github.com/dart-lang/sdk/issues/40706):
+ The dummy object returned if `FileStat.stat()` and `FileStat.statSync()` fail
+ now contains Unix epoch timestamps instead of `null` for the `accessed`,
+ `changed`, and `modified` getters.
+
#### `dart:mirrors`
* Added `MirrorSystem.neverType`.
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index d715141..739dd20 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -1185,25 +1185,40 @@
variableInfo[variable] ?? _freshVariableInfo;
/// Updates the state to indicate that variables that are not definitely
- /// unassigned in the [other] are also not definitely unassigned in the
- /// result.
- FlowModel<Variable, Type> joinUnassigned(FlowModel<Variable, Type> other) {
+ /// unassigned in the [other], or are [written], are also not definitely
+ /// unassigned in the result.
+ FlowModel<Variable, Type> joinUnassigned({
+ FlowModel<Variable, Type> other,
+ Iterable<Variable> written,
+ }) {
Map<Variable, VariableModel<Type>> newVariableInfo;
- for (Variable variable in other.variableInfo.keys) {
- VariableModel<Type> otherInfo = other.variableInfo[variable];
- if (otherInfo.unassigned) continue;
-
+ void markNotUnassigned(Variable variable) {
VariableModel<Type> info = variableInfo[variable];
- if (info == null) continue;
+ if (info == null) return;
VariableModel<Type> newInfo = info.markNotUnassigned();
- if (identical(newInfo, info)) continue;
+ if (identical(newInfo, info)) return;
(newVariableInfo ??= new Map<Variable, VariableModel<Type>>.from(
variableInfo))[variable] = newInfo;
}
+ if (other != null) {
+ for (Variable variable in other.variableInfo.keys) {
+ VariableModel<Type> otherInfo = other.variableInfo[variable];
+ if (!otherInfo.unassigned) {
+ markNotUnassigned(variable);
+ }
+ }
+ }
+
+ if (written != null) {
+ for (Variable variable in written) {
+ markNotUnassigned(variable);
+ }
+ }
+
if (newVariableInfo == null) return this;
return FlowModel<Variable, Type>._(reachable, newVariableInfo);
@@ -2217,7 +2232,7 @@
FlowModel<Variable, Type> falseCondition = context._conditionInfo.ifFalse;
_current = _join(falseCondition, breakState);
- _current = _current.joinUnassigned(afterUpdate);
+ _current = _current.joinUnassigned(other: afterUpdate);
}
@override
@@ -2256,6 +2271,9 @@
_stack.add(new _SimpleContext(_current));
_current = _current.removePromotedAll(_assignedVariables._anywhere._written,
_assignedVariables._anywhere._captured);
+ _current = _current.joinUnassigned(
+ written: _assignedVariables._anywhere._written,
+ );
}
@override
@@ -2266,7 +2284,7 @@
_SimpleContext<Variable, Type> context =
_stack.removeLast() as _SimpleContext<Variable, Type>;
_current = context._previous;
- _current = _current.joinUnassigned(afterBody);
+ _current = _current.joinUnassigned(other: afterBody);
}
@override
@@ -2597,7 +2615,7 @@
_stack.removeLast() as _WhileContext<Variable, Type>;
var afterBody = _current;
_current = _join(context._conditionInfo.ifFalse, context._breakModel);
- _current = _current.joinUnassigned(afterBody);
+ _current = _current.joinUnassigned(other: afterBody);
}
@override
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 18cf339..e3e5ffb 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -3565,7 +3565,7 @@
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageFinalAndCovariantLateWithInitializer = const MessageCode(
"FinalAndCovariantLateWithInitializer",
- analyzerCodes: <String>["ParserErrorCode.FINAL_AND_COVARIANT"],
+ index: 101,
message:
r"""Members marked 'late' with an initializer can't be declared to be both 'final' and 'covariant'.""",
tip:
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 26608af..b18db89 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -4267,21 +4267,6 @@
return isConditional;
}
- Token parseNullAwareBracketOrConditionalExpressionRest(
- Token token, TypeParamOrArgInfo typeArg) {
- Token question = token.next;
- assert(optional('?', question));
- Token bracket = question.next;
- assert(optional('[', bracket));
-
- bool isConditional = canParseAsConditional(question);
- if (isConditional) {
- return parseConditionalExpressionRest(token);
- }
- // It wasn't a conditional expression. Must be a null aware bracket then.
- return parseArgumentOrIndexStar(token, typeArg, true);
- }
-
Token parseConditionalExpressionRest(Token token) {
Token question = token = token.next;
assert(optional('?', question));
@@ -4375,6 +4360,10 @@
identical(type, TokenType.OPEN_SQUARE_BRACKET) ||
identical(type, TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET)) {
token = parseArgumentOrIndexStar(token, typeArg, false);
+ } else if (identical(type, TokenType.QUESTION)) {
+ // We have determined selector precedence so this is a null-aware
+ // bracket operator.
+ token = parseArgumentOrIndexStar(token, typeArg, true);
} else if (identical(type, TokenType.INDEX)) {
BeginToken replacement = link(
new BeginToken(TokenType.OPEN_SQUARE_BRACKET, next.charOffset,
@@ -4397,12 +4386,7 @@
} else if (identical(type, TokenType.AS)) {
token = parseAsOperatorRest(token);
} else if (identical(type, TokenType.QUESTION)) {
- if (optional('[', next.next)) {
- token = parseNullAwareBracketOrConditionalExpressionRest(
- token, typeArg);
- } else {
- token = parseConditionalExpressionRest(token);
- }
+ token = parseConditionalExpressionRest(token);
} else {
if (level == EQUALITY_PRECEDENCE || level == RELATIONAL_PRECEDENCE) {
// We don't allow (a == b == c) or (a < b < c).
@@ -4444,6 +4428,14 @@
return SELECTOR_PRECEDENCE;
}
return POSTFIX_PRECEDENCE;
+ } else if (identical(type, TokenType.QUESTION) &&
+ optional('[', token.next)) {
+ // "?[" can be a null-aware bracket or a conditional. If it's a
+ // null-aware bracket it has selector precedence.
+ bool isConditional = canParseAsConditional(token);
+ if (!isConditional) {
+ return SELECTOR_PRECEDENCE;
+ }
}
return type.precedence;
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/function_expression.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/function_expression.dart
index d614577..1bcbfc1 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/function_expression.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/function_expression.dart
@@ -2,29 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-closure_read() {
- late int v1, v2;
-
- v1 = 0;
-
- [0, 1, 2].forEach((t) {
- v1;
- /*unassigned*/ v2;
- });
-}
-
-closure_write() {
- late int v;
-
- /*unassigned*/ v;
-
- [0, 1, 2].forEach((t) {
- v = t;
- });
-
- v;
-}
-
localFunction_local() {
late int v;
@@ -50,32 +27,21 @@
}
}
-localFunction_read() {
+readInClosure_writeInMain() {
late int v1, v2, v3;
v1 = 0;
- void f() {
+ [0, 1, 2].forEach((t) {
v1;
- /*unassigned*/ v2;
- }
+ v2;
+ /*unassigned*/ v3;
+ });
v2 = 0;
}
-localFunction_write() {
- late int v;
-
- /*unassigned*/ v;
-
- void f() {
- v = 0;
- }
-
- v;
-}
-
-writeCaptured() {
+readInLocal_writeInLocal() {
late int v1, v2;
void f() {
@@ -91,6 +57,46 @@
g();
f();
+}
+
+readInLocal_writeInMain() {
+ late int v1, v2, v3;
+
+ v1 = 0;
+
+ void f() {
+ v1;
+ v2;
+ /*unassigned*/ v3;
+ }
+
+ v2 = 0;
+ f();
+}
+
+readInMain_writeInClosure() {
+ late int v1, v2;
+
+ /*unassigned*/ v1;
+ /*unassigned*/ v2;
+
+ [0, 1, 2].forEach((t) {
+ v1 = t;
+ });
+
+ v1;
+ /*unassigned*/ v2;
+}
+
+readInMain_writeInLocal() {
+ late int v1, v2;
+
+ /*unassigned*/ v1;
+ /*unassigned*/ v2;
+
+ void f() {
+ v1 = 0;
+ }
v1;
/*unassigned*/ v2;
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 93374c3..f28c2e9 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -2118,76 +2118,110 @@
});
group('joinUnassigned', () {
- test('unchanged', () {
- var h = _Harness();
+ group('other', () {
+ test('unchanged', () {
+ var h = _Harness();
- var a = _Var('a', _Type('int'));
- var b = _Var('b', _Type('int'));
+ var a = _Var('a', _Type('int'));
+ var b = _Var('b', _Type('int'));
- var s1 = FlowModel<_Var, _Type>(true)
- .declare(a, false)
- .declare(b, false)
- .write(a, _Type('int'), h);
- expect(s1.variableInfo, {
- a: _matchVariableModel(assigned: true, unassigned: false),
- b: _matchVariableModel(assigned: false, unassigned: true),
+ var s1 = FlowModel<_Var, _Type>(true)
+ .declare(a, false)
+ .declare(b, false)
+ .write(a, _Type('int'), h);
+ expect(s1.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: true),
+ });
+
+ var s2 = s1.write(a, _Type('int'), h);
+ expect(s2.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: true),
+ });
+
+ var s3 = s1.joinUnassigned(other: s2);
+ expect(s3, same(s1));
});
- var s2 = s1.write(a, _Type('int'), h);
- expect(s2.variableInfo, {
- a: _matchVariableModel(assigned: true, unassigned: false),
- b: _matchVariableModel(assigned: false, unassigned: true),
- });
+ test('changed', () {
+ var h = _Harness();
- var s3 = s1.joinUnassigned(s2);
- expect(s3, same(s1));
- });
+ var a = _Var('a', _Type('int'));
+ var b = _Var('b', _Type('int'));
+ var c = _Var('c', _Type('int'));
- test('written', () {
- var h = _Harness();
+ var s1 = FlowModel<_Var, _Type>(true)
+ .declare(a, false)
+ .declare(b, false)
+ .declare(c, false)
+ .write(a, _Type('int'), h);
+ expect(s1.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: true),
+ c: _matchVariableModel(assigned: false, unassigned: true),
+ });
- var a = _Var('a', _Type('int'));
- var b = _Var('b', _Type('int'));
- var c = _Var('c', _Type('int'));
+ var s2 = s1.write(b, _Type('int'), h);
+ expect(s2.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: true, unassigned: false),
+ c: _matchVariableModel(assigned: false, unassigned: true),
+ });
- var s1 = FlowModel<_Var, _Type>(true)
- .declare(a, false)
- .declare(b, false)
- .declare(c, false)
- .write(a, _Type('int'), h);
- expect(s1.variableInfo, {
- a: _matchVariableModel(assigned: true, unassigned: false),
- b: _matchVariableModel(assigned: false, unassigned: true),
- c: _matchVariableModel(assigned: false, unassigned: true),
- });
-
- var s2 = s1.write(b, _Type('int'), h);
- expect(s2.variableInfo, {
- a: _matchVariableModel(assigned: true, unassigned: false),
- b: _matchVariableModel(assigned: true, unassigned: false),
- c: _matchVariableModel(assigned: false, unassigned: true),
- });
-
- var s3 = s1.joinUnassigned(s2);
- expect(s3.variableInfo, {
- a: _matchVariableModel(assigned: true, unassigned: false),
- b: _matchVariableModel(assigned: false, unassigned: false),
- c: _matchVariableModel(assigned: false, unassigned: true),
+ var s3 = s1.joinUnassigned(other: s2);
+ expect(s3.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: false),
+ c: _matchVariableModel(assigned: false, unassigned: true),
+ });
});
});
- test('write captured', () {
- var h = _Harness();
- var s1 = FlowModel<_Var, _Type>(true)
- .tryPromote(h, objectQVar, _Type('int'))
- .ifTrue
- .tryPromote(h, intQVar, _Type('int'))
- .ifTrue;
- var s2 = s1.removePromotedAll([], [intQVar]);
- expect(s2.reachable, true);
- expect(s2.variableInfo, {
- objectQVar: _matchVariableModel(chain: ['int'], ofInterest: ['int']),
- intQVar: _matchVariableModel(chain: null, ofInterest: isEmpty)
+ group('written', () {
+ test('unchanged', () {
+ var h = _Harness();
+
+ var a = _Var('a', _Type('int'));
+ var b = _Var('b', _Type('int'));
+
+ var s1 = FlowModel<_Var, _Type>(true)
+ .declare(a, false)
+ .declare(b, false)
+ .write(a, _Type('int'), h);
+ expect(s1.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: true),
+ });
+
+ var s2 = s1.joinUnassigned(written: [a]);
+ expect(s2, same(s1));
+ });
+
+ test('changed', () {
+ var h = _Harness();
+
+ var a = _Var('a', _Type('int'));
+ var b = _Var('b', _Type('int'));
+ var c = _Var('c', _Type('int'));
+
+ var s1 = FlowModel<_Var, _Type>(true)
+ .declare(a, false)
+ .declare(b, false)
+ .declare(c, false)
+ .write(a, _Type('int'), h);
+ expect(s1.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: true),
+ c: _matchVariableModel(assigned: false, unassigned: true),
+ });
+
+ var s2 = s1.joinUnassigned(written: [b]);
+ expect(s2.variableInfo, {
+ a: _matchVariableModel(assigned: true, unassigned: false),
+ b: _matchVariableModel(assigned: false, unassigned: false),
+ c: _matchVariableModel(assigned: false, unassigned: true),
+ });
});
});
});
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 6b68d27..75045dd 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -5126,6 +5126,11 @@
an analysis root, or the requested operation is not available
for the file.
</p>
+ </dd><dt class="value">FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED</dt><dd>
+
+ <p>
+ A file was change while widget descriptions were being computed.
+ </p>
</dd><dt class="value">FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET</dt><dd>
<p>
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index 4d8dc58..1300974 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -17642,6 +17642,7 @@
/// CONTENT_MODIFIED
/// DEBUG_PORT_COULD_NOT_BE_OPENED
/// FILE_NOT_ANALYZED
+/// FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED
/// FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET
/// FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION
/// FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID
@@ -17691,6 +17692,11 @@
static const RequestErrorCode FILE_NOT_ANALYZED =
RequestErrorCode._('FILE_NOT_ANALYZED');
+ /// A file was change while widget descriptions were being computed.
+ static const RequestErrorCode
+ FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED =
+ RequestErrorCode._('FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED');
+
/// The given location does not have a supported widget.
static const RequestErrorCode FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET =
RequestErrorCode._('FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET');
@@ -17848,6 +17854,7 @@
CONTENT_MODIFIED,
DEBUG_PORT_COULD_NOT_BE_OPENED,
FILE_NOT_ANALYZED,
+ FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED,
FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET,
FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION,
FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID,
@@ -17893,6 +17900,8 @@
return DEBUG_PORT_COULD_NOT_BE_OPENED;
case 'FILE_NOT_ANALYZED':
return FILE_NOT_ANALYZED;
+ case 'FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED':
+ return FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED;
case 'FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET':
return FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET;
case 'FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION':
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart
index 6c2468b..4a4e1da 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart
@@ -514,27 +514,18 @@
}).toList();
}
- TraceEntryInfo _computeTraceEntry(PropagationStepInfo step) {
- var codeReference = step.codeReference;
- var length = 1; // TODO(paulberry): figure out the correct value.
- var description = step.toString(); // TODO(paulberry): improve this message.
- return TraceEntryInfo(
- description,
- codeReference?.function,
- codeReference == null
- ? null
- : NavigationTarget(codeReference.path, codeReference.column,
- codeReference.line, length));
- }
-
TraceInfo _computeTraceInfo(NullabilityNodeInfo node) {
List<TraceEntryInfo> entries = [];
var step = node.whyNullable;
+ assert(identical(step.targetNode, node));
while (step != null) {
- entries.add(_computeTraceEntry(step));
+ entries.add(_nodeToTraceEntry(step.targetNode));
+ if (step.codeReference != null) {
+ entries.add(_stepToTraceEntry(step));
+ }
step = step.principalCause;
}
- var description = node.toString(); // TODO(paulberry): improve this message.
+ var description = 'Nullability reason';
return TraceInfo(description, entries);
}
@@ -728,6 +719,23 @@
return resourceProvider.pathContext.split(filePath).contains('test');
}
+ TraceEntryInfo _makeTraceEntry(
+ String description, CodeReference codeReference) {
+ var length = 1; // TODO(paulberry): figure out the correct value.
+ return TraceEntryInfo(
+ description,
+ codeReference?.function,
+ codeReference == null
+ ? null
+ : NavigationTarget(codeReference.path, codeReference.column,
+ codeReference.line, length));
+ }
+
+ TraceEntryInfo _nodeToTraceEntry(NullabilityNodeInfo node) {
+ var description = node.toString(); // TODO(paulberry): improve this message
+ return _makeTraceEntry(description, node.codeReference);
+ }
+
/// Return the navigation target corresponding to the given [node] in the file
/// with the given [filePath].
///
@@ -764,6 +772,11 @@
}
}
+ TraceEntryInfo _stepToTraceEntry(PropagationStepInfo step) {
+ var description = step.toString(); // TODO(paulberry): improve this message.
+ return _makeTraceEntry(description, step.codeReference);
+ }
+
/// Return the navigation target in the file with the given [filePath] at the
/// given [offset] ans with the given [length].
NavigationTarget _targetForNode(
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
index bada9dd..7686e8f 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/domain_abstract.dart';
import 'package:analysis_server/src/protocol/protocol_internal.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/analysis/session.dart';
/// A [RequestHandler] that handles requests in the `flutter` domain.
class FlutterDomainHandler extends AbstractRequestHandler {
@@ -31,10 +32,24 @@
var computer = server.flutterWidgetDescriptions;
- var result = await computer.getDescription(
- resolvedUnit,
- offset,
- );
+ FlutterGetWidgetDescriptionResult result;
+ try {
+ result = await computer.getDescription(
+ resolvedUnit,
+ offset,
+ );
+ } on InconsistentAnalysisException {
+ server.sendResponse(
+ Response(
+ request.id,
+ error: RequestError(
+ RequestErrorCode.FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED,
+ 'Concurrent modification detected.',
+ ),
+ ),
+ );
+ return;
+ }
if (result == null) {
server.sendResponse(
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
index 9613ccd..901d588 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
@@ -121,6 +121,13 @@
double startsWithDollarFeature(String name) =>
name.startsWith('\$') ? 0.0 : 1.0;
+ /// Return the value of the _super matches_ feature.
+ double superMatchesFeature(
+ String containingMethodName, String proposedMemberName) =>
+ containingMethodName == null
+ ? -1.0
+ : (proposedMemberName == containingMethodName ? 1.0 : 0.0);
+
/// Return the inheritance distance between the [subclass] and the
/// [superclass]. The set of [visited] elements is used to guard against
/// cycles in the type graph.
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index e4570fe..d08d787 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -524,6 +524,7 @@
// See similar logic in `imported_reference_contributor`.
_addSuggestion(Keyword.DYNAMIC);
+ _addSuggestion(Keyword.VOID);
} else {
super.visitMethodInvocation(node);
}
@@ -666,6 +667,7 @@
@override
void visitTypeArgumentList(TypeArgumentList node) {
_addSuggestion(Keyword.DYNAMIC);
+ _addSuggestion(Keyword.VOID);
}
@override
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index 7eb0343..5325ebd 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -271,9 +271,10 @@
if (request.useNewRelevance) {
var contextType = featureComputer.contextTypeFeature(
request.target.containingNode, method.returnType);
- var superMatches = method.name == containingMethodName ? 1.0 : 0.0;
var startsWithDollar =
featureComputer.startsWithDollarFeature(method.name);
+ var superMatches = featureComputer.superMatchesFeature(
+ containingMethodName, method.name);
relevance = _computeRelevance(
contextType: contextType,
inheritanceDistance: inheritanceDistance,
@@ -299,11 +300,13 @@
request.target.containingNode, variable.type);
var startsWithDollar = featureComputer
.startsWithDollarFeature(propertyAccessor.name);
+ var superMatches = featureComputer.superMatchesFeature(
+ containingMethodName, propertyAccessor.name);
relevance = _computeRelevance(
contextType: contextType,
inheritanceDistance: inheritanceDistance,
startsWithDollar: startsWithDollar,
- superMatches: -1.0);
+ superMatches: superMatches);
}
addSuggestion(variable, relevance: relevance);
}
@@ -317,11 +320,13 @@
request.target.containingNode, type);
var startsWithDollar = featureComputer
.startsWithDollarFeature(propertyAccessor.name);
+ var superMatches = featureComputer.superMatchesFeature(
+ containingMethodName, propertyAccessor.name);
relevance = _computeRelevance(
contextType: contextType,
inheritanceDistance: inheritanceDistance,
startsWithDollar: startsWithDollar,
- superMatches: -1.0);
+ superMatches: superMatches);
}
addSuggestion(propertyAccessor, relevance: relevance);
}
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 58cd025..785aec6 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/base_processor.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/dart/add_return_type.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_list_literal.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
@@ -161,9 +162,6 @@
)) {
await _addProposal_addDiagnosticPropertyReference();
}
- if (!_containsErrorCode({LintNames.always_declare_return_types})) {
- await _addProposal_addReturnType();
- }
if (experimentStatus.control_flow_collections) {
if (!_containsErrorCode(
{LintNames.prefer_if_elements_to_conditional_expressions},
@@ -269,6 +267,10 @@
}
await computeIfNotErrorCode(
+ AddReturnType(),
+ {LintNames.always_declare_return_types},
+ );
+ await computeIfNotErrorCode(
ConvertToListLiteral(),
{LintNames.prefer_collection_literals},
);
@@ -349,11 +351,6 @@
}
}
- Future<void> _addProposal_addReturnType() async {
- final changeBuilder = await createBuilder_addReturnType();
- _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_RETURN_TYPE);
- }
-
Future<void> _addProposal_assignToLocalVariable() async {
// prepare enclosing ExpressionStatement
ExpressionStatement expressionStatement;
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
index 01d7a94..3bbc4f0 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -12,7 +12,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
-import 'package:analyzer/dart/element/type_system.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/analysis/session_helper.dart';
@@ -235,45 +234,6 @@
return null;
}
- Future<ChangeBuilder> createBuilder_addReturnType() async {
- var node = this.node;
- if (node is SimpleIdentifier) {
- FunctionBody body;
- var parent = node.parent;
- if (parent is MethodDeclaration) {
- if (parent.returnType != null) {
- _coverageMarker();
- return null;
- }
- body = parent.body;
- } else if (parent is FunctionDeclaration) {
- if (parent.returnType != null) {
- _coverageMarker();
- return null;
- }
- body = parent.functionExpression.body;
- } else {
- _coverageMarker();
- return null;
- }
- var returnType = inferReturnType(body);
- if (returnType == null) {
- _coverageMarker();
- return null;
- }
- var changeBuilder = _newDartChangeBuilder();
- bool validChange = true;
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addInsertion(node.offset, (DartEditBuilder builder) {
- validChange = builder.writeType(returnType);
- builder.write(' ');
- });
- });
- return validChange ? changeBuilder : null;
- }
- return null;
- }
-
Future<ChangeBuilder>
createBuilder_addTypeAnnotation_DeclaredIdentifier() async {
DeclaredIdentifier declaredIdentifier =
@@ -1388,47 +1348,6 @@
return null;
}
- /// Return the type of value returned by the function [body], or `null` if a
- /// type can't be inferred.
- DartType inferReturnType(FunctionBody body) {
- bool isAsynchronous;
- bool isGenerator;
- DartType baseType;
- if (body is ExpressionFunctionBody) {
- isAsynchronous = body.isAsynchronous;
- isGenerator = body.isGenerator;
- baseType = body.expression.staticType;
- } else if (body is BlockFunctionBody) {
- isAsynchronous = body.isAsynchronous;
- isGenerator = body.isGenerator;
- var computer = _ReturnTypeComputer(resolvedResult.typeSystem);
- body.block.accept(computer);
- baseType = computer.returnType;
- if (baseType == null && computer.hasReturn) {
- baseType = typeProvider.voidType;
- }
- }
- if (baseType == null) {
- return null;
- }
- if (isAsynchronous) {
- if (isGenerator) {
- return typeProvider.streamElement.instantiate(
- typeArguments: [baseType],
- nullabilitySuffix: baseType.nullabilitySuffix);
- } else {
- return typeProvider.futureElement.instantiate(
- typeArguments: [baseType],
- nullabilitySuffix: baseType.nullabilitySuffix);
- }
- } else if (isGenerator) {
- return typeProvider.iterableElement.instantiate(
- typeArguments: [baseType],
- nullabilitySuffix: baseType.nullabilitySuffix);
- }
- return baseType;
- }
-
bool isEnum(DartType type) {
final element = type.element;
return element is ClassElement && element.isEnum;
@@ -1617,45 +1536,3 @@
}
}
}
-
-/// Copied from lib/src/services/correction/base_processor.dart, but [hasReturn]
-/// was added.
-// TODO(brianwilkerson) Decide whether to unify the two classes.
-class _ReturnTypeComputer extends RecursiveAstVisitor<void> {
- final TypeSystem typeSystem;
-
- DartType returnType;
-
- /// A flag indicating whether at least one return statement was found.
- bool hasReturn = false;
-
- _ReturnTypeComputer(this.typeSystem);
-
- @override
- void visitBlockFunctionBody(BlockFunctionBody node) {}
-
- @override
- void visitReturnStatement(ReturnStatement node) {
- hasReturn = true;
- // prepare expression
- Expression expression = node.expression;
- if (expression == null) {
- return;
- }
- // prepare type
- DartType type = expression.staticType;
- if (type.isBottom) {
- return;
- }
- // combine types
- if (returnType == null) {
- returnType = type;
- } else {
- if (returnType is InterfaceType && type is InterfaceType) {
- returnType = InterfaceType.getSmartLeastUpperBound(returnType, type);
- } else {
- returnType = typeSystem.leastUpperBound(returnType, type);
- }
- }
- }
-}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index a39e416..9f7282e 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -43,6 +43,8 @@
/// producer doesn't support fixes.
FixKind get fixKind => null;
+ Flutter get flutter => _context.flutter;
+
AstNode get node => _context.node;
ResolvedUnitResult get resolvedResult => _context.resolvedResult;
@@ -68,6 +70,11 @@
return utils.getRangeText(range);
}
+ /// Return `true` the lint with the given [name] is enabled.
+ bool isLintEnabled(String name) {
+ return _context.isLintEnabled(name);
+ }
+
/// Return `true` if the selection covers an operator of the given
/// [binaryExpression].
bool isOperatorSelected(BinaryExpression binaryExpression) {
@@ -126,6 +133,12 @@
AstNode get node => _node;
+ /// Return `true` the lint with the given [name] is enabled.
+ bool isLintEnabled(String name) {
+ var analysisOptions = session.analysisContext.analysisOptions;
+ return analysisOptions.isLintEnabled(name);
+ }
+
bool setupCompute() {
final locator = NodeLocator(selectionOffset, selectionEnd);
_node = locator.searchWithin(resolvedResult.unit);
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart
new file mode 100644
index 0000000..76a79c7
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_field_formal_parameters.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+class AddFieldFormalParameters extends CorrectionProducer {
+ @override
+ FixKind get fixKind => DartFixKind.ADD_FIELD_FORMAL_PARAMETERS;
+
+ @override
+ Future<void> compute(DartChangeBuilder builder) async {
+ if (node is! SimpleIdentifier || node.parent is! ConstructorDeclaration) {
+ return;
+ }
+ ConstructorDeclaration constructor = node.parent;
+ List<FormalParameter> parameters = constructor.parameters.parameters;
+
+ ClassDeclaration classNode = constructor.parent;
+ InterfaceType superType = classNode.declaredElement.supertype;
+
+ // Compute uninitialized final fields.
+ List<FieldElement> fields =
+ ErrorVerifier.computeNotInitializedFields(constructor);
+ fields.retainWhere((FieldElement field) => field.isFinal);
+
+ // Prepare new parameters code.
+ fields.sort((a, b) => a.nameOffset - b.nameOffset);
+ String fieldParametersCode =
+ fields.map((field) => 'this.${field.name}').join(', ');
+
+ // Specialize for Flutter widgets.
+ if (flutter.isExactlyStatelessWidgetType(superType) ||
+ flutter.isExactlyStatefulWidgetType(superType)) {
+ if (parameters.isNotEmpty && parameters.last.isNamed) {
+ await builder.addFileEdit(file, (builder) {
+ builder.addSimpleInsertion(
+ parameters.last.end,
+ ', $fieldParametersCode',
+ );
+ });
+ return;
+ }
+ }
+
+ // Prepare the last required parameter.
+ FormalParameter lastRequiredParameter;
+ for (FormalParameter parameter in parameters) {
+ if (parameter.isRequiredPositional) {
+ lastRequiredParameter = parameter;
+ }
+ }
+
+ await builder.addFileEdit(file, (builder) {
+ if (lastRequiredParameter != null) {
+ builder.addSimpleInsertion(
+ lastRequiredParameter.end,
+ ', $fieldParametersCode',
+ );
+ } else {
+ int offset = constructor.parameters.leftParenthesis.end;
+ if (parameters.isNotEmpty) {
+ fieldParametersCode += ', ';
+ }
+ builder.addSimpleInsertion(offset, fieldParametersCode);
+ }
+ });
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart
new file mode 100644
index 0000000..ede0d75
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/syntactic_entity.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+class AddReturnType extends CorrectionProducer {
+ @override
+ AssistKind get assistKind => DartAssistKind.ADD_RETURN_TYPE;
+
+ @override
+ FixKind get fixKind => DartFixKind.ADD_RETURN_TYPE;
+
+ @override
+ Future<void> compute(DartChangeBuilder builder) async {
+ SyntacticEntity insertBeforeEntity;
+ FunctionBody body;
+ if (node is SimpleIdentifier) {
+ var executable = node.parent;
+ if (executable is MethodDeclaration && executable.name == node) {
+ if (executable.returnType != null) {
+ return;
+ }
+ if (isLintEnabled(LintNames.avoid_return_types_on_setters) &&
+ executable.isSetter) {
+ return;
+ }
+ insertBeforeEntity = executable.propertyKeyword ?? executable.name;
+ body = executable.body;
+ } else if (executable is FunctionDeclaration && executable.name == node) {
+ if (executable.returnType != null) {
+ return;
+ }
+ if (isLintEnabled(LintNames.avoid_return_types_on_setters) &&
+ executable.isSetter) {
+ return;
+ }
+ insertBeforeEntity = executable.propertyKeyword ?? executable.name;
+ body = executable.functionExpression.body;
+ } else {
+ return;
+ }
+ }
+
+ var returnType = _inferReturnType(body);
+ if (returnType == null) {
+ return null;
+ }
+
+ await builder.addFileEdit(file, (builder) {
+ builder.addInsertion(insertBeforeEntity.offset, (builder) {
+ if (returnType.isDynamic) {
+ builder.write('dynamic');
+ } else {
+ builder.writeType(returnType);
+ }
+ builder.write(' ');
+ });
+ });
+ }
+
+ /// Return the type of value returned by the function [body], or `null` if a
+ /// type can't be inferred.
+ DartType _inferReturnType(FunctionBody body) {
+ DartType baseType;
+ if (body is ExpressionFunctionBody) {
+ baseType = body.expression.staticType;
+ } else if (body is BlockFunctionBody) {
+ var computer = _ReturnTypeComputer(resolvedResult.typeSystem);
+ body.block.accept(computer);
+ baseType = computer.returnType;
+ if (baseType == null && computer.hasReturn) {
+ baseType = typeProvider.voidType;
+ }
+ }
+
+ if (baseType == null) {
+ return null;
+ }
+
+ var isAsynchronous = body.isAsynchronous;
+ var isGenerator = body.isGenerator;
+ if (isAsynchronous) {
+ if (isGenerator) {
+ return typeProvider.streamElement.instantiate(
+ typeArguments: [baseType],
+ nullabilitySuffix: baseType.nullabilitySuffix,
+ );
+ } else {
+ return typeProvider.futureElement.instantiate(
+ typeArguments: [baseType],
+ nullabilitySuffix: baseType.nullabilitySuffix,
+ );
+ }
+ } else if (isGenerator) {
+ return typeProvider.iterableElement.instantiate(
+ typeArguments: [baseType],
+ nullabilitySuffix: baseType.nullabilitySuffix,
+ );
+ }
+ return baseType;
+ }
+}
+
+/// Copied from lib/src/services/refactoring/extract_method.dart", but
+/// [hasReturn] was added.
+// TODO(brianwilkerson) Decide whether to unify the two classes.
+class _ReturnTypeComputer extends RecursiveAstVisitor<void> {
+ final TypeSystem typeSystem;
+
+ DartType returnType;
+
+ /// A flag indicating whether at least one return statement was found.
+ bool hasReturn = false;
+
+ _ReturnTypeComputer(this.typeSystem);
+
+ @override
+ void visitBlockFunctionBody(BlockFunctionBody node) {}
+
+ @override
+ void visitReturnStatement(ReturnStatement node) {
+ hasReturn = true;
+ // prepare expression
+ Expression expression = node.expression;
+ if (expression == null) {
+ return;
+ }
+ // prepare type
+ DartType type = expression.staticType;
+ if (type.isBottom) {
+ return;
+ }
+ // combine types
+ if (returnType == null) {
+ returnType = type;
+ } else {
+ if (returnType is InterfaceType && type is InterfaceType) {
+ returnType = InterfaceType.getSmartLeastUpperBound(returnType, type);
+ } else {
+ returnType = typeSystem.leastUpperBound(returnType, type);
+ }
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_unused_local_variable.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_unused_local_variable.dart
index febeea4..366a7c1 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_unused_local_variable.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_unused_local_variable.dart
@@ -30,29 +30,26 @@
final sourceRanges = <SourceRange>[];
final functionBody = declaration.thisOrAncestorOfType<FunctionBody>();
+ if (functionBody == null) {
+ return;
+ }
+
final references = findLocalElementReferences(functionBody, element);
for (var reference in references) {
final node = reference.thisOrAncestorMatching((node) =>
node is VariableDeclaration || node is AssignmentExpression);
- var sourceRange;
- if (node is VariableDeclaration) {
- VariableDeclarationList parent = node.parent;
- if (parent.variables.length == 1) {
- sourceRange = utils.getLinesRange(range.node(parent.parent));
- } else {
- sourceRange = range.nodeInList(parent.variables, node);
- }
- } else if (node is AssignmentExpression) {
- // todo (pq): consider node.parent is! ExpressionStatement to handle
- // assignments in parens, etc.
- if (node.parent is ArgumentList) {
- sourceRange = range.startStart(node, node.operator.next);
- } else {
- sourceRange = utils.getLinesRange(range.node(node.parent));
- }
- } else {
+
+ SourceRange sourceRange;
+ if (node is AssignmentExpression) {
+ sourceRange = _forAssignmentExpression(node);
+ } else if (node is VariableDeclaration) {
+ sourceRange = _forVariableDeclaration(node);
+ }
+
+ if (sourceRange == null) {
return;
}
+
sourceRanges.add(sourceRange);
}
@@ -62,4 +59,29 @@
}
});
}
+
+ SourceRange _forAssignmentExpression(AssignmentExpression node) {
+ // todo (pq): consider node.parent is! ExpressionStatement to handle
+ // assignments in parens, etc.
+ if (node.parent is ArgumentList) {
+ return range.startStart(node, node.operator.next);
+ } else {
+ return utils.getLinesRange(range.node(node.parent));
+ }
+ }
+
+ SourceRange _forVariableDeclaration(VariableDeclaration node) {
+ var declarationList = node.parent as VariableDeclarationList;
+
+ var declarationListParent = declarationList.parent;
+ if (declarationListParent is VariableDeclarationStatement) {
+ if (declarationList.variables.length == 1) {
+ return utils.getLinesRange(range.node(declarationListParent));
+ } else {
+ return range.nodeInList(declarationList.variables, node);
+ }
+ } else {
+ return null;
+ }
+ }
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 65b4196..5e9f9df 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -12,6 +12,8 @@
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server/src/services/correction/base_processor.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/dart/add_field_formal_parameters.dart';
+import 'package:analysis_server/src/services/correction/dart/add_return_type.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_list_literal.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
@@ -52,7 +54,6 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/error/inheritance_override.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/error_verifier.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -453,12 +454,6 @@
if (errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED) {
await _addFix_createConstructor_forUninitializedFinalFields();
}
- if (errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
- errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
- errorCode ==
- StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS) {
- await _addFix_updateConstructor_forUninitializedFinalFields();
- }
if (errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER) {
await _addFix_undefinedClassAccessor_useSimilar();
await _addFix_createClass();
@@ -592,9 +587,6 @@
// lints
if (errorCode is LintCode) {
String name = errorCode.name;
- if (name == LintNames.always_declare_return_types) {
- await _addFix_addReturnType();
- }
if (name == LintNames.always_specify_types ||
name == LintNames.type_annotate_public_apis) {
await _addFix_addTypeAnnotation();
@@ -1274,11 +1266,6 @@
_addFixFromBuilder(changeBuilder, DartFixKind.ADD_REQUIRED);
}
- Future<void> _addFix_addReturnType() async {
- var changeBuilder = await createBuilder_addReturnType();
- _addFixFromBuilder(changeBuilder, DartFixKind.ADD_RETURN_TYPE);
- }
-
Future<void> _addFix_addStatic() async {
FieldDeclaration declaration =
node.thisOrAncestorOfType<FieldDeclaration>();
@@ -4349,68 +4336,6 @@
}
}
- /// Here we handle cases when a constructors does not initialize all of the
- /// final fields.
- Future<void> _addFix_updateConstructor_forUninitializedFinalFields() async {
- if (node is! SimpleIdentifier || node.parent is! ConstructorDeclaration) {
- return;
- }
- ConstructorDeclaration constructor = node.parent;
- List<FormalParameter> parameters = constructor.parameters.parameters;
-
- ClassDeclaration classNode = constructor.parent;
- InterfaceType superType = classNode.declaredElement.supertype;
-
- // Compute uninitialized final fields.
- List<FieldElement> fields =
- ErrorVerifier.computeNotInitializedFields(constructor);
- fields.retainWhere((FieldElement field) => field.isFinal);
-
- // Prepare new parameters code.
- fields.sort((a, b) => a.nameOffset - b.nameOffset);
- String fieldParametersCode =
- fields.map((field) => 'this.${field.name}').join(', ');
-
- // Specialize for Flutter widgets.
- if (flutter.isExactlyStatelessWidgetType(superType) ||
- flutter.isExactlyStatefulWidgetType(superType)) {
- if (parameters.isNotEmpty && parameters.last.isNamed) {
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addSimpleInsertion(
- parameters.last.end, ', $fieldParametersCode');
- });
- _addFixFromBuilder(
- changeBuilder, DartFixKind.ADD_FIELD_FORMAL_PARAMETERS);
- return;
- }
- }
-
- // Prepare the last required parameter.
- FormalParameter lastRequiredParameter;
- for (FormalParameter parameter in parameters) {
- if (parameter.isRequiredPositional) {
- lastRequiredParameter = parameter;
- }
- }
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- // append new field formal initializers
- if (lastRequiredParameter != null) {
- builder.addSimpleInsertion(
- lastRequiredParameter.end, ', $fieldParametersCode');
- } else {
- int offset = constructor.parameters.leftParenthesis.end;
- if (parameters.isNotEmpty) {
- fieldParametersCode += ', ';
- }
- builder.addSimpleInsertion(offset, fieldParametersCode);
- }
- });
- _addFixFromBuilder(changeBuilder, DartFixKind.ADD_FIELD_FORMAL_PARAMETERS);
- }
-
Future<void> _addFix_updateSdkConstraints(String minimumVersion) async {
Context context = resourceProvider.pathContext;
File pubspecFile;
@@ -4562,9 +4487,17 @@
await compute(RemoveUnusedLocalVariable());
} else if (errorCode == StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION) {
await compute(RemoveDeadIfNull());
+ } else if (errorCode ==
+ StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
+ errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
+ errorCode ==
+ StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS) {
+ await compute(AddFieldFormalParameters());
} else if (errorCode is LintCode) {
String name = errorCode.name;
- if (name == LintNames.avoid_private_typedef_functions) {
+ if (name == LintNames.always_declare_return_types) {
+ await compute(AddReturnType());
+ } else if (name == LintNames.avoid_private_typedef_functions) {
await compute(InlineTypedef());
} else if (name == LintNames.avoid_returning_null_for_future) {
await compute(WrapInFuture());
diff --git a/pkg/analysis_server/test/client/completion_driver_test.dart b/pkg/analysis_server/test/client/completion_driver_test.dart
index 0e41a7d..e318791 100644
--- a/pkg/analysis_server/test/client/completion_driver_test.dart
+++ b/pkg/analysis_server/test/client/completion_driver_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -28,6 +29,8 @@
String get projectPath => '/$projectName';
+ AnalysisServerOptions get serverOptions => AnalysisServerOptions();
+
bool get supportsAvailableSuggestions;
String get testFilePath => '$projectPath/bin/test.dart';
@@ -131,10 +134,12 @@
@mustCallSuper
void setUp() {
driver = CompletionDriver(
- supportsAvailableSuggestions: supportsAvailableSuggestions,
- projectPath: projectPath,
- testFilePath: testFilePath,
- resourceProvider: resourceProvider);
+ supportsAvailableSuggestions: supportsAvailableSuggestions,
+ projectPath: projectPath,
+ testFilePath: testFilePath,
+ resourceProvider: resourceProvider,
+ serverOptions: serverOptions,
+ );
driver.createProject(packageRoots: packageRoots);
newFile('$projectPath/pubspec.yaml', content: '');
diff --git a/pkg/analysis_server/test/client/impl/abstract_client.dart b/pkg/analysis_server/test/client/impl/abstract_client.dart
index b8f60a0..0c82e50 100644
--- a/pkg/analysis_server/test/client/impl/abstract_client.dart
+++ b/pkg/analysis_server/test/client/impl/abstract_client.dart
@@ -38,10 +38,13 @@
MockSdk sdk;
+ final AnalysisServerOptions serverOptions;
+
AbstractClient({
@required this.projectPath,
@required this.testFilePath,
@required String sdkPath,
+ @required this.serverOptions,
}) : serverChannel = MockServerChannel(),
pluginManager = TestPluginManager() {
server = createAnalysisServer(sdkPath);
@@ -54,11 +57,11 @@
AnalysisDomainHandler get analysisHandler => server.handlers
.singleWhere((handler) => handler is AnalysisDomainHandler);
+ AnalysisOptions get analysisOptions => testDriver.analysisOptions;
+
CompletionDomainHandler get completionHandler =>
server.handlers.whereType<CompletionDomainHandler>().single;
- AnalysisOptions get analysisOptions => testDriver.analysisOptions;
-
ResourceProvider get resourceProvider;
AnalysisDriver get testDriver => server.getAnalysisDriver(testFilePath);
@@ -104,11 +107,10 @@
/// Create an analysis server with the given [sdkPath].
AnalysisServer createAnalysisServer(String sdkPath) {
sdk = MockSdk(resourceProvider: resourceProvider);
- var options = AnalysisServerOptions();
return AnalysisServer(
serverChannel,
resourceProvider,
- options,
+ serverOptions,
DartSdkManager(sdkPath, true),
CrashReportingAttachmentsBuilder.empty,
InstrumentationService.NULL_SERVICE);
diff --git a/pkg/analysis_server/test/client/impl/completion_driver.dart b/pkg/analysis_server/test/client/impl/completion_driver.dart
index 2b80c19..b586253 100644
--- a/pkg/analysis_server/test/client/impl/completion_driver.dart
+++ b/pkg/analysis_server/test/client/impl/completion_driver.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'
hide AnalysisOptions;
+import 'package:analysis_server/src/analysis_server.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -77,11 +78,13 @@
CompletionDriver({
@required this.supportsAvailableSuggestions,
+ AnalysisServerOptions serverOptions,
@required MemoryResourceProvider resourceProvider,
@required String projectPath,
@required String testFilePath,
}) : _resourceProvider = resourceProvider,
super(
+ serverOptions: serverOptions ?? AnalysisServerOptions(),
projectPath: resourceProvider.convertPath(projectPath),
testFilePath: resourceProvider.convertPath(testFilePath),
sdkPath: resourceProvider.convertPath('/sdk'));
diff --git a/pkg/analysis_server/test/client/relevance/test_all.dart b/pkg/analysis_server/test/client/relevance/test_all.dart
new file mode 100644
index 0000000..26af7cd
--- /dev/null
+++ b/pkg/analysis_server/test/client/relevance/test_all.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'type_member_relevance_test.dart' as type_member_relevance_test;
+
+void main() {
+ defineReflectiveSuite(() {
+ type_member_relevance_test.main();
+ });
+}
diff --git a/pkg/analysis_server/test/client/relevance/type_member_relevance_test.dart b/pkg/analysis_server/test/client/relevance/type_member_relevance_test.dart
new file mode 100644
index 0000000..22a526f
--- /dev/null
+++ b/pkg/analysis_server/test/client/relevance/type_member_relevance_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../completion_driver_test.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(TypeMemberRelevanceTest);
+ });
+}
+
+@reflectiveTest
+class TypeMemberRelevanceTest extends AbstractCompletionDriverTest {
+ @override
+ AnalysisServerOptions get serverOptions =>
+ AnalysisServerOptions()..useNewRelevance = true;
+
+ @override
+ bool get supportsAvailableSuggestions => true;
+
+ Future<void> test_type_member_relevance() async {
+ await addTestFile('''
+class A {
+ void a() { }
+}
+
+class B extends A {
+ void b() { }
+}
+
+void main() {
+ var b = B();
+ b.^
+}
+''');
+
+ expect(
+ suggestionWith(
+ completion: 'b',
+ element: ElementKind.METHOD,
+ kind: CompletionSuggestionKind.INVOCATION)
+ .relevance,
+ greaterThan(suggestionWith(
+ completion: 'a',
+ element: ElementKind.METHOD,
+ kind: CompletionSuggestionKind.INVOCATION)
+ .relevance));
+ }
+}
diff --git a/pkg/analysis_server/test/client/test_all.dart b/pkg/analysis_server/test/client/test_all.dart
index 417c4d3..1d2a312 100644
--- a/pkg/analysis_server/test/client/test_all.dart
+++ b/pkg/analysis_server/test/client/test_all.dart
@@ -5,9 +5,11 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'completion_driver_test.dart' as completion_driver;
+import 'relevance/test_all.dart' as relevance_tests;
void main() {
defineReflectiveSuite(() {
completion_driver.main();
+ relevance_tests.main();
});
}
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index eb1ad52..cf1d8fd 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -2422,6 +2422,10 @@
/// If the location does not have a support widget, an error of type
/// FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET will be generated.
///
+ /// If a change to a file happens while widget descriptions are computed, an
+ /// error of type FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED will be
+ /// generated.
+ ///
/// Parameters
///
/// file: FilePath
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 6cf2b8a..e1f3fcb 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1350,6 +1350,7 @@
/// CONTENT_MODIFIED
/// DEBUG_PORT_COULD_NOT_BE_OPENED
/// FILE_NOT_ANALYZED
+/// FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED
/// FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET
/// FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION
/// FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID
@@ -1385,6 +1386,7 @@
'CONTENT_MODIFIED',
'DEBUG_PORT_COULD_NOT_BE_OPENED',
'FILE_NOT_ANALYZED',
+ 'FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED',
'FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET',
'FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION',
'FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID',
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 15bf575..abff347 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -177,7 +177,6 @@
'references': {'dynamicRegistration': true},
'documentHighlight': {'dynamicRegistration': true},
'documentSymbol': {'dynamicRegistration': true},
- 'synchronization': {'dynamicRegistration': true},
'formatting': {'dynamicRegistration': true},
'onTypeFormatting': {'dynamicRegistration': true},
'declaration': {'dynamicRegistration': true},
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index cf1b4b7..14b27ab 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -2153,7 +2153,7 @@
Future<void> test_variable_decl_type_args() async {
addTestSource('void m() {List<^> list;}');
await computeSuggestions();
- assertSuggestKeywords([Keyword.DYNAMIC]);
+ assertSuggestKeywords([Keyword.DYNAMIC, Keyword.VOID]);
}
Future<void> test_while_break_continue() async {
@@ -2273,7 +2273,7 @@
''');
await computeSuggestions();
- assertSuggestKeywords([Keyword.DYNAMIC]);
+ assertSuggestKeywords([Keyword.DYNAMIC, Keyword.VOID]);
}
}
diff --git a/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart b/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart
index c1c9e05..ca2f5f1 100644
--- a/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart
+++ b/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart
@@ -1761,15 +1761,27 @@
regionInfo.offset == unit.content.indexOf('? i) {} // f'))
.single;
expect(region.traces, hasLength(1));
- var entries = region.traces.single.entries;
- expect(entries, hasLength(3));
- // Entry 0 is the edge from g's argument to f's argument, due to g's call to
+ var trace = region.traces.single;
+ expect(trace.description, 'Nullability reason');
+ var entries = trace.entries;
+ expect(entries, hasLength(6));
+ // Entry 0 is the nullability of f's argument
+ assertTraceEntry(
+ unit, entries[0], 'f', unit.content.indexOf('int? i) {} // f'));
+ // Entry 1 is the edge from g's argument to f's argument, due to g's call to
// f.
- assertTraceEntry(unit, entries[0], 'g', unit.content.indexOf('i);'));
- // Entry 1 is the edge from null to g's argument, due to h's call to g.
- assertTraceEntry(unit, entries[1], 'h', unit.content.indexOf('null'));
- // Entry 2 is the edge from always to null.
- assertTraceEntry(unit, entries[2], 'h', unit.content.indexOf('null'));
+ assertTraceEntry(unit, entries[1], 'g', unit.content.indexOf('i);'));
+ // Entry 2 is the nullability of g's argument
+ assertTraceEntry(
+ unit, entries[2], 'g', unit.content.indexOf('int? i) { // g'));
+ // Entry 3 is the edge from null to g's argument, due to h's call to g.
+ assertTraceEntry(unit, entries[3], 'h', unit.content.indexOf('null'));
+ // Entry 4 is the nullability of the null literal.
+ assertTraceEntry(unit, entries[4], 'h', unit.content.indexOf('null'));
+ // Entry 5 is the edge from always to null.
+ // TODO(paulberry): this edge provides no additional useful information and
+ // shouldn't be included in the trace.
+ assertTraceEntry(unit, entries[5], 'h', unit.content.indexOf('null'));
}
Future<void> test_trace_nullCheck() async {
@@ -1780,10 +1792,16 @@
.where((regionInfo) => regionInfo.offset == unit.content.indexOf('! +'))
.single;
expect(region.traces, hasLength(1));
- var entries = region.traces.single.entries;
- expect(entries, hasLength(1));
- // Entry 0 is the edge from always to the type of i.
+ var trace = region.traces.single;
+ expect(trace.description, 'Nullability reason');
+ var entries = trace.entries;
+ expect(entries, hasLength(2));
+ // Entry 0 is the nullability of the type of i.
assertTraceEntry(unit, entries[0], 'f', unit.content.indexOf('int?'));
+ // Entry 1 is the edge from always to the type of i.
+ // TODO(paulberry): this edge provides no additional useful information and
+ // shouldn't be included in the trace.
+ assertTraceEntry(unit, entries[1], 'f', unit.content.indexOf('int?'));
}
Future<void> test_uninitializedField() async {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/add_return_type_test.dart b/pkg/analysis_server/test/src/services/correction/assist/add_return_type_test.dart
index 7f9bc17..748ec86 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/add_return_type_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/add_return_type_test.dart
@@ -11,12 +11,12 @@
void main() {
defineReflectiveSuite(() {
- defineReflectiveTests(AddTypeAnnotationTest);
+ defineReflectiveTests(AddReturnTypeTest);
});
}
@reflectiveTest
-class AddTypeAnnotationTest extends AssistProcessorTest {
+class AddReturnTypeTest extends AssistProcessorTest {
@override
AssistKind get kind => DartAssistKind.ADD_RETURN_TYPE;
@@ -76,7 +76,13 @@
}
}
''');
- await assertNoAssist();
+ await assertHasAssist('''
+class A {
+ dynamic m(p) {
+ return p;
+ }
+}
+''');
}
Future<void> test_method_block_returnNoValue() async {
@@ -126,6 +132,50 @@
''');
}
+ Future<void> test_method_getter() async {
+ await resolveTestUnit('''
+class A {
+ get /*caret*/foo => 0;
+}
+''');
+ await assertHasAssist('''
+class A {
+ int get foo => 0;
+}
+''');
+ }
+
+ Future<void> test_method_setter() async {
+ await resolveTestUnit('''
+class A {
+ set /*caret*/foo(int a) {
+ if (a == 0) return;
+ }
+}
+''');
+ await assertHasAssist('''
+class A {
+ void set foo(int a) {
+ if (a == 0) return;
+ }
+}
+''');
+ }
+
+ Future<void> test_method_setter_lint_avoidReturnTypesOnSetters() async {
+ createAnalysisOptionsFile(lints: [
+ LintNames.avoid_return_types_on_setters,
+ ]);
+ await resolveTestUnit('''
+class A {
+ set /*caret*/foo(int a) {
+ if (a == 0) return;
+ }
+}
+''');
+ await assertNoAssist();
+ }
+
Future<void> test_topLevelFunction_block() async {
await resolveTestUnit('''
/*caret*/f() {
@@ -156,4 +206,39 @@
''');
await assertNoAssist();
}
+
+ Future<void> test_topLevelFunction_getter() async {
+ await resolveTestUnit('''
+get /*caret*/foo => 0;
+''');
+ await assertHasAssist('''
+int get foo => 0;
+''');
+ }
+
+ Future<void> test_topLevelFunction_setter() async {
+ await resolveTestUnit('''
+set /*caret*/foo(int a) {
+ if (a == 0) return;
+}
+''');
+ await assertHasAssist('''
+void set foo(int a) {
+ if (a == 0) return;
+}
+''');
+ }
+
+ Future<void>
+ test_topLevelFunction_setter_lint_avoidReturnTypesOnSetters() async {
+ createAnalysisOptionsFile(lints: [
+ LintNames.avoid_return_types_on_setters,
+ ]);
+ await resolveTestUnit('''
+set /*caret*/foo(int a) {
+ if (a == 0) return;
+}
+''');
+ await assertNoAssist();
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart
index 614490f..b3a2423 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_return_type_test.dart
@@ -83,7 +83,13 @@
}
}
''');
- await assertNoFix();
+ await assertHasFix('''
+class A {
+ dynamic m(p) {
+ return p;
+ }
+}
+''');
}
Future<void> test_method_block_returnNoValue() async {
@@ -133,6 +139,19 @@
''');
}
+ Future<void> test_method_getter() async {
+ await resolveTestUnit('''
+class A {
+ get foo => 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ int get foo => 0;
+}
+''');
+ }
+
Future<void> test_topLevelFunction_block() async {
await resolveTestUnit('''
f() {
@@ -154,4 +173,13 @@
String f() => '';
''');
}
+
+ Future<void> test_topLevelFunction_getter() async {
+ await resolveTestUnit('''
+get foo => 0;
+''');
+ await assertHasFix('''
+int get foo => 0;
+''');
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_local_variable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_local_variable_test.dart
index cf625ca..5d6b701 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_local_variable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_local_variable_test.dart
@@ -97,6 +97,13 @@
''');
}
+ Future<void> test_notInFunctionBody() async {
+ await resolveTestUnit(r'''
+var a = [for (var v = 0;;) 0];
+''');
+ await assertNoFix();
+ }
+
Future<void> test_withReferences() async {
await resolveTestUnit(r'''
main() {
diff --git a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
index a1ab90c..75e5568 100644
--- a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
+++ b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
@@ -30,12 +30,17 @@
ArgParser parser = createArgParser();
ArgResults result = parser.parse(args);
- if (validArguments(parser, result)) {
- var code = await CompletionCoverageMetrics(result.rest[0])
- .compute(corpus: result['corpus'], verbose: result['verbose']);
- io.exit(code);
+ var stopwatch = Stopwatch()..start();
+ if (!validArguments(parser, result)) {
+ return io.exit(1);
}
- return io.exit(1);
+ var code = await CompletionMetricsComputer(result.rest[0])
+ .compute(corpus: result['corpus'], verbose: result['verbose']);
+ stopwatch.stop();
+
+ var duration = Duration(milliseconds: stopwatch.elapsedMilliseconds);
+ print('\nMetrics computed in $duration');
+ return io.exit(code);
}
/// Create a parser that can be used to parse the command-line arguments.
@@ -94,7 +99,7 @@
/// This is the main metrics computer class for code completions. After the
/// object is constructed, [computeCompletionMetrics] is executed to do analysis
/// and print a summary of the metrics gathered from the completion tests.
-class CompletionCoverageMetrics {
+class CompletionMetricsComputer {
final String _rootPath;
String _currentFilePath;
@@ -106,20 +111,9 @@
/// The int to be returned from the [compute] call.
int resultCode;
- var completionCounter = Counter('successful/ unsuccessful completions');
- var completionMissedTokenCounter =
- Counter('unsuccessful completion token counter');
- var completionKindCounter = Counter('unsuccessful completion kind counter');
- var completionElementKindCounter =
- Counter('unsuccessful completion element kind counter');
- var mRRComputer =
- MeanReciprocalRankComputer('successful/ unsuccessful completions');
- var typeMemberMRRComputer =
- MeanReciprocalRankComputer('type member completions');
- var nonTypeMemberMRRComputer =
- MeanReciprocalRankComputer('non-type member completions');
+ CompletionMetrics metricsOldMode, metricsNewMode;
- CompletionCoverageMetrics(this._rootPath);
+ CompletionMetricsComputer(this._rootPath);
/// The path to the current file.
String get currentFilePath => _currentFilePath;
@@ -130,6 +124,8 @@
Future<int> compute({bool corpus = false, bool verbose = false}) async {
_verbose = verbose;
resultCode = 0;
+ metricsOldMode = CompletionMetrics('useNewRelevance = false');
+ metricsNewMode = CompletionMetrics('useNewRelevance = true');
var roots = _computeRootPaths(_rootPath, corpus);
for (var root in roots) {
@@ -173,10 +169,30 @@
_resolvedUnitResult.unit.accept(visitor);
for (var expectedCompletion in visitor.expectedCompletions) {
+ // As this point the completion suggestions are computed,
+ // and results are collected with varying settings for
+ // comparison:
+
+ // First we compute the completions useNewRelevance set to
+ // false:
+ var suggestions = await _computeCompletionSuggestions(
+ _resolvedUnitResult,
+ expectedCompletion.offset,
+ declarationsTracker,
+ false);
+
forEachExpectedCompletion(
- expectedCompletion,
- await _computeCompletionSuggestions(_resolvedUnitResult,
- expectedCompletion.offset, declarationsTracker));
+ expectedCompletion, suggestions, metricsOldMode);
+
+ // And again here with useNewRelevance set to true:
+ suggestions = await _computeCompletionSuggestions(
+ _resolvedUnitResult,
+ expectedCompletion.offset,
+ declarationsTracker,
+ true);
+
+ forEachExpectedCompletion(
+ expectedCompletion, suggestions, metricsNewMode);
}
} catch (e) {
print('Exception caught analyzing: $filePath');
@@ -187,32 +203,33 @@
}
}
}
- printAndClearComputers();
+ printAndClearComputers(metricsOldMode);
+ printAndClearComputers(metricsNewMode);
return resultCode;
}
void forEachExpectedCompletion(ExpectedCompletion expectedCompletion,
- List<CompletionSuggestion> suggestions) {
+ List<CompletionSuggestion> suggestions, CompletionMetrics metrics) {
assert(suggestions != null);
var place = placementInSuggestionList(suggestions, expectedCompletion);
- mRRComputer.addRank(place.rank);
+ metrics.mRRComputer.addRank(place.rank);
if (place.denominator != 0) {
- completionCounter.count('successful');
+ metrics.completionCounter.count('successful');
if (isTypeMember(expectedCompletion.syntacticEntity)) {
- typeMemberMRRComputer.addRank(place.rank);
+ metrics.typeMemberMRRComputer.addRank(place.rank);
} else {
- nonTypeMemberMRRComputer.addRank(place.rank);
+ metrics.nonTypeMemberMRRComputer.addRank(place.rank);
}
} else {
- completionCounter.count('unsuccessful');
+ metrics.completionCounter.count('unsuccessful');
- completionMissedTokenCounter.count(expectedCompletion.completion);
- completionKindCounter.count(expectedCompletion.kind.toString());
- completionElementKindCounter
+ metrics.completionMissedTokenCounter.count(expectedCompletion.completion);
+ metrics.completionKindCounter.count(expectedCompletion.kind.toString());
+ metrics.completionElementKindCounter
.count(expectedCompletion.elementKind.toString());
if (_verbose) {
@@ -227,45 +244,51 @@
}
}
- void printAndClearComputers() {
- print('');
- completionMissedTokenCounter.printCounterValues();
+ void printAndClearComputers(CompletionMetrics metrics) {
+ print('\n\n');
+ print('====================');
+ print('Completion metrics for ${metrics.name}:');
+ if (_verbose) {
+ metrics.completionMissedTokenCounter.printCounterValues();
+ print('');
+
+ metrics.completionKindCounter.printCounterValues();
+ print('');
+
+ metrics.completionElementKindCounter.printCounterValues();
+ print('');
+ }
+
+ metrics.mRRComputer.printMean();
print('');
- completionKindCounter.printCounterValues();
+ metrics.typeMemberMRRComputer.printMean();
print('');
- completionElementKindCounter.printCounterValues();
- print('');
-
- mRRComputer.printMean();
- print('');
-
- typeMemberMRRComputer.printMean();
- print('');
-
- nonTypeMemberMRRComputer.printMean();
+ metrics.nonTypeMemberMRRComputer.printMean();
print('');
print('Summary for $_rootPath:');
- completionCounter.printCounterValues();
+ metrics.completionCounter.printCounterValues();
+ print('====================');
- completionMissedTokenCounter.clear();
- completionKindCounter.clear();
- completionElementKindCounter.clear();
- completionCounter.clear();
- mRRComputer.clear();
- typeMemberMRRComputer.clear();
- nonTypeMemberMRRComputer.clear();
+ metrics.completionMissedTokenCounter.clear();
+ metrics.completionKindCounter.clear();
+ metrics.completionElementKindCounter.clear();
+ metrics.completionCounter.clear();
+ metrics.mRRComputer.clear();
+ metrics.typeMemberMRRComputer.clear();
+ metrics.nonTypeMemberMRRComputer.clear();
}
Future<List<CompletionSuggestion>> _computeCompletionSuggestions(
ResolvedUnitResult resolvedUnitResult, int offset,
- [DeclarationsTracker declarationsTracker]) async {
+ [DeclarationsTracker declarationsTracker,
+ bool useNewRelevance = false]) async {
var completionRequestImpl = CompletionRequestImpl(
resolvedUnitResult,
offset,
- false,
+ useNewRelevance,
CompletionPerformance(),
);
@@ -338,3 +361,24 @@
return roots;
}
}
+
+/// A wrapper for the collection of [Counter] and [MeanReciprocalRankComputer]
+/// objects for a run of [CompletionMetricsComputer].
+class CompletionMetrics {
+ final String name;
+
+ CompletionMetrics(this.name);
+
+ var completionCounter = Counter('successful/ unsuccessful completions');
+ var completionMissedTokenCounter =
+ Counter('unsuccessful completion token counter');
+ var completionKindCounter = Counter('unsuccessful completion kind counter');
+ var completionElementKindCounter =
+ Counter('unsuccessful completion element kind counter');
+ var mRRComputer =
+ MeanReciprocalRankComputer('successful/ unsuccessful completions');
+ var typeMemberMRRComputer =
+ MeanReciprocalRankComputer('type member completions');
+ var nonTypeMemberMRRComputer =
+ MeanReciprocalRankComputer('non-type member completions');
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 7f9bbc7..53267ad 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -790,6 +790,9 @@
* If the location does not have a support widget, an error of type
* FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET will be generated.
*
+ * If a change to a file happens while widget descriptions are computed, an error of type
+ * FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED will be generated.
+ *
* @param file The file where the widget instance is created.
* @param offset The offset in the file where the widget instance is created.
*/
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index c968830..0129bac 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -33,6 +33,11 @@
public static final String FILE_NOT_ANALYZED = "FILE_NOT_ANALYZED";
/**
+ * A file was change while widget descriptions were being computed.
+ */
+ public static final String FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED = "FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED";
+
+ /**
* The given location does not have a supported widget.
*/
public static final String FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET = "FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET";
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index b422873..59f2af9 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -3191,6 +3191,11 @@
If the location does not have a support widget, an error of type
<tt>FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET</tt> will be generated.
</p>
+ <p>
+ If a change to a file happens while widget descriptions are computed,
+ an error of type <tt>FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED</tt>
+ will be generated.
+ </p>
<params>
<field name="file">
<ref>FilePath</ref>
@@ -4909,6 +4914,12 @@
</p>
</value>
<value>
+ <code>FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED</code>
+ <p>
+ A file was change while widget descriptions were being computed.
+ </p>
+ </value>
+ <value>
<code>FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET</code>
<p>
The given location does not have a supported widget.
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 2aa0e9b..21a2c04 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -17642,6 +17642,7 @@
/// CONTENT_MODIFIED
/// DEBUG_PORT_COULD_NOT_BE_OPENED
/// FILE_NOT_ANALYZED
+/// FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED
/// FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET
/// FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION
/// FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID
@@ -17691,6 +17692,11 @@
static const RequestErrorCode FILE_NOT_ANALYZED =
RequestErrorCode._('FILE_NOT_ANALYZED');
+ /// A file was change while widget descriptions were being computed.
+ static const RequestErrorCode
+ FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED =
+ RequestErrorCode._('FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED');
+
/// The given location does not have a supported widget.
static const RequestErrorCode FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET =
RequestErrorCode._('FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET');
@@ -17848,6 +17854,7 @@
CONTENT_MODIFIED,
DEBUG_PORT_COULD_NOT_BE_OPENED,
FILE_NOT_ANALYZED,
+ FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED,
FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET,
FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION,
FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID,
@@ -17893,6 +17900,8 @@
return DEBUG_PORT_COULD_NOT_BE_OPENED;
case 'FILE_NOT_ANALYZED':
return FILE_NOT_ANALYZED;
+ case 'FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED':
+ return FLUTTER_GET_WIDGET_DESCRIPTION_CONTENT_MODIFIED;
case 'FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET':
return FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET;
case 'FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION':
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index c85edce..bb65367 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -131,6 +131,7 @@
CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR,
CompileTimeErrorCode.DEFAULT_VALUE_ON_REQUIRED_PARAMETER,
CompileTimeErrorCode.DEFERRED_IMPORT_OF_EXTENSION,
+ CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT,
CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME,
CompileTimeErrorCode.DUPLICATE_DEFINITION,
@@ -542,6 +543,7 @@
ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
ParserErrorCode.FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS,
ParserErrorCode.FINAL_AND_COVARIANT,
+ ParserErrorCode.FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER,
ParserErrorCode.FINAL_AND_VAR,
ParserErrorCode.FINAL_CLASS,
ParserErrorCode.FINAL_CONSTRUCTOR,
diff --git a/pkg/analyzer/lib/src/context/packages.dart b/pkg/analyzer/lib/src/context/packages.dart
index 9c8d40c..8d79d78 100644
--- a/pkg/analyzer/lib/src/context/packages.dart
+++ b/pkg/analyzer/lib/src/context/packages.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/src/context/package_config_json.dart';
import 'package:analyzer/src/util/uri.dart';
import 'package:meta/meta.dart';
+// ignore: deprecated_member_use
import 'package:package_config/packages_file.dart' as dot_packages;
import 'package:pub_semver/pub_semver.dart';
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index ada9a29..5d9e1e5 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -604,8 +604,20 @@
useFasta: useFasta,
);
parser.enableOptionalNewAndConst = true;
- CompilationUnit unit = parser.parseCompilationUnit(token);
- unit.lineInfo = lineInfo;
+
+ // TODO(scheglov) https://github.com/dart-lang/sdk/issues/41023
+ CompilationUnit unit;
+ try {
+ unit = parser.parseCompilationUnit(token);
+ unit.lineInfo = lineInfo;
+ } catch (e) {
+ throw StateError('''
+Parser error.
+path: $path
+${'-' * 40}
+$content
+''');
+ }
// StringToken uses a static instance of StringCanonicalizer, so we need
// to clear it explicitly once we are done using it for this file.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 3b812a2..ff2cdda 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4254,7 +4254,7 @@
reference: enclosingRef.getChild('@getter').getChild(name),
);
- if (!isConst && !isFinal) {
+ if (_hasSetter) {
this.setter = PropertyAccessorElementImpl_ImplicitSetter(
this,
reference: enclosingRef.getChild('@setter').getChild(name),
@@ -6408,6 +6408,26 @@
// We don't support type inference errors without linking.
return null;
}
+
+ bool get _hasInitializer {
+ return linkedNode != null && linkedContext.hasInitializer(linkedNode);
+ }
+
+ /// Return `true` if this variable needs the setter.
+ bool get _hasSetter {
+ if (isConst) {
+ return false;
+ }
+
+ if (isLate) {
+ if (isFinal) {
+ return !_hasInitializer;
+ }
+ return true;
+ }
+
+ return !isFinal;
+ }
}
/// A concrete implementation of a [ParameterElement].
@@ -7361,7 +7381,7 @@
reference: enclosingRef.getChild('@getter').getChild(name),
);
- if (!isConst && !isFinal) {
+ if (_hasSetter) {
this.setter = PropertyAccessorElementImpl_ImplicitSetter(
this,
reference: enclosingRef.getChild('@setter').getChild(name),
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 1f70c7b..eda8b3d 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -832,6 +832,14 @@
@override
bool get isInitializingFormal => declaration.isInitializingFormal;
+ @override
+ bool get isRequiredNamed {
+ if (isLegacy) {
+ return false;
+ }
+ return super.isRequiredNamed;
+ }
+
@deprecated
@override
ParameterKind get parameterKind => declaration.parameterKind;
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index 56aa287..88fc991 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -352,6 +352,9 @@
static const ParserErrorCode FINAL_AND_COVARIANT = _FINAL_AND_COVARIANT;
+ static const ParserErrorCode FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER =
+ _FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER;
+
static const ParserErrorCode FINAL_AND_VAR = _FINAL_AND_VAR;
static const ParserErrorCode FINAL_CLASS = ParserErrorCode(
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index a07b175..a6061ec 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -108,6 +108,7 @@
_INVALID_USE_OF_COVARIANT_IN_EXTENSION,
_TYPE_PARAMETER_ON_CONSTRUCTOR,
_VOID_WITH_TYPE_ARGUMENTS,
+ _FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER,
];
const ParserErrorCode _ABSTRACT_CLASS_MEMBER = ParserErrorCode(
@@ -328,6 +329,12 @@
r"Members can't be declared to be both 'final' and 'covariant'.",
correction: "Try removing either the 'final' or 'covariant' keyword.");
+const ParserErrorCode _FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER = ParserErrorCode(
+ 'FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER',
+ r"Members marked 'late' with an initializer can't be declared to be both 'final' and 'covariant'.",
+ correction:
+ "Try removing either the 'final' or 'covariant' keyword, or removing the initializer.");
+
const ParserErrorCode _FINAL_AND_VAR = ParserErrorCode(
'FINAL_AND_VAR', r"Members can't be declared to be both 'final' and 'var'.",
correction: "Try removing the keyword 'var'.");
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index fbccb1d..c74a46d 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -54,13 +54,6 @@
*/
final Source source;
- /*
- * A function that returns the digest for a file as a String. The function
- * returns a non null value, can return an empty string if file does
- * not exist/has no contents.
- */
- final String Function(String path) getFileDigest;
-
final List<FileState> importedFiles = [];
final List<FileState> exportedFiles = [];
final List<FileState> partedFiles = [];
@@ -73,8 +66,7 @@
UnlinkedUnit2 unlinked2;
LibraryCycle _libraryCycle;
- FileState._(
- this._fsState, this.path, this.uri, this.source, this.getFileDigest);
+ FileState._(this._fsState, this.path, this.uri, this.source);
List<int> get apiSignature => _apiSignature;
@@ -132,7 +124,7 @@
}
void refresh() {
- var digest = utf8.encode(getFileDigest(path));
+ var digest = utf8.encode(_fsState.getFileDigest(path));
_exists = digest.isNotEmpty;
String unlinkedKey = path;
@@ -163,6 +155,9 @@
bytes = unlinkedBuilder.toBuffer();
_fsState._byteStore.put(unlinkedKey, bytes);
});
+
+ unlinked2 = CiderUnlinkedUnit.fromBuffer(bytes).unlinkedUnit;
+ _prefetchDirectReferences(unlinked2);
}
}
@@ -209,6 +204,41 @@
return _fsState.getFileForUri(absoluteUri);
}
+ void _prefetchDirectReferences(UnlinkedUnit2 unlinkedUnit2) {
+ if (_fsState.prefetchFiles == null) {
+ return;
+ }
+
+ var paths = <String>{};
+
+ void findPathForUri(String relativeUri) {
+ if (relativeUri.isEmpty) {
+ return;
+ }
+ Uri absoluteUri;
+ try {
+ absoluteUri = resolveRelativeUri(uri, Uri.parse(relativeUri));
+ } on FormatException {
+ return;
+ }
+ var p = _fsState.getPathForUri(absoluteUri);
+ if (p != null) {
+ paths.add(p);
+ }
+ }
+
+ for (var directive in unlinked2.imports) {
+ findPathForUri(directive.uri);
+ }
+ for (var directive in unlinked2.exports) {
+ findPathForUri(directive.uri);
+ }
+ for (var uri in unlinked2.parts) {
+ findPathForUri(uri);
+ }
+ _fsState.prefetchFiles(paths.toList());
+ }
+
static CiderUnlinkedUnitBuilder serializeAstCiderUnlinked(
List<int> digest, CompilationUnit unit) {
var exports = <UnlinkedNamespaceDirectiveBuilder>[];
@@ -282,6 +312,12 @@
final SourceFactory _sourceFactory;
final AnalysisOptions _analysisOptions;
final Uint32List _linkedSalt;
+
+ /**
+ * A function that returns the digest for a file as a String. The function
+ * returns a non null value, returns an empty string if file does
+ * not exist/has no contents.
+ */
final String Function(String path) getFileDigest;
final Map<String, FileState> _pathToFile = {};
@@ -290,6 +326,12 @@
final FeatureSetProvider featureSetProvider;
/**
+ * A function that fetches the given list of files. This function can be used
+ * to batch file reads in systems where file fetches are expensive.
+ */
+ final void Function(List<String> paths) prefetchFiles;
+
+ /**
* The [FileState] instance that correspond to an unresolved URI.
*/
FileState _unresolvedFile;
@@ -303,6 +345,7 @@
this._linkedSalt,
this.featureSetProvider,
this.getFileDigest,
+ this.prefetchFiles,
);
/**
@@ -310,7 +353,7 @@
*/
FileState get unresolvedFile {
if (_unresolvedFile == null) {
- _unresolvedFile = FileState._(this, null, null, null, null);
+ _unresolvedFile = FileState._(this, null, null, null);
_unresolvedFile.refresh();
}
return _unresolvedFile;
@@ -325,7 +368,7 @@
);
var source = _sourceFactory.forUri2(uri);
- file = FileState._(this, path, uri, source, getFileDigest);
+ file = FileState._(this, path, uri, source);
_pathToFile[path] = file;
_uriToFile[uri] = file;
@@ -344,7 +387,7 @@
}
var path = source.fullName;
- file = FileState._(this, path, uri, source, getFileDigest);
+ file = FileState._(this, path, uri, source);
_pathToFile[path] = file;
_uriToFile[uri] = file;
@@ -352,6 +395,14 @@
}
return file;
}
+
+ String getPathForUri(Uri uri) {
+ var source = _sourceFactory.forUri2(uri);
+ if (source == null) {
+ return null;
+ }
+ return source.fullName;
+ }
}
/// Information about libraries that reference each other, so form a cycle.
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 4930380..401bbe7 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -49,12 +49,18 @@
*/
final String Function(String path) getFileDigest;
+ /**
+ * A function that fetches the given list of files. This function can be used
+ * to batch file reads in systems where file fetches are expensive.
+ */
+ final void Function(List<String> paths) prefetchFiles;
+
Workspace workspace;
MicroAnalysisContextImpl analysisContext;
FileResolver(this.logger, this.resourceProvider, this.byteStore,
- this.sourceFactory, this.getFileDigest,
+ this.sourceFactory, this.getFileDigest, this.prefetchFiles,
{Workspace workspace})
: this.workspace = workspace;
@@ -115,6 +121,7 @@
Uint32List(0), // linkedSalt
featureSetProvider,
getFileDigest,
+ prefetchFiles,
);
FileState file;
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 35941b2..81ce4ed 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -180,10 +180,6 @@
var element = node.staticElement;
if (element is LocalVariableElement) {
- if (flow.isUnassigned(element)) {
- dataForTesting?.definitelyUnassignedNodes?.add(node);
- }
-
var typeSystem = _typeOperations.typeSystem;
if (typeSystem.isPotentiallyNonNullable(element.type)) {
var isUnassigned = !flow.isAssigned(element);
@@ -204,6 +200,25 @@
return false;
}
+ bool isReadOfDefinitelyUnassignedLateLocal(SimpleIdentifier node) {
+ if (flow == null) return false;
+
+ if (node.inDeclarationContext()) return false;
+ if (!node.inGetterContext()) return false;
+
+ var element = node.staticElement;
+ if (element is LocalVariableElement) {
+ if (flow.isUnassigned(element)) {
+ dataForTesting?.definitelyUnassignedNodes?.add(node);
+ if (element.isLate) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
void topLevelDeclaration_enter(
Declaration node, FormalParameterList parameters, FunctionBody body) {
assert(node != null);
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 4b9438d..6ec81e3 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -1430,6 +1430,21 @@
"extensions.");
/**
+ * It is a compile time error to read a local variable marked `late` when the
+ * variable is definitely unassigned. This includes all forms of reads,
+ * including implicit reads via the composite assignment operators as well
+ * as pre and post-fix operators.
+ *
+ * Parameters:
+ * 0: the name of the variable that is invalid
+ */
+ static const CompileTimeErrorCode DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE =
+ CompileTimeErrorCode('DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE',
+ "The late local variable '{0}' is definitely unassigned.",
+ correction:
+ "Ensure that it is assigned on necessary execution paths.");
+
+ /**
* No parameters.
*/
// #### Description
diff --git a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
index 4ada2b5..3ad3883 100644
--- a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
+++ b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
@@ -41,11 +41,7 @@
_initFieldsMap(node.declaredElement);
}
- void enterMixin(MixinDeclaration node) {
- _initFieldsMap(node.declaredElement);
- }
-
- void leaveClassOrMixin() {
+ void leaveClass() {
_isInNativeClass = false;
_initialFieldMap = null;
}
@@ -60,6 +56,10 @@
return;
}
+ if (node.parent is! ClassDeclaration) {
+ return;
+ }
+
if (_isInNativeClass) {
return;
}
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 41ff1ec..7eb47a4 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -1474,6 +1474,12 @@
TypeAnnotation returnType = pop();
List<Annotation> metadata = pop();
Comment comment = _findComment(metadata, typedefKeyword);
+
+ // TODO(scheglov) https://github.com/dart-lang/sdk/issues/41023
+ if (parameters == null) {
+ throw StateError('FunctionTypeAlias without parameters.');
+ }
+
declarations.add(ast.functionTypeAlias(comment, metadata, typedefKeyword,
returnType, name, typeParameters, parameters, semicolon));
} else {
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 82d2949..2d2182c 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -476,7 +476,7 @@
super.visitClassDeclaration(node);
} finally {
_isInNativeClass = false;
- _constructorFieldsVerifier.leaveClassOrMixin();
+ _constructorFieldsVerifier.leaveClass();
_enclosingClass = outerClass;
}
}
@@ -1018,13 +1018,11 @@
_checkMixinInheritance(node, onClause, implementsClause);
}
- _constructorFieldsVerifier.enterMixin(node);
_checkForFinalNotInitializedInClass(members);
_checkForWrongTypeParameterVarianceInSuperinterfaces();
// _checkForBadFunctionUse(node);
super.visitMixinDeclaration(node);
} finally {
- _constructorFieldsVerifier.leaveClassOrMixin();
_enclosingClass = outerClass;
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index b6d3ae7..02015c3 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1118,7 +1118,7 @@
var body = node.body;
if (_flowAnalysis != null) {
- if (!isFunctionDeclaration) {
+ if (_flowAnalysis.flow != null && !isFunctionDeclaration) {
_flowAnalysis.executableDeclaration_enter(node, node.parameters, true);
}
} else {
@@ -1142,7 +1142,7 @@
super.visitFunctionExpression(node);
if (_flowAnalysis != null) {
- if (!isFunctionDeclaration) {
+ if (_flowAnalysis.flow != null && !isFunctionDeclaration) {
_checkForBodyMayCompleteNormally(
returnType: returnType,
body: body,
@@ -1511,14 +1511,22 @@
return;
}
- if (_flowAnalysis != null &&
- _flowAnalysis.isPotentiallyNonNullableLocalReadBeforeWrite(node)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode
- .NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
- node,
- [node.name],
- );
+ if (_flowAnalysis != null) {
+ if (_flowAnalysis.isPotentiallyNonNullableLocalReadBeforeWrite(node)) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
+ node,
+ [node.name],
+ );
+ }
+ if (_flowAnalysis.isReadOfDefinitelyUnassignedLateLocal(node)) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
+ node,
+ [node.name],
+ );
+ }
}
super.visitSimpleIdentifier(node);
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index 3ae599f..bb5b05d 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -127,6 +127,32 @@
/// parameter declarations and their bounds are not included.
static List<TypeAnnotation> _collectTypedefRhsTypes(AstNode node) {
if (node is FunctionTypeAlias) {
+ // TODO(scheglov) https://github.com/dart-lang/sdk/issues/41023
+ if (node.parameters == null) {
+ var buffer = StringBuffer();
+ buffer.writeln('Unexpected FunctionTypeAlias state.');
+ try {
+ buffer.writeln('unit: ');
+ buffer.writeln(node.parent.toSource());
+ } catch (_) {
+ try {
+ buffer.writeln('node: ');
+ buffer.writeln(node.toSource());
+ } catch (_) {
+ try {
+ buffer.writeln('node parts:');
+ buffer.writeln(' name: ${node.name}');
+ buffer.writeln(' typeParameters: ${node.typeParameters}');
+ buffer.writeln(' returnType: ${node.returnType}');
+ buffer.writeln(' parameters: ${node.parameters}');
+ } catch (_) {
+ buffer.writeln('nothing worked');
+ }
+ }
+ }
+ throw StateError(buffer.toString());
+ }
+
var collector = _TypeCollector();
collector.addType(node.returnType);
collector.visitParameters(node.parameters);
diff --git a/pkg/analyzer/test/generated/invalid_code_test.dart b/pkg/analyzer/test/generated/invalid_code_test.dart
index 64f79ab..db7160f 100644
--- a/pkg/analyzer/test/generated/invalid_code_test.dart
+++ b/pkg/analyzer/test/generated/invalid_code_test.dart
@@ -4,7 +4,9 @@
import 'dart:async';
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/driver_resolution.dart';
@@ -12,6 +14,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidCodeTest);
+ defineReflectiveTests(InvalidCodeWithNullSafetyTest);
});
}
@@ -306,3 +309,30 @@
assertHasTestErrors();
}
}
+
+@reflectiveTest
+class InvalidCodeWithNullSafetyTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+
+ @override
+ bool get typeToStringWithNullability => true;
+
+ test_issue_40837() async {
+ await _assertCanBeAnalyzed('''
+class A {
+ const A(_);
+}
+
+@A(() => 0)
+class B {}
+''');
+ }
+
+ Future<void> _assertCanBeAnalyzed(String text) async {
+ await resolveTestCode(text);
+ assertHasTestErrors();
+ }
+}
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 11abdce..ed796bf 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -87,6 +87,18 @@
expect(invocation.toSource(), 'new C().late()');
}
+ void test_parseClassMember_finalAndCovariantLateWithInitializer() {
+ createParser(
+ 'covariant late final int f = 0;',
+ featureSet: nonNullable,
+ );
+ parser.parseClassMember('C');
+ assertErrors(errors: [
+ expectedError(
+ ParserErrorCode.FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER, 0, 9)
+ ]);
+ }
+
void test_parseClassMember_operator_gtgtgt() {
CompilationUnitImpl unit = parseCompilationUnit(
'class C { bool operator >>>(other) => false; }',
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 46e0226..7469fd0 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -9,6 +9,7 @@
show ScannerResult, scanString;
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/language_version.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@@ -111,7 +112,12 @@
* For any analyzer test where the last token is not EOF, set this value.
* It is ignored when not using the fasta parser.
*/
- void createParser(String content, {int expectedEndOffset});
+ void createParser(
+ String content, {
+ int expectedEndOffset,
+ LanguageVersion languageVersion,
+ FeatureSet featureSet,
+ });
ExpectedError expectedError(ErrorCode code, int offset, int length);
@@ -9467,7 +9473,12 @@
* prepared to parse the tokens scanned from the given [content].
*/
@override
- void createParser(String content, {int expectedEndOffset}) {
+ void createParser(
+ String content, {
+ int expectedEndOffset,
+ LanguageVersion languageVersion,
+ FeatureSet featureSet,
+ }) {
Source source = TestSource();
listener = GatheringErrorListener();
@@ -9477,8 +9488,8 @@
parser = Parser(
source,
listener,
- languageVersion: null,
- featureSet: FeatureSet.forTesting(),
+ languageVersion: languageVersion,
+ featureSet: featureSet,
);
parser.allowNativeClause = allowNativeClause;
parser.parseFunctionBodies = parseFunctionBodies;
diff --git a/pkg/analyzer/test/id_tests/definite_assignment_test.dart b/pkg/analyzer/test/id_tests/definite_assignment_test.dart
index 929b8df..732c27a 100644
--- a/pkg/analyzer/test/id_tests/definite_assignment_test.dart
+++ b/pkg/analyzer/test/id_tests/definite_assignment_test.dart
@@ -9,8 +9,10 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/null_safety_understanding_flag.dart';
+import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/analysis/testing_data.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/util/ast_data_extractor.dart';
import '../util/id_testing_helper.dart';
@@ -37,6 +39,18 @@
const _DefiniteAssignmentDataInterpreter();
@override
+ bool get supportsErrors => true;
+
+ @override
+ String computeErrorData(TestConfig config, TestingData testingData, Id id,
+ List<AnalysisError> errors) {
+ var errorCodes = errors.map((e) => e.errorCode).where((errorCode) =>
+ errorCode !=
+ CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE);
+ return errorCodes.isNotEmpty ? errorCodes.join(',') : null;
+ }
+
+ @override
void computeUnitData(TestingData testingData, CompilationUnit unit,
Map<Id, ActualData<String>> actualMap) {
var flowResult =
diff --git a/pkg/analyzer/test/id_tests/definite_unassignment_test.dart b/pkg/analyzer/test/id_tests/definite_unassignment_test.dart
index 963815a..1e2b9c5 100644
--- a/pkg/analyzer/test/id_tests/definite_unassignment_test.dart
+++ b/pkg/analyzer/test/id_tests/definite_unassignment_test.dart
@@ -9,8 +9,10 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/null_safety_understanding_flag.dart';
+import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/analysis/testing_data.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/util/ast_data_extractor.dart';
import '../util/id_testing_helper.dart';
@@ -37,6 +39,18 @@
const _DefiniteUnassignmentDataInterpreter();
@override
+ bool get supportsErrors => true;
+
+ @override
+ String computeErrorData(TestConfig config, TestingData testingData, Id id,
+ List<AnalysisError> errors) {
+ var errorCodes = errors.map((e) => e.errorCode).where((errorCode) =>
+ errorCode !=
+ CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE);
+ return errorCodes.isNotEmpty ? errorCodes.join(',') : null;
+ }
+
+ @override
void computeUnitData(TestingData testingData, CompilationUnit unit,
Map<Id, ActualData<String>> actualMap) {
var flowResult =
diff --git a/pkg/analyzer/test/src/dart/micro/file_resolution.dart b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
index fb0cfd0..22f938e 100644
--- a/pkg/analyzer/test/src/dart/micro/file_resolution.dart
+++ b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
@@ -76,6 +76,7 @@
PackageMapUriResolver(resourceProvider, packageMap),
ResourceUriResolver(resourceProvider)
]),
- (String path) => _getDigest(path));
+ (String path) => _getDigest(path),
+ null);
}
}
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index dee6f43..f3bb225 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/error/codes.dart';
@@ -308,38 +307,6 @@
''');
}
- test_error_finalNotInitializedConstructor() async {
- await assertErrorsInCode(r'''
-mixin M {
- final int f;
- M();
-}
-''', [
- error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
- error(StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1, 27, 1),
- ]);
- }
-
- test_error_finalNotInitializedConstructor_OK() async {
- await assertErrorsInCode(r'''
-mixin M {
- final int f;
- M(this.f);
-}
-''', [
- error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
- ]);
-
- var element = findElement.mixin('M');
- var constructorElement = element.constructors.single;
-
- var fpNode = findNode.fieldFormalParameter('f);');
- assertElement(fpNode.identifier, constructorElement.parameters[0]);
-
- FieldFormalParameterElement fpElement = fpNode.declaredElement;
- expect(fpElement.field, same(findElement.field('f')));
- }
-
test_error_implementsClause_deferredClass() async {
await assertErrorsInCode(r'''
import 'dart:math' deferred as math;
@@ -820,37 +787,6 @@
]);
}
- test_error_mixinDeclaresConstructor() async {
- await assertErrorsInCode(r'''
-mixin M {
- M(int a) {
- a; // read
- }
-}
-''', [
- error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
- ]);
-
- // Even though it is an error for a mixin to declare a constructor,
- // we still build elements for constructors, and resolve them.
-
- var element = findElement.mixin('M');
- var constructors = element.constructors;
- expect(constructors, hasLength(1));
- var constructorElement = constructors[0];
-
- var constructorNode = findNode.constructor('M(int a)');
- assertElement(constructorNode, constructorElement);
-
- var aElement = constructorElement.parameters[0];
- var aNode = constructorNode.parameters.parameters[0];
- assertElement(aNode, aElement);
-
- var aRef = findNode.simple('a; // read');
- assertElement(aRef, aElement);
- assertType(aRef, 'int');
- }
-
test_error_mixinInstantiate_default() async {
await assertErrorsInCode(r'''
mixin M {}
diff --git a/pkg/analyzer/test/src/diagnostics/definitely_unassigned_late_local_variable_test.dart b/pkg/analyzer/test/src/diagnostics/definitely_unassigned_late_local_variable_test.dart
new file mode 100644
index 0000000..24bb1e0
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/definitely_unassigned_late_local_variable_test.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(DefinitelyUnassignedLateLocalVariableTest);
+ });
+}
+
+@reflectiveTest
+class DefinitelyUnassignedLateLocalVariableTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = FeatureSet.fromEnableFlags(
+ [EnableString.non_nullable],
+ );
+
+ CompileTimeErrorCode get _errorCode {
+ return CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE;
+ }
+
+ test_definitelyAssigned_after_compoundAssignment() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ v += 1;
+ v;
+}
+''', [
+ error(_errorCode, 27, 1),
+ ]);
+ }
+
+ test_definitelyAssigned_after_postfixExpression_increment() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ v++;
+ v;
+}
+''', [
+ error(_errorCode, 27, 1),
+ ]);
+ }
+
+ test_mightBeAssigned_if_else() async {
+ await assertNoErrorsInCode(r'''
+void f(bool c) {
+ late int v;
+ if (c) {
+ print(0);
+ } else {
+ v = 0;
+ }
+ v;
+}
+''');
+ }
+
+ test_mightBeAssigned_if_then() async {
+ await assertNoErrorsInCode(r'''
+void f(bool c) {
+ late int v;
+ if (c) {
+ v = 0;
+ }
+ v;
+}
+''');
+ }
+
+ test_mightBeAssigned_while() async {
+ await assertNoErrorsInCode(r'''
+void f(bool c) {
+ late int v;
+ while (c) {
+ v = 0;
+ }
+ v;
+}
+''');
+ }
+
+ test_neverAssigned_assignment_compound() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ v += 1;
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 22, 1),
+ error(_errorCode, 27, 1),
+ ]);
+ }
+
+ test_neverAssigned_assignment_pure() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ v = 0;
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 22, 1),
+ ]);
+ }
+
+ test_neverAssigned_nullable() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int? v;
+ v;
+}
+''', [
+ error(_errorCode, 28, 1),
+ ]);
+ }
+
+ test_neverAssigned_prefixExpression() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ ++v;
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 22, 1),
+ error(_errorCode, 29, 1),
+ ]);
+ }
+
+ test_neverAssigned_read() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ v;
+}
+''', [
+ error(_errorCode, 27, 1),
+ ]);
+ }
+
+ test_neverAssigned_suffixExpression() async {
+ await assertErrorsInCode(r'''
+void f() {
+ late int v;
+ v++;
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 22, 1),
+ error(_errorCode, 27, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
index 2157307..fb6002e 100644
--- a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
@@ -72,6 +72,16 @@
error(StaticWarningCode.FINAL_NOT_INITIALIZED, 18, 1),
]);
}
+
+ test_mixin() async {
+ await assertErrorsInCode('''
+mixin M {
+ final int x;
+}
+''', [
+ error(StaticWarningCode.FINAL_NOT_INITIALIZED, 22, 1),
+ ]);
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart b/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart
index ff8fa6a..8cc3c98 100644
--- a/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart
@@ -354,6 +354,22 @@
]);
}
+ test_method_legacy() async {
+ newFile('/test/lib/a.dart', content: r'''
+class A {
+ void foo({required int a}) {}
+}
+''');
+ await assertNoErrorsInCode(r'''
+// @dart = 2.7
+import "a.dart";
+
+f() {
+ A().foo();
+}
+''');
+ }
+
test_typedef_function() async {
await assertErrorsInCode(r'''
String test(C c) => c.m()();
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart
new file mode 100644
index 0000000..355a804
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/mixin_declares_constructor_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MixinDeclaresConstructorTest);
+ });
+}
+
+@reflectiveTest
+class MixinDeclaresConstructorTest extends DriverResolutionTest {
+ test_fieldFormalParameter() async {
+ await assertErrorsInCode(r'''
+mixin M {
+ final int f;
+ M(this.f);
+}
+''', [
+ error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
+ ]);
+
+ var element = findElement.mixin('M');
+ var constructorElement = element.constructors.single;
+
+ var fpNode = findNode.fieldFormalParameter('f);');
+ assertElement(fpNode.identifier, constructorElement.parameters[0]);
+
+ FieldFormalParameterElement fpElement = fpNode.declaredElement;
+ assertElement(fpElement.field, findElement.field('f'));
+ }
+
+ test_resolved() async {
+ await assertErrorsInCode(r'''
+mixin M {
+ M(int a) {
+ a; // read
+ }
+}
+''', [
+ error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
+ ]);
+
+ // Even though it is an error for a mixin to declare a constructor,
+ // we still build elements for constructors, and resolve them.
+
+ var element = findElement.mixin('M');
+ var constructorElement = element.constructors.single;
+
+ var constructorNode = findNode.constructor('M(int a)');
+ assertElement(constructorNode, constructorElement);
+
+ var aElement = constructorElement.parameters[0];
+ var aNode = constructorNode.parameters.parameters[0];
+ assertElement(aNode, aElement);
+
+ var aRef = findNode.simple('a; // read');
+ assertElement(aRef, aElement);
+ assertType(aRef, 'int');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
index 9a758ed..50e9132 100644
--- a/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_assigned_potentially_non_nullable_local_variable_test.dart
@@ -903,6 +903,12 @@
await assertNoErrorsInCode('''
f() {
late int v;
+
+ void g() {
+ v = 0;
+ }
+
+ g();
v;
}
''');
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 9275a0a..1d56343 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -69,6 +69,8 @@
import 'default_value_on_required_parameter_test.dart'
as default_value_on_required_parameter;
import 'deferred_import_of_extension_test.dart' as deferred_import_of_extension;
+import 'definitely_unassigned_late_local_variable_test.dart'
+ as definitely_unassigned_late_local_variable;
import 'deprecated_extends_function_test.dart' as deprecated_extends_function;
import 'deprecated_function_class_declaration_test.dart'
as deprecated_function_class_declaration;
@@ -267,6 +269,7 @@
as mixin_application_not_implemented_interface;
import 'mixin_class_declares_constructor_test.dart'
as mixin_class_declares_constructor;
+import 'mixin_declares_constructor_test.dart' as mixin_declares_constructor;
import 'mixin_deferred_class_test.dart' as mixin_deferred_class;
import 'mixin_inherits_from_not_object_test.dart'
as mixin_inherits_from_not_object;
@@ -545,6 +548,7 @@
default_value_in_redirecting_factory_constructor.main();
default_value_on_required_parameter.main();
deferred_import_of_extension.main();
+ definitely_unassigned_late_local_variable.main();
deprecated_extends_function.main();
deprecated_function_class_declaration.main();
deprecated_member_use.main();
@@ -678,6 +682,7 @@
missing_return.main();
mixin_application_not_implemented_interface.main();
mixin_class_declares_constructor.main();
+ mixin_declares_constructor.main();
mixin_deferred_class.main();
mixin_inherits_from_not_object.main();
mixin_of_disallowed_class.main();
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index dee20b0..227d445 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -964,11 +964,8 @@
expect(e.getter, isNotNull);
_assertSyntheticAccessorEnclosing(e, e.getter);
- if (e.isFinal || e.isConst) {
- expect(e.setter, isNull);
- } else {
- expect(e.setter, isNotNull);
- _assertSyntheticAccessorEnclosing(e, e.getter);
+ if (e.setter != null) {
+ _assertSyntheticAccessorEnclosing(e, e.setter);
}
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 1472711..e312162 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -960,13 +960,58 @@
test_class_fields_late() async {
featureSet = enableNnbd;
- var library = await checkLibrary('class C { int i; late int j; }');
- checkElementText(library, r'''
+ var library = await checkLibrary('''
class C {
- int i;
- late int j;
+ late int foo;
}
''');
+ checkElementText(
+ library,
+ r'''
+class C {
+ late int foo;
+ synthetic int get foo {}
+ synthetic void set foo(int _foo) {}
+}
+''',
+ withSyntheticAccessors: true);
+ }
+
+ test_class_fields_late_final() async {
+ featureSet = enableNnbd;
+ var library = await checkLibrary('''
+class C {
+ late final int foo;
+}
+''');
+ checkElementText(
+ library,
+ r'''
+class C {
+ late final int foo;
+ synthetic int get foo {}
+ synthetic void set foo(int _foo) {}
+}
+''',
+ withSyntheticAccessors: true);
+ }
+
+ test_class_fields_late_final_initialized() async {
+ featureSet = enableNnbd;
+ var library = await checkLibrary('''
+class C {
+ late final int foo = 0;
+}
+''');
+ checkElementText(
+ library,
+ r'''
+class C {
+ late final int foo;
+ synthetic int get foo {}
+}
+''',
+ withSyntheticAccessors: true);
}
test_class_getter_abstract() async {
@@ -11240,14 +11285,6 @@
''');
}
- test_variable_final_late() async {
- featureSet = enableNnbd;
- var library = await checkLibrary('late final int x = 0;');
- checkElementText(library, r'''
-late final int x;
-''');
- }
-
test_variable_getterInLib_setterInPart() async {
addSource('/a.dart', '''
part of my.lib;
@@ -11373,9 +11410,39 @@
test_variable_late() async {
featureSet = enableNnbd;
var library = await checkLibrary('late int x = 0;');
- checkElementText(library, r'''
+ checkElementText(
+ library,
+ r'''
late int x;
-''');
+synthetic int get x {}
+synthetic void set x(int _x) {}
+''',
+ withSyntheticAccessors: true);
+ }
+
+ test_variable_late_final() async {
+ featureSet = enableNnbd;
+ var library = await checkLibrary('late final int x;');
+ checkElementText(
+ library,
+ r'''
+late final int x;
+synthetic int get x {}
+synthetic void set x(int _x) {}
+''',
+ withSyntheticAccessors: true);
+ }
+
+ test_variable_late_final_initialized() async {
+ featureSet = enableNnbd;
+ var library = await checkLibrary('late final int x = 0;');
+ checkElementText(
+ library,
+ r'''
+late final int x;
+synthetic int get x {}
+''',
+ withSyntheticAccessors: true);
}
test_variable_propagatedType_const_noDep() async {
diff --git a/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart b/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
index 7e4c9f9..384f2dc 100644
--- a/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
+++ b/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
@@ -39,11 +39,13 @@
}
dynamic tempSkipped(File file) {
+ const String prefix = "front_end/parser_testcases";
String uriString = file.uri.toString();
- if (uriString.endsWith(
- "front_end/parser_testcases/nnbd/issue_40267_case_02.dart") ||
- uriString.endsWith(
- "front_end/parser_testcases/nnbd/issue_40267_case_05.dart")) {
+ if (uriString.endsWith("$prefix/nnbd/issue_40267_case_02.dart") ||
+ uriString.endsWith("$prefix/nnbd/issue_40267_case_05.dart") ||
+ uriString.endsWith("$prefix/nnbd/issue_40267_lookup_plus_plus.dart") ||
+ uriString.endsWith("$prefix/nnbd/issue_40267_lookup_plus.dart") ||
+ uriString.endsWith("$prefix/nnbd/issue_40267_plus_plus_lookup.dart")) {
return "Temporarily skipped because of "
"https://dart-review.googlesource.com/c/sdk/+/135903";
}
diff --git a/pkg/analyzer_fe_comparison/bin/compare_programs.dart b/pkg/analyzer_fe_comparison/bin/compare_programs.dart
deleted file mode 100644
index 0118aee..0000000
--- a/pkg/analyzer_fe_comparison/bin/compare_programs.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:analyzer/src/command_line/arguments.dart';
-import 'package:analyzer_fe_comparison/comparison.dart';
-import 'package:args/args.dart';
-import 'package:path/path.dart' as path;
-
-/// Compares the analyzer and front_end behavior when compiling a program.
-main(List<String> args) async {
- ArgResults options = _parseArgs(args);
- var sourcePaths = options.rest;
- if (sourcePaths.length != 1) {
- throw new StateError('Exactly one source file must be specified.');
- }
- var sourcePath = sourcePaths[0];
- var scriptPath = Platform.script.toFilePath();
- var sdkRepoPath =
- path.normalize(path.join(path.dirname(scriptPath), '..', '..', '..'));
- var buildPath = await _findBuildDir(sdkRepoPath, 'ReleaseX64');
- var dillPath = path.join(buildPath, 'vm_platform_strong.dill');
- var packagesFilePath = path.join(sdkRepoPath, '.packages');
-
- await compareTestPrograms(sourcePath, dillPath, packagesFilePath);
-}
-
-Future<String> _findBuildDir(String sdkRepoPath, String targetName) async {
- for (var subdirName in ['out', 'xcodebuild']) {
- var candidatePath = path.join(sdkRepoPath, subdirName, targetName);
- if (await new Directory(candidatePath).exists()) {
- return candidatePath;
- }
- }
- throw new StateError('Cannot find build directory');
-}
-
-ArgResults _parseArgs(List<String> args) {
- var parser = new ArgParser(allowTrailingOptions: true);
- parser.addOption('dart-sdk', help: 'The path to the Dart SDK.');
- if (args.contains('--ignore-unrecognized-flags')) {
- args = filterUnknownArguments(args, parser);
- }
- return parser.parse(args);
-}
diff --git a/pkg/analyzer_fe_comparison/bin/compare_sdk_tests b/pkg/analyzer_fe_comparison/bin/compare_sdk_tests
deleted file mode 100755
index b84851f..0000000
--- a/pkg/analyzer_fe_comparison/bin/compare_sdk_tests
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# Run analyzer_fe_comparison on the Dart VM. This script assumes the Dart
-# repo's directory structure.
-
-function follow_links() {
- file="$1"
- while [ -h "$file" ]; do
- # On Mac OS, readlink -f doesn't work.
- file="$(readlink "$file")"
- done
- echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Find directories.
-PKG_BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-DART_ROOT="$(cd "${PKG_BIN_DIR}/../../.." ; pwd -P)"
-SDK_DIR="${DART_ROOT}/sdk"
-BIN_DIR="${SDK_DIR}/bin"
-
-SDK_ARG="--dart-sdk=$SDK_DIR"
-
-DART="$BIN_DIR/dart"
-
-unset EXTRA_VM_OPTIONS
-declare -a EXTRA_VM_OPTIONS
-
-# We allow extra vm options to be passed in through an environment variable.
-if [[ $DART_VM_OPTIONS ]]; then
- read -a OPTIONS <<< "$DART_VM_OPTIONS"
- EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
-fi
-
-COMPARE_PROGRAMS="$PKG_BIN_DIR/compare_programs.dart"
-
-exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$COMPARE_PROGRAMS" "$SDK_ARG" "$@"
diff --git a/pkg/analyzer_fe_comparison/lib/comparison.dart b/pkg/analyzer_fe_comparison/lib/comparison.dart
deleted file mode 100644
index a8dcf37..0000000
--- a/pkg/analyzer_fe_comparison/lib/comparison.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer_fe_comparison/src/analyzer.dart' as analyzer;
-import 'package:analyzer_fe_comparison/src/comparison_node.dart';
-import 'package:analyzer_fe_comparison/src/kernel.dart' as kernel;
-import 'package:path/path.dart' as path;
-
-/// Compares the analyzer and kernel representations of a package, and prints
-/// the resulting diff.
-void comparePackages(
- String platformPath, String projectLibPath, String packagesFilePath) async {
- ComparisonNode analyzerNode = await analyzer.analyzePackage(projectLibPath);
- var packagesFileUri = Uri.file(packagesFilePath);
- var inputs = <Uri>[];
- for (var library in analyzerNode.children) {
- inputs.add(Uri.parse(library.text));
- }
- var platformUri = Uri.file(platformPath);
- ComparisonNode kernelNode =
- await kernel.analyzePackage(inputs, packagesFileUri, platformUri);
- print(ComparisonNode.diff(kernelNode, analyzerNode, 'CFE', 'analyzer'));
-}
-
-/// Compares the analyzer and kernel representations of a test file, and prints
-/// the resulting diff.
-///
-/// Only libraries reached by a "file:" URI are compared.
-void compareTestPrograms(
- String sourcePath, String platformPath, String packagesFilePath) async {
- var packagesFileUri = Uri.file(packagesFilePath);
- var platformUri = Uri.file(platformPath);
- ComparisonNode kernelNode = await kernel.analyzeProgram(
- path.toUri(sourcePath),
- packagesFileUri,
- platformUri,
- (uri) => uri.scheme == 'file');
- if (kernelNode.text == 'Error occurred') {
- // TODO(paulberry): really we should verify that the analyzer detects an
- // error as well. But that's not easy to do right now because we use the
- // front end to chase imports so that we know which files to pass to the
- // analyzer, and we can't rely on the front end import chasing when an error
- // occurred.
- print('No differences found (skipped due to front end compilation error)');
- return;
- }
- String startingPath;
- var inputs = <String>[];
- for (var library in kernelNode.children) {
- var filePath = path.fromUri(Uri.parse(library.text));
- if (startingPath == null) {
- startingPath = path.dirname(filePath);
- } else {
- while (!path.isWithin(startingPath, filePath)) {
- startingPath = path.dirname(startingPath);
- }
- }
- inputs.add(filePath);
- }
- ComparisonNode analyzerNode =
- await analyzer.analyzeFiles(startingPath, inputs);
- if (kernelNode == analyzerNode) {
- print('No differences found!');
- } else {
- print('Differences found:');
- print(ComparisonNode.diff(kernelNode, analyzerNode, 'CFE', 'analyzer'));
- }
-}
diff --git a/pkg/analyzer_fe_comparison/lib/src/analyzer.dart b/pkg/analyzer_fe_comparison/lib/src/analyzer.dart
deleted file mode 100644
index c1a9ad6..0000000
--- a/pkg/analyzer_fe_comparison/lib/src/analyzer.dart
+++ /dev/null
@@ -1,341 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
-import 'package:analyzer/dart/analysis/context_root.dart';
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/analysis/uri_converter.dart';
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart' show SourceKind;
-import 'package:analyzer_fe_comparison/src/comparison_node.dart';
-
-/// Analyzes the files in [filePaths] using the analyzer, and returns a
-/// [ComparisonNode] representing them.
-Future<ComparisonNode> analyzeFiles(
- String startingPath, List<String> filePaths) async {
- var driver = await _AnalyzerDriver.create(startingPath);
- return driver.analyzeFiles(filePaths);
-}
-
-/// Analyzes the package located at [libPath] using the analyzer, and returns a
-/// [ComparisonNode] representing it.
-Future<ComparisonNode> analyzePackage(String libPath) async {
- var driver = await _AnalyzerDriver.create(libPath);
- return driver.analyzePackage();
-}
-
-class _AnalyzerDriver {
- final AnalysisSession _session;
-
- final TypeProvider _typeProvider;
-
- final UriConverter _uriConverter;
-
- final ContextRoot _contextRoot;
-
- _AnalyzerDriver._(
- this._session, this._typeProvider, this._uriConverter, this._contextRoot);
-
- Future<ComparisonNode> analyzeFiles(Iterable<String> filePaths) async {
- var libraryNodes = <ComparisonNode>[];
- for (var filePath in filePaths) {
- var kind = await _session.getSourceKind(filePath);
- if (kind == SourceKind.LIBRARY) {
- var importUri = _uriConverter.pathToUri(filePath);
- var libraryElement =
- await _session.getLibraryByUri(importUri.toString());
- var childNodes = <ComparisonNode>[];
- if (libraryElement.name.isNotEmpty) {
- childNodes.add(ComparisonNode('name=${libraryElement.name}'));
- }
- for (var compilationUnit in libraryElement.units) {
- var unitResult =
- await _session.getResolvedAst(compilationUnit.source.fullName);
- _AnalyzerVisitor(_typeProvider, childNodes)
- ._visitList(unitResult.unit.declarations);
- }
- libraryNodes
- .add(ComparisonNode.sorted(importUri.toString(), childNodes));
- }
- }
- return ComparisonNode.sorted('Component', libraryNodes);
- }
-
- Future<ComparisonNode> analyzePackage() async {
- return analyzeFiles(_contextRoot.analyzedFiles());
- }
-
- static Future<_AnalyzerDriver> create(String startingPath) async {
- var contextCollection =
- AnalysisContextCollection(includedPaths: [startingPath]);
- var contexts = contextCollection.contexts;
- if (contexts.length != 1) {
- throw new StateError('Expected exactly one context');
- }
- var context = contexts[0];
- var session = context.currentSession;
- var typeProvider = await session.typeProvider;
- var uriConverter = session.uriConverter;
- var contextRoot = context.contextRoot;
- return _AnalyzerDriver._(session, typeProvider, uriConverter, contextRoot);
- }
-}
-
-/// Visitor for serializing the contents of an analyzer AST into
-/// ComparisonNodes.
-///
-/// Results are accumulated into [_resultNodes].
-class _AnalyzerVisitor extends UnifyingAstVisitor<void> {
- final TypeProvider _typeProvider;
-
- final List<ComparisonNode> _resultNodes;
-
- _AnalyzerVisitor(this._typeProvider, this._resultNodes);
-
- @override
- void visitClassDeclaration(ClassDeclaration node) {
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._handleClassOrClassTypeAlias(node.declaredElement);
- visitor._visitList(node.members);
- _resultNodes
- .add(ComparisonNode.sorted('Class ${node.name.name}', children));
- }
-
- @override
- void visitClassTypeAlias(ClassTypeAlias node) {
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._handleClassOrClassTypeAlias(node.declaredElement);
- _resultNodes.add(
- ComparisonNode.sorted('MixinApplication ${node.name.name}', children));
- }
-
- @override
- void visitConstructorDeclaration(ConstructorDeclaration node) {
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._visitParameters(node.parameters);
- _resultNodes.add(ComparisonNode.sorted(
- 'Constructor ${node.name?.name ?? '(unnamed)'}', children));
- }
-
- @override
- void visitEnumDeclaration(EnumDeclaration node) {
- var children = <ComparisonNode>[];
- for (var enumValue in node.constants) {
- children.add(ComparisonNode('EnumValue ${enumValue.name.name}'));
- }
- _resultNodes.add(ComparisonNode.sorted('Enum ${node.name.name}', children));
- }
-
- @override
- void visitFieldDeclaration(FieldDeclaration node) {
- node.fields.accept(this);
- }
-
- @override
- void visitFunctionDeclaration(FunctionDeclaration node) {
- String kind;
- if (node.isGetter) {
- kind = 'Getter';
- } else if (node.isSetter) {
- kind = 'Setter';
- } else {
- // Kernel calls top level functions "methods".
- kind = 'Method';
- }
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._visitTypeParameters(node.declaredElement.typeParameters);
- visitor._visitParameters(node.functionExpression.parameters);
- children
- .add(_translateType('Return type: ', node.declaredElement.returnType));
- _resultNodes
- .add(ComparisonNode.sorted('$kind ${node.name.name}', children));
- }
-
- @override
- void visitFunctionTypeAlias(FunctionTypeAlias node) {
- _visitTypedef(node);
- }
-
- @override
- void visitGenericTypeAlias(GenericTypeAlias node) {
- _visitTypedef(node);
- }
-
- @override
- void visitMethodDeclaration(MethodDeclaration node) {
- var name = node.name.name;
- String kind;
- if (node.isGetter) {
- kind = 'Getter';
- } else if (node.isSetter) {
- kind = 'Setter';
- } else if (node.isOperator) {
- kind = 'Operator';
- if (name == '-' && node.declaredElement.parameters.isEmpty) {
- name = 'unary-';
- }
- } else {
- kind = 'Method';
- }
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._visitTypeParameters(node.declaredElement.typeParameters);
- visitor._visitParameters(node.parameters);
- children
- .add(_translateType('Return type: ', node.declaredElement.returnType));
- _resultNodes.add(ComparisonNode.sorted('$kind $name', children));
- }
-
- @override
- void visitMixinDeclaration(MixinDeclaration node) {
- // At present, kernel doesn't distinguish between mixin and class
- // declarations. So treat the mixin as a class.
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._handleClassOrClassTypeAlias(node.declaredElement);
- visitor._visitList(node.members);
- _resultNodes
- .add(ComparisonNode.sorted('Mixin ${node.name.name}', children));
- }
-
- @override
- Null visitNode(AstNode node) {
- throw new UnimplementedError('AnalyzerVisitor: ${node.runtimeType}');
- }
-
- @override
- void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- node.variables.accept(this);
- }
-
- @override
- void visitVariableDeclarationList(VariableDeclarationList node) {
- for (var variableDeclaration in node.variables) {
- var children = <ComparisonNode>[];
- children.add(
- _translateType('Type: ', variableDeclaration.declaredElement.type));
- // Kernel calls both fields and top level variable declarations "fields".
- _resultNodes.add(ComparisonNode.sorted(
- 'Field ${variableDeclaration.name.name}', children));
- }
- }
-
- void _handleClassOrClassTypeAlias(ClassElement element) {
- _visitTypeParameters(element.typeParameters);
- if (element.isMixin) {
- for (int i = 0; i < element.superclassConstraints.length; i++) {
- _resultNodes
- .add(_translateType('On $i: ', element.superclassConstraints[i]));
- }
- } else {
- if (element.supertype != null) {
- _resultNodes.add(_translateType('Extends: ', element.supertype));
- }
- for (int i = 0; i < element.mixins.length; i++) {
- _resultNodes.add(_translateType('Mixin $i: ', element.mixins[i]));
- }
- }
- for (int i = 0; i < element.interfaces.length; i++) {
- _resultNodes
- .add(_translateType('Implements $i: ', element.interfaces[i]));
- }
- }
-
- /// Converts the analyzer representation of a type into a ComparisonNode.
- ComparisonNode _translateType(String prefix, DartType type) {
- if (type is InterfaceType) {
- var children = <ComparisonNode>[];
- children
- .add(ComparisonNode('Library: ${type.element.librarySource.uri}'));
- for (int i = 0; i < type.typeArguments.length; i++) {
- children.add(_translateType('Type arg $i: ', type.typeArguments[i]));
- }
- return ComparisonNode('${prefix}InterfaceType ${type.name}', children);
- }
- if (type is TypeParameterType) {
- // TODO(paulberry): disambiguate if needed.
- return ComparisonNode('${prefix}TypeParameterType: ${type.name}');
- }
- if (type.isDynamic) {
- return ComparisonNode('${prefix}Dynamic');
- }
- if (type.isVoid) {
- return ComparisonNode('${prefix}Void');
- }
- if (type is FunctionType) {
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- visitor._visitTypeParameters(type.typeFormals);
- children.add(_translateType('Return type: ', type.returnType));
- int positionalParameterIndex = 0;
- for (var parameterElement in type.parameters) {
- var kind = parameterElement.isNotOptional
- ? 'Required'
- : parameterElement.isOptionalPositional ? 'Optional' : 'Named';
- var name = parameterElement.isNamed
- ? parameterElement.name
- : '${positionalParameterIndex++}';
- children.add(
- _translateType('$kind parameter $name: ', parameterElement.type));
- }
- return ComparisonNode.sorted('${prefix}FunctionType', children);
- }
- throw new UnimplementedError('_translateType: ${type.runtimeType}');
- }
-
- /// Visits all the nodes in [nodes].
- void _visitList(List<AstNode> nodes) {
- for (var astNode in nodes) {
- astNode.accept(this);
- }
- }
-
- void _visitParameters(FormalParameterList parameters) {
- var children = <ComparisonNode>[];
- // Note: parameters == null for getters
- if (parameters != null) {
- for (var parameter in parameters.parameters) {
- var element = parameter.declaredElement;
- var kind = element.isNotOptional
- ? 'Required'
- : element.isOptionalPositional ? 'Optional' : 'Named';
- var parameterChildren = <ComparisonNode>[];
- parameterChildren.add(_translateType('Type: ', element.type));
- children.add(
- ComparisonNode.sorted('$kind: ${element.name}', parameterChildren));
- }
- }
- _resultNodes.add(ComparisonNode('Parameters', children));
- }
-
- void _visitTypedef(TypeAlias node) {
- var children = <ComparisonNode>[];
- var visitor = _AnalyzerVisitor(_typeProvider, children);
- GenericTypeAliasElement element = node.declaredElement;
- visitor._visitTypeParameters(element.typeParameters);
- children.add(_translateType('Type: ', element.function.type));
- _resultNodes
- .add(ComparisonNode.sorted('Typedef ${node.name.name}', children));
- }
-
- void _visitTypeParameters(List<TypeParameterElement> typeParameters) {
- for (int i = 0; i < typeParameters.length; i++) {
- _resultNodes.add(ComparisonNode(
- 'Type parameter $i: ${typeParameters[i].name}', [
- _translateType(
- 'Bound: ', typeParameters[i].bound ?? _typeProvider.objectType)
- ]));
- }
- }
-}
diff --git a/pkg/analyzer_fe_comparison/lib/src/comparison_node.dart b/pkg/analyzer_fe_comparison/lib/src/comparison_node.dart
deleted file mode 100644
index 44ea835..0000000
--- a/pkg/analyzer_fe_comparison/lib/src/comparison_node.dart
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:math';
-
-/// [ComparisonNode] defines a simple tree structure that can be used to compare
-/// two representations of Dart code.
-///
-/// Each node contains a textual string and a list of child nodes.
-class ComparisonNode {
- final String text;
- final List<ComparisonNode> children;
-
- ComparisonNode(this.text, [List<ComparisonNode> children])
- : children = children ?? <ComparisonNode>[];
-
- factory ComparisonNode.sorted(
- String text, Iterable<ComparisonNode> children) =>
- ComparisonNode(text, sortList(children));
-
- @override
- bool operator ==(Object other) {
- if (other is ComparisonNode) {
- if (text != other.text) return false;
- if (children.length != other.children.length) return false;
- for (int i = 0; i < children.length; i++) {
- if (children[i] != other.children[i]) return false;
- }
- return true;
- }
- return false;
- }
-
- String toString({String newline: '\n'}) {
- var lines = ['$text'];
- var indentedNewline = '$newline ';
- for (var child in children) {
- lines.add(child.toString(newline: indentedNewline));
- }
- return lines.join(indentedNewline);
- }
-
- static ComparisonNode diff(
- ComparisonNode a, ComparisonNode b, String aName, String bName) {
- if (a.text == b.text) {
- return ComparisonNode(
- a.text, diffLists(a.children, b.children, aName, bName));
- } else {
- return ComparisonNode('Root nodes differ',
- [_prefix('In $aName: ', a), _prefix('In $bName: ', b)]);
- }
- }
-
- static List<ComparisonNode> diffLists(List<ComparisonNode> a,
- List<ComparisonNode> b, String aName, String bName) {
- // Note: this is an O(n) "poor man's" diff algorithm; it produces optimal
- // results if the incoming results are sorted by text or if there is just
- // one contiguous hunk of differences. Otherwise it may not find the
- // shortest diff. This should be sufficient for our purposes, since we are
- // not expecting many diffs.
-
- // We'll exclude common nodes at the beginning of both lists
- var shorterLength = min(a.length, b.length);
- var commonInitialNodes = 0;
- while (commonInitialNodes < shorterLength &&
- a[commonInitialNodes] == b[commonInitialNodes]) {
- commonInitialNodes++;
- }
-
- // Fast exit if a == b
- if (commonInitialNodes == a.length && a.length == b.length) {
- return [];
- }
-
- // We'll exclude common nodes at the end of both lists (note: we don't want
- // to overcount by re-testing the common nodes identified above)
- var commonFinalNodes = 0;
- while (commonInitialNodes + commonFinalNodes < shorterLength &&
- a[a.length - commonFinalNodes - 1] ==
- b[b.length - commonFinalNodes - 1]) {
- commonFinalNodes++;
- }
-
- // Walk the remaining nodes starting at the first node that's different,
- // matching up nodes by their text.
- var aIndex = commonInitialNodes;
- var bIndex = commonInitialNodes;
- var aEnd = a.length - commonFinalNodes;
- var bEnd = b.length - commonFinalNodes;
- var result = <ComparisonNode>[];
- while (aIndex < aEnd && bIndex < bEnd) {
- var comparisonResult = a[aIndex].text.compareTo(b[bIndex].text);
- if (comparisonResult < 0) {
- // a[aIndex].text sorts before b[bIndex].text. Assume that this means
- // a[aIndex] was removed.
- result.add(_prefix('Only in $aName: ', a[aIndex++]));
- } else if (comparisonResult > 0) {
- // b[bIndex].text sorts before a[aIndex].text. Assume that this means
- // b[bIndex] was added.
- result.add(_prefix('Only in $bName: ', b[bIndex++]));
- } else {
- // a[aIndex].text matches b[bIndex].text, so diff the nodes if
- // necessary.
- var aNode = a[aIndex++];
- var bNode = b[bIndex++];
- if (aNode != bNode) {
- result.add(diff(aNode, bNode, aName, bName));
- }
- }
- }
-
- // Deal with any nodes left over.
- while (aIndex < aEnd) {
- result.add(_prefix('Only in $aName: ', a[aIndex++]));
- }
- while (bIndex < bEnd) {
- result.add(_prefix('Only in $bName: ', b[bIndex++]));
- }
-
- // If we get here and we haven't added any nodes, something has gone wrong.
- if (result.isEmpty) {
- throw StateError('Diff produced empty diff for non-matching lists');
- }
-
- return result;
- }
-
- static List<ComparisonNode> sortList(Iterable<ComparisonNode> nodes) {
- var result = nodes.toList();
- result.sort((a, b) => a.text.compareTo(b.text));
- return result;
- }
-
- static ComparisonNode _prefix(String prefixString, ComparisonNode node) {
- return ComparisonNode(prefixString + node.text, node.children);
- }
-}
diff --git a/pkg/analyzer_fe_comparison/lib/src/kernel.dart b/pkg/analyzer_fe_comparison/lib/src/kernel.dart
deleted file mode 100644
index be9f0ad..0000000
--- a/pkg/analyzer_fe_comparison/lib/src/kernel.dart
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
- show DiagnosticMessage, DiagnosticMessageHandler, getMessageHeaderText;
-import 'package:analyzer_fe_comparison/src/comparison_node.dart';
-import 'package:front_end/src/api_prototype/compiler_options.dart'
- show CompilerOptions;
-import 'package:front_end/src/api_prototype/kernel_generator.dart';
-import 'package:front_end/src/api_prototype/standard_file_system.dart';
-import 'package:kernel/ast.dart';
-import 'package:kernel/target/targets.dart';
-
-/// Compiles the given [inputs] to kernel using the front_end, and returns a
-/// [ComparisonNode] representing them.
-Future<ComparisonNode> analyzePackage(
- List<Uri> inputs, Uri packagesFileUri, Uri platformUri) async {
- var messages = <DiagnosticMessage>[];
- var component = (await kernelForModule(inputs,
- _makeCompilerOptions(packagesFileUri, platformUri, messages.add)))
- .component;
- if (messages.isNotEmpty) {
- return ComparisonNode(
- 'Error occurred', messages.map(_diagnosticMessageToNode).toList());
- }
- var libraryNodes = <ComparisonNode>[];
- var visitor = _KernelVisitor(libraryNodes);
- for (var library in component.libraries) {
- if (inputs.contains(library.importUri)) {
- library.accept(visitor);
- }
- }
- return ComparisonNode.sorted('Component', libraryNodes);
-}
-
-/// Compiles the given [input] to kernel using the front_end, and returns a
-/// [ComparisonNode] representing it.
-///
-/// Only libraries whose URI passes the [uriFilter] are included in the results.
-Future<ComparisonNode> analyzeProgram(Uri input, Uri packagesFileUri,
- Uri platformUri, bool uriFilter(Uri uri)) async {
- var messages = <DiagnosticMessage>[];
- var component = (await kernelForProgram(input,
- _makeCompilerOptions(packagesFileUri, platformUri, messages.add)))
- .component;
- if (messages.isNotEmpty) {
- return ComparisonNode(
- 'Error occurred', messages.map(_diagnosticMessageToNode).toList());
- }
- var libraryNodes = <ComparisonNode>[];
- var visitor = _KernelVisitor(libraryNodes);
- for (var library in component.libraries) {
- if (uriFilter(library.importUri)) {
- library.accept(visitor);
- }
- }
- return ComparisonNode.sorted('Component', libraryNodes);
-}
-
-ComparisonNode _diagnosticMessageToNode(DiagnosticMessage message) {
- return ComparisonNode(getMessageHeaderText(message));
-}
-
-CompilerOptions _makeCompilerOptions(Uri packagesFileUri, Uri platformUri,
- DiagnosticMessageHandler onDiagnostic) {
- var targetFlags = TargetFlags();
- var target = NoneTarget(targetFlags);
- var fileSystem = StandardFileSystem.instance;
-
- return CompilerOptions()
- ..fileSystem = fileSystem
- ..packagesFileUri = packagesFileUri
- ..sdkSummary = platformUri
- ..target = target
- ..throwOnErrorsForDebugging = false
- ..embedSourceText = false
- ..onDiagnostic = onDiagnostic;
-}
-
-/// Visitor for serializing a kernel representation of a program into
-/// ComparisonNodes.
-///
-/// Results are accumulated into [_resultNodes].
-class _KernelVisitor extends TreeVisitor<void> {
- final List<ComparisonNode> _resultNodes;
-
- _KernelVisitor(this._resultNodes);
-
- @override
- void defaultTreeNode(TreeNode node) {
- throw new UnimplementedError('KernelVisitor: ${node.runtimeType}');
- }
-
- @override
- void visitClass(Class class_) {
- if (class_.isAnonymousMixin) return null;
- var kind = class_.isEnum
- ? 'Enum'
- : class_.isMixinApplication
- ? 'MixinApplication'
- : class_.isMixinDeclaration ? 'Mixin' : 'Class';
- var children = <ComparisonNode>[];
- var visitor = _KernelVisitor(children);
- if (class_.isEnum) {
- for (var field in class_.fields) {
- if (!field.isStatic) continue;
- if (field.name.name == 'values') continue;
- // TODO(paulberry): handle index
- children.add(ComparisonNode('EnumValue ${field.name.name}'));
- }
- } else {
- visitor._visitTypeParameters(class_.typeParameters);
- if (class_.supertype != null) {
- var declaredSupertype = class_.supertype.asInterfaceType;
- if (class_.isMixinDeclaration) {
- var constraints = <DartType>[];
- // Kernel represents a mixin declaration such as:
- // mixin M on S0, S1, S2 {...}
- // By desugaring it to:
- // abstract class _M&S0&S1 implements S0, S1 {}
- // abstract class _M&S0&S1&S2 implements _M&S0&S1 {}
- // abstract class M extends M&S0&S1&S2 {...}
- // (See dartbug.com/34783)
- while (declaredSupertype.classNode.isAnonymousMixin) {
- // Since we're walking up the class hierarchy, we encounter the
- // mixins in the reverse order that they were declared, so we have
- // to use [List.insert] to add them to [constraints].
- constraints.insert(
- 0,
- declaredSupertype
- .classNode.implementedTypes[1].asInterfaceType);
- declaredSupertype =
- declaredSupertype.classNode.implementedTypes[0].asInterfaceType;
- }
- constraints.insert(0, declaredSupertype);
- for (int i = 0; i < constraints.length; i++) {
- children.add(_TypeVisitor.translate('On $i: ', constraints[i]));
- }
- } else {
- var mixedInTypes = <DartType>[];
- if (class_.isMixinApplication) {
- mixedInTypes.add(class_.mixedInType.asInterfaceType);
- }
- while (declaredSupertype.classNode.isAnonymousMixin) {
- // Since we're walking from the class to its declared supertype, we
- // encounter the mixins in the reverse order that they were declared,
- // so we have to use [List.insert] to add them to [mixedInTypes].
- mixedInTypes.insert(
- 0, declaredSupertype.classNode.mixedInType.asInterfaceType);
- declaredSupertype =
- declaredSupertype.classNode.supertype.asInterfaceType;
- }
- children.add(_TypeVisitor.translate('Extends: ', declaredSupertype));
- for (int i = 0; i < mixedInTypes.length; i++) {
- children.add(_TypeVisitor.translate('Mixin $i: ', mixedInTypes[i]));
- }
- }
- }
- for (int i = 0; i < class_.implementedTypes.length; i++) {
- children.add(_TypeVisitor.translate(
- 'Implements $i: ', class_.implementedTypes[i].asInterfaceType));
- }
- visitor._visitList(class_.fields);
- visitor._visitList(class_.constructors);
- visitor._visitList(class_.procedures);
- }
- // TODO(paulberry): handle more fields from Class
- _resultNodes.add(ComparisonNode.sorted('$kind ${class_.name}', children));
- }
-
- @override
- void visitConstructor(Constructor constructor) {
- if (constructor.isSynthetic) return null;
- var name = constructor.name.name;
- if (name.isEmpty) {
- name = '(unnamed)';
- }
- var children = <ComparisonNode>[];
- var visitor = _KernelVisitor(children);
- constructor.function.accept(visitor);
- // TODO(paulberry): handle more fields from Constructor
- _resultNodes.add(ComparisonNode.sorted('Constructor $name', children));
- }
-
- @override
- void visitField(Field field) {
- if (field.name.name == '_redirecting#') return null;
- if (field.name.name == '_exports#') return null;
- var children = <ComparisonNode>[];
- children.add(_TypeVisitor.translate('Type: ', field.type));
- // TODO(paulberry): handle more fields from Field
- _resultNodes
- .add(ComparisonNode.sorted('Field ${field.name.name}', children));
- }
-
- @override
- void visitFunctionNode(FunctionNode node) {
- var parent = node.parent;
- if (!(parent is Constructor || parent is Procedure && parent.isFactory)) {
- _visitTypeParameters(node.typeParameters);
- _resultNodes
- .add(_TypeVisitor.translate('Return type: ', node.returnType));
- }
- var parameterChildren = <ComparisonNode>[];
- var parameterVisitor = _KernelVisitor(parameterChildren);
- for (int i = 0; i < node.positionalParameters.length; i++) {
- parameterVisitor._visitParameter(node.positionalParameters[i],
- i < node.requiredParameterCount ? 'Required' : 'Optional');
- }
- for (int i = 0; i < node.namedParameters.length; i++) {
- parameterVisitor._visitParameter(node.namedParameters[i], 'Named');
- }
- _resultNodes.add(ComparisonNode('Parameters', parameterChildren));
- // TODO(paulberry): handle more fields from FunctionNode
- }
-
- @override
- void visitLibrary(Library library) {
- var children = <ComparisonNode>[];
- if (library.name != null) {
- children.add(ComparisonNode('name=${library.name}'));
- }
- var visitor = _KernelVisitor(children);
- visitor._visitList(library.typedefs);
- visitor._visitList(library.classes);
- visitor._visitList(library.procedures);
- visitor._visitList(library.fields);
- // TODO(paulberry): handle more fields from Library
- _resultNodes
- .add(ComparisonNode.sorted(library.importUri.toString(), children));
- }
-
- @override
- void visitProcedure(Procedure procedure) {
- if (procedure.isSyntheticForwarder) {
- return null;
- }
- if (procedure.name.name.startsWith('_#loadLibrary_')) {
- // Sometimes the front end generates procedures with this name that don't
- // correspond to anything in the source file. Ignore them.
- return null;
- }
- // TODO(paulberry): add an annotation to the ComparisonNode when the
- // procedure is a factory.
- var kind = procedure.isFactory
- ? 'Constructor'
- : procedure.kind.toString().replaceAll('ProcedureKind.', '');
- var name = procedure.name.name;
- if (name.isEmpty) {
- name = '(unnamed)';
- }
- var children = <ComparisonNode>[];
- var visitor = _KernelVisitor(children);
- procedure.function.accept(visitor);
- // TODO(paulberry): handle more fields from Procedure
- _resultNodes.add(ComparisonNode.sorted('$kind $name', children));
- }
-
- @override
- void visitTypedef(Typedef typedef) {
- var children = <ComparisonNode>[];
- var visitor = _KernelVisitor(children);
- visitor._visitTypeParameters(typedef.typeParameters);
- children.add(_TypeVisitor.translate('Type: ', typedef.type));
- // TODO(paulberry): handle more fields from Typedef
- _resultNodes
- .add(ComparisonNode.sorted('Typedef ${typedef.name}', children));
- }
-
- /// Visits all the nodes in [nodes].
- void _visitList(List<TreeNode> nodes) {
- for (var node in nodes) {
- node.accept(this);
- }
- }
-
- void _visitParameter(VariableDeclaration parameter, String kind) {
- var children = <ComparisonNode>[];
- children.add(_TypeVisitor.translate('Type: ', parameter.type));
- // TODO(paulberry): handle more fields from VariableDeclaration
- _resultNodes
- .add(ComparisonNode.sorted('$kind: ${parameter.name}', children));
- }
-
- void _visitTypeParameters(List<TypeParameter> typeParameters) {
- for (int i = 0; i < typeParameters.length; i++) {
- _resultNodes.add(ComparisonNode(
- 'Type parameter $i: ${typeParameters[i].name}',
- [_TypeVisitor.translate('Bound: ', typeParameters[i].bound)]));
- }
- }
-}
-
-/// Visitor for serializing a kernel representation of a type into
-/// ComparisonNodes.
-class _TypeVisitor extends DartTypeVisitor<ComparisonNode> {
- /// Text to prepend to the node text.
- String _prefix;
-
- _TypeVisitor(this._prefix);
-
- @override
- ComparisonNode defaultDartType(DartType node) {
- throw new UnimplementedError('_TypeVisitor: ${node.runtimeType}');
- }
-
- @override
- ComparisonNode visitDynamicType(DynamicType node) {
- return ComparisonNode('${_prefix}Dynamic');
- }
-
- @override
- ComparisonNode visitFunctionType(FunctionType node) {
- var children = <ComparisonNode>[];
- var visitor = _KernelVisitor(children);
- visitor._visitTypeParameters(node.typeParameters);
- children.add(translate('Return type: ', node.returnType));
- for (int i = 0; i < node.positionalParameters.length; i++) {
- var kind = i < node.requiredParameterCount ? 'Required' : 'Optional';
- children
- .add(translate('$kind parameter $i: ', node.positionalParameters[i]));
- }
- for (var namedType in node.namedParameters) {
- children.add(
- translate('Named parameter ${namedType.name}: ', namedType.type));
- }
- return ComparisonNode.sorted('${_prefix}FunctionType', children);
- }
-
- @override
- ComparisonNode visitInterfaceType(InterfaceType node) {
- var children = <ComparisonNode>[];
- children.add(ComparisonNode(
- 'Library: ${node.classNode.enclosingLibrary.importUri}'));
- for (int i = 0; i < node.typeArguments.length; i++) {
- children.add(translate('Type arg $i: ', node.typeArguments[i]));
- }
- return ComparisonNode(
- '${_prefix}InterfaceType ${node.classNode.name}', children);
- }
-
- @override
- ComparisonNode visitTypeParameterType(TypeParameterType node) {
- // TODO(paulberry): disambiguate if needed.
- return ComparisonNode(
- '${_prefix}TypeParameterType: ${node.parameter.name}');
- }
-
- @override
- ComparisonNode visitVoidType(VoidType node) {
- return ComparisonNode('${_prefix}Void');
- }
-
- static ComparisonNode translate(String prefix, DartType type) {
- return type.accept(new _TypeVisitor(prefix));
- }
-}
diff --git a/pkg/analyzer_fe_comparison/pubspec.yaml b/pkg/analyzer_fe_comparison/pubspec.yaml
deleted file mode 100644
index fb579c8..0000000
--- a/pkg/analyzer_fe_comparison/pubspec.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: analyzer_fe_comparison
-publish_to: none
-author: Dart Team <misc@dartlang.org>
-description: Tool for comparing the behavior of the analyzer and the front end.
-homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_fe_comparison
-environment:
- sdk: '>=2.0.0-dev-48.0 <3.0.0'
-dependencies:
- kernel: ^0.3.4
diff --git a/pkg/analyzer_fe_comparison/tool/compare_packages.dart b/pkg/analyzer_fe_comparison/tool/compare_packages.dart
deleted file mode 100644
index e1a7b71..0000000
--- a/pkg/analyzer_fe_comparison/tool/compare_packages.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:analyzer_fe_comparison/comparison.dart';
-import 'package:path/path.dart' as path;
-
-/// Compares the analyzer and front_end behavior when compiling a package.
-///
-/// Currently hardcoded to use the package "analyzer".
-main() async {
- var scriptPath = Platform.script.toFilePath();
- var sdkRepoPath =
- path.normalize(path.join(path.dirname(scriptPath), '..', '..', '..'));
- var buildPath = await _findBuildDir(sdkRepoPath, 'ReleaseX64');
- var dillPath = path.join(buildPath, 'vm_platform_strong.dill');
- var analyzerLibPath = path.join(sdkRepoPath, 'pkg', 'analyzer', 'lib');
- var packagesFilePath = path.join(sdkRepoPath, '.packages');
- comparePackages(dillPath, analyzerLibPath, packagesFilePath);
-}
-
-Future<String> _findBuildDir(String sdkRepoPath, String targetName) async {
- for (var subdirName in ['out', 'xcodebuild']) {
- var candidatePath = path.join(sdkRepoPath, subdirName, targetName);
- if (await new Directory(candidatePath).exists()) {
- return candidatePath;
- }
- }
- throw new StateError('Cannot find build directory');
-}
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index bb3a129..61368d5 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -74,15 +74,6 @@
/// method.
bool inStaticMethodBody = false;
- /// Indicates whether the completion location is in the body of a method.
- bool inMethodBody = false;
-
- /// Indicates whether the completion location is in the body of a function.
- bool inFunctionBody = false;
-
- /// Indicates whether the completion location is in the body of a constructor.
- bool inConstructorBody = false;
-
/// Indicates whether the completion target is prefixed.
bool isPrefixed = false;
@@ -112,16 +103,7 @@
if (functionBody != null) {
var parent = functionBody.parent;
- if (parent is ConstructorDeclaration) {
- optype.inConstructorBody = true;
- }
-
- if (parent is FunctionExpression) {
- optype.inFunctionBody = true;
- }
-
if (parent is MethodDeclaration) {
- optype.inMethodBody = true;
optype.inStaticMethodBody = parent.isStatic;
}
}
@@ -164,13 +146,6 @@
!includeReturnValueSuggestions &&
!includeVoidReturnSuggestions;
- /// Indicate whether only type names should be suggested
- bool get includeOnlyTypeNameSuggestions =>
- includeTypeNameSuggestions &&
- !includeNamedArgumentSuggestions &&
- !includeReturnValueSuggestions &&
- !includeVoidReturnSuggestions;
-
/// Try to determine the required context type, and configure filters.
void _computeRequiredTypeAndFilters(CompletionTarget target) {
Object entity = target.entity;
@@ -849,13 +824,7 @@
// Check for named parameters in constructor calls.
AstNode grandparent = node.parent.parent;
if (grandparent is ConstructorReferenceNode) {
- ConstructorElement element =
- // TODO(paulberry): remove the unnecessary cast when we are ready to
- // depend on a version of the analyzer that includes
- // https://dart-review.googlesource.com/c/sdk/+/89923
- (grandparent // ignore: unnecessary_cast
- as ConstructorReferenceNode)
- .staticElement;
+ ConstructorElement element = grandparent.staticElement;
if (element != null) {
List<ParameterElement> parameters = element.parameters;
ParameterElement parameterElement = parameters.firstWhere((e) {
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
index b975c97..581775c 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/optype_test.dart
@@ -23,24 +23,16 @@
}
@reflectiveTest
-// TODO: determine if tests here need to be fixed for Dart2.
class OpTypeDart1OnlyTest extends OpTypeTestCommon {
@failingTest
Future<void> test_Annotation() async {
// SimpleIdentifier Annotation MethodDeclaration ClassDeclaration
addTestSource('class C { @A^ }');
await assertOpType(constructors: true, returnValue: true, typeNames: true);
- // TODO(danrubel): This test fails when fasta parser is enabled
- // because the @A is dropped from the Analyzer AST.
+ // TODO(danrubel): This test fails because the @A is dropped from the AST.
// Ideally we generate a synthetic field and associate the annotation
// with that field, but doing so breaks test_constructorAndMethodNameCollision.
// See https://dart-review.googlesource.com/c/sdk/+/65760/3/pkg/analyzer/lib/src/fasta/ast_builder.dart#2395
-
- // The old Analyzer parser passes this test, but will be turned off soon.
- // It is preferable to throw only if the old analyzer is being used,
- // but there does not seem to be a reliable way to determine that here.
- // TODO(danrubel): remove this once fasta parser is enabled by default.
- throw 'Remove this exception once fasta parser is the default';
}
Future<void> test_ArgumentList() async {
@@ -52,40 +44,27 @@
constructors: true,
namedArgs: true,
returnValue: true,
- typeNames: true,
- functionBody: true);
+ typeNames: true);
}
Future<void> test_ArgumentList_namedParam() async {
// SimpleIdentifier NamedExpression ArgumentList MethodInvocation
// ExpressionStatement
addTestSource('void main() {expect(foo: ^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ArgumentList_prefixedIdentifier() async {
// SimpleIdentifier PrefixedIdentifier ArgumentList
addTestSource('void main() {expect(aa.^)}');
await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- prefixed: true,
- functionBody: true);
+ constructors: true, returnValue: true, typeNames: true, prefixed: true);
}
Future<void> test_ArgumentList_resolved() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('void main() {int.parse(^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AsIdentifier() async {
@@ -94,17 +73,12 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_Assert() async {
addTestSource('main() {assert(^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AssertInitializer() async {
@@ -116,11 +90,7 @@
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('class A {} main() {int a; int b = ^}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AssignmentExpression_type() async {
@@ -139,8 +109,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_AssignmentExpression_type_newline() async {
@@ -158,8 +127,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_AssignmentExpression_type_partial() async {
@@ -178,8 +146,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_AssignmentExpression_type_partial_newline() async {
@@ -197,104 +164,63 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_AwaitExpression() async {
// SimpleIdentifier AwaitExpression ExpressionStatement
addTestSource('main() async {A a; await ^}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AwaitExpression2() async {
addTestSource('main() async {A a; await c^ await}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AwaitExpression3() async {
addTestSource('main() async {A a; await ^ await foo;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AwaitExpression4() async {
addTestSource('main() async {A a; await ^ await bar();}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AwaitExpression_assignment() async {
addTestSource('main() async {A a; int x = await ^}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AwaitExpression_assignment2() async {
addTestSource('main() async {A a; int x = await ^ await foo;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_AwaitExpression_assignment3() async {
addTestSource('main() async {A a; int x = await v^ int y = await foo;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_BinaryExpression_LHS() async {
// SimpleIdentifier BinaryExpression VariableDeclaration
// VariableDeclarationList VariableDeclarationStatement
addTestSource('main() {int a = 1, b = ^ + 2;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_BinaryExpression_RHS() async {
// SimpleIdentifier BinaryExpression VariableDeclaration
// VariableDeclarationList VariableDeclarationStatement
addTestSource('main() {int a = 1, b = 2 + ^;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_BinaryExpression_RHS2() async {
// SimpleIdentifier BinaryExpression
addTestSource('main() {if (c < ^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_Block() async {
@@ -312,8 +238,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_2a() async {
@@ -323,8 +248,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_2b() async {
@@ -334,8 +258,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_2c() async {
@@ -345,8 +268,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_2d() async {
@@ -356,8 +278,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_3a() async {
@@ -367,8 +288,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_3b() async {
@@ -378,8 +298,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_3c() async {
@@ -389,8 +308,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_catch_3d() async {
@@ -400,8 +318,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_empty() async {
@@ -411,8 +328,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_Block_identifier_partial() async {
@@ -421,8 +337,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_Block_in_constructor() async {
@@ -431,7 +346,6 @@
constructors: true,
returnValue: true,
typeNames: true,
- constructorBody: true,
voidReturn: true);
}
@@ -441,7 +355,6 @@
constructors: true,
returnValue: true,
typeNames: true,
- functionBody: true,
voidReturn: true);
}
@@ -451,7 +364,6 @@
constructors: true,
returnValue: true,
typeNames: true,
- methodBody: true,
voidReturn: true);
}
@@ -462,8 +374,7 @@
prefixed: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_Block_static() async {
@@ -473,7 +384,6 @@
returnValue: true,
typeNames: true,
staticMethodBody: true,
- methodBody: true,
voidReturn: true);
}
@@ -488,8 +398,7 @@
returnValue: true,
typeNames: true,
voidReturn: true,
- prefixed: true,
- functionBody: true);
+ prefixed: true);
}
Future<void> test_CascadeExpression_selector2() async {
@@ -499,8 +408,7 @@
constructors: true,
returnValue: true,
voidReturn: true,
- prefixed: true,
- functionBody: true);
+ prefixed: true);
}
Future<void> test_CascadeExpression_selector2_withTrailingReturn() async {
@@ -510,8 +418,7 @@
constructors: true,
returnValue: true,
voidReturn: true,
- prefixed: true,
- functionBody: true);
+ prefixed: true);
}
Future<void> test_CascadeExpression_target() async {
@@ -521,8 +428,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_CatchClause_typed() async {
@@ -532,8 +438,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_CatchClause_untyped() async {
@@ -543,8 +448,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_CommentReference() async {
@@ -561,51 +465,31 @@
Future<void> test_ConditionalExpression_elseExpression() async {
// SimpleIdentifier ConditionalExpression ReturnStatement
addTestSource('class C {foo(){var f; {var x;} return a ? T1 : T^}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ConditionalExpression_elseExpression_empty() async {
// SimpleIdentifier ConditionalExpression ReturnStatement
addTestSource('class C {foo(){var f; {var x;} return a ? T1 : ^}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ConditionalExpression_partial_thenExpression() async {
// SimpleIdentifier ConditionalExpression ReturnStatement
addTestSource('class C {foo(){var f; {var x;} return a ? T^}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ConditionalExpression_partial_thenExpression_empty() async {
// SimpleIdentifier ConditionalExpression ReturnStatement
addTestSource('class C {foo(){var f; {var x;} return a ? ^}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ConditionalExpression_thenExpression() async {
// SimpleIdentifier ConditionalExpression ReturnStatement
addTestSource('class C {foo(){var f; {var x;} return a ? T^ : c}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ConstructorFieldInitializer_name() async {
@@ -647,21 +531,13 @@
Future<void> test_DoStatement() async {
// SimpleIdentifier DoStatement Block
addTestSource('main() {do{} while(^x);}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ExpressionFunctionBody() async {
// SimpleIdentifier ExpressionFunctionBody FunctionExpression
addTestSource('m(){[1].forEach((x)=>^x);}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ExpressionStatement() async {
@@ -671,18 +547,13 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_ForEachStatement() async {
// SimpleIdentifier ForEachStatement Block
addTestSource('main() {for(z in ^zs) {}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ForEachStatement_body_typed() async {
@@ -692,8 +563,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_ForEachStatement_body_untyped() async {
@@ -703,41 +573,28 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_ForEachStatement_iterable() async {
// SimpleIdentifier ForEachStatement Block
addTestSource('main(args) {for (int foo in ^) {}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ForElement_body() async {
addTestSource('main(args) {[for (var foo in [0]) ^];}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ForElement_forEachParts_iterable() async {
addTestSource('main(args) {[for (var foo in ^) foo];}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ForElement_forEachParts_type() async {
addTestSource('main(args) {[for (i^ foo in [0]) foo];}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_FormalParameter_partialType() async {
@@ -776,11 +633,7 @@
Future<void> test_ForStatement_condition() async {
// SimpleIdentifier ForStatement
addTestSource('main() {for (int index = 0; i^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ForStatement_updaters() async {
@@ -791,18 +644,13 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_ForStatement_updaters_prefix_expression() async {
// SimpleIdentifier PrefixExpression ForStatement
addTestSource('main() {for (int index = 0; index < 10; ++i^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_IfElement_condition() async {
@@ -811,11 +659,7 @@
[if (^)];
}
''');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_IfElement_else() async {
@@ -828,7 +672,6 @@
constructors: true,
returnValue: true,
typeNames: true,
- functionBody: true,
voidReturn: true);
}
@@ -842,7 +685,6 @@
constructors: true,
returnValue: true,
typeNames: true,
- functionBody: true,
voidReturn: true);
}
@@ -853,57 +695,36 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_IfStatement_condition() async {
// SimpleIdentifier IfStatement Block BlockFunctionBody
addTestSource('main(){var a; if (^)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_IfStatement_empty() async {
// SimpleIdentifier PrefixIdentifier IfStatement
addTestSource('class A {foo() {A a; if (^) something}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_IfStatement_invocation() async {
// SimpleIdentifier PrefixIdentifier IfStatement
addTestSource('main() {var a; if (a.^) something}');
await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- prefixed: true,
- functionBody: true);
+ constructors: true, returnValue: true, typeNames: true, prefixed: true);
}
Future<void> test_IndexExpression() async {
addTestSource('class C {foo(){var f; {var x;} f[^]}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_IndexExpression2() async {
addTestSource('class C {foo(){var f; {var x;} f[T^]}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_InstanceCreationExpression_keyword() async {
@@ -913,8 +734,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_InstanceCreationExpression_keyword2() async {
@@ -924,76 +744,50 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_InterpolationExpression() async {
// SimpleIdentifier InterpolationExpression StringInterpolation
addTestSource('main() {String name; print("hello \$^");}');
- await assertOpType(
- constructors: true, returnValue: true, functionBody: true);
+ await assertOpType(constructors: true, returnValue: true);
}
Future<void> test_InterpolationExpression_block() async {
// SimpleIdentifier InterpolationExpression StringInterpolation
addTestSource('main() {String name; print("hello \${n^}");}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_InterpolationExpression_prefix_selector() async {
// SimpleIdentifier PrefixedIdentifier InterpolationExpression
addTestSource('main() {String name; print("hello \${name.^}");}');
await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- prefixed: true,
- functionBody: true);
+ constructors: true, returnValue: true, typeNames: true, prefixed: true);
}
Future<void> test_InterpolationExpression_prefix_target() async {
// SimpleIdentifier PrefixedIdentifier InterpolationExpression
addTestSource('main() {String name; print("hello \${nam^e.length}");}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_IsExpression_target() async {
// IfStatement Block BlockFunctionBody
addTestSource('main(){var a; if (^ is A)}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_Literal_list() async {
// ']' ListLiteral ArgumentList MethodInvocation
addTestSource('main() {var Some; print([^]);}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_Literal_list2() async {
// SimpleIdentifier ListLiteral ArgumentList MethodInvocation
addTestSource('main() {var Some; print([S^]);}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_MapLiteralEntry() async {
@@ -1026,18 +820,13 @@
returnValue: true,
typeNames: true,
voidReturn: true,
- prefixed: true,
- methodBody: true);
+ prefixed: true);
}
Future<void> test_PostfixExpression() async {
// SimpleIdentifier PostfixExpression ForStatement
addTestSource('int x = 0; main() {ax+^+;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_PrefixedIdentifier_class_const() async {
@@ -1048,8 +837,7 @@
returnValue: true,
typeNames: true,
voidReturn: true,
- prefixed: true,
- functionBody: true);
+ prefixed: true);
}
Future<void> test_PrefixedIdentifier_class_imported() async {
@@ -1060,8 +848,7 @@
returnValue: true,
typeNames: true,
voidReturn: true,
- prefixed: true,
- functionBody: true);
+ prefixed: true);
}
Future<void> test_PrefixedIdentifier_prefix() async {
@@ -1071,8 +858,7 @@
constructors: true,
typeNames: true,
returnValue: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_PropertyAccess_expression() async {
@@ -1083,8 +869,7 @@
returnValue: true,
typeNames: true,
voidReturn: true,
- prefixed: true,
- methodBody: true);
+ prefixed: true);
}
Future<void> test_PropertyAccess_selector() async {
@@ -1095,18 +880,13 @@
returnValue: true,
typeNames: true,
voidReturn: true,
- prefixed: true,
- methodBody: true);
+ prefixed: true);
}
Future<void> test_ReturnStatement() async {
// ReturnStatement Block
addTestSource('f() { var vvv = 42; return ^ }');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_SpreadElement() async {
@@ -1115,11 +895,7 @@
[...^];
}
''');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_SwitchCase_between() async {
@@ -1129,28 +905,19 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_SwitchCase_expression1() async {
// SimpleIdentifier SwitchCase SwitchStatement
addTestSource('''m() {switch (x) {case ^D: return;}}''');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_SwitchCase_expression2() async {
// SimpleIdentifier SwitchCase SwitchStatement
addTestSource('''m() {switch (x) {case ^}}''');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_SwitchDefault_between() async {
@@ -1160,8 +927,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_SwitchStatement_body_end() async {
@@ -1171,8 +937,7 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_SwitchStatement_body_end2() async {
@@ -1181,39 +946,26 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- functionBody: true);
+ voidReturn: true);
}
Future<void> test_SwitchStatement_expression1() async {
// SimpleIdentifier SwitchStatement Block
addTestSource('main() {switch(^k) {case 1:{}}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_SwitchStatement_expression2() async {
// SimpleIdentifier SwitchStatement Block
addTestSource('main() {switch(k^) {case 1:{}}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
//
Future<void> test_SwitchStatement_expression_empty() async {
// SimpleIdentifier SwitchStatement Block
addTestSource('main() {switch(^) {case 1:{}}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_ThisExpression_block() async {
@@ -1228,8 +980,7 @@
constructors: true,
returnValue: true,
voidReturn: true,
- prefixed: true,
- methodBody: true);
+ prefixed: true);
}
Future<void> test_ThisExpression_constructor() async {
@@ -1242,18 +993,13 @@
constructors: true,
returnValue: true,
voidReturn: true,
- prefixed: true,
- constructorBody: true);
+ prefixed: true);
}
Future<void> test_ThrowExpression() async {
// SimpleIdentifier ThrowExpression ExpressionStatement
addTestSource('main() {throw ^;}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_VariableDeclarationStatement_afterSemicolon() async {
@@ -1263,40 +1009,27 @@
constructors: true,
returnValue: true,
typeNames: true,
- voidReturn: true,
- methodBody: true);
+ voidReturn: true);
}
Future<void> test_VariableDeclarationStatement_RHS() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement
addTestSource('class C {bar(){var f; {var x;} var e = ^}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_VariableDeclarationStatement_RHS_missing_semicolon() async {
// VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement
addTestSource('class C {bar(){var f; {var x;} var e = ^ var g}}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- methodBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
Future<void> test_WhileStatement() async {
// SimpleIdentifier WhileStatement Block
addTestSource('mth() { while (b^) {} }}');
- await assertOpType(
- constructors: true,
- returnValue: true,
- typeNames: true,
- functionBody: true);
+ await assertOpType(constructors: true, returnValue: true, typeNames: true);
}
@failingTest
@@ -1315,7 +1048,7 @@
'main() { new A.b(^); }'
'class A{ A.b({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_constructor_named_resolved_1_1() async {
@@ -1324,7 +1057,7 @@
'main() { new A.b(o^); }'
'class A { A.b({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_constructor_resolved_1_0() async {
@@ -1333,7 +1066,7 @@
'main() { new A(^); }'
'class A{ A({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_constructor_resolved_1_1() async {
@@ -1342,7 +1075,7 @@
'main() { new A(o^); }'
'class A { A({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_factory_named_resolved_1_0() async {
@@ -1351,7 +1084,7 @@
'main() { new A.b(^); }'
'class A{ factory A.b({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_factory_named_resolved_1_1() async {
@@ -1360,7 +1093,7 @@
'main() { new A.b(o^); }'
'class A { factory A.b({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_factory_resolved_1_0() async {
@@ -1369,7 +1102,7 @@
'main() { new A(^); }'
'class A{ factory A({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_factory_resolved_1_1() async {
@@ -1378,163 +1111,163 @@
'main() { new A(o^); }'
'class A { factory A({one, two}) {} }',
);
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_method_resolved_1_0() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('main() { foo(^);} foo({one, two}) {}');
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_method_resolved_1_1() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('main() { foo(o^);} foo({one, two}) {}');
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_ArgumentList_resolved_2_0() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('void main() {int.parse("16", ^)}');
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_AsExpression() async {
// SimpleIdentifier TypeName AsExpression
addTestSource('class A {var b; X _c; foo() {var a; (a as ^).foo();}');
- await assertOpType(typeNames: true, methodBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_AsIdentifier2() async {
addTestSource('class A {var asdf; foo() {A as^}');
- await assertOpType(methodBody: true);
+ await assertOpType();
}
Future<void> test_AssignmentExpression_name() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('class A {} main() {int a; int ^b = 1;}');
- await assertOpType(varNames: true, functionBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_Block_catch_1a() async {
// '}' Block BlockFunctionBody FunctionExpression
addTestSource('main() {try {} ^}');
// Only return 'on', 'catch', and 'finally' keywords
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_Block_catch_1b() async {
// [ExpressionStatement 'c'] Block BlockFunctionBody
addTestSource('main() {try {} c^}');
// Only return 'on', 'catch', and 'finally' keywords
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_Block_catch_1c() async {
// [EmptyStatement] Block BlockFunctionBody FunctionExpression
addTestSource('main() {try {} ^;}');
// Only return 'on', 'catch', and 'finally' keywords
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_Block_catch_1d() async {
// [VariableDeclarationStatement 'Foo foo'] Block BlockFunctionBody
addTestSource('main() {try {} ^ Foo foo;}');
// Only return 'on', 'catch', and 'finally' keywords
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_Block_final() async {
addTestSource('main() {final ^}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_Block_final2() async {
addTestSource('main() {final S^ v;}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_Block_final3() async {
addTestSource('main() {final ^ v;}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_Block_final_final() async {
addTestSource('main() {final ^ final S x;}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_Block_final_final2() async {
addTestSource('main() {final S^ final S x;}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_Break_after_label() async {
addTestSource('main() { foo: while (true) { break foo ^ ; } }');
- await assertOpType(/* No valid completions */ functionBody: true);
+ await assertOpType(/* No valid completions */);
}
Future<void> test_Break_before_label() async {
addTestSource('main() { foo: while (true) { break ^ foo; } }');
- await assertOpType(statementLabel: true, functionBody: true);
+ await assertOpType(statementLabel: true);
}
Future<void> test_Break_no_label() async {
addTestSource('main() { foo: while (true) { break ^; } }');
- await assertOpType(statementLabel: true, functionBody: true);
+ await assertOpType(statementLabel: true);
}
Future<void> test_catch_4a1() async {
addTestSource('main() {try {} ^ on SomeException {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_catch_4a2() async {
addTestSource('main() {try {} c^ on SomeException {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_catch_4b1() async {
addTestSource('main() {try {} ^ catch (e) {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_catch_4b2() async {
addTestSource('main() {try {} c^ catch (e) {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_catch_4c1() async {
addTestSource('main() {try {} ^ finally {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_catch_4c2() async {
addTestSource('main() {try {} c^ finally {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_catch_5a() async {
addTestSource('main() {try {} on ^ finally {}}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_catch_5b() async {
addTestSource('main() {try {} on E^ finally {}}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_CatchClause_onType() async {
// TypeName CatchClause TryStatement
addTestSource('class A {a() {try{var x;} on ^ {}}}');
- await assertOpType(typeNames: true, methodBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_CatchClause_onType_noBrackets() async {
// TypeName CatchClause TryStatement
addTestSource('class A {a() {try{var x;} on ^}}');
- await assertOpType(typeNames: true, methodBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_ClassDeclaration_body() async {
@@ -1570,14 +1303,14 @@
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new X.^}');
- await assertOpType(constructors: true, prefixed: true, functionBody: true);
+ await assertOpType(constructors: true, prefixed: true);
}
Future<void> test_ConstructorName_name_resolved() async {
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new Str^ing.fromCharCodes([]);}');
- await assertOpType(constructors: true, functionBody: true);
+ await assertOpType(constructors: true);
}
Future<void> test_ConstructorName_nameAndPrefix_resolved() async {
@@ -1587,68 +1320,65 @@
import 'dart:core' as core;
main() {new core.String.from^CharCodes([]);}
''');
- await assertOpType(constructors: true, prefixed: true, functionBody: true);
+ await assertOpType(constructors: true, prefixed: true);
}
Future<void> test_ConstructorName_resolved() async {
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new String.fr^omCharCodes([]);}');
- await assertOpType(constructors: true, prefixed: true, functionBody: true);
+ await assertOpType(constructors: true, prefixed: true);
}
Future<void> test_ConstructorName_unresolved() async {
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new String.fr^omCharCodes([]);}');
- await assertOpType(constructors: true, prefixed: true, functionBody: true);
+ await assertOpType(constructors: true, prefixed: true);
}
Future<void> test_Continue_after_label() async {
addTestSource('main() { foo: while (true) { continue foo ^ ; } }');
- await assertOpType(/* No valid completions */ functionBody: true);
+ await assertOpType(/* No valid completions */);
}
Future<void> test_Continue_before_label() async {
addTestSource('main() { foo: while (true) { continue ^ foo; } }');
- await assertOpType(
- statementLabel: true, caseLabel: true, functionBody: true);
+ await assertOpType(statementLabel: true, caseLabel: true);
}
Future<void> test_Continue_no_label() async {
addTestSource('main() { foo: while (true) { continue ^; } }');
- await assertOpType(
- statementLabel: true, caseLabel: true, functionBody: true);
+ await assertOpType(statementLabel: true, caseLabel: true);
}
Future<void> test_DoubleLiteral() async {
addTestSource('main() { print(1.2^); }');
- // TODO expected functionBody: true
- await assertOpType(functionBody: false);
+ await assertOpType();
}
Future<void> test_ExpressionStatement_name() async {
// ExpressionStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class C {a() {C ^}}');
- await assertOpType(varNames: true, methodBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_ExpressionStatement_name_semicolon() async {
// ExpressionStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class C {a() {C ^;}}');
- await assertOpType(varNames: true, methodBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_ExpressionStatement_prefixed_name() async {
// ExpressionStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class C {a() {x.Y ^}}');
- await assertOpType(varNames: true, methodBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_ExpressionStatement_prefixed_name_semicolon() async {
// ExpressionStatement Block BlockFunctionBody MethodDeclaration
addTestSource('class C {a() {x.Y ^;}}');
- await assertOpType(varNames: true, methodBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_ExtendsClause() async {
@@ -1674,31 +1404,31 @@
Future<void> test_ForEachStatement_loopVariable() async {
// SimpleIdentifier ForEachStatement Block
addTestSource('main(args) {for (^ in args) {}}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_ForEachStatement_loopVariable_name() async {
// DeclaredIdentifier ForEachStatement Block
addTestSource('main(args) {for (String ^ in args) {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_ForEachStatement_loopVariable_name2() async {
// DeclaredIdentifier ForEachStatement Block
addTestSource('main(args) {for (String f^ in args) {}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_ForEachStatement_loopVariable_type() async {
// SimpleIdentifier ForEachStatement Block
addTestSource('main(args) {for (^ foo in args) {}}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_ForEachStatement_loopVariable_type2() async {
// DeclaredIdentifier ForEachStatement Block
addTestSource('main(args) {for (S^ foo in args) {}}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_FormalParameterList() async {
@@ -1710,24 +1440,24 @@
Future<void> test_ForStatement_initializer() async {
// SimpleIdentifier ForStatement
addTestSource('main() {List a; for (^)}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_ForStatement_initializer_inKeyword() async {
addTestSource('main() { for (var v i^) }');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_ForStatement_initializer_type() async {
// SimpleIdentifier ForStatement
addTestSource('main() {List a; for (i^ v = 0;)}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void>
test_ForStatement_initializer_variableNameEmpty_afterType() async {
addTestSource('main() { for (String ^) }');
- await assertOpType(varNames: true, functionBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_FunctionDeclaration1() async {
@@ -1890,7 +1620,7 @@
Future<void> test_FunctionExpressionInvocation() async {
// ArgumentList FunctionExpressionInvocation ExpressionStatement
addTestSource('main() { ((x) => x + 7)^(2) }');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_FunctionTypeAlias() async {
@@ -1916,43 +1646,41 @@
Future<void> test_InstanceCreationExpression() async {
// SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
addTestSource('class C {foo(){var f; {var x;} new ^}}');
- await assertOpType(constructors: true, methodBody: true);
+ await assertOpType(constructors: true);
}
Future<void> test_InstanceCreationExpression_trailingStmt() async {
// SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
addTestSource('class C {foo(){var f; {var x;} new ^ int x = 7;}}');
- await assertOpType(constructors: true, methodBody: true);
+ await assertOpType(constructors: true);
}
Future<void> test_IntegerLiteral_inArgumentList() async {
- // TODO expected functionBody: true
addTestSource('main() { print(1^); }');
- await assertOpType(functionBody: false);
+ await assertOpType();
}
Future<void> test_IntegerLiteral_inListLiteral() async {
- // TODO expected functionBody: true
addTestSource('main() { var items = [1^]; }');
- await assertOpType(functionBody: false);
+ await assertOpType();
}
Future<void> test_IsExpression() async {
// SimpleIdentifier TypeName IsExpression IfStatement
addTestSource('main() {var x; if (x is ^) { }}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_IsExpression_type_partial() async {
// SimpleIdentifier TypeName IsExpression IfStatement
addTestSource('main(){var a; if (a is Obj^)}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_Literal_string() async {
// SimpleStringLiteral ExpressionStatement Block
addTestSource('class A {a() {"hel^lo"}}');
- await assertOpType(methodBody: true);
+ await assertOpType();
}
Future<void> test_MethodDeclaration_inClass1() async {
@@ -2147,7 +1875,7 @@
main() { f(3, ^); }
void f(int a, {int b}) {}
''');
- await assertOpType(namedArgs: true, functionBody: true);
+ await assertOpType(namedArgs: true);
}
Future<void> test_OnClause() async {
@@ -2159,25 +1887,25 @@
Future<void> test_PropertyAccess_noTarget() async {
// SimpleIdentifier PropertyAccess ExpressionStatement
addTestSource('main() {.^}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_PropertyAccess_noTarget2() async {
// SimpleIdentifier PropertyAccess CascadeExpressions
addTestSource('main() {.^.}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_PropertyAccess_noTarget3() async {
// SimpleIdentifier PropertyAccess CascadeExpressions
addTestSource('main() {..^}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_SimpleFormalParameter_closure() async {
// SimpleIdentifier SimpleFormalParameter FormalParameterList
addTestSource('mth() { PNGS.sort((String a, Str^) => a.compareTo(b)); }');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_SimpleFormalParameter_name_typed() async {
@@ -2249,19 +1977,19 @@
Future<void> test_SwitchCase_before() async {
// SwitchCase SwitchStatement Block
addTestSource('main() {switch(k) {^case 1:}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_SwitchDefault_before() async {
// SwitchDefault SwitchStatement Block
addTestSource('main() {switch(k) { ^ default: return;}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_SwitchStatement_body_empty() async {
// Token('}') SwitchStatement Block
addTestSource('main() {switch(k) {^}}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_ThisExpression_constructor_param() async {
@@ -2328,13 +2056,13 @@
Future<void> test_TypeArgumentList() async {
// SimpleIdentifier BinaryExpression ExpressionStatement
addTestSource('main() { C<^> c; }');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_TypeArgumentList2() async {
// TypeName TypeArgumentList TypeName
addTestSource('main() { C<C^> c; }');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
Future<void> test_TypeParameter() async {
@@ -2353,27 +2081,27 @@
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('main() {var ^}');
- await assertOpType(functionBody: true);
+ await assertOpType();
}
Future<void> test_VariableDeclaration_name_hasSome_parameterizedType() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('main() {List<int> m^}');
- await assertOpType(varNames: true, functionBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_VariableDeclaration_name_hasSome_simpleType() async {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
addTestSource('main() {String m^}');
- await assertOpType(varNames: true, functionBody: true);
+ await assertOpType(varNames: true);
}
Future<void> test_VariableDeclarationList_final() async {
// VariableDeclarationList VariableDeclarationStatement Block
addTestSource('main() {final ^}');
- await assertOpType(typeNames: true, functionBody: true);
+ await assertOpType(typeNames: true);
}
}
@@ -2401,9 +2129,6 @@
bool returnValue = false,
bool statementLabel = false,
bool staticMethodBody = false,
- bool methodBody = false,
- bool functionBody = false,
- bool constructorBody = false,
bool typeNames = false,
bool varNames = false,
bool voidReturn = false,
@@ -2430,10 +2155,6 @@
reason: 'voidReturn');
expect(visitor.inStaticMethodBody, staticMethodBody,
reason: 'staticMethodBody');
- expect(visitor.inMethodBody, methodBody, reason: 'methodBody');
- expect(visitor.inFunctionBody, functionBody, reason: 'functionBody');
- expect(visitor.inConstructorBody, constructorBody,
- reason: 'constructorBody');
expect(visitor.isPrefixed, prefixed, reason: 'prefixed');
expect(visitor.suggestKind, kind, reason: 'suggestion kind');
}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 2a882d5..4f3613f 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -1165,9 +1165,29 @@
subscription.pause();
exitCode = 0;
if (line == null) exit(0);
- List<String> args = <String>[];
- args.addAll(batchArguments);
- args.addAll(splitLine(line, windows: Platform.isWindows));
+ List<String> testArgs = splitLine(line, windows: Platform.isWindows);
+
+ // Merge experiment flags from the batch and the test arguments.
+ //
+ // Batch arguments are provided when the batch compiler is created, and
+ // contain flags that are generally enabled for all tests. Tests
+ // may have more specific flags that could conflict with the batch flags.
+ // For example, the compiler might be setup to run the non-nullable
+ // experiment, but the test may enable more experiments.
+ //
+ // At this time we are only aware of these kind of conflicts with
+ // experiment flags, so we handle those directly. We know that if the
+ // batch compiler has an experiment flag, the test itself will
+ // have it too (either identical or more accurate when the test requires
+ // additional experiments).
+ bool hasExperiment(List<String> list) =>
+ list.any((a) => a.startsWith('--enable-experiment'));
+ assert(!hasExperiment(batchArguments) || hasExperiment(testArgs));
+ List<String> args = [
+ for (var arg in batchArguments)
+ if (!arg.startsWith('--enable-experiment')) arg,
+ ...testArgs,
+ ];
return internalMain(args,
kernelInitializedCompilerState: kernelInitializedCompilerState);
}).catchError((exception, trace) {
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 7083e91..3c49a8c 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -314,10 +314,10 @@
DartType type = typeUse.type;
switch (typeUse.kind) {
case TypeUseKind.TYPE_LITERAL:
- if (type is InterfaceType) {
- InterfaceType interface = type;
+ var typeWithoutNullability = type.withoutNullability;
+ if (typeWithoutNullability is InterfaceType) {
dependencies.addClass(
- interface.element, typeUse.deferredImport);
+ typeWithoutNullability.element, typeUse.deferredImport);
}
break;
case TypeUseKind.CONST_INSTANTIATION:
@@ -395,6 +395,7 @@
}
if (constant is InstantiationConstantValue) {
for (DartType type in constant.typeArguments) {
+ type = type.withoutNullability;
if (type is InterfaceType) {
_updateClassRecursive(
closedWorld, type.element, oldSet, newSet, queue);
@@ -549,7 +550,7 @@
LibraryEntity library, Spannable context) {
if (info.isDeferred || compiler.options.newDeferredSplit) return;
if (constant is TypeConstantValue) {
- var type = constant.representedType;
+ var type = constant.representedType.withoutNullability;
if (type is InterfaceType) {
var imports = classImportsTo(type.element, library);
_fixDependencyInfo(
@@ -1465,7 +1466,10 @@
/// Returns the [OutputUnit] where [constant] belongs.
OutputUnit outputUnitForConstant(ConstantValue constant) {
if (!isProgramSplit) return mainOutputUnit;
- return _constantToUnit[constant];
+ OutputUnit unit = _constantToUnit[constant];
+ // TODO(sigmund): enforce unit is not null: it is sometimes null on some
+ // corner cases on internal apps.
+ return unit ?? mainOutputUnit;
}
OutputUnit outputUnitForConstantForTesting(ConstantValue constant) =>
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index 94e3f0a..669f45e 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -388,7 +388,8 @@
void addProcedure(ir.Procedure member,
{bool includeStatic, bool includeNoSuchMethodForwarders}) {
- if (member.isForwardingStub && member.isAbstract) {
+ if ((member.isMemberSignature || member.isForwardingStub) &&
+ member.isAbstract) {
// Skip abstract forwarding stubs. These are never emitted but they
// might shadow the inclusion of a mixed in method in code like:
//
@@ -403,7 +404,8 @@
// `Mixin.method` is inherited by `Class`.
return;
}
- if (member.isForwardingStub && cls.isAnonymousMixin) {
+ if ((member.isMemberSignature || member.isForwardingStub) &&
+ cls.isAnonymousMixin) {
return;
}
if (!includeStatic && member.isStatic) return;
diff --git a/pkg/dart2native/pubspec.yaml b/pkg/dart2native/pubspec.yaml
index 99e6f94..feca449 100644
--- a/pkg/dart2native/pubspec.yaml
+++ b/pkg/dart2native/pubspec.yaml
@@ -1,8 +1,5 @@
name: dart2native
-version: 0.0.1
-author: Dart Team <misc@dartlang.org>
-homepage: https://github.com/dart-lang/sdk/tree/master/pkg/aot
-
+publish_to: none
# Add the bin/dart2native.dart script to the scripts pub installs.
executables:
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index e36af94..7317c59 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2577,7 +2577,14 @@
if (typeArgument is InterfaceType &&
typeArgument.classNode == _coreTypes.objectClass) {
// Normalize FutureOr of Object, Object?, Object*.
- normalizedType = typeArgument;
+ var nullable = futureOr.nullability == Nullability.nullable ||
+ typeArgument.nullability == Nullability.nullable;
+ var legacy = futureOr.nullability == Nullability.legacy ||
+ typeArgument.nullability == Nullability.legacy;
+ var nullability = nullable
+ ? Nullability.nullable
+ : legacy ? Nullability.legacy : Nullability.nonNullable;
+ normalizedType = typeArgument.withNullability(nullability);
} else if (typeArgument is NeverType) {
// FutureOr<Never> --> Future<Never>
normalizedType = InterfaceType(
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index 3a3084c..cb9e036 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -594,10 +594,6 @@
Expect.throws(f, (error) => error is AssertionError, reason);
}
- static void throwsCastError(void f(), [String reason = "CastError"]) {
- Expect.throws(f, (error) => error is CastError, reason);
- }
-
static void throwsFormatException(void f(),
[String reason = "FormatException"]) {
Expect.throws(f, (error) => error is FormatException, reason);
@@ -707,10 +703,10 @@
final String name;
ExpectException(this.message)
- : name = (_getTestName == null) ? null : _getTestName();
+ : name = (_getTestName == null) ? "" : _getTestName();
String toString() {
- if (name != null) return 'In test "$name" $message';
+ if (name != "") return 'In test "$name" $message';
return message;
}
}
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index b0cacef..a65e500 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -512,7 +512,7 @@
/// If the file does exist but is invalid an error is always reported and an
/// empty package config is returned.
Future<PackageConfig> _createPackagesFromFile(
- Uri requestedUri, bool forceCreation) async {
+ Uri requestedUri, bool forceCreation, bool requireJson) async {
Uint8List contents = await _readFile(requestedUri, forceCreation);
if (contents == null) {
if (forceCreation) {
@@ -524,14 +524,7 @@
_packagesUri = requestedUri;
try {
- return await loadPackageConfigUri(requestedUri, preferNewest: false,
- loader: (uri) {
- if (uri != requestedUri) {
- throw new StateError(
- "Unexpected request from package config package");
- }
- return new Future.value(contents);
- }, onError: (Object error) {
+ void Function(Object error) onError = (Object error) {
if (error is FormatException) {
report(
templatePackagesFileFormat
@@ -543,7 +536,19 @@
templateCantReadFile.withArguments(requestedUri, "$error"),
Severity.error);
}
- });
+ };
+ if (requireJson) {
+ return PackageConfig.parseBytes(contents, requestedUri,
+ onError: onError);
+ }
+ return await loadPackageConfigUri(requestedUri, preferNewest: false,
+ loader: (uri) {
+ if (uri != requestedUri) {
+ throw new StateError(
+ "Unexpected request from package config package");
+ }
+ return new Future.value(contents);
+ }, onError: onError);
} on FormatException catch (e) {
report(
templatePackagesFileFormat
@@ -566,16 +571,17 @@
/// (relative to the .packages file) `package_config.json` file exists, the
/// `package_config.json` file will be used instead.
Future<PackageConfig> createPackagesFromFile(Uri file) async {
- if (file.path.endsWith("/.dart_tool/package_config.json")) {
- // Already a package config json file.
- return _createPackagesFromFile(file, true);
- } else {
+ // If the input is a ".packages" file we assume the standard layout, and
+ // if a ".dart_tool/package_config.json" exists, we'll use that (and require
+ // it to be a json file).
+ if (file.path.endsWith("/.packages")) {
// .packages -> try the package_config first.
Uri tryFirst = file.resolve(".dart_tool/package_config.json");
- PackageConfig result = await _createPackagesFromFile(tryFirst, false);
+ PackageConfig result =
+ await _createPackagesFromFile(tryFirst, false, true);
if (result != null) return result;
- return await _createPackagesFromFile(file, true);
}
+ return _createPackagesFromFile(file, true, false);
}
/// Finds a package resolution strategy using a [FileSystem].
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index df4c39b..02883c3 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -8,6 +8,7 @@
import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/core_types.dart';
+import 'package:kernel/src/future_or.dart';
import 'package:kernel/src/legacy_erasure.dart';
import '../constant_context.dart' show ConstantContext;
@@ -774,7 +775,7 @@
if (_lateSetter != null) {
_lateSetter.function.positionalParameters.single.type = value;
}
- if (!_type.isPotentiallyNullable && !_forceIncludeIsSetField) {
+ if (!isPotentiallyNullable(_type, null) && !_forceIncludeIsSetField) {
// We only need the is-set field if the field is potentially nullable.
// Otherwise we use `null` to signal that the field is uninitialized.
_lateIsSetField = null;
@@ -934,7 +935,8 @@
Statement _createSetterBody(
CoreTypes coreTypes, String name, VariableDeclaration parameter) {
assert(_type != null, "Type has not been computed for field $name.");
- return late_lowering.createSetterBody(fileOffset, name, parameter, _type,
+ return late_lowering.createSetterBody(
+ coreTypes, fileOffset, name, parameter, _type,
shouldReturnValue: false,
createVariableWrite: (Expression value) =>
_createFieldSet(_field, value),
@@ -989,7 +991,7 @@
CoreTypes coreTypes, String name, Expression initializer) {
assert(_type != null, "Type has not been computed for field $name.");
return late_lowering.createGetterWithInitializer(
- fileOffset, name, _type, initializer,
+ coreTypes, fileOffset, name, _type, initializer,
createVariableRead: _createFieldRead,
createVariableWrite: (Expression value) =>
_createFieldSet(_field, value),
diff --git a/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
index 521e537..027d8c3 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
@@ -74,13 +74,15 @@
FunctionType build(LibraryBuilder library,
[TypedefType origin, bool notInstanceContext]) {
DartType builtReturnType =
- returnType?.build(library) ?? const DynamicType();
+ returnType?.build(library, null, notInstanceContext) ??
+ const DynamicType();
List<DartType> positionalParameters = <DartType>[];
List<NamedType> namedParameters;
int requiredParameterCount = 0;
if (formals != null) {
for (FormalParameterBuilder formal in formals) {
- DartType type = formal.type?.build(library) ?? const DynamicType();
+ DartType type = formal.type?.build(library, null, notInstanceContext) ??
+ const DynamicType();
if (formal.isPositional) {
positionalParameters.add(type);
if (formal.isRequired) requiredParameterCount++;
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 7cadadf..b3f2461 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -5764,8 +5764,10 @@
if (!isDeclarationInstanceContext &&
(typeParameter.parent is Class ||
typeParameter.parent is Extension)) {
- message = fasta.messageTypeVariableInStaticContext
- .withLocation(fileUri, charOffset, typeParameter.name.length);
+ message = fasta.messageTypeVariableInStaticContext.withLocation(
+ builder.fileUri ?? fileUri,
+ builder.charOffset ?? charOffset,
+ typeParameter.name.length);
} else if (constantContext == ConstantContext.inferred) {
message = fasta.messageTypeVariableInConstantContext
.withLocation(fileUri, charOffset, typeParameter.name.length);
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index be297da..a5d05ad 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -2943,7 +2943,7 @@
}
}
return new NamedTypeBuilder(
- targetName, nullabilityBuilder, argumentBuilders)
+ targetName, nullabilityBuilder, argumentBuilders, _uri, fileOffset)
..bind(declaration);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 60fa08e..9cf058f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -2347,7 +2347,8 @@
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
if (receiverType is! DynamicType &&
receiverType is! InvalidType &&
- receiverType.isPotentiallyNullable) {
+ isPotentiallyNullable(
+ receiverType, inferrer.coreTypes.futureOrClass)) {
if (inferrer.nnbdMode == NnbdMode.Weak) {
inferrer.helper.addProblem(
templateNullableExpressionCallWarning.withArguments(
@@ -3587,7 +3588,8 @@
}
}
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
- if (leftType is! DynamicType && leftType.isPotentiallyNullable) {
+ if (leftType is! DynamicType &&
+ isPotentiallyNullable(leftType, inferrer.coreTypes.futureOrClass)) {
if (inferrer.nnbdMode == NnbdMode.Weak) {
inferrer.helper.addProblem(
templateNullableOperatorCallWarning.withArguments(
@@ -3675,7 +3677,8 @@
}
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
if (expressionType is! DynamicType &&
- expressionType.isPotentiallyNullable) {
+ isPotentiallyNullable(
+ expressionType, inferrer.coreTypes.futureOrClass)) {
// TODO(johnniwinther): Special case 'unary-' in messages. It should
// probably be referred to as "Unary operator '-' ...".
if (inferrer.nnbdMode == NnbdMode.Weak) {
@@ -3755,7 +3758,8 @@
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
if (receiverType is! DynamicType &&
receiverType is! InvalidType &&
- receiverType.isPotentiallyNullable) {
+ isPotentiallyNullable(
+ receiverType, inferrer.coreTypes.futureOrClass)) {
if (inferrer.nnbdMode == NnbdMode.Weak) {
inferrer.helper.addProblem(
templateNullableOperatorCallWarning.withArguments(
@@ -3815,7 +3819,9 @@
..fileOffset = fileOffset;
}
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
- if (receiverType is! DynamicType && receiverType.isPotentiallyNullable) {
+ if (receiverType is! DynamicType &&
+ isPotentiallyNullable(
+ receiverType, inferrer.coreTypes.futureOrClass)) {
if (inferrer.nnbdMode == NnbdMode.Weak) {
inferrer.helper.addProblem(
templateNullableOperatorCallWarning.withArguments(
@@ -3937,7 +3943,8 @@
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
if (receiverType is! DynamicType &&
receiverType is! InvalidType &&
- receiverType.isPotentiallyNullable &&
+ isPotentiallyNullable(
+ receiverType, inferrer.coreTypes.futureOrClass) &&
!inferrer.matchesObjectMemberCall(
propertyName, const [], const [], const [])) {
if (inferrer.nnbdMode == NnbdMode.Weak) {
@@ -4020,7 +4027,9 @@
..fileOffset = fileOffset;
}
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
- if (receiverType is! DynamicType && receiverType.isPotentiallyNullable) {
+ if (receiverType is! DynamicType &&
+ isPotentiallyNullable(
+ receiverType, inferrer.coreTypes.futureOrClass)) {
if (inferrer.nnbdMode == NnbdMode.Weak) {
inferrer.helper.addProblem(
templateNullablePropertyAccessWarning.withArguments(
@@ -5409,7 +5418,7 @@
result.add(node);
VariableDeclaration isSetVariable;
- if (node.type.isPotentiallyNullable) {
+ if (isPotentiallyNullable(node.type, inferrer.coreTypes.futureOrClass)) {
isSetVariable = new VariableDeclaration('#${node.name}#isSet',
initializer: new BoolLiteral(false)..fileOffset = fileOffset,
type: inferrer.coreTypes.boolRawType(inferrer.library.nonNullable))
@@ -5446,7 +5455,11 @@
createVariableRead: createVariableRead,
createIsSetRead: createIsSetRead)
: late_lowering.createGetterWithInitializer(
- fileOffset, node.name, node.type, node.initializer,
+ inferrer.coreTypes,
+ fileOffset,
+ node.name,
+ node.type,
+ node.initializer,
createVariableRead: createVariableRead,
createVariableWrite: createVariableWrite,
createIsSetRead: createIsSetRead,
@@ -5481,7 +5494,7 @@
createVariableWrite: createVariableWrite,
createIsSetRead: createIsSetRead,
createIsSetWrite: createIsSetWrite)
- : late_lowering.createSetterBody(
+ : late_lowering.createSetterBody(inferrer.coreTypes,
fileOffset, node.name, setterParameter, node.type,
shouldReturnValue: true,
createVariableWrite: createVariableWrite,
@@ -5776,7 +5789,9 @@
void reportNonNullableInNullAwareWarningIfNeeded(
DartType operandType, String operationName, int offset) {
if (inferrer.isNonNullableByDefault && inferrer.performNnbdChecks) {
- if (operandType is! InvalidType && !operandType.isPotentiallyNullable) {
+ if (operandType is! InvalidType &&
+ !isPotentiallyNullable(
+ operandType, inferrer.coreTypes.futureOrClass)) {
inferrer.library.addProblem(
templateNonNullableInNullAware.withArguments(
operationName, operandType, inferrer.isNonNullableByDefault),
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index 171e1fd..51904ae 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -4,6 +4,7 @@
import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/core_types.dart';
+import 'package:kernel/src/future_or.dart';
import '../names.dart';
@@ -15,13 +16,13 @@
/// uses [createGetterWithInitializerWithRecheck] instead. Late final locals
/// cannot have writes during initialization since they are not in scope in
/// their own initializer.
-Statement createGetterWithInitializer(
- int fileOffset, String name, DartType type, Expression initializer,
+Statement createGetterWithInitializer(CoreTypes coreTypes, int fileOffset,
+ String name, DartType type, Expression initializer,
{Expression createVariableRead({bool needsPromotion}),
Expression createVariableWrite(Expression value),
Expression createIsSetRead(),
Expression createIsSetWrite(Expression value)}) {
- if (type.isPotentiallyNullable) {
+ if (isPotentiallyNullable(type, coreTypes.futureOrClass)) {
// Generate:
//
// if (!_#isSet#field) {
@@ -48,7 +49,9 @@
// If [type] is a type variable with undetermined nullability we need
// to create a read of the field that is promoted to the type variable
// type.
- createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+ createVariableRead(
+ needsPromotion:
+ isPotentiallyNonNullable(type, coreTypes.futureOrClass)))
..fileOffset = fileOffset
])
..fileOffset = fileOffset;
@@ -113,7 +116,7 @@
VariableDeclaration temp =
new VariableDeclaration.forValue(initializer, type: type)
..fileOffset = fileOffset;
- if (type.isPotentiallyNullable) {
+ if (isPotentiallyNullable(type, coreTypes.futureOrClass)) {
// Generate:
//
// if (!_#isSet#field) {
@@ -150,7 +153,9 @@
// If [type] is a type variable with undetermined nullability we need
// to create a read of the field that is promoted to the type variable
// type.
- createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+ createVariableRead(
+ needsPromotion:
+ isPotentiallyNonNullable(type, coreTypes.futureOrClass)))
..fileOffset = fileOffset
])
..fileOffset = fileOffset;
@@ -218,14 +223,16 @@
..fileOffset = fileOffset)
..fileOffset = fileOffset)
..fileOffset = fileOffset;
- if (type.isPotentiallyNullable) {
+ if (isPotentiallyNullable(type, coreTypes.futureOrClass)) {
// Generate:
//
// return _#isSet#field ? _#field : throw '...';
return new ReturnStatement(
new ConditionalExpression(
createIsSetRead()..fileOffset = fileOffset,
- createVariableRead(needsPromotion: type.isPotentiallyNonNullable)
+ createVariableRead(
+ needsPromotion:
+ isPotentiallyNonNullable(type, coreTypes.futureOrClass))
..fileOffset = fileOffset,
exception,
type)
@@ -262,8 +269,8 @@
/// Creates the body for the synthesized setter used to encode the lowering
/// of a non-final late field or local.
-Statement createSetterBody(
- int fileOffset, String name, VariableDeclaration parameter, DartType type,
+Statement createSetterBody(CoreTypes coreTypes, int fileOffset, String name,
+ VariableDeclaration parameter, DartType type,
{bool shouldReturnValue,
Expression createVariableWrite(Expression value),
Expression createIsSetWrite(Expression value)}) {
@@ -279,7 +286,7 @@
createVariableWrite(new VariableGet(parameter)..fileOffset = fileOffset)
..fileOffset = fileOffset);
- if (type.isPotentiallyNullable) {
+ if (isPotentiallyNullable(type, coreTypes.futureOrClass)) {
// Generate:
//
// _#isSet#field = true;
@@ -335,7 +342,7 @@
}
}
- if (type.isPotentiallyNullable) {
+ if (isPotentiallyNullable(type, coreTypes.futureOrClass)) {
// Generate:
//
// if (_#isSet#field) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index c823d27..b3b0a5f 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -1073,6 +1073,7 @@
}
}
});
+ ticker.logMs("Build outline expressions");
}
void buildClassHierarchy(
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index d2dbbc0..c9e3fe2 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -55,45 +55,64 @@
}
/// Returns [type] in which all promoted type variables have been replace with
-/// their unpromoted equivalents, and, if [library] is non-nullable by default,
-/// replaces all legacy types with their non-nullable equivalents.
+/// their unpromoted equivalents, and where all nullabilities have been
+/// normalized to the default nullability of [library].
+///
+/// If [library] is non-nullable by default all legacy types have been replaced
+/// with non-nullable types. Otherwise all non-legacy types have been replaced
+/// with legacy types.
DartType demoteTypeInLibrary(DartType type, Library library) {
if (library.isNonNullableByDefault) {
- return type.accept(const _DemotionNonNullification()) ?? type;
+ return type.accept(const _DemotionNullabilityNormalization(
+ demoteTypeVariables: true, forNonNullableByDefault: true)) ??
+ type;
} else {
- return type
- .accept(const _DemotionNonNullification(nonNullifyTypes: false)) ??
+ return type.accept(const _DemotionNullabilityNormalization(
+ demoteTypeVariables: true, forNonNullableByDefault: false)) ??
type;
}
}
-/// Returns [type] in which all legacy types have been replaced with
-/// non-nullable types.
-DartType nonNullifyInLibrary(DartType type, Library library) {
+/// Returns [type] normalized to the default nullability of [library].
+///
+/// If [library] is non-nullable by default all legacy types have been replaced
+/// with non-nullable types. Otherwise all non-legacy types have been replaced
+/// with legacy types.
+DartType normalizeNullabilityInLibrary(DartType type, Library library) {
if (library.isNonNullableByDefault) {
- return type.accept(
- const _DemotionNonNullification(demoteTypeVariables: false)) ??
+ return type.accept(const _DemotionNullabilityNormalization(
+ demoteTypeVariables: false, forNonNullableByDefault: true)) ??
+ type;
+ } else {
+ return type.accept(const _DemotionNullabilityNormalization(
+ demoteTypeVariables: false, forNonNullableByDefault: false)) ??
type;
}
- return type;
}
/// Visitor that replaces all promoted type variables the type variable itself
-/// and/or replaces all legacy types with non-nullable types.
+/// and normalizes the type nullabilities.
///
/// The visitor returns `null` if the type wasn't changed.
-class _DemotionNonNullification extends ReplacementVisitor {
+class _DemotionNullabilityNormalization extends ReplacementVisitor {
final bool demoteTypeVariables;
- final bool nonNullifyTypes;
+ final bool forNonNullableByDefault;
- const _DemotionNonNullification(
- {this.demoteTypeVariables: true, this.nonNullifyTypes: true})
- : assert(demoteTypeVariables || nonNullifyTypes);
+ const _DemotionNullabilityNormalization(
+ {this.demoteTypeVariables, this.forNonNullableByDefault})
+ : assert(demoteTypeVariables != null),
+ assert(forNonNullableByDefault != null);
@override
Nullability visitNullability(DartType node) {
- if (nonNullifyTypes && node.nullability == Nullability.legacy) {
- return Nullability.nonNullable;
+ if (forNonNullableByDefault) {
+ if (node.nullability == Nullability.legacy) {
+ return Nullability.nonNullable;
+ }
+ } else {
+ if (node.nullability != Nullability.legacy) {
+ return Nullability.legacy;
+ }
}
return null;
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 3a83aa2..cdb7703 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -945,7 +945,8 @@
if (callMember is Procedure && callMember.kind == ProcedureKind.Method) {
if (_shouldTearOffCall(contextType, expressionType)) {
needsTearoff = true;
- if (isStrongNullabilityMode && expressionType.isPotentiallyNullable) {
+ if (isStrongNullabilityMode &&
+ isPotentiallyNullable(expressionType, coreTypes.futureOrClass)) {
return AssignabilityKind.unassignableCantTearoff;
}
expressionType =
@@ -1898,7 +1899,7 @@
return const DynamicType();
}
if (forSyntheticVariable) {
- return nonNullifyInLibrary(initializerType, library.library);
+ return normalizeNullabilityInLibrary(initializerType, library.library);
} else {
return demoteTypeInLibrary(initializerType, library.library);
}
@@ -2424,7 +2425,7 @@
if (isNonNullableByDefault && performNnbdChecks) {
if (receiverType != null &&
receiverType is! DynamicType &&
- receiverType.isPotentiallyNullable &&
+ isPotentiallyNullable(receiverType, coreTypes.futureOrClass) &&
!matchesObjectMemberCall(targetName, inferredTypes,
positionalArgumentTypes, namedArgumentTypes)) {
// Use length 1 for .call -- in most cases its name is skipped.
diff --git a/pkg/front_end/lib/src/testing/compiler_common.dart b/pkg/front_end/lib/src/testing/compiler_common.dart
index e47eb41..0f698a84 100644
--- a/pkg/front_end/lib/src/testing/compiler_common.dart
+++ b/pkg/front_end/lib/src/testing/compiler_common.dart
@@ -105,8 +105,10 @@
options
..verify = true
..fileSystem = new HybridFileSystem(fs)
- ..additionalDills = additionalDills.map(toTestUri).toList()
- ..packagesFileUri = toTestUri('.packages');
+ ..additionalDills = additionalDills.map(toTestUri).toList();
+ if (options.packagesFileUri == null) {
+ options.packagesFileUri = toTestUri('.packages');
+ }
if (options.sdkSummary == null) {
options.sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart
index 17be137..b106164 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -51,7 +51,7 @@
this.librariesSpecificationUri,
this.compileSdk: false});
- void customizeCompilerOptions(CompilerOptions options) {}
+ void customizeCompilerOptions(CompilerOptions options, TestData testData) {}
}
// TODO(johnniwinther): Support annotations for compile-time errors.
@@ -293,7 +293,7 @@
options.compileSdk = config.compileSdk;
}
}
- config.customizeCompilerOptions(options);
+ config.customizeCompilerOptions(options, testData);
InternalCompilerResult compilerResult = await compileScript(
testData.memorySourceFiles,
options: options,
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 8b833caa..edbf467 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -814,9 +814,10 @@
- "class C { final covariant f = 5; }"
FinalAndCovariantLateWithInitializer:
+ index: 101
template: "Members marked 'late' with an initializer can't be declared to be both 'final' and 'covariant'."
tip: "Try removing either the 'final' or 'covariant' keyword, or removing the initializer."
- analyzerCode: ParserErrorCode.FINAL_AND_COVARIANT
+ analyzerCode: ParserErrorCode.FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER
# Weak and strong doesn't matter in this instance.
configuration: nnbd-strong
script:
diff --git a/pkg/front_end/parser_testcases/error_recovery/await_not_in_async.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/await_not_in_async.dart.intertwined.expect
index 44432d6..afe1750 100644
--- a/pkg/front_end/parser_testcases/error_recovery/await_not_in_async.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/await_not_in_async.dart.intertwined.expect
@@ -89,12 +89,14 @@
parseStatementX({)
inPlainSync()
looksLikeAwaitExpression({)
+ looksLikeExpression(await)
parseExpressionStatement({)
parseExpression({)
parsePrecedenceExpression({, 1, true)
parseUnaryExpression({, true)
inPlainSync()
looksLikeAwaitExpression({)
+ looksLikeExpression(await)
parseAwaitExpression({, true)
listener: beginAwaitExpression(await)
parsePrecedenceExpression(await, 16, true)
diff --git a/pkg/front_end/parser_testcases/error_recovery/yield_not_in_generator.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/yield_not_in_generator.dart.intertwined.expect
index 25d0a2e..ccafa7e 100644
--- a/pkg/front_end/parser_testcases/error_recovery/yield_not_in_generator.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/yield_not_in_generator.dart.intertwined.expect
@@ -100,6 +100,8 @@
notEofOrValue(}, yield)
parseStatement({)
parseStatementX({)
+ looksLikeYieldStatement({)
+ looksLikeExpression(yield)
parseYieldStatement({)
listener: beginYieldStatement(yield)
parseExpression(yield)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_01.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_01.dart.intertwined.expect
index 9f44e64..11cef0c 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_01.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_01.dart.intertwined.expect
@@ -64,65 +64,64 @@
parseArgumentsOpt(b)
listener: handleNoArguments(?)
listener: handleSend(b, ?)
- parseNullAwareBracketOrConditionalExpressionRest(b, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(c)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(d)
- parseConditionalExpressionRest(b)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(c)
- listener: handleNoArguments(])
- listener: handleSend(c, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(d, expression)
- listener: handleNoTypeArguments(:)
- parseArgumentsOpt(d)
- listener: handleNoArguments(:)
- listener: handleSend(d, :)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(c)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(d)
+ parseConditionalExpressionRest(b)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(])
+ listener: handleSend(c, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(d, expression)
+ listener: handleNoTypeArguments(:)
+ parseArgumentsOpt(d)
+ listener: handleNoArguments(:)
+ listener: handleSend(d, :)
+ listener: endConditionalExpression(?, :)
ensureColon(d)
listener: endCaseExpression(:)
listener: handleCaseMatch(case, :)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_02.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_02.dart.intertwined.expect
index bad7824..193d377 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_02.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_02.dart.intertwined.expect
@@ -64,56 +64,55 @@
parseArgumentsOpt(b)
listener: handleNoArguments(?)
listener: handleSend(b, ?)
- parseNullAwareBracketOrConditionalExpressionRest(b, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(c)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralSetOrMapSuffix(:, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- inPlainSync()
- parseSend({, expression)
- ensureIdentifier({, expression)
- reportRecoverableErrorWithToken(break, Instance of 'Template<(Token) => Message>')
- rewriter()
- parseArgumentsOpt()
- reportRecoverableError(break, Message[ExpectedButGot, Expected '}' before this., null, {string: }}])
- parseArgumentOrIndexStar(b, Instance of 'NoTypeParamOrArg', true)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(c)
- listener: handleNoArguments(])
- listener: handleSend(c, ])
- listener: handleIndexedExpression(?, [, ])
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(c)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralSetOrMapSuffix(:, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ inPlainSync()
+ parseSend({, expression)
+ ensureIdentifier({, expression)
+ reportRecoverableErrorWithToken(break, Instance of 'Template<(Token) => Message>')
+ rewriter()
+ parseArgumentsOpt()
+ reportRecoverableError(break, Message[ExpectedButGot, Expected '}' before this., null, {string: }}])
+ parseArgumentOrIndexStar(b, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(])
+ listener: handleSend(c, ])
+ listener: handleIndexedExpression(?, [, ])
ensureColon(])
listener: endCaseExpression(:)
listener: handleCaseMatch(case, :)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_03.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_03.dart.intertwined.expect
index cb93b62..dd08234 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_03.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_03.dart.intertwined.expect
@@ -64,56 +64,55 @@
parseArgumentsOpt(x)
listener: handleNoArguments(?)
listener: handleSend(x, ?)
- parseNullAwareBracketOrConditionalExpressionRest(x, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseLiteralInt([)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(baz)
- parseConditionalExpressionRest(x)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseLiteralInt([)
- listener: handleLiteralInt(4)
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(baz, expression)
- listener: handleNoTypeArguments(:)
- parseArgumentsOpt(baz)
- listener: handleNoArguments(:)
- listener: handleSend(baz, :)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(baz)
+ parseConditionalExpressionRest(x)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ listener: handleLiteralInt(4)
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(baz, expression)
+ listener: handleNoTypeArguments(:)
+ parseArgumentsOpt(baz)
+ listener: handleNoArguments(:)
+ listener: handleSend(baz, :)
+ listener: endConditionalExpression(?, :)
ensureColon(baz)
listener: endCaseExpression(:)
listener: handleCaseMatch(case, :)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_04.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_04.dart.intertwined.expect
index b402784..9e05db0 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_04.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_04.dart.intertwined.expect
@@ -64,83 +64,82 @@
parseArgumentsOpt(x)
listener: handleNoArguments(?)
listener: handleSend(x, ?)
- parseNullAwareBracketOrConditionalExpressionRest(x, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseLiteralInt([)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralSetOrMapSuffix(:, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralInt({)
- parseConditionalExpressionRest(x)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseLiteralInt([)
- listener: handleLiteralInt(4)
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- listener: handleNoTypeArguments({)
- parseLiteralSetOrMapSuffix(:, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- listener: handleNoTypeArguments({)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- listener: handleNoTypeArguments({)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralInt({)
- listener: handleLiteralInt(2)
- listener: handleLiteralSetOrMap(1, {, null, }, true)
- listener: handleLiteralSetOrMap(1, {, null, }, true)
- listener: handleLiteralSetOrMap(1, {, null, }, true)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralSetOrMapSuffix(:, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralInt({)
+ parseConditionalExpressionRest(x)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ listener: handleLiteralInt(4)
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ listener: handleNoTypeArguments({)
+ parseLiteralSetOrMapSuffix(:, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ listener: handleNoTypeArguments({)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ listener: handleNoTypeArguments({)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralInt({)
+ listener: handleLiteralInt(2)
+ listener: handleLiteralSetOrMap(1, {, null, }, true)
+ listener: handleLiteralSetOrMap(1, {, null, }, true)
+ listener: handleLiteralSetOrMap(1, {, null, }, true)
+ listener: endConditionalExpression(?, :)
ensureColon(})
rewriteAndRecover(}, Message[ExpectedButGot, Expected ':' before this., null, {string: :}], :)
reportRecoverableError(;, Message[ExpectedButGot, Expected ':' before this., null, {string: :}])
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_05.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_05.dart.intertwined.expect
index d64328e..ac93388 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_case_05.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_case_05.dart.intertwined.expect
@@ -64,47 +64,46 @@
parseArgumentsOpt(x)
listener: handleNoArguments(?)
listener: handleSend(x, ?)
- parseNullAwareBracketOrConditionalExpressionRest(x, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseLiteralInt([)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralSetOrMapSuffix(:, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralSetOrMapSuffix({, null)
- parseExpression({)
- parsePrecedenceExpression({, 1, true)
- parseUnaryExpression({, true)
- parsePrimary({, expression)
- parseLiteralInt({)
- reportRecoverableError(;, Message[ExpectedButGot, Expected '}' before this., null, {string: }}])
- parseArgumentOrIndexStar(x, Instance of 'NoTypeParamOrArg', true)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseLiteralInt([)
- listener: handleLiteralInt(4)
- listener: handleIndexedExpression(?, [, ])
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralSetOrMapSuffix(:, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralSetOrMapSuffix({, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseLiteralInt({)
+ reportRecoverableError(;, Message[ExpectedButGot, Expected '}' before this., null, {string: }}])
+ parseArgumentOrIndexStar(x, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ listener: handleLiteralInt(4)
+ listener: handleIndexedExpression(?, [, ])
ensureColon(])
listener: endCaseExpression(:)
listener: handleCaseMatch(case, :)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional.dart.intertwined.expect
index b9e60d7..7d4e907 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional.dart.intertwined.expect
@@ -76,65 +76,64 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
@@ -155,65 +154,64 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
@@ -234,87 +232,86 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- listener: handleIdentifier(toString, expressionContinuation)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- listener: beginArguments(()
- listener: endArguments(0, (, ))
- listener: handleSend(toString, :)
- listener: endBinaryExpression(.)
- ensureColon())
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ listener: handleIdentifier(toString, expressionContinuation)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ listener: endArguments(0, (, ))
+ listener: handleSend(toString, :)
+ listener: endBinaryExpression(.)
+ ensureColon())
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
@@ -335,87 +332,86 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- listener: handleIdentifier(toString, expressionContinuation)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- listener: beginArguments(()
- listener: endArguments(0, (, ))
- listener: handleSend(toString, :)
- listener: endBinaryExpression(.)
- ensureColon())
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ listener: handleIdentifier(toString, expressionContinuation)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ listener: endArguments(0, (, ))
+ listener: handleSend(toString, :)
+ listener: endBinaryExpression(.)
+ ensureColon())
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional_2.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional_2.dart.intertwined.expect
index d636a7e..3af70bd 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional_2.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_conditional_2.dart.intertwined.expect
@@ -68,81 +68,80 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- looksLikeFunctionBody(])
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseArguments(b)
- parseArgumentsRest(()
- parseExpression(()
- parsePrecedenceExpression((, 1, true)
- parseUnaryExpression((, true)
- parsePrimary((, expression)
- parseLiteralListSuffix((, null)
- rewriteSquareBrackets(()
- link([, ])
- rewriter()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralNull(:)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- looksLikeFunctionBody(])
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(b)
- parseArguments(b)
- parseArgumentsRest(()
- listener: beginArguments(()
- parseExpression(()
- parsePrecedenceExpression((, 1, true)
- parseUnaryExpression((, true)
- parsePrimary((, expression)
- listener: handleNoTypeArguments([])
- parseLiteralListSuffix((, null)
- rewriteSquareBrackets(()
- link([, ])
- rewriter()
- listener: handleLiteralList(0, [, null, ])
- listener: endArguments(1, (, ))
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralNull(:)
- listener: handleLiteralNull(null)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ looksLikeFunctionBody(])
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseArguments(b)
+ parseArgumentsRest(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralListSuffix((, null)
+ rewriteSquareBrackets(()
+ link([, ])
+ rewriter()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralNull(:)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ looksLikeFunctionBody(])
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(b)
+ parseArguments(b)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ listener: handleNoTypeArguments([])
+ parseLiteralListSuffix((, null)
+ rewriteSquareBrackets(()
+ link([, ])
+ rewriter()
+ listener: handleLiteralList(0, [, null, ])
+ listener: endArguments(1, (, ))
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralNull(:)
+ listener: handleLiteralNull(null)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(null)
listener: endReturnStatement(true, return, ;)
inGenerator()
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_index_access.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_index_access.dart.intertwined.expect
index 243c2ea..4674f50 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_index_access.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_index_access.dart.intertwined.expect
@@ -103,35 +103,34 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseArgumentOrIndexStar(a, Instance of 'NoTypeParamOrArg', true)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleIndexedExpression(?, [, ])
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseArgumentOrIndexStar(a, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleIndexedExpression(?, [, ])
ensureSemicolon(])
listener: handleExpressionStatement(;)
notEofOrValue(}, })
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_index_set.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_index_set.dart.intertwined.expect
index 7fd92a2..ecd4668 100644
--- a/pkg/front_end/parser_testcases/nnbd/issue_40267_index_set.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_index_set.dart.intertwined.expect
@@ -122,42 +122,41 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parsePrecedenceExpression(=, 1, false)
- parseUnaryExpression(=, false)
- parsePrimary(=, expression)
- parseSendOrFunctionLiteral(=, expression)
- parseSend(=, expression)
- ensureIdentifier(=, expression)
- parseArgumentsOpt(c)
- parseArgumentOrIndexStar(a, Instance of 'NoTypeParamOrArg', true)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleIndexedExpression(?, [, ])
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parsePrecedenceExpression(=, 1, false)
+ parseUnaryExpression(=, false)
+ parsePrimary(=, expression)
+ parseSendOrFunctionLiteral(=, expression)
+ parseSend(=, expression)
+ ensureIdentifier(=, expression)
+ parseArgumentsOpt(c)
+ parseArgumentOrIndexStar(a, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleIndexedExpression(?, [, ])
parsePrecedenceExpression(=, 1, true)
parseUnaryExpression(=, true)
parsePrimary(=, expression)
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart
new file mode 100644
index 0000000..af2c6b2
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart
@@ -0,0 +1,3 @@
+f(dynamic a) {
+ a?[0] + 1;
+}
\ No newline at end of file
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.expect
new file mode 100644
index 0000000..29249f9
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.expect
@@ -0,0 +1,35 @@
+beginCompilationUnit(f)
+ beginMetadataStar(f)
+ endMetadataStar(0)
+ beginTopLevelMember(f)
+ beginTopLevelMethod(, null)
+ handleNoType()
+ handleIdentifier(f, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(a)
+ handleType(dynamic, null)
+ handleIdentifier(a, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, a, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ handleIdentifier(a, expression)
+ handleNoTypeArguments(?)
+ handleNoArguments(?)
+ handleSend(a, ?)
+ handleLiteralInt(0)
+ handleIndexedExpression(?, [, ])
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(1, {, })
+ endTopLevelMethod(f, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.intertwined.expect
new file mode 100644
index 0000000..2475c14
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.intertwined.expect
@@ -0,0 +1,95 @@
+parseUnit(f)
+ skipErrorTokens(f)
+ listener: beginCompilationUnit(f)
+ syntheticPreviousToken(f)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(f)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(f)
+ parseTopLevelMethod(, null, , Instance of 'NoType', null, f)
+ listener: beginTopLevelMethod(, null)
+ listener: handleNoType()
+ ensureIdentifier(, topLevelFunctionDeclaration)
+ listener: handleIdentifier(f, topLevelFunctionDeclaration)
+ parseMethodTypeVar(f)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(f, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(a)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(a, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, a, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, a)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(a)
+ parseExpressionStatement({)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseSendOrFunctionLiteral({, expression)
+ parseSend({, expression)
+ ensureIdentifier({, expression)
+ listener: handleIdentifier(a, expression)
+ listener: handleNoTypeArguments(?)
+ parseArgumentsOpt(a)
+ listener: handleNoArguments(?)
+ listener: handleSend(a, ?)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ parsePrecedenceExpression(+, 14, false)
+ parseUnaryExpression(+, false)
+ parsePrimary(+, expression)
+ parseLiteralInt(+)
+ parseArgumentOrIndexStar(a, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ listener: handleLiteralInt(0)
+ listener: handleIndexedExpression(?, [, ])
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true)
+ parseUnaryExpression(+, true)
+ parsePrimary(+, expression)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+)
+ ensureSemicolon(1)
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endTopLevelMethod(f, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(f)
+ listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.parser.expect
new file mode 100644
index 0000000..b216698
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.parser.expect
@@ -0,0 +1,7 @@
+f(dynamic a) {
+a?[0] + 1;
+}
+
+f[StringToken]([BeginToken]dynamic[KeywordToken] a[StringToken])[SimpleToken] {[BeginToken]
+a[StringToken]?[SimpleToken][[BeginToken]0[StringToken]][SimpleToken] +[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.scanner.expect
new file mode 100644
index 0000000..b216698
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus.dart.scanner.expect
@@ -0,0 +1,7 @@
+f(dynamic a) {
+a?[0] + 1;
+}
+
+f[StringToken]([BeginToken]dynamic[KeywordToken] a[StringToken])[SimpleToken] {[BeginToken]
+a[StringToken]?[SimpleToken][[BeginToken]0[StringToken]][SimpleToken] +[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart
new file mode 100644
index 0000000..8b33d56
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart
@@ -0,0 +1,3 @@
+f(dynamic x, dynamic i) {
+ x?[i]++;
+}
\ No newline at end of file
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.expect
new file mode 100644
index 0000000..90d68a0
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.expect
@@ -0,0 +1,45 @@
+beginCompilationUnit(f)
+ beginMetadataStar(f)
+ endMetadataStar(0)
+ beginTopLevelMember(f)
+ beginTopLevelMethod(, null)
+ handleNoType()
+ handleIdentifier(f, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(x)
+ handleType(dynamic, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue(,)
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(i)
+ handleType(dynamic, null)
+ handleIdentifier(i, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ handleIdentifier(x, expression)
+ handleNoTypeArguments(?)
+ handleNoArguments(?)
+ handleSend(x, ?)
+ handleIdentifier(i, expression)
+ handleNoTypeArguments(])
+ handleNoArguments(])
+ handleSend(i, ])
+ handleIndexedExpression(?, [, ])
+ handleUnaryPostfixAssignmentExpression(++)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(1, {, })
+ endTopLevelMethod(f, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.intertwined.expect
new file mode 100644
index 0000000..244201e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.intertwined.expect
@@ -0,0 +1,106 @@
+parseUnit(f)
+ skipErrorTokens(f)
+ listener: beginCompilationUnit(f)
+ syntheticPreviousToken(f)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(f)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(f)
+ parseTopLevelMethod(, null, , Instance of 'NoType', null, f)
+ listener: beginTopLevelMethod(, null)
+ listener: handleNoType()
+ ensureIdentifier(, topLevelFunctionDeclaration)
+ listener: handleIdentifier(f, topLevelFunctionDeclaration)
+ parseMethodTypeVar(f)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(f, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue(,)
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseFormalParameter(,, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(i)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(i, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, x)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(x)
+ parseExpressionStatement({)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseSendOrFunctionLiteral({, expression)
+ parseSend({, expression)
+ ensureIdentifier({, expression)
+ listener: handleIdentifier(x, expression)
+ listener: handleNoTypeArguments(?)
+ parseArgumentsOpt(x)
+ listener: handleNoArguments(?)
+ listener: handleSend(x, ?)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(i)
+ parseArgumentOrIndexStar(x, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(i, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(i)
+ listener: handleNoArguments(])
+ listener: handleSend(i, ])
+ listener: handleIndexedExpression(?, [, ])
+ listener: handleUnaryPostfixAssignmentExpression(++)
+ ensureSemicolon(++)
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endTopLevelMethod(f, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(f)
+ listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.parser.expect
new file mode 100644
index 0000000..98a6966
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.parser.expect
@@ -0,0 +1,7 @@
+f(dynamic x, dynamic i) {
+x?[i]++;
+}
+
+f[StringToken]([BeginToken]dynamic[KeywordToken] x[StringToken],[SimpleToken] dynamic[KeywordToken] i[StringToken])[SimpleToken] {[BeginToken]
+x[StringToken]?[SimpleToken][[BeginToken]i[StringToken]][SimpleToken]++[SimpleToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.scanner.expect
new file mode 100644
index 0000000..98a6966
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_lookup_plus_plus.dart.scanner.expect
@@ -0,0 +1,7 @@
+f(dynamic x, dynamic i) {
+x?[i]++;
+}
+
+f[StringToken]([BeginToken]dynamic[KeywordToken] x[StringToken],[SimpleToken] dynamic[KeywordToken] i[StringToken])[SimpleToken] {[BeginToken]
+x[StringToken]?[SimpleToken][[BeginToken]i[StringToken]][SimpleToken]++[SimpleToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart
new file mode 100644
index 0000000..23d8492
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart
@@ -0,0 +1,3 @@
+f(dynamic x, dynamic i) {
+ ++x?[i];
+}
\ No newline at end of file
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.expect
new file mode 100644
index 0000000..6d91dd6
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.expect
@@ -0,0 +1,45 @@
+beginCompilationUnit(f)
+ beginMetadataStar(f)
+ endMetadataStar(0)
+ beginTopLevelMember(f)
+ beginTopLevelMethod(, null)
+ handleNoType()
+ handleIdentifier(f, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(x)
+ handleType(dynamic, null)
+ handleIdentifier(x, formalParameterDeclaration)
+ handleFormalParameterWithoutValue(,)
+ endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(i)
+ handleType(dynamic, null)
+ handleIdentifier(i, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ handleIdentifier(x, expression)
+ handleNoTypeArguments(?)
+ handleNoArguments(?)
+ handleSend(x, ?)
+ handleIdentifier(i, expression)
+ handleNoTypeArguments(])
+ handleNoArguments(])
+ handleSend(i, ])
+ handleIndexedExpression(?, [, ])
+ handleUnaryPrefixAssignmentExpression(++)
+ handleExpressionStatement(;)
+ endBlockFunctionBody(1, {, })
+ endTopLevelMethod(f, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.intertwined.expect
new file mode 100644
index 0000000..2b47b0f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.intertwined.expect
@@ -0,0 +1,109 @@
+parseUnit(f)
+ skipErrorTokens(f)
+ listener: beginCompilationUnit(f)
+ syntheticPreviousToken(f)
+ parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+ parseMetadataStar()
+ listener: beginMetadataStar(f)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl()
+ listener: beginTopLevelMember(f)
+ parseTopLevelMethod(, null, , Instance of 'NoType', null, f)
+ listener: beginTopLevelMethod(, null)
+ listener: handleNoType()
+ ensureIdentifier(, topLevelFunctionDeclaration)
+ listener: handleIdentifier(f, topLevelFunctionDeclaration)
+ parseMethodTypeVar(f)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(f, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(x)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(x, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue(,)
+ listener: endFormalParameter(null, null, x, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseFormalParameter(,, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ parseMetadataStar(,)
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.TopLevelMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(i)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(i, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, i, null, null, FormalParameterKind.mandatory, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(2, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, ++)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclaration({, false)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(++)
+ parseExpressionStatement({)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrecedenceExpression(++, 16, true)
+ parseUnaryExpression(++, true)
+ parsePrimary(++, expression)
+ parseSendOrFunctionLiteral(++, expression)
+ parseSend(++, expression)
+ ensureIdentifier(++, expression)
+ listener: handleIdentifier(x, expression)
+ listener: handleNoTypeArguments(?)
+ parseArgumentsOpt(x)
+ listener: handleNoArguments(?)
+ listener: handleSend(x, ?)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(i)
+ parseArgumentOrIndexStar(x, Instance of 'NoTypeParamOrArg', true)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(i, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(i)
+ listener: handleNoArguments(])
+ listener: handleSend(i, ])
+ listener: handleIndexedExpression(?, [, ])
+ listener: handleUnaryPrefixAssignmentExpression(++)
+ ensureSemicolon(])
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endTopLevelMethod(f, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(f)
+ listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.parser.expect
new file mode 100644
index 0000000..999ca84
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.parser.expect
@@ -0,0 +1,7 @@
+f(dynamic x, dynamic i) {
+++x?[i];
+}
+
+f[StringToken]([BeginToken]dynamic[KeywordToken] x[StringToken],[SimpleToken] dynamic[KeywordToken] i[StringToken])[SimpleToken] {[BeginToken]
+++[SimpleToken]x[StringToken]?[SimpleToken][[BeginToken]i[StringToken]][SimpleToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.scanner.expect
new file mode 100644
index 0000000..999ca84
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/issue_40267_plus_plus_lookup.dart.scanner.expect
@@ -0,0 +1,7 @@
+f(dynamic x, dynamic i) {
+++x?[i];
+}
+
+f[StringToken]([BeginToken]dynamic[KeywordToken] x[StringToken],[SimpleToken] dynamic[KeywordToken] i[StringToken])[SimpleToken] {[BeginToken]
+++[SimpleToken]x[StringToken]?[SimpleToken][[BeginToken]i[StringToken]][SimpleToken];[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional.dart.intertwined.expect
index b9e60d7..7d4e907 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional.dart.intertwined.expect
@@ -76,65 +76,64 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
@@ -155,65 +154,64 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
@@ -234,87 +232,86 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- listener: handleIdentifier(toString, expressionContinuation)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- listener: beginArguments(()
- listener: endArguments(0, (, ))
- listener: handleSend(toString, :)
- listener: endBinaryExpression(.)
- ensureColon())
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ listener: handleIdentifier(toString, expressionContinuation)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ listener: endArguments(0, (, ))
+ listener: handleSend(toString, :)
+ listener: endBinaryExpression(.)
+ ensureColon())
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
@@ -335,87 +332,86 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- parseArgumentsOpt(c)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(b)
- listener: handleNoArguments(])
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- parsePrimary(., expressionContinuation)
- parseSendOrFunctionLiteral(., expressionContinuation)
- looksLikeFunctionBody(:)
- parseSend(., expressionContinuation)
- ensureIdentifier(., expressionContinuation)
- listener: handleIdentifier(toString, expressionContinuation)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(toString)
- parseArguments(toString)
- parseArgumentsRest(()
- listener: beginArguments(()
- listener: endArguments(0, (, ))
- listener: handleSend(toString, :)
- listener: endBinaryExpression(.)
- ensureColon())
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseSendOrFunctionLiteral(:, expression)
- parseSend(:, expression)
- ensureIdentifier(:, expression)
- listener: handleIdentifier(c, expression)
- listener: handleNoTypeArguments(;)
- parseArgumentsOpt(c)
- listener: handleNoArguments(;)
- listener: handleSend(c, ;)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ parseArgumentsOpt(c)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(b)
+ listener: handleNoArguments(])
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ parsePrimary(., expressionContinuation)
+ parseSendOrFunctionLiteral(., expressionContinuation)
+ looksLikeFunctionBody(:)
+ parseSend(., expressionContinuation)
+ ensureIdentifier(., expressionContinuation)
+ listener: handleIdentifier(toString, expressionContinuation)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(toString)
+ parseArguments(toString)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ listener: endArguments(0, (, ))
+ listener: handleSend(toString, :)
+ listener: endBinaryExpression(.)
+ ensureColon())
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseSendOrFunctionLiteral(:, expression)
+ parseSend(:, expression)
+ ensureIdentifier(:, expression)
+ listener: handleIdentifier(c, expression)
+ listener: handleNoTypeArguments(;)
+ parseArgumentsOpt(c)
+ listener: handleNoArguments(;)
+ listener: handleSend(c, ;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(c)
listener: handleExpressionStatement(;)
notEofOrValue(}, a)
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_2.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_2.dart.intertwined.expect
index d636a7e..3af70bd 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_2.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_2.dart.intertwined.expect
@@ -68,81 +68,80 @@
parseArgumentsOpt(a)
listener: handleNoArguments(?)
listener: handleSend(a, ?)
- parseNullAwareBracketOrConditionalExpressionRest(a, Instance of 'NoTypeParamOrArg')
- canParseAsConditional(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- looksLikeFunctionBody(])
- parseSend([, expression)
- ensureIdentifier([, expression)
- parseArgumentsOpt(b)
- parseArguments(b)
- parseArgumentsRest(()
- parseExpression(()
- parsePrecedenceExpression((, 1, true)
- parseUnaryExpression((, true)
- parsePrimary((, expression)
- parseLiteralListSuffix((, null)
- rewriteSquareBrackets(()
- link([, ])
- rewriter()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralNull(:)
- parseConditionalExpressionRest(a)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- looksLikeFunctionBody(])
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(b, expression)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(b)
- parseArguments(b)
- parseArgumentsRest(()
- listener: beginArguments(()
- parseExpression(()
- parsePrecedenceExpression((, 1, true)
- parseUnaryExpression((, true)
- parsePrimary((, expression)
- listener: handleNoTypeArguments([])
- parseLiteralListSuffix((, null)
- rewriteSquareBrackets(()
- link([, ])
- rewriter()
- listener: handleLiteralList(0, [, null, ])
- listener: endArguments(1, (, ))
- listener: handleSend(b, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseLiteralNull(:)
- listener: handleLiteralNull(null)
- listener: endConditionalExpression(?, :)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ looksLikeFunctionBody(])
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(b)
+ parseArguments(b)
+ parseArgumentsRest(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseLiteralListSuffix((, null)
+ rewriteSquareBrackets(()
+ link([, ])
+ rewriter()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralNull(:)
+ parseConditionalExpressionRest(a)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ looksLikeFunctionBody(])
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(b, expression)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(b)
+ parseArguments(b)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ listener: handleNoTypeArguments([])
+ parseLiteralListSuffix((, null)
+ rewriteSquareBrackets(()
+ link([, ])
+ rewriter()
+ listener: handleLiteralList(0, [, null, ])
+ listener: endArguments(1, (, ))
+ listener: handleSend(b, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralNull(:)
+ listener: handleLiteralNull(null)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(null)
listener: endReturnStatement(true, return, ;)
inGenerator()
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_3.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_3.dart.intertwined.expect
index f19df50..0df432d 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_3.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_3.dart.intertwined.expect
@@ -67,8 +67,6 @@
parsePrimary(!=, expression)
parseLiteralNull(!=)
listener: handleLiteralNull(null)
- listener: endBinaryExpression(!=)
- parseNullAwareBracketOrConditionalExpressionRest(null, Instance of 'NoTypeParamOrArg')
canParseAsConditional(?)
parseExpressionWithoutCascade(?)
parsePrecedenceExpression(?, 1, false)
@@ -92,43 +90,67 @@
rewriteSquareBrackets(const)
link([, ])
rewriter()
- parseConditionalExpressionRest(null)
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(a, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(a)
- listener: handleNoArguments(])
- listener: handleSend(a, ])
- listener: handleLiteralList(1, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- parseConstExpression(:)
- listener: beginConstLiteral([])
- listener: handleNoTypeArguments([])
- parseLiteralListSuffix(const, const)
- rewriteSquareBrackets(const)
- link([, ])
- rewriter()
- listener: handleLiteralList(0, [, const, ])
- listener: endConstLiteral(;)
- listener: endConditionalExpression(?, :)
+ listener: endBinaryExpression(!=)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(a)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseConstExpression(:)
+ parseLiteralListSuffix(const, const)
+ rewriteSquareBrackets(const)
+ link([, ])
+ rewriter()
+ parseConditionalExpressionRest(null)
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(a, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(a)
+ listener: handleNoArguments(])
+ listener: handleSend(a, ])
+ listener: handleLiteralList(1, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseConstExpression(:)
+ listener: beginConstLiteral([])
+ listener: handleNoTypeArguments([])
+ parseLiteralListSuffix(const, const)
+ rewriteSquareBrackets(const)
+ link([, ])
+ rewriter()
+ listener: handleLiteralList(0, [, const, ])
+ listener: endConstLiteral(;)
+ listener: endConditionalExpression(?, :)
ensureSemicolon(])
listener: endReturnStatement(true, return, ;)
inGenerator()
diff --git a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_4.dart.intertwined.expect b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_4.dart.intertwined.expect
index efef438..1f6b298 100644
--- a/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_4.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/non-nnbd/issue_40267_conditional_4.dart.intertwined.expect
@@ -163,8 +163,6 @@
parseSend([, expression)
ensureIdentifier([, expression)
parseArgumentsOpt(a)
- listener: endBinaryExpression(&&)
- parseNullAwareBracketOrConditionalExpressionRest(], Instance of 'NoTypeParamOrArg')
canParseAsConditional(?)
parseExpressionWithoutCascade(?)
parsePrecedenceExpression(?, 1, false)
@@ -211,77 +209,124 @@
parseSend([, expression)
ensureIdentifier([, expression)
parseArgumentsOpt(a)
- parseConditionalExpressionRest(])
- listener: beginConditionalExpression(?)
- parseExpressionWithoutCascade(?)
- parsePrecedenceExpression(?, 1, false)
- parseUnaryExpression(?, false)
- parsePrimary(?, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(?, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(a, expression)
- listener: handleNoTypeArguments(,)
- parseArgumentsOpt(a)
- listener: handleNoArguments(,)
- listener: handleSend(a, ,)
- parseExpression(,)
- parsePrecedenceExpression(,, 1, true)
- parseUnaryExpression(,, true)
- parsePrimary(,, expression)
- parseSendOrFunctionLiteral(,, expression)
- looksLikeFunctionBody(])
- parseSend(,, expression)
- ensureIdentifier(,, expression)
- listener: handleIdentifier(e, expression)
- listener: handleNoTypeArguments(()
- parseArgumentsOpt(e)
- parseArguments(e)
- parseArgumentsRest(()
- listener: beginArguments(()
- parseExpression(()
- parsePrecedenceExpression((, 1, true)
- parseUnaryExpression((, true)
- parsePrimary((, expression)
- parseSendOrFunctionLiteral((, expression)
- parseSend((, expression)
- ensureIdentifier((, expression)
- listener: handleIdentifier(f, expression)
- listener: handleNoTypeArguments())
- parseArgumentsOpt(f)
- listener: handleNoArguments())
- listener: handleSend(f, ))
- listener: endArguments(1, (, ))
- listener: handleSend(e, ])
- listener: handleLiteralList(2, [, null, ])
- ensureColon(])
- listener: handleConditionalExpressionColon()
- parseExpressionWithoutCascade(:)
- parsePrecedenceExpression(:, 1, false)
- parseUnaryExpression(:, false)
- parsePrimary(:, expression)
- listener: handleNoTypeArguments([)
- parseLiteralListSuffix(:, null)
- parseExpression([)
- parsePrecedenceExpression([, 1, true)
- parseUnaryExpression([, true)
- parsePrimary([, expression)
- parseSendOrFunctionLiteral([, expression)
- parseSend([, expression)
- ensureIdentifier([, expression)
- listener: handleIdentifier(a, expression)
- listener: handleNoTypeArguments(])
- parseArgumentsOpt(a)
- listener: handleNoArguments(])
- listener: handleSend(a, ])
- listener: handleLiteralList(1, [, null, ])
- listener: endConditionalExpression(?, :)
+ listener: endBinaryExpression(&&)
+ canParseAsConditional(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(a)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true)
+ parseUnaryExpression(,, true)
+ parsePrimary(,, expression)
+ parseSendOrFunctionLiteral(,, expression)
+ looksLikeFunctionBody(])
+ parseSend(,, expression)
+ ensureIdentifier(,, expression)
+ parseArgumentsOpt(e)
+ parseArguments(e)
+ parseArgumentsRest(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseSendOrFunctionLiteral((, expression)
+ parseSend((, expression)
+ ensureIdentifier((, expression)
+ parseArgumentsOpt(f)
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ parseLiteralListSuffix(:, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ parseArgumentsOpt(a)
+ parseConditionalExpressionRest(])
+ listener: beginConditionalExpression(?)
+ parseExpressionWithoutCascade(?)
+ parsePrecedenceExpression(?, 1, false)
+ parseUnaryExpression(?, false)
+ parsePrimary(?, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(?, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(a, expression)
+ listener: handleNoTypeArguments(,)
+ parseArgumentsOpt(a)
+ listener: handleNoArguments(,)
+ listener: handleSend(a, ,)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true)
+ parseUnaryExpression(,, true)
+ parsePrimary(,, expression)
+ parseSendOrFunctionLiteral(,, expression)
+ looksLikeFunctionBody(])
+ parseSend(,, expression)
+ ensureIdentifier(,, expression)
+ listener: handleIdentifier(e, expression)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(e)
+ parseArguments(e)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseSendOrFunctionLiteral((, expression)
+ parseSend((, expression)
+ ensureIdentifier((, expression)
+ listener: handleIdentifier(f, expression)
+ listener: handleNoTypeArguments())
+ parseArgumentsOpt(f)
+ listener: handleNoArguments())
+ listener: handleSend(f, ))
+ listener: endArguments(1, (, ))
+ listener: handleSend(e, ])
+ listener: handleLiteralList(2, [, null, ])
+ ensureColon(])
+ listener: handleConditionalExpressionColon()
+ parseExpressionWithoutCascade(:)
+ parsePrecedenceExpression(:, 1, false)
+ parseUnaryExpression(:, false)
+ parsePrimary(:, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(:, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseSendOrFunctionLiteral([, expression)
+ parseSend([, expression)
+ ensureIdentifier([, expression)
+ listener: handleIdentifier(a, expression)
+ listener: handleNoTypeArguments(])
+ parseArgumentsOpt(a)
+ listener: handleNoArguments(])
+ listener: handleSend(a, ])
+ listener: handleLiteralList(1, [, null, ])
+ listener: endConditionalExpression(?, :)
listener: endArguments(1, (, ))
listener: handleSend(addAll, ;)
listener: endBinaryExpression(..)
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/.dart_tool/package_config.json b/pkg/front_end/test/language_versioning/data/specified_packages_01/.dart_tool/package_config.json
new file mode 100644
index 0000000..9280e5a
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/.dart_tool/package_config.json
@@ -0,0 +1,9 @@
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "../foo2/"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/.packages b/pkg/front_end/test/language_versioning/data/specified_packages_01/.packages
new file mode 100644
index 0000000..a0a43fc
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/.packages
@@ -0,0 +1 @@
+foo:foo1/
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/foo1/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_01/foo1/foo.dart
new file mode 100644
index 0000000..4d80ea2
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/foo1/foo.dart
@@ -0,0 +1,5 @@
+// No language version --- this file shouldn't even be compiled.
+
+int notNamedFoo() {
+ return 42;
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/foo2/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_01/foo2/foo.dart
new file mode 100644
index 0000000..0f5e6ce
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/foo2/foo.dart
@@ -0,0 +1,5 @@
+/*library: languageVersion=2.8*/
+
+String foo() {
+ return "42";
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/main.dart b/pkg/front_end/test/language_versioning/data/specified_packages_01/main.dart
new file mode 100644
index 0000000..f5a4c34
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/main.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Set version of this file (not technically in package) explicitly to test as
+// much as possibly separately.
+
+// @dart = 2.4
+
+import 'package:foo/foo.dart';
+
+/*library: languageVersion=2.4*/
+
+main() {
+ var result = foo();
+ print(result);
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/pubspec.yaml b/pkg/front_end/test/language_versioning/data/specified_packages_01/pubspec.yaml
new file mode 100644
index 0000000..ff98642
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/pubspec.yaml
@@ -0,0 +1,5 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Analyzer workaround, see https://github.com/dart-lang/sdk/issues/37513
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_01/test.options b/pkg/front_end/test/language_versioning/data/specified_packages_01/test.options
new file mode 100644
index 0000000..9044751
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_01/test.options
@@ -0,0 +1,2 @@
+# Point to .packages => Standard layout; redirect to .dart_tool/package_config.json
+--packages=.packages
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/.dart_tool/package_config.json b/pkg/front_end/test/language_versioning/data/specified_packages_02/.dart_tool/package_config.json
new file mode 100644
index 0000000..9280e5a
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/.dart_tool/package_config.json
@@ -0,0 +1,9 @@
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "../foo2/"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/.packagesX b/pkg/front_end/test/language_versioning/data/specified_packages_02/.packagesX
new file mode 100644
index 0000000..a0a43fc
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/.packagesX
@@ -0,0 +1 @@
+foo:foo1/
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/foo1/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_02/foo1/foo.dart
new file mode 100644
index 0000000..bb0fb7c
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/foo1/foo.dart
@@ -0,0 +1,5 @@
+/*library: languageVersion=2.8*/
+
+int notNamedFoo() {
+ return 42;
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/foo2/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_02/foo2/foo.dart
new file mode 100644
index 0000000..449c3f0
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/foo2/foo.dart
@@ -0,0 +1,5 @@
+// No language version --- this file shouldn't even be compiled.
+
+String foo() {
+ return "42";
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/main.dart b/pkg/front_end/test/language_versioning/data/specified_packages_02/main.dart
new file mode 100644
index 0000000..3dc5e95
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/main.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Set version of this file (not technically in package) explicitly to test as
+// much as possibly separately.
+
+// @dart = 2.4
+
+import 'package:foo/foo.dart';
+
+/*library: languageVersion=2.4*/
+
+main() {
+ var result = notNamedFoo();
+ print(result);
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/pubspec.yaml b/pkg/front_end/test/language_versioning/data/specified_packages_02/pubspec.yaml
new file mode 100644
index 0000000..ff98642
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/pubspec.yaml
@@ -0,0 +1,5 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Analyzer workaround, see https://github.com/dart-lang/sdk/issues/37513
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_02/test.options b/pkg/front_end/test/language_versioning/data/specified_packages_02/test.options
new file mode 100644
index 0000000..d3ccc47
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_02/test.options
@@ -0,0 +1,2 @@
+# Point to .packagesX => non-standard layout; use it directly
+--packages=.packagesX
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/.packages b/pkg/front_end/test/language_versioning/data/specified_packages_03/.packages
new file mode 100644
index 0000000..a0a43fc
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/.packages
@@ -0,0 +1 @@
+foo:foo1/
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/foo1/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_03/foo1/foo.dart
new file mode 100644
index 0000000..4d80ea2
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/foo1/foo.dart
@@ -0,0 +1,5 @@
+// No language version --- this file shouldn't even be compiled.
+
+int notNamedFoo() {
+ return 42;
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/foo2/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_03/foo2/foo.dart
new file mode 100644
index 0000000..0f5e6ce
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/foo2/foo.dart
@@ -0,0 +1,5 @@
+/*library: languageVersion=2.8*/
+
+String foo() {
+ return "42";
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/main.dart b/pkg/front_end/test/language_versioning/data/specified_packages_03/main.dart
new file mode 100644
index 0000000..f5a4c34
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/main.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Set version of this file (not technically in package) explicitly to test as
+// much as possibly separately.
+
+// @dart = 2.4
+
+import 'package:foo/foo.dart';
+
+/*library: languageVersion=2.4*/
+
+main() {
+ var result = foo();
+ print(result);
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/package_config.json b/pkg/front_end/test/language_versioning/data/specified_packages_03/package_config.json
new file mode 100644
index 0000000..d67acb0
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/package_config.json
@@ -0,0 +1,9 @@
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "foo",
+ "rootUri": "foo2/"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/pubspec.yaml b/pkg/front_end/test/language_versioning/data/specified_packages_03/pubspec.yaml
new file mode 100644
index 0000000..ff98642
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/pubspec.yaml
@@ -0,0 +1,5 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Analyzer workaround, see https://github.com/dart-lang/sdk/issues/37513
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_03/test.options b/pkg/front_end/test/language_versioning/data/specified_packages_03/test.options
new file mode 100644
index 0000000..c01a27e
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_03/test.options
@@ -0,0 +1,2 @@
+# Point to package_config.json => non-standard layout; use it directly
+--packages=package_config.json
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/.dart_tool/package_config.json b/pkg/front_end/test/language_versioning/data/specified_packages_04/.dart_tool/package_config.json
new file mode 100644
index 0000000..c4b490f
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/.dart_tool/package_config.json
@@ -0,0 +1 @@
+/*error: PackagesFileFormat*/foo:foo2/
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/.packages b/pkg/front_end/test/language_versioning/data/specified_packages_04/.packages
new file mode 100644
index 0000000..a0a43fc
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/.packages
@@ -0,0 +1 @@
+foo:foo1/
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/foo1/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_04/foo1/foo.dart
new file mode 100644
index 0000000..4d80ea2
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/foo1/foo.dart
@@ -0,0 +1,5 @@
+// No language version --- this file shouldn't even be compiled.
+
+int notNamedFoo() {
+ return 42;
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/foo2/foo.dart b/pkg/front_end/test/language_versioning/data/specified_packages_04/foo2/foo.dart
new file mode 100644
index 0000000..449c3f0
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/foo2/foo.dart
@@ -0,0 +1,5 @@
+// No language version --- this file shouldn't even be compiled.
+
+String foo() {
+ return "42";
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/main.dart b/pkg/front_end/test/language_versioning/data/specified_packages_04/main.dart
new file mode 100644
index 0000000..e625dcd
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/main.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Set version of this file (not technically in package) explicitly to test as
+// much as possibly separately.
+
+// @dart = 2.4
+
+import /*error: UntranslatableUri*/ 'package:foo/foo.dart';
+
+/*library: languageVersion=2.4*/
+
+main() {
+ var result = /*error: MethodNotFound*/ notNamedFoo();
+ print(result);
+}
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/null b/pkg/front_end/test/language_versioning/data/specified_packages_04/null
new file mode 100644
index 0000000..508fd9c
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/null
@@ -0,0 +1 @@
+/*error: PackageNotFound*/
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/pubspec.yaml b/pkg/front_end/test/language_versioning/data/specified_packages_04/pubspec.yaml
new file mode 100644
index 0000000..ff98642
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/pubspec.yaml
@@ -0,0 +1,5 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Analyzer workaround, see https://github.com/dart-lang/sdk/issues/37513
\ No newline at end of file
diff --git a/pkg/front_end/test/language_versioning/data/specified_packages_04/test.options b/pkg/front_end/test/language_versioning/data/specified_packages_04/test.options
new file mode 100644
index 0000000..5c8ed21
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/specified_packages_04/test.options
@@ -0,0 +1,2 @@
+# Point to .packages => Standard layout; redirect to .dart_tool/package_config.json which in this case isn't a json file. That's an error!
+--packages=.packages
diff --git a/pkg/front_end/test/language_versioning/language_versioning_test.dart b/pkg/front_end/test/language_versioning/language_versioning_test.dart
index 8b4b12b..66b3e37 100644
--- a/pkg/front_end/test/language_versioning/language_versioning_test.dart
+++ b/pkg/front_end/test/language_versioning/language_versioning_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'dart:io' show Directory, Platform;
+import 'dart:io' show Directory, File, Platform;
import 'package:_fe_analyzer_shared/src/testing/id.dart' show ActualData, Id;
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'
show DataInterpreter, StringDataInterpreter, runTests;
@@ -43,8 +43,24 @@
: super(marker, name);
@override
- void customizeCompilerOptions(CompilerOptions options) {
+ void customizeCompilerOptions(CompilerOptions options, TestData testData) {
options.currentSdkVersion = "2.8";
+
+ File f = new File.fromUri(testData.testFileUri.resolve("test.options"));
+ if (f.existsSync()) {
+ List<String> lines = f.readAsStringSync().split("\n");
+ for (String line in lines) {
+ const String packages = "--packages=";
+ if (line == "" || line.startsWith("#")) continue;
+ if (line.startsWith(packages)) {
+ String value = line.substring(packages.length);
+ options.packagesFileUri = testData.entryPoint.resolve(value);
+ print("Setting package file uri to ${options.packagesFileUri}");
+ } else {
+ throw "Unsupported: $line";
+ }
+ }
+ }
}
}
diff --git a/pkg/front_end/test/parser_test_parser.dart b/pkg/front_end/test/parser_test_parser.dart
index d8a9095..e916571 100644
--- a/pkg/front_end/test/parser_test_parser.dart
+++ b/pkg/front_end/test/parser_test_parser.dart
@@ -1218,18 +1218,6 @@
return result;
}
- Token parseNullAwareBracketOrConditionalExpressionRest(
- Token token, TypeParamOrArgInfo typeArg) {
- doPrint('parseNullAwareBracketOrConditionalExpressionRest('
- '$token, '
- '$typeArg)');
- indent++;
- var result =
- super.parseNullAwareBracketOrConditionalExpressionRest(token, typeArg);
- indent--;
- return result;
- }
-
Token parseConditionalExpressionRest(Token token) {
doPrint('parseConditionalExpressionRest(' '$token)');
indent++;
@@ -1755,6 +1743,14 @@
return result;
}
+ bool looksLikeExpression(Token token) {
+ doPrint('looksLikeExpression(' '$token)');
+ indent++;
+ var result = super.looksLikeExpression(token);
+ indent--;
+ return result;
+ }
+
bool looksLikeAwaitExpression(Token token) {
doPrint('looksLikeAwaitExpression(' '$token)');
indent++;
@@ -1763,6 +1759,14 @@
return result;
}
+ bool looksLikeYieldStatement(Token token) {
+ doPrint('looksLikeYieldStatement(' '$token)');
+ indent++;
+ var result = super.looksLikeYieldStatement(token);
+ indent--;
+ return result;
+ }
+
Token parseAwaitExpression(Token token, bool allowCascades) {
doPrint('parseAwaitExpression(' '$token, ' '$allowCascades)');
indent++;
diff --git a/pkg/front_end/test/patching/patching_test.dart b/pkg/front_end/test/patching/patching_test.dart
index 753ef203..389a779 100644
--- a/pkg/front_end/test/patching/patching_test.dart
+++ b/pkg/front_end/test/patching/patching_test.dart
@@ -53,7 +53,7 @@
experimentalFlags: experimentalFlags);
@override
- void customizeCompilerOptions(CompilerOptions options) {
+ void customizeCompilerOptions(CompilerOptions options, TestData testData) {
options.currentSdkVersion = "2.9999";
}
}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 1552922..f38f1d0 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -538,6 +538,7 @@
largest
lattice
layer
+layout
leafp
len
lets
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index c043412..0d1bb73 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -102,6 +102,7 @@
confirm
consecutive
considering
+consolidated
constrains
consts
contract
diff --git a/pkg/front_end/testcases/extensions/extension_methods.dart.hierarchy.expect b/pkg/front_end/testcases/extensions/extension_methods.dart.hierarchy.expect
index 70bc80b..468454b 100644
--- a/pkg/front_end/testcases/extensions/extension_methods.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/extensions/extension_methods.dart.hierarchy.expect
@@ -42,7 +42,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/function_type_is_check.dart.hierarchy.expect b/pkg/front_end/testcases/general/function_type_is_check.dart.hierarchy.expect
index 257f1e9..4f5c506 100644
--- a/pkg/front_end/testcases/general/function_type_is_check.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general/function_type_is_check.dart.hierarchy.expect
@@ -24,7 +24,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/implicit_scope_test.dart.hierarchy.expect b/pkg/front_end/testcases/general/implicit_scope_test.dart.hierarchy.expect
index ad35f25..e04e5f9 100644
--- a/pkg/front_end/testcases/general/implicit_scope_test.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general/implicit_scope_test.dart.hierarchy.expect
@@ -43,7 +43,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.hierarchy.expect b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.hierarchy.expect
index 56e565b..3d588b6 100644
--- a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.hierarchy.expect
@@ -198,7 +198,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart.hierarchy.expect b/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart.hierarchy.expect
index 4b4ba3b..1eaa41a 100644
--- a/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart.hierarchy.expect
@@ -82,7 +82,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/redirection_chain_type_arguments_subst.dart.hierarchy.expect b/pkg/front_end/testcases/general/redirection_chain_type_arguments_subst.dart.hierarchy.expect
index 4b4ba3b..1eaa41a 100644
--- a/pkg/front_end/testcases/general/redirection_chain_type_arguments_subst.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general/redirection_chain_type_arguments_subst.dart.hierarchy.expect
@@ -82,7 +82,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/redirection_type_arguments.dart.hierarchy.expect b/pkg/front_end/testcases/general/redirection_type_arguments.dart.hierarchy.expect
index 41b4b7f..8fd8c13 100644
--- a/pkg/front_end/testcases/general/redirection_type_arguments.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general/redirection_type_arguments.dart.hierarchy.expect
@@ -61,7 +61,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart
index 9a01ce1..d39e9de 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart
@@ -20,6 +20,7 @@
// old syntax: variable named "b" of type "U" of a function called 'Function'.
static void foo13(void Function(U b)) { return null; }
static U foo14 = null;
+ static U Function(U) foo15 = null;
}
main() {}
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.outline.expect b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.outline.expect
index 5db43ea..725cfb7 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.outline.expect
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.outline.expect
@@ -34,11 +34,20 @@
// static U foo14 = null;
// ^
//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:23:10: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:23:21: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
import self as self;
import "dart:core" as core;
class Foo<U extends core::Object* = dynamic> extends core::Object {
static field invalid-type foo14;
+ static field (invalid-type) →* invalid-type foo15;
synthetic constructor •() → self::Foo<self::Foo::U*>*
;
static method foo1() → dynamic
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.expect b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.expect
index 966ed95..dfd67aa 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.expect
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.expect
@@ -34,6 +34,14 @@
// static U foo14 = null;
// ^
//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:23:10: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:23:21: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:7:20: Error: Type variables can't be used in static members.
// static void foo2(U x) { return null; }
// ^
@@ -58,31 +66,24 @@
// void Function (U y) foo7 = (U y) => y;
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:12:19: Error: Type variables can't be used in static members.
-// void Function (U y) foo7 = (U y) => y;
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:31: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:21: Error: Type variables can't be used in static members.
// static void foo10(U Function()) { return null; }
-// ^
+// ^
//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:35: Error: Type variables can't be used in static members.
// static void foo12(void Function(U) b) { return null; }
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:34: Error: Type variables can't be used in static members.
-// static void foo12(void Function(U) b) { return null; }
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:34: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:35: Error: Type variables can't be used in static members.
// static void foo13(void Function(U b)) { return null; }
-// ^
+// ^
//
import self as self;
import "dart:core" as core;
class Foo<U extends core::Object* = dynamic> extends core::Object {
static field invalid-type foo14 = null;
+ static field (invalid-type) →* invalid-type foo15 = null;
synthetic constructor •() → self::Foo<self::Foo::U*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.transformed.expect b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.transformed.expect
index 966ed95..dfd67aa 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart.strong.transformed.expect
@@ -34,6 +34,14 @@
// static U foo14 = null;
// ^
//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:23:10: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:23:21: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:7:20: Error: Type variables can't be used in static members.
// static void foo2(U x) { return null; }
// ^
@@ -58,31 +66,24 @@
// void Function (U y) foo7 = (U y) => y;
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:12:19: Error: Type variables can't be used in static members.
-// void Function (U y) foo7 = (U y) => y;
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:31: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:16:21: Error: Type variables can't be used in static members.
// static void foo10(U Function()) { return null; }
-// ^
+// ^
//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:35: Error: Type variables can't be used in static members.
// static void foo12(void Function(U) b) { return null; }
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:19:34: Error: Type variables can't be used in static members.
-// static void foo12(void Function(U) b) { return null; }
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:34: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_class.dart:21:35: Error: Type variables can't be used in static members.
// static void foo13(void Function(U b)) { return null; }
-// ^
+// ^
//
import self as self;
import "dart:core" as core;
class Foo<U extends core::Object* = dynamic> extends core::Object {
static field invalid-type foo14 = null;
+ static field (invalid-type) →* invalid-type foo15 = null;
synthetic constructor •() → self::Foo<self::Foo::U*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart
index 7c56bec..78b773e 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart
@@ -20,6 +20,7 @@
// old syntax: variable named "b" of type "U" of a function called 'Function'.
static void foo13(void Function(U b)) { return null; }
static U foo14 = null;
+ static U Function(U) foo15 = null;
}
main() {}
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.outline.expect b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.outline.expect
index ef530f4..d6da116 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.outline.expect
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.outline.expect
@@ -34,6 +34,14 @@
// static U foo14 = null;
// ^
//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:23:10: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:23:21: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
import self as self;
import "dart:core" as core;
@@ -48,8 +56,10 @@
static method foo12 = self::Foo|foo12;
static method foo13 = self::Foo|foo13;
static field foo14 = self::Foo|foo14;
+ static field foo15 = self::Foo|foo15;
}
static field invalid-type Foo|foo14;
+static field (invalid-type) →* invalid-type Foo|foo15;
static method Foo|foo1() → dynamic
;
static method Foo|foo2(dynamic x) → void
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.expect b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.expect
index e6a1aa9..c1f1018 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.expect
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.expect
@@ -34,6 +34,14 @@
// static U foo14 = null;
// ^
//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:23:10: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:23:21: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:7:20: Error: Type variables can't be used in static members.
// static void foo2(U x) { return null; }
// ^
@@ -58,25 +66,17 @@
// void Function (U y) foo7 = (U y) => y;
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:12:19: Error: Type variables can't be used in static members.
-// void Function (U y) foo7 = (U y) => y;
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:16:31: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:16:21: Error: Type variables can't be used in static members.
// static void foo10(U Function()) { return null; }
-// ^
+// ^
//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:19:35: Error: Type variables can't be used in static members.
// static void foo12(void Function(U) b) { return null; }
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:19:34: Error: Type variables can't be used in static members.
-// static void foo12(void Function(U) b) { return null; }
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:21:34: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:21:35: Error: Type variables can't be used in static members.
// static void foo13(void Function(U b)) { return null; }
-// ^
+// ^
//
import self as self;
import "dart:core" as core;
@@ -92,8 +92,10 @@
static method foo12 = self::Foo|foo12;
static method foo13 = self::Foo|foo13;
static field foo14 = self::Foo|foo14;
+ static field foo15 = self::Foo|foo15;
}
static field invalid-type Foo|foo14 = null;
+static field (invalid-type) →* invalid-type Foo|foo15 = null;
static method Foo|foo1() → dynamic {
return null;
}
diff --git a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.transformed.expect b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.transformed.expect
index e6a1aa9..c1f1018 100644
--- a/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart.strong.transformed.expect
@@ -34,6 +34,14 @@
// static U foo14 = null;
// ^
//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:23:10: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:23:21: Error: Type variables can't be used in static members.
+// static U Function(U) foo15 = null;
+// ^
+//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:7:20: Error: Type variables can't be used in static members.
// static void foo2(U x) { return null; }
// ^
@@ -58,25 +66,17 @@
// void Function (U y) foo7 = (U y) => y;
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:12:19: Error: Type variables can't be used in static members.
-// void Function (U y) foo7 = (U y) => y;
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:16:31: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:16:21: Error: Type variables can't be used in static members.
// static void foo10(U Function()) { return null; }
-// ^
+// ^
//
// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:19:35: Error: Type variables can't be used in static members.
// static void foo12(void Function(U) b) { return null; }
// ^
//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:19:34: Error: Type variables can't be used in static members.
-// static void foo12(void Function(U) b) { return null; }
-// ^
-//
-// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:21:34: Error: Type variables can't be used in static members.
+// pkg/front_end/testcases/general/type_parameter_usage_in_static_method_in_extension.dart:21:35: Error: Type variables can't be used in static members.
// static void foo13(void Function(U b)) { return null; }
-// ^
+// ^
//
import self as self;
import "dart:core" as core;
@@ -92,8 +92,10 @@
static method foo12 = self::Foo|foo12;
static method foo13 = self::Foo|foo13;
static field foo14 = self::Foo|foo14;
+ static field foo15 = self::Foo|foo15;
}
static field invalid-type Foo|foo14 = null;
+static field (invalid-type) →* invalid-type Foo|foo15 = null;
static method Foo|foo1() → dynamic {
return null;
}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/function_type_is_check.dart.hierarchy.expect b/pkg/front_end/testcases/general_nnbd_opt_out/function_type_is_check.dart.hierarchy.expect
index 257f1e9..4f5c506 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/function_type_is_check.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/function_type_is_check.dart.hierarchy.expect
@@ -24,7 +24,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/implicit_scope_test.dart.hierarchy.expect b/pkg/front_end/testcases/general_nnbd_opt_out/implicit_scope_test.dart.hierarchy.expect
index ad35f25..e04e5f9 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/implicit_scope_test.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/implicit_scope_test.dart.hierarchy.expect
@@ -43,7 +43,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_constructors_with_default_values.dart.hierarchy.expect b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_constructors_with_default_values.dart.hierarchy.expect
index 56e565b..3d588b6 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/mixin_constructors_with_default_values.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/mixin_constructors_with_default_values.dart.hierarchy.expect
@@ -198,7 +198,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments.dart.hierarchy.expect b/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments.dart.hierarchy.expect
index 4b4ba3b..1eaa41a 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments.dart.hierarchy.expect
@@ -82,7 +82,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments_subst.dart.hierarchy.expect b/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments_subst.dart.hierarchy.expect
index 4b4ba3b..1eaa41a 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments_subst.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/redirection_chain_type_arguments_subst.dart.hierarchy.expect
@@ -82,7 +82,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/redirection_type_arguments.dart.hierarchy.expect b/pkg/front_end/testcases/general_nnbd_opt_out/redirection_type_arguments.dart.hierarchy.expect
index 41b4b7f..8fd8c13 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/redirection_type_arguments.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/redirection_type_arguments.dart.hierarchy.expect
@@ -61,7 +61,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/instantiate_to_bound/supertypes.dart.hierarchy.expect b/pkg/front_end/testcases/instantiate_to_bound/supertypes.dart.hierarchy.expect
index f3acb23..a7e1277 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/supertypes.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/supertypes.dart.hierarchy.expect
@@ -76,7 +76,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/late_lowering/late_future_or.dart b/pkg/front_end/testcases/late_lowering/late_future_or.dart
new file mode 100644
index 0000000..c211da1
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_future_or.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+FutureOr method1() => null;
+FutureOr? method2() => null;
+FutureOr<dynamic> method3() => null;
+FutureOr<int> method4() => 0;
+FutureOr<int?> method5() => null;
+FutureOr<int?>? method6() => null;
+
+late var field1 = method1();
+late var field2 = method2();
+late var field3 = method3();
+late var field4 = method4();
+late var field5 = method5();
+late var field6 = method6();
+
+class C<T> {
+ late FutureOr field1;
+ late FutureOr? field2;
+ late FutureOr<T> field3;
+ late FutureOr<T?> field4;
+ late FutureOr<T?>? field5;
+
+ method() {
+ late FutureOr local1;
+ late FutureOr? local2;
+ late FutureOr<T> local3;
+ late FutureOr<T?> local4;
+ late FutureOr<T?>? local5;
+ }
+}
+
+// TODO(johnniwinther): Add test for override inference when the consolidated
+// model is implemented.
+
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering/late_future_or.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_future_or.dart.outline.expect
new file mode 100644
index 0000000..0cc888e
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_future_or.dart.outline.expect
@@ -0,0 +1,71 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ field asy::FutureOr<dynamic>? _#C#field1;
+ field core::bool _#C#field1#isSet;
+ field asy::FutureOr<dynamic>? _#C#field2;
+ field core::bool _#C#field2#isSet;
+ generic-covariant-impl field asy::FutureOr<self::C::T%>? _#C#field3;
+ field core::bool _#C#field3#isSet;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field4;
+ field core::bool _#C#field4#isSet;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field5;
+ field core::bool _#C#field5#isSet;
+ synthetic constructor •() → self::C<self::C::T%>
+ ;
+ get field1() → asy::FutureOr<dynamic>;
+ set field1(asy::FutureOr<dynamic> #t1) → void;
+ get field2() → asy::FutureOr<dynamic>?;
+ set field2(asy::FutureOr<dynamic>? #t2) → void;
+ get field3() → asy::FutureOr<self::C::T%>;
+ set field3(asy::FutureOr<self::C::T%> #t3) → void;
+ get field4() → asy::FutureOr<self::C::T?>;
+ set field4(asy::FutureOr<self::C::T?> #t4) → void;
+ get field5() → asy::FutureOr<self::C::T?>?;
+ set field5(asy::FutureOr<self::C::T?>? #t5) → void;
+ method method() → dynamic
+ ;
+}
+static field asy::FutureOr<dynamic>? _#field1;
+static field core::bool _#field1#isSet;
+static field asy::FutureOr<dynamic>? _#field2;
+static field core::bool _#field2#isSet;
+static field asy::FutureOr<dynamic>? _#field3;
+static field core::bool _#field3#isSet;
+static field asy::FutureOr<core::int>? _#field4;
+static field core::bool _#field4#isSet;
+static field asy::FutureOr<core::int?>? _#field5;
+static field core::bool _#field5#isSet;
+static field asy::FutureOr<core::int?>? _#field6;
+static field core::bool _#field6#isSet;
+static method method1() → asy::FutureOr<dynamic>
+ ;
+static method method2() → asy::FutureOr<dynamic>?
+ ;
+static method method3() → asy::FutureOr<dynamic>
+ ;
+static method method4() → asy::FutureOr<core::int>
+ ;
+static method method5() → asy::FutureOr<core::int?>
+ ;
+static method method6() → asy::FutureOr<core::int?>?
+ ;
+static get field1() → asy::FutureOr<dynamic>;
+static set field1(asy::FutureOr<dynamic> #t6) → void;
+static get field2() → asy::FutureOr<dynamic>?;
+static set field2(asy::FutureOr<dynamic>? #t7) → void;
+static get field3() → asy::FutureOr<dynamic>;
+static set field3(asy::FutureOr<dynamic> #t8) → void;
+static get field4() → asy::FutureOr<core::int>;
+static set field4(asy::FutureOr<core::int> #t9) → void;
+static get field5() → asy::FutureOr<core::int?>;
+static set field5(asy::FutureOr<core::int?> #t10) → void;
+static get field6() → asy::FutureOr<core::int?>?;
+static set field6(asy::FutureOr<core::int?>? #t11) → void;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/late_lowering/late_future_or.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_future_or.dart.strong.expect
new file mode 100644
index 0000000..3ad795c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_future_or.dart.strong.expect
@@ -0,0 +1,179 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+import "dart:_internal" as _in;
+
+import "dart:async";
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ field asy::FutureOr<dynamic>? _#C#field1 = null;
+ field core::bool _#C#field1#isSet = false;
+ field asy::FutureOr<dynamic>? _#C#field2 = null;
+ field core::bool _#C#field2#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T%>? _#C#field3 = null;
+ field core::bool _#C#field3#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field4 = null;
+ field core::bool _#C#field4#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field5 = null;
+ field core::bool _#C#field5#isSet = false;
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ get field1() → asy::FutureOr<dynamic>
+ return this.{self::C::_#C#field1#isSet} ?{asy::FutureOr<dynamic>} this.{self::C::_#C#field1} : throw new _in::LateInitializationErrorImpl::•("Field 'field1' has not been initialized.");
+ set field1(asy::FutureOr<dynamic> #t1) → void {
+ this.{self::C::_#C#field1#isSet} = true;
+ this.{self::C::_#C#field1} = #t1;
+ }
+ get field2() → asy::FutureOr<dynamic>?
+ return this.{self::C::_#C#field2#isSet} ?{asy::FutureOr<dynamic>?} this.{self::C::_#C#field2} : throw new _in::LateInitializationErrorImpl::•("Field 'field2' has not been initialized.");
+ set field2(asy::FutureOr<dynamic>? #t2) → void {
+ this.{self::C::_#C#field2#isSet} = true;
+ this.{self::C::_#C#field2} = #t2;
+ }
+ get field3() → asy::FutureOr<self::C::T%>
+ return this.{self::C::_#C#field3#isSet} ?{asy::FutureOr<self::C::T%>} let final asy::FutureOr<self::C::T%>? #t3 = this.{self::C::_#C#field3} in #t3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Field 'field3' has not been initialized.");
+ set field3(asy::FutureOr<self::C::T%> #t4) → void {
+ this.{self::C::_#C#field3#isSet} = true;
+ this.{self::C::_#C#field3} = #t4;
+ }
+ get field4() → asy::FutureOr<self::C::T?>
+ return this.{self::C::_#C#field4#isSet} ?{asy::FutureOr<self::C::T?>} this.{self::C::_#C#field4} : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
+ set field4(asy::FutureOr<self::C::T?> #t5) → void {
+ this.{self::C::_#C#field4#isSet} = true;
+ this.{self::C::_#C#field4} = #t5;
+ }
+ get field5() → asy::FutureOr<self::C::T?>?
+ return this.{self::C::_#C#field5#isSet} ?{asy::FutureOr<self::C::T?>?} this.{self::C::_#C#field5} : throw new _in::LateInitializationErrorImpl::•("Field 'field5' has not been initialized.");
+ set field5(asy::FutureOr<self::C::T?>? #t6) → void {
+ this.{self::C::_#C#field5#isSet} = true;
+ this.{self::C::_#C#field5} = #t6;
+ }
+ method method() → dynamic {
+ asy::FutureOr<dynamic>? local1;
+ core::bool #local1#isSet = false;
+ function #local1#get() → asy::FutureOr<dynamic>
+ return #local1#isSet ?{asy::FutureOr<dynamic>} local1 : throw new _in::LateInitializationErrorImpl::•("Local 'local1' has not been initialized.");
+ function #local1#set(asy::FutureOr<dynamic> #t7) → dynamic {
+ #local1#isSet = true;
+ return local1 = #t7;
+ }
+ asy::FutureOr<dynamic>? local2;
+ core::bool #local2#isSet = false;
+ function #local2#get() → asy::FutureOr<dynamic>?
+ return #local2#isSet ?{asy::FutureOr<dynamic>?} local2 : throw new _in::LateInitializationErrorImpl::•("Local 'local2' has not been initialized.");
+ function #local2#set(asy::FutureOr<dynamic>? #t8) → dynamic {
+ #local2#isSet = true;
+ return local2 = #t8;
+ }
+ asy::FutureOr<self::C::T%>? local3;
+ core::bool #local3#isSet = false;
+ function #local3#get() → asy::FutureOr<self::C::T%>
+ return #local3#isSet ?{asy::FutureOr<self::C::T%>} local3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Local 'local3' has not been initialized.");
+ function #local3#set(asy::FutureOr<self::C::T%> #t9) → dynamic {
+ #local3#isSet = true;
+ return local3 = #t9;
+ }
+ asy::FutureOr<self::C::T?>? local4;
+ core::bool #local4#isSet = false;
+ function #local4#get() → asy::FutureOr<self::C::T?>
+ return #local4#isSet ?{asy::FutureOr<self::C::T?>} local4 : throw new _in::LateInitializationErrorImpl::•("Local 'local4' has not been initialized.");
+ function #local4#set(asy::FutureOr<self::C::T?> #t10) → dynamic {
+ #local4#isSet = true;
+ return local4 = #t10;
+ }
+ asy::FutureOr<self::C::T?>? local5;
+ core::bool #local5#isSet = false;
+ function #local5#get() → asy::FutureOr<self::C::T?>?
+ return #local5#isSet ?{asy::FutureOr<self::C::T?>?} local5 : throw new _in::LateInitializationErrorImpl::•("Local 'local5' has not been initialized.");
+ function #local5#set(asy::FutureOr<self::C::T?>? #t11) → dynamic {
+ #local5#isSet = true;
+ return local5 = #t11;
+ }
+ }
+}
+static field asy::FutureOr<dynamic>? _#field1 = null;
+static field core::bool _#field1#isSet = false;
+static field asy::FutureOr<dynamic>? _#field2 = null;
+static field core::bool _#field2#isSet = false;
+static field asy::FutureOr<dynamic>? _#field3 = null;
+static field core::bool _#field3#isSet = false;
+static field asy::FutureOr<core::int>? _#field4 = null;
+static field core::bool _#field4#isSet = false;
+static field asy::FutureOr<core::int?>? _#field5 = null;
+static field core::bool _#field5#isSet = false;
+static field asy::FutureOr<core::int?>? _#field6 = null;
+static field core::bool _#field6#isSet = false;
+static method method1() → asy::FutureOr<dynamic>
+ return null;
+static method method2() → asy::FutureOr<dynamic>?
+ return null;
+static method method3() → asy::FutureOr<dynamic>
+ return null;
+static method method4() → asy::FutureOr<core::int>
+ return 0;
+static method method5() → asy::FutureOr<core::int?>
+ return null;
+static method method6() → asy::FutureOr<core::int?>?
+ return null;
+static get field1() → asy::FutureOr<dynamic> {
+ if(!self::_#field1#isSet) {
+ self::_#field1#isSet = true;
+ self::_#field1 = self::method1();
+ }
+ return self::_#field1;
+}
+static set field1(asy::FutureOr<dynamic> #t12) → void {
+ self::_#field1#isSet = true;
+ self::_#field1 = #t12;
+}
+static get field2() → asy::FutureOr<dynamic>? {
+ if(!self::_#field2#isSet) {
+ self::_#field2#isSet = true;
+ self::_#field2 = self::method2();
+ }
+ return self::_#field2;
+}
+static set field2(asy::FutureOr<dynamic>? #t13) → void {
+ self::_#field2#isSet = true;
+ self::_#field2 = #t13;
+}
+static get field3() → asy::FutureOr<dynamic> {
+ if(!self::_#field3#isSet) {
+ self::_#field3#isSet = true;
+ self::_#field3 = self::method3();
+ }
+ return self::_#field3;
+}
+static set field3(asy::FutureOr<dynamic> #t14) → void {
+ self::_#field3#isSet = true;
+ self::_#field3 = #t14;
+}
+static get field4() → asy::FutureOr<core::int>
+ return let final asy::FutureOr<core::int>? #t15 = self::_#field4 in #t15.==(null) ?{asy::FutureOr<core::int>} self::_#field4 = self::method4() : #t15{asy::FutureOr<core::int>};
+static set field4(asy::FutureOr<core::int> #t16) → void
+ self::_#field4 = #t16;
+static get field5() → asy::FutureOr<core::int?> {
+ if(!self::_#field5#isSet) {
+ self::_#field5#isSet = true;
+ self::_#field5 = self::method5();
+ }
+ return self::_#field5;
+}
+static set field5(asy::FutureOr<core::int?> #t17) → void {
+ self::_#field5#isSet = true;
+ self::_#field5 = #t17;
+}
+static get field6() → asy::FutureOr<core::int?>? {
+ if(!self::_#field6#isSet) {
+ self::_#field6#isSet = true;
+ self::_#field6 = self::method6();
+ }
+ return self::_#field6;
+}
+static set field6(asy::FutureOr<core::int?>? #t18) → void {
+ self::_#field6#isSet = true;
+ self::_#field6 = #t18;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering/late_future_or.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_future_or.dart.strong.transformed.expect
new file mode 100644
index 0000000..3ad795c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_future_or.dart.strong.transformed.expect
@@ -0,0 +1,179 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+import "dart:_internal" as _in;
+
+import "dart:async";
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ field asy::FutureOr<dynamic>? _#C#field1 = null;
+ field core::bool _#C#field1#isSet = false;
+ field asy::FutureOr<dynamic>? _#C#field2 = null;
+ field core::bool _#C#field2#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T%>? _#C#field3 = null;
+ field core::bool _#C#field3#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field4 = null;
+ field core::bool _#C#field4#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field5 = null;
+ field core::bool _#C#field5#isSet = false;
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ get field1() → asy::FutureOr<dynamic>
+ return this.{self::C::_#C#field1#isSet} ?{asy::FutureOr<dynamic>} this.{self::C::_#C#field1} : throw new _in::LateInitializationErrorImpl::•("Field 'field1' has not been initialized.");
+ set field1(asy::FutureOr<dynamic> #t1) → void {
+ this.{self::C::_#C#field1#isSet} = true;
+ this.{self::C::_#C#field1} = #t1;
+ }
+ get field2() → asy::FutureOr<dynamic>?
+ return this.{self::C::_#C#field2#isSet} ?{asy::FutureOr<dynamic>?} this.{self::C::_#C#field2} : throw new _in::LateInitializationErrorImpl::•("Field 'field2' has not been initialized.");
+ set field2(asy::FutureOr<dynamic>? #t2) → void {
+ this.{self::C::_#C#field2#isSet} = true;
+ this.{self::C::_#C#field2} = #t2;
+ }
+ get field3() → asy::FutureOr<self::C::T%>
+ return this.{self::C::_#C#field3#isSet} ?{asy::FutureOr<self::C::T%>} let final asy::FutureOr<self::C::T%>? #t3 = this.{self::C::_#C#field3} in #t3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Field 'field3' has not been initialized.");
+ set field3(asy::FutureOr<self::C::T%> #t4) → void {
+ this.{self::C::_#C#field3#isSet} = true;
+ this.{self::C::_#C#field3} = #t4;
+ }
+ get field4() → asy::FutureOr<self::C::T?>
+ return this.{self::C::_#C#field4#isSet} ?{asy::FutureOr<self::C::T?>} this.{self::C::_#C#field4} : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
+ set field4(asy::FutureOr<self::C::T?> #t5) → void {
+ this.{self::C::_#C#field4#isSet} = true;
+ this.{self::C::_#C#field4} = #t5;
+ }
+ get field5() → asy::FutureOr<self::C::T?>?
+ return this.{self::C::_#C#field5#isSet} ?{asy::FutureOr<self::C::T?>?} this.{self::C::_#C#field5} : throw new _in::LateInitializationErrorImpl::•("Field 'field5' has not been initialized.");
+ set field5(asy::FutureOr<self::C::T?>? #t6) → void {
+ this.{self::C::_#C#field5#isSet} = true;
+ this.{self::C::_#C#field5} = #t6;
+ }
+ method method() → dynamic {
+ asy::FutureOr<dynamic>? local1;
+ core::bool #local1#isSet = false;
+ function #local1#get() → asy::FutureOr<dynamic>
+ return #local1#isSet ?{asy::FutureOr<dynamic>} local1 : throw new _in::LateInitializationErrorImpl::•("Local 'local1' has not been initialized.");
+ function #local1#set(asy::FutureOr<dynamic> #t7) → dynamic {
+ #local1#isSet = true;
+ return local1 = #t7;
+ }
+ asy::FutureOr<dynamic>? local2;
+ core::bool #local2#isSet = false;
+ function #local2#get() → asy::FutureOr<dynamic>?
+ return #local2#isSet ?{asy::FutureOr<dynamic>?} local2 : throw new _in::LateInitializationErrorImpl::•("Local 'local2' has not been initialized.");
+ function #local2#set(asy::FutureOr<dynamic>? #t8) → dynamic {
+ #local2#isSet = true;
+ return local2 = #t8;
+ }
+ asy::FutureOr<self::C::T%>? local3;
+ core::bool #local3#isSet = false;
+ function #local3#get() → asy::FutureOr<self::C::T%>
+ return #local3#isSet ?{asy::FutureOr<self::C::T%>} local3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Local 'local3' has not been initialized.");
+ function #local3#set(asy::FutureOr<self::C::T%> #t9) → dynamic {
+ #local3#isSet = true;
+ return local3 = #t9;
+ }
+ asy::FutureOr<self::C::T?>? local4;
+ core::bool #local4#isSet = false;
+ function #local4#get() → asy::FutureOr<self::C::T?>
+ return #local4#isSet ?{asy::FutureOr<self::C::T?>} local4 : throw new _in::LateInitializationErrorImpl::•("Local 'local4' has not been initialized.");
+ function #local4#set(asy::FutureOr<self::C::T?> #t10) → dynamic {
+ #local4#isSet = true;
+ return local4 = #t10;
+ }
+ asy::FutureOr<self::C::T?>? local5;
+ core::bool #local5#isSet = false;
+ function #local5#get() → asy::FutureOr<self::C::T?>?
+ return #local5#isSet ?{asy::FutureOr<self::C::T?>?} local5 : throw new _in::LateInitializationErrorImpl::•("Local 'local5' has not been initialized.");
+ function #local5#set(asy::FutureOr<self::C::T?>? #t11) → dynamic {
+ #local5#isSet = true;
+ return local5 = #t11;
+ }
+ }
+}
+static field asy::FutureOr<dynamic>? _#field1 = null;
+static field core::bool _#field1#isSet = false;
+static field asy::FutureOr<dynamic>? _#field2 = null;
+static field core::bool _#field2#isSet = false;
+static field asy::FutureOr<dynamic>? _#field3 = null;
+static field core::bool _#field3#isSet = false;
+static field asy::FutureOr<core::int>? _#field4 = null;
+static field core::bool _#field4#isSet = false;
+static field asy::FutureOr<core::int?>? _#field5 = null;
+static field core::bool _#field5#isSet = false;
+static field asy::FutureOr<core::int?>? _#field6 = null;
+static field core::bool _#field6#isSet = false;
+static method method1() → asy::FutureOr<dynamic>
+ return null;
+static method method2() → asy::FutureOr<dynamic>?
+ return null;
+static method method3() → asy::FutureOr<dynamic>
+ return null;
+static method method4() → asy::FutureOr<core::int>
+ return 0;
+static method method5() → asy::FutureOr<core::int?>
+ return null;
+static method method6() → asy::FutureOr<core::int?>?
+ return null;
+static get field1() → asy::FutureOr<dynamic> {
+ if(!self::_#field1#isSet) {
+ self::_#field1#isSet = true;
+ self::_#field1 = self::method1();
+ }
+ return self::_#field1;
+}
+static set field1(asy::FutureOr<dynamic> #t12) → void {
+ self::_#field1#isSet = true;
+ self::_#field1 = #t12;
+}
+static get field2() → asy::FutureOr<dynamic>? {
+ if(!self::_#field2#isSet) {
+ self::_#field2#isSet = true;
+ self::_#field2 = self::method2();
+ }
+ return self::_#field2;
+}
+static set field2(asy::FutureOr<dynamic>? #t13) → void {
+ self::_#field2#isSet = true;
+ self::_#field2 = #t13;
+}
+static get field3() → asy::FutureOr<dynamic> {
+ if(!self::_#field3#isSet) {
+ self::_#field3#isSet = true;
+ self::_#field3 = self::method3();
+ }
+ return self::_#field3;
+}
+static set field3(asy::FutureOr<dynamic> #t14) → void {
+ self::_#field3#isSet = true;
+ self::_#field3 = #t14;
+}
+static get field4() → asy::FutureOr<core::int>
+ return let final asy::FutureOr<core::int>? #t15 = self::_#field4 in #t15.==(null) ?{asy::FutureOr<core::int>} self::_#field4 = self::method4() : #t15{asy::FutureOr<core::int>};
+static set field4(asy::FutureOr<core::int> #t16) → void
+ self::_#field4 = #t16;
+static get field5() → asy::FutureOr<core::int?> {
+ if(!self::_#field5#isSet) {
+ self::_#field5#isSet = true;
+ self::_#field5 = self::method5();
+ }
+ return self::_#field5;
+}
+static set field5(asy::FutureOr<core::int?> #t17) → void {
+ self::_#field5#isSet = true;
+ self::_#field5 = #t17;
+}
+static get field6() → asy::FutureOr<core::int?>? {
+ if(!self::_#field6#isSet) {
+ self::_#field6#isSet = true;
+ self::_#field6 = self::method6();
+ }
+ return self::_#field6;
+}
+static set field6(asy::FutureOr<core::int?>? #t18) → void {
+ self::_#field6#isSet = true;
+ self::_#field6 = #t18;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering/late_future_or.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_future_or.dart.weak.expect
new file mode 100644
index 0000000..3ad795c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_future_or.dart.weak.expect
@@ -0,0 +1,179 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+import "dart:_internal" as _in;
+
+import "dart:async";
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ field asy::FutureOr<dynamic>? _#C#field1 = null;
+ field core::bool _#C#field1#isSet = false;
+ field asy::FutureOr<dynamic>? _#C#field2 = null;
+ field core::bool _#C#field2#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T%>? _#C#field3 = null;
+ field core::bool _#C#field3#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field4 = null;
+ field core::bool _#C#field4#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field5 = null;
+ field core::bool _#C#field5#isSet = false;
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ get field1() → asy::FutureOr<dynamic>
+ return this.{self::C::_#C#field1#isSet} ?{asy::FutureOr<dynamic>} this.{self::C::_#C#field1} : throw new _in::LateInitializationErrorImpl::•("Field 'field1' has not been initialized.");
+ set field1(asy::FutureOr<dynamic> #t1) → void {
+ this.{self::C::_#C#field1#isSet} = true;
+ this.{self::C::_#C#field1} = #t1;
+ }
+ get field2() → asy::FutureOr<dynamic>?
+ return this.{self::C::_#C#field2#isSet} ?{asy::FutureOr<dynamic>?} this.{self::C::_#C#field2} : throw new _in::LateInitializationErrorImpl::•("Field 'field2' has not been initialized.");
+ set field2(asy::FutureOr<dynamic>? #t2) → void {
+ this.{self::C::_#C#field2#isSet} = true;
+ this.{self::C::_#C#field2} = #t2;
+ }
+ get field3() → asy::FutureOr<self::C::T%>
+ return this.{self::C::_#C#field3#isSet} ?{asy::FutureOr<self::C::T%>} let final asy::FutureOr<self::C::T%>? #t3 = this.{self::C::_#C#field3} in #t3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Field 'field3' has not been initialized.");
+ set field3(asy::FutureOr<self::C::T%> #t4) → void {
+ this.{self::C::_#C#field3#isSet} = true;
+ this.{self::C::_#C#field3} = #t4;
+ }
+ get field4() → asy::FutureOr<self::C::T?>
+ return this.{self::C::_#C#field4#isSet} ?{asy::FutureOr<self::C::T?>} this.{self::C::_#C#field4} : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
+ set field4(asy::FutureOr<self::C::T?> #t5) → void {
+ this.{self::C::_#C#field4#isSet} = true;
+ this.{self::C::_#C#field4} = #t5;
+ }
+ get field5() → asy::FutureOr<self::C::T?>?
+ return this.{self::C::_#C#field5#isSet} ?{asy::FutureOr<self::C::T?>?} this.{self::C::_#C#field5} : throw new _in::LateInitializationErrorImpl::•("Field 'field5' has not been initialized.");
+ set field5(asy::FutureOr<self::C::T?>? #t6) → void {
+ this.{self::C::_#C#field5#isSet} = true;
+ this.{self::C::_#C#field5} = #t6;
+ }
+ method method() → dynamic {
+ asy::FutureOr<dynamic>? local1;
+ core::bool #local1#isSet = false;
+ function #local1#get() → asy::FutureOr<dynamic>
+ return #local1#isSet ?{asy::FutureOr<dynamic>} local1 : throw new _in::LateInitializationErrorImpl::•("Local 'local1' has not been initialized.");
+ function #local1#set(asy::FutureOr<dynamic> #t7) → dynamic {
+ #local1#isSet = true;
+ return local1 = #t7;
+ }
+ asy::FutureOr<dynamic>? local2;
+ core::bool #local2#isSet = false;
+ function #local2#get() → asy::FutureOr<dynamic>?
+ return #local2#isSet ?{asy::FutureOr<dynamic>?} local2 : throw new _in::LateInitializationErrorImpl::•("Local 'local2' has not been initialized.");
+ function #local2#set(asy::FutureOr<dynamic>? #t8) → dynamic {
+ #local2#isSet = true;
+ return local2 = #t8;
+ }
+ asy::FutureOr<self::C::T%>? local3;
+ core::bool #local3#isSet = false;
+ function #local3#get() → asy::FutureOr<self::C::T%>
+ return #local3#isSet ?{asy::FutureOr<self::C::T%>} local3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Local 'local3' has not been initialized.");
+ function #local3#set(asy::FutureOr<self::C::T%> #t9) → dynamic {
+ #local3#isSet = true;
+ return local3 = #t9;
+ }
+ asy::FutureOr<self::C::T?>? local4;
+ core::bool #local4#isSet = false;
+ function #local4#get() → asy::FutureOr<self::C::T?>
+ return #local4#isSet ?{asy::FutureOr<self::C::T?>} local4 : throw new _in::LateInitializationErrorImpl::•("Local 'local4' has not been initialized.");
+ function #local4#set(asy::FutureOr<self::C::T?> #t10) → dynamic {
+ #local4#isSet = true;
+ return local4 = #t10;
+ }
+ asy::FutureOr<self::C::T?>? local5;
+ core::bool #local5#isSet = false;
+ function #local5#get() → asy::FutureOr<self::C::T?>?
+ return #local5#isSet ?{asy::FutureOr<self::C::T?>?} local5 : throw new _in::LateInitializationErrorImpl::•("Local 'local5' has not been initialized.");
+ function #local5#set(asy::FutureOr<self::C::T?>? #t11) → dynamic {
+ #local5#isSet = true;
+ return local5 = #t11;
+ }
+ }
+}
+static field asy::FutureOr<dynamic>? _#field1 = null;
+static field core::bool _#field1#isSet = false;
+static field asy::FutureOr<dynamic>? _#field2 = null;
+static field core::bool _#field2#isSet = false;
+static field asy::FutureOr<dynamic>? _#field3 = null;
+static field core::bool _#field3#isSet = false;
+static field asy::FutureOr<core::int>? _#field4 = null;
+static field core::bool _#field4#isSet = false;
+static field asy::FutureOr<core::int?>? _#field5 = null;
+static field core::bool _#field5#isSet = false;
+static field asy::FutureOr<core::int?>? _#field6 = null;
+static field core::bool _#field6#isSet = false;
+static method method1() → asy::FutureOr<dynamic>
+ return null;
+static method method2() → asy::FutureOr<dynamic>?
+ return null;
+static method method3() → asy::FutureOr<dynamic>
+ return null;
+static method method4() → asy::FutureOr<core::int>
+ return 0;
+static method method5() → asy::FutureOr<core::int?>
+ return null;
+static method method6() → asy::FutureOr<core::int?>?
+ return null;
+static get field1() → asy::FutureOr<dynamic> {
+ if(!self::_#field1#isSet) {
+ self::_#field1#isSet = true;
+ self::_#field1 = self::method1();
+ }
+ return self::_#field1;
+}
+static set field1(asy::FutureOr<dynamic> #t12) → void {
+ self::_#field1#isSet = true;
+ self::_#field1 = #t12;
+}
+static get field2() → asy::FutureOr<dynamic>? {
+ if(!self::_#field2#isSet) {
+ self::_#field2#isSet = true;
+ self::_#field2 = self::method2();
+ }
+ return self::_#field2;
+}
+static set field2(asy::FutureOr<dynamic>? #t13) → void {
+ self::_#field2#isSet = true;
+ self::_#field2 = #t13;
+}
+static get field3() → asy::FutureOr<dynamic> {
+ if(!self::_#field3#isSet) {
+ self::_#field3#isSet = true;
+ self::_#field3 = self::method3();
+ }
+ return self::_#field3;
+}
+static set field3(asy::FutureOr<dynamic> #t14) → void {
+ self::_#field3#isSet = true;
+ self::_#field3 = #t14;
+}
+static get field4() → asy::FutureOr<core::int>
+ return let final asy::FutureOr<core::int>? #t15 = self::_#field4 in #t15.==(null) ?{asy::FutureOr<core::int>} self::_#field4 = self::method4() : #t15{asy::FutureOr<core::int>};
+static set field4(asy::FutureOr<core::int> #t16) → void
+ self::_#field4 = #t16;
+static get field5() → asy::FutureOr<core::int?> {
+ if(!self::_#field5#isSet) {
+ self::_#field5#isSet = true;
+ self::_#field5 = self::method5();
+ }
+ return self::_#field5;
+}
+static set field5(asy::FutureOr<core::int?> #t17) → void {
+ self::_#field5#isSet = true;
+ self::_#field5 = #t17;
+}
+static get field6() → asy::FutureOr<core::int?>? {
+ if(!self::_#field6#isSet) {
+ self::_#field6#isSet = true;
+ self::_#field6 = self::method6();
+ }
+ return self::_#field6;
+}
+static set field6(asy::FutureOr<core::int?>? #t18) → void {
+ self::_#field6#isSet = true;
+ self::_#field6 = #t18;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering/late_future_or.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_future_or.dart.weak.transformed.expect
new file mode 100644
index 0000000..3ad795c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_future_or.dart.weak.transformed.expect
@@ -0,0 +1,179 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+import "dart:_internal" as _in;
+
+import "dart:async";
+
+class C<T extends core::Object? = dynamic> extends core::Object {
+ field asy::FutureOr<dynamic>? _#C#field1 = null;
+ field core::bool _#C#field1#isSet = false;
+ field asy::FutureOr<dynamic>? _#C#field2 = null;
+ field core::bool _#C#field2#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T%>? _#C#field3 = null;
+ field core::bool _#C#field3#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field4 = null;
+ field core::bool _#C#field4#isSet = false;
+ generic-covariant-impl field asy::FutureOr<self::C::T?>? _#C#field5 = null;
+ field core::bool _#C#field5#isSet = false;
+ synthetic constructor •() → self::C<self::C::T%>
+ : super core::Object::•()
+ ;
+ get field1() → asy::FutureOr<dynamic>
+ return this.{self::C::_#C#field1#isSet} ?{asy::FutureOr<dynamic>} this.{self::C::_#C#field1} : throw new _in::LateInitializationErrorImpl::•("Field 'field1' has not been initialized.");
+ set field1(asy::FutureOr<dynamic> #t1) → void {
+ this.{self::C::_#C#field1#isSet} = true;
+ this.{self::C::_#C#field1} = #t1;
+ }
+ get field2() → asy::FutureOr<dynamic>?
+ return this.{self::C::_#C#field2#isSet} ?{asy::FutureOr<dynamic>?} this.{self::C::_#C#field2} : throw new _in::LateInitializationErrorImpl::•("Field 'field2' has not been initialized.");
+ set field2(asy::FutureOr<dynamic>? #t2) → void {
+ this.{self::C::_#C#field2#isSet} = true;
+ this.{self::C::_#C#field2} = #t2;
+ }
+ get field3() → asy::FutureOr<self::C::T%>
+ return this.{self::C::_#C#field3#isSet} ?{asy::FutureOr<self::C::T%>} let final asy::FutureOr<self::C::T%>? #t3 = this.{self::C::_#C#field3} in #t3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Field 'field3' has not been initialized.");
+ set field3(asy::FutureOr<self::C::T%> #t4) → void {
+ this.{self::C::_#C#field3#isSet} = true;
+ this.{self::C::_#C#field3} = #t4;
+ }
+ get field4() → asy::FutureOr<self::C::T?>
+ return this.{self::C::_#C#field4#isSet} ?{asy::FutureOr<self::C::T?>} this.{self::C::_#C#field4} : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has not been initialized.");
+ set field4(asy::FutureOr<self::C::T?> #t5) → void {
+ this.{self::C::_#C#field4#isSet} = true;
+ this.{self::C::_#C#field4} = #t5;
+ }
+ get field5() → asy::FutureOr<self::C::T?>?
+ return this.{self::C::_#C#field5#isSet} ?{asy::FutureOr<self::C::T?>?} this.{self::C::_#C#field5} : throw new _in::LateInitializationErrorImpl::•("Field 'field5' has not been initialized.");
+ set field5(asy::FutureOr<self::C::T?>? #t6) → void {
+ this.{self::C::_#C#field5#isSet} = true;
+ this.{self::C::_#C#field5} = #t6;
+ }
+ method method() → dynamic {
+ asy::FutureOr<dynamic>? local1;
+ core::bool #local1#isSet = false;
+ function #local1#get() → asy::FutureOr<dynamic>
+ return #local1#isSet ?{asy::FutureOr<dynamic>} local1 : throw new _in::LateInitializationErrorImpl::•("Local 'local1' has not been initialized.");
+ function #local1#set(asy::FutureOr<dynamic> #t7) → dynamic {
+ #local1#isSet = true;
+ return local1 = #t7;
+ }
+ asy::FutureOr<dynamic>? local2;
+ core::bool #local2#isSet = false;
+ function #local2#get() → asy::FutureOr<dynamic>?
+ return #local2#isSet ?{asy::FutureOr<dynamic>?} local2 : throw new _in::LateInitializationErrorImpl::•("Local 'local2' has not been initialized.");
+ function #local2#set(asy::FutureOr<dynamic>? #t8) → dynamic {
+ #local2#isSet = true;
+ return local2 = #t8;
+ }
+ asy::FutureOr<self::C::T%>? local3;
+ core::bool #local3#isSet = false;
+ function #local3#get() → asy::FutureOr<self::C::T%>
+ return #local3#isSet ?{asy::FutureOr<self::C::T%>} local3{asy::FutureOr<self::C::T%>} : throw new _in::LateInitializationErrorImpl::•("Local 'local3' has not been initialized.");
+ function #local3#set(asy::FutureOr<self::C::T%> #t9) → dynamic {
+ #local3#isSet = true;
+ return local3 = #t9;
+ }
+ asy::FutureOr<self::C::T?>? local4;
+ core::bool #local4#isSet = false;
+ function #local4#get() → asy::FutureOr<self::C::T?>
+ return #local4#isSet ?{asy::FutureOr<self::C::T?>} local4 : throw new _in::LateInitializationErrorImpl::•("Local 'local4' has not been initialized.");
+ function #local4#set(asy::FutureOr<self::C::T?> #t10) → dynamic {
+ #local4#isSet = true;
+ return local4 = #t10;
+ }
+ asy::FutureOr<self::C::T?>? local5;
+ core::bool #local5#isSet = false;
+ function #local5#get() → asy::FutureOr<self::C::T?>?
+ return #local5#isSet ?{asy::FutureOr<self::C::T?>?} local5 : throw new _in::LateInitializationErrorImpl::•("Local 'local5' has not been initialized.");
+ function #local5#set(asy::FutureOr<self::C::T?>? #t11) → dynamic {
+ #local5#isSet = true;
+ return local5 = #t11;
+ }
+ }
+}
+static field asy::FutureOr<dynamic>? _#field1 = null;
+static field core::bool _#field1#isSet = false;
+static field asy::FutureOr<dynamic>? _#field2 = null;
+static field core::bool _#field2#isSet = false;
+static field asy::FutureOr<dynamic>? _#field3 = null;
+static field core::bool _#field3#isSet = false;
+static field asy::FutureOr<core::int>? _#field4 = null;
+static field core::bool _#field4#isSet = false;
+static field asy::FutureOr<core::int?>? _#field5 = null;
+static field core::bool _#field5#isSet = false;
+static field asy::FutureOr<core::int?>? _#field6 = null;
+static field core::bool _#field6#isSet = false;
+static method method1() → asy::FutureOr<dynamic>
+ return null;
+static method method2() → asy::FutureOr<dynamic>?
+ return null;
+static method method3() → asy::FutureOr<dynamic>
+ return null;
+static method method4() → asy::FutureOr<core::int>
+ return 0;
+static method method5() → asy::FutureOr<core::int?>
+ return null;
+static method method6() → asy::FutureOr<core::int?>?
+ return null;
+static get field1() → asy::FutureOr<dynamic> {
+ if(!self::_#field1#isSet) {
+ self::_#field1#isSet = true;
+ self::_#field1 = self::method1();
+ }
+ return self::_#field1;
+}
+static set field1(asy::FutureOr<dynamic> #t12) → void {
+ self::_#field1#isSet = true;
+ self::_#field1 = #t12;
+}
+static get field2() → asy::FutureOr<dynamic>? {
+ if(!self::_#field2#isSet) {
+ self::_#field2#isSet = true;
+ self::_#field2 = self::method2();
+ }
+ return self::_#field2;
+}
+static set field2(asy::FutureOr<dynamic>? #t13) → void {
+ self::_#field2#isSet = true;
+ self::_#field2 = #t13;
+}
+static get field3() → asy::FutureOr<dynamic> {
+ if(!self::_#field3#isSet) {
+ self::_#field3#isSet = true;
+ self::_#field3 = self::method3();
+ }
+ return self::_#field3;
+}
+static set field3(asy::FutureOr<dynamic> #t14) → void {
+ self::_#field3#isSet = true;
+ self::_#field3 = #t14;
+}
+static get field4() → asy::FutureOr<core::int>
+ return let final asy::FutureOr<core::int>? #t15 = self::_#field4 in #t15.==(null) ?{asy::FutureOr<core::int>} self::_#field4 = self::method4() : #t15{asy::FutureOr<core::int>};
+static set field4(asy::FutureOr<core::int> #t16) → void
+ self::_#field4 = #t16;
+static get field5() → asy::FutureOr<core::int?> {
+ if(!self::_#field5#isSet) {
+ self::_#field5#isSet = true;
+ self::_#field5 = self::method5();
+ }
+ return self::_#field5;
+}
+static set field5(asy::FutureOr<core::int?> #t17) → void {
+ self::_#field5#isSet = true;
+ self::_#field5 = #t17;
+}
+static get field6() → asy::FutureOr<core::int?>? {
+ if(!self::_#field6#isSet) {
+ self::_#field6#isSet = true;
+ self::_#field6 = self::method6();
+ }
+ return self::_#field6;
+}
+static set field6(asy::FutureOr<core::int?>? #t18) → void {
+ self::_#field6#isSet = true;
+ self::_#field6 = #t18;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart
new file mode 100644
index 0000000..6eec70e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.5
+
+import 'literal_from_opt_in_lib.dart';
+
+main() {
+ var l1 = const [a];
+ var l2 = const [b];
+ var l3 = const [c];
+ var l4 = const [d];
+ var l5 = const [e];
+}
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.outline.expect b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.outline.expect
new file mode 100644
index 0000000..7086aea
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///literal_from_opt_in_lib.dart";
+
+static method main() → dynamic
+ ;
+
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+
+class Const<T extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field self2::Const::T% field;
+ const constructor •(self2::Const::T% field) → self2::Const<self2::Const::T%>
+ : self2::Const::field = field, super core::Object::•()
+ ;
+}
+static const field self2::Const<core::int> a = const self2::Const::•<core::int>(0);
+static const field self2::Const<core::int?> b = const self2::Const::•<core::int?>(0);
+static const field self2::Const<core::int?> c = const self2::Const::•<core::int?>(null);
+static const field self2::Const<core::int>? d = const self2::Const::•<core::int>(0);
+static const field self2::Const<core::int>? e = null;
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.strong.expect b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.strong.expect
new file mode 100644
index 0000000..e5e0414
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.strong.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "literal_from_opt_in_lib.dart" as lit;
+
+import "org-dartlang-testcase:///literal_from_opt_in_lib.dart";
+
+static method main() → dynamic {
+ core::List<lit::Const<core::int*>*>* l1 = #C3;
+ core::List<lit::Const<core::int*>*>* l2 = #C5;
+ core::List<lit::Const<core::int*>*>* l3 = #C8;
+ core::List<lit::Const<core::int*>*>* l4 = #C3;
+ core::List<lit::Const<core::int*>*>* l5 = #C9;
+}
+
+library /*isNonNullableByDefault*/;
+import self as lit;
+import "dart:core" as core;
+
+class Const<T extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field lit::Const::T% field;
+ const constructor •(lit::Const::T% field) → lit::Const<lit::Const::T%>
+ : lit::Const::field = field, super core::Object::•()
+ ;
+}
+static const field lit::Const<core::int> a = #C2;
+static const field lit::Const<core::int?> b = #C4;
+static const field lit::Const<core::int?> c = #C7;
+static const field lit::Const<core::int>? d = #C2;
+static const field lit::Const<core::int>? e = #C6;
+
+constants {
+ #C1 = 0
+ #C2 = lit::Const<core::int> {field:#C1}
+ #C3 = <lit::Const<core::int*>*>[#C2]
+ #C4 = lit::Const<core::int?> {field:#C1}
+ #C5 = <lit::Const<core::int*>*>[#C4]
+ #C6 = null
+ #C7 = lit::Const<core::int?> {field:#C6}
+ #C8 = <lit::Const<core::int*>*>[#C7]
+ #C9 = <lit::Const<core::int*>*>[#C6]
+}
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.strong.transformed.expect
new file mode 100644
index 0000000..e5e0414
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.strong.transformed.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "literal_from_opt_in_lib.dart" as lit;
+
+import "org-dartlang-testcase:///literal_from_opt_in_lib.dart";
+
+static method main() → dynamic {
+ core::List<lit::Const<core::int*>*>* l1 = #C3;
+ core::List<lit::Const<core::int*>*>* l2 = #C5;
+ core::List<lit::Const<core::int*>*>* l3 = #C8;
+ core::List<lit::Const<core::int*>*>* l4 = #C3;
+ core::List<lit::Const<core::int*>*>* l5 = #C9;
+}
+
+library /*isNonNullableByDefault*/;
+import self as lit;
+import "dart:core" as core;
+
+class Const<T extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field lit::Const::T% field;
+ const constructor •(lit::Const::T% field) → lit::Const<lit::Const::T%>
+ : lit::Const::field = field, super core::Object::•()
+ ;
+}
+static const field lit::Const<core::int> a = #C2;
+static const field lit::Const<core::int?> b = #C4;
+static const field lit::Const<core::int?> c = #C7;
+static const field lit::Const<core::int>? d = #C2;
+static const field lit::Const<core::int>? e = #C6;
+
+constants {
+ #C1 = 0
+ #C2 = lit::Const<core::int> {field:#C1}
+ #C3 = <lit::Const<core::int*>*>[#C2]
+ #C4 = lit::Const<core::int?> {field:#C1}
+ #C5 = <lit::Const<core::int*>*>[#C4]
+ #C6 = null
+ #C7 = lit::Const<core::int?> {field:#C6}
+ #C8 = <lit::Const<core::int*>*>[#C7]
+ #C9 = <lit::Const<core::int*>*>[#C6]
+}
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.weak.expect b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.weak.expect
new file mode 100644
index 0000000..f236f21
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.weak.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "literal_from_opt_in_lib.dart" as lit;
+
+import "org-dartlang-testcase:///literal_from_opt_in_lib.dart";
+
+static method main() → dynamic {
+ core::List<lit::Const<core::int*>*>* l1 = #C3;
+ core::List<lit::Const<core::int*>*>* l2 = #C3;
+ core::List<lit::Const<core::int*>*>* l3 = #C6;
+ core::List<lit::Const<core::int*>*>* l4 = #C3;
+ core::List<lit::Const<core::int*>*>* l5 = #C7;
+}
+
+library /*isNonNullableByDefault*/;
+import self as lit;
+import "dart:core" as core;
+
+class Const<T extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field lit::Const::T% field;
+ const constructor •(lit::Const::T% field) → lit::Const<lit::Const::T%>
+ : lit::Const::field = field, super core::Object::•()
+ ;
+}
+static const field lit::Const<core::int> a = #C2;
+static const field lit::Const<core::int?> b = #C2;
+static const field lit::Const<core::int?> c = #C5;
+static const field lit::Const<core::int>? d = #C2;
+static const field lit::Const<core::int>? e = #C4;
+
+constants {
+ #C1 = 0
+ #C2 = lit::Const<core::int*> {field:#C1}
+ #C3 = <lit::Const<core::int*>*>[#C2]
+ #C4 = null
+ #C5 = lit::Const<core::int*> {field:#C4}
+ #C6 = <lit::Const<core::int*>*>[#C5]
+ #C7 = <lit::Const<core::int*>*>[#C4]
+}
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.weak.transformed.expect
new file mode 100644
index 0000000..f236f21
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in.dart.weak.transformed.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "literal_from_opt_in_lib.dart" as lit;
+
+import "org-dartlang-testcase:///literal_from_opt_in_lib.dart";
+
+static method main() → dynamic {
+ core::List<lit::Const<core::int*>*>* l1 = #C3;
+ core::List<lit::Const<core::int*>*>* l2 = #C3;
+ core::List<lit::Const<core::int*>*>* l3 = #C6;
+ core::List<lit::Const<core::int*>*>* l4 = #C3;
+ core::List<lit::Const<core::int*>*>* l5 = #C7;
+}
+
+library /*isNonNullableByDefault*/;
+import self as lit;
+import "dart:core" as core;
+
+class Const<T extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field lit::Const::T% field;
+ const constructor •(lit::Const::T% field) → lit::Const<lit::Const::T%>
+ : lit::Const::field = field, super core::Object::•()
+ ;
+}
+static const field lit::Const<core::int> a = #C2;
+static const field lit::Const<core::int?> b = #C2;
+static const field lit::Const<core::int?> c = #C5;
+static const field lit::Const<core::int>? d = #C2;
+static const field lit::Const<core::int>? e = #C4;
+
+constants {
+ #C1 = 0
+ #C2 = lit::Const<core::int*> {field:#C1}
+ #C3 = <lit::Const<core::int*>*>[#C2]
+ #C4 = null
+ #C5 = lit::Const<core::int*> {field:#C4}
+ #C6 = <lit::Const<core::int*>*>[#C5]
+ #C7 = <lit::Const<core::int*>*>[#C4]
+}
diff --git a/pkg/front_end/testcases/nnbd/literal_from_opt_in_lib.dart b/pkg/front_end/testcases/nnbd/literal_from_opt_in_lib.dart
new file mode 100644
index 0000000..86c3129
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/literal_from_opt_in_lib.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Const<T> {
+ final T field;
+
+ const Const(this.field);
+}
+
+const Const<int> a = const Const<int>(0);
+const Const<int?> b = const Const<int?>(0);
+const Const<int?> c = const Const<int?>(null);
+const Const<int>? d = const Const<int>(0);
+const Const<int>? e = null;
diff --git a/pkg/front_end/testcases/nnbd/never_opt_out.dart.strong.expect b/pkg/front_end/testcases/nnbd/never_opt_out.dart.strong.expect
index 0fb13f2..83a210a 100644
--- a/pkg/front_end/testcases/nnbd/never_opt_out.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/never_opt_out.dart.strong.expect
@@ -44,7 +44,7 @@
static method main() → dynamic {
Never* localNever = null;
core::Null? localNull = null;
- Never inferredLocalNever = nev::optInNever;
+ Never* inferredLocalNever = nev::optInNever;
localNever = localNever;
self::optOutNever = localNever;
nev::optInNever = localNever;
@@ -68,25 +68,25 @@
nev::optInNever = localNull as{TypeError} Never;
localNull = localNull;
self::inferredOptOutNever = localNull;
- inferredLocalNever = localNull as{TypeError} Never;
+ inferredLocalNever = localNull;
localNever = self::inferredOptOutNever;
self::optOutNever = self::inferredOptOutNever;
nev::optInNever = self::inferredOptOutNever as{TypeError} Never;
localNull = self::inferredOptOutNever;
self::inferredOptOutNever = self::inferredOptOutNever;
- inferredLocalNever = self::inferredOptOutNever as{TypeError} Never;
+ inferredLocalNever = self::inferredOptOutNever;
localNever = inferredLocalNever;
self::optOutNever = inferredLocalNever;
nev::optInNever = inferredLocalNever;
localNull = inferredLocalNever;
self::inferredOptOutNever = inferredLocalNever;
inferredLocalNever = inferredLocalNever;
- self::throws(() → Never => self::optOutNever = nev::throwing());
- self::throws(() → Never => localNever = nev::throwing());
- self::throws(() → Never => self::optOutNever = nev::throwing());
- self::throws(() → Never => nev::optInNever = nev::throwing());
- self::throws(() → Never => self::inferredOptOutNever = nev::throwing());
- self::throws(() → Never => inferredLocalNever = nev::throwing());
+ self::throws(() → Never* => self::optOutNever = nev::throwing());
+ self::throws(() → Never* => localNever = nev::throwing());
+ self::throws(() → Never* => self::optOutNever = nev::throwing());
+ self::throws(() → Never* => nev::optInNever = nev::throwing());
+ self::throws(() → Never* => self::inferredOptOutNever = nev::throwing());
+ self::throws(() → Never* => inferredLocalNever = nev::throwing());
}
static method throws(() →* void f) → dynamic {
try {
diff --git a/pkg/front_end/testcases/nnbd/never_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd/never_opt_out.dart.weak.expect
index e4651a2..ecb173e 100644
--- a/pkg/front_end/testcases/nnbd/never_opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/never_opt_out.dart.weak.expect
@@ -44,7 +44,7 @@
static method main() → dynamic {
Never* localNever = null;
core::Null? localNull = null;
- Never inferredLocalNever = nev::optInNever;
+ Never* inferredLocalNever = nev::optInNever;
localNever = localNever;
self::optOutNever = localNever;
nev::optInNever = localNever;
@@ -68,25 +68,25 @@
nev::optInNever = localNull as{TypeError} Never;
localNull = localNull;
self::inferredOptOutNever = localNull;
- inferredLocalNever = localNull as{TypeError} Never;
+ inferredLocalNever = localNull;
localNever = self::inferredOptOutNever;
self::optOutNever = self::inferredOptOutNever;
nev::optInNever = self::inferredOptOutNever as{TypeError} Never;
localNull = self::inferredOptOutNever;
self::inferredOptOutNever = self::inferredOptOutNever;
- inferredLocalNever = self::inferredOptOutNever as{TypeError} Never;
+ inferredLocalNever = self::inferredOptOutNever;
localNever = inferredLocalNever;
self::optOutNever = inferredLocalNever;
nev::optInNever = inferredLocalNever;
localNull = inferredLocalNever;
self::inferredOptOutNever = inferredLocalNever;
inferredLocalNever = inferredLocalNever;
- self::throws(() → Never => self::optOutNever = nev::throwing());
- self::throws(() → Never => localNever = nev::throwing());
- self::throws(() → Never => self::optOutNever = nev::throwing());
- self::throws(() → Never => nev::optInNever = nev::throwing());
- self::throws(() → Never => self::inferredOptOutNever = nev::throwing());
- self::throws(() → Never => inferredLocalNever = nev::throwing());
+ self::throws(() → Never* => self::optOutNever = nev::throwing());
+ self::throws(() → Never* => localNever = nev::throwing());
+ self::throws(() → Never* => self::optOutNever = nev::throwing());
+ self::throws(() → Never* => nev::optInNever = nev::throwing());
+ self::throws(() → Never* => self::inferredOptOutNever = nev::throwing());
+ self::throws(() → Never* => inferredLocalNever = nev::throwing());
}
static method throws(() →* void f) → dynamic {
try {
diff --git a/pkg/front_end/testcases/rasta/issue_000002.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/issue_000002.dart.hierarchy.expect
index 355be78..3c0c735 100644
--- a/pkg/front_end/testcases/rasta/issue_000002.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/issue_000002.dart.hierarchy.expect
@@ -42,7 +42,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/rasta/issue_000004.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/issue_000004.dart.hierarchy.expect
index 257f1e9..4f5c506 100644
--- a/pkg/front_end/testcases/rasta/issue_000004.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/issue_000004.dart.hierarchy.expect
@@ -24,7 +24,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/rasta/issue_000067.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/issue_000067.dart.hierarchy.expect
index 7f642c2..b93d5f7 100644
--- a/pkg/front_end/testcases/rasta/issue_000067.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/issue_000067.dart.hierarchy.expect
@@ -85,7 +85,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/rasta/issue_000068.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/issue_000068.dart.hierarchy.expect
index 4f43eef..6c40be8 100644
--- a/pkg/front_end/testcases/rasta/issue_000068.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/issue_000068.dart.hierarchy.expect
@@ -95,7 +95,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/rasta/issue_000070.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/issue_000070.dart.hierarchy.expect
index 2c66573..1b8b8b9 100644
--- a/pkg/front_end/testcases/rasta/issue_000070.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/issue_000070.dart.hierarchy.expect
@@ -79,7 +79,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/rasta/parser_error.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/parser_error.dart.hierarchy.expect
index 257f1e9..4f5c506 100644
--- a/pkg/front_end/testcases/rasta/parser_error.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/parser_error.dart.hierarchy.expect
@@ -24,7 +24,7 @@
interfaces:
classMembers:
Expect.identical
- Expect.throwsCastError
+ Expect.throwsTypeError
Expect._fail
Expect.notIdentical
Expect.isNotNull
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 78eabf1..72977f5 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -1224,6 +1224,7 @@
late_lowering/late_final_nullable_field_without_initializer: TextSerializationFailure
late_lowering/late_final_nullable_local_with_initializer: TextSerializationFailure
late_lowering/late_final_nullable_local_without_initializer: TextSerializationFailure
+late_lowering/late_future_or: TextSerializationFailure
late_lowering/late_local_with_initializer: TextSerializationFailure
late_lowering/late_local_without_initializer: TextSerializationFailure
late_lowering/late_nullable_field_with_initializer: TextSerializationFailure
@@ -1271,6 +1272,7 @@
nnbd/later: TextSerializationFailure
nnbd/lhs_of_if_null: TextSerializationFailure
nnbd/list_constructor: TextSerializationFailure
+nnbd/literal_from_opt_in: TextSerializationFailure
nnbd/member_inheritance_from_opt_in: TextSerializationFailure
nnbd/member_inheritance_from_opt_out: TextSerializationFailure
nnbd/messages_with_types_opt_in: TypeCheckError
diff --git a/pkg/kernel/lib/src/future_or.dart b/pkg/kernel/lib/src/future_or.dart
index f655959..5555a0b 100644
--- a/pkg/kernel/lib/src/future_or.dart
+++ b/pkg/kernel/lib/src/future_or.dart
@@ -35,7 +35,7 @@
Nullability computeNullabilityOfFutureOr(
InterfaceType futureOr, Class futureOrClass) {
- assert(futureOr.classNode == futureOrClass);
+ assert(_isFutureOr(futureOr, futureOrClass));
// Performance note: the algorithm is linear.
DartType argument = futureOr.typeArguments.single;
@@ -46,8 +46,7 @@
}
if (argument is TypeParameterType && argument.promotedBound != null) {
DartType promotedBound = argument.promotedBound;
- if (promotedBound is InterfaceType &&
- promotedBound.className == futureOrClass) {
+ if (_isFutureOr(promotedBound, futureOrClass)) {
return uniteNullabilities(
intersectNullabilities(argument.typeParameterTypeNullability,
computeNullabilityOfFutureOr(promotedBound, futureOrClass)),
@@ -59,8 +58,21 @@
return uniteNullabilities(argumentNullability, futureOr.nullability);
}
+bool _isFutureOr(DartType type, Class futureOrClass) {
+ if (type is InterfaceType) {
+ if (futureOrClass != null) {
+ return type.classNode == futureOrClass;
+ } else {
+ return type.classNode.name == 'FutureOr' &&
+ type.classNode.enclosingLibrary.importUri.scheme == 'dart' &&
+ type.classNode.enclosingLibrary.importUri.path == 'async';
+ }
+ }
+ return false;
+}
+
Nullability computeNullability(DartType type, Class futureOrClass) {
- if (type is InterfaceType && type.classNode == futureOrClass) {
+ if (_isFutureOr(type, futureOrClass)) {
return computeNullabilityOfFutureOr(type, futureOrClass);
}
return type.nullability;
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index dcd6fd6..c0a7c0d 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -146,6 +146,11 @@
// No nullability or type arguments needed to be substituted.
return null;
} else {
+ if (node.classNode.name == 'Null' &&
+ node.classNode.enclosingLibrary.importUri.scheme == 'dart' &&
+ node.classNode.enclosingLibrary.importUri.path == 'core') {
+ return null;
+ }
return new InterfaceType(
node.classNode,
newNullability ?? node.nullability,
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index b80d616..5320c4a 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -286,7 +286,8 @@
return const IsSubtypeOf.onlyIfIgnoringNullabilities();
}
- if (subtype.isPotentiallyNullable && supertype.isPotentiallyNonNullable) {
+ if (isPotentiallyNullable(subtype, futureOrClass) &&
+ isPotentiallyNonNullable(supertype, futureOrClass)) {
// It's a special case to test X% <: X%, FutureOr<X%> <: FutureOr<X%>,
// FutureOr<FutureOr<X%>> <: FutureOr<FutureOr<X%>>, etc, where X is a
// type parameter. In that case, the nullabilities of the subtype and the
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index 51c2c0a..93f3a9d 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -22,12 +22,31 @@
CodeReference(this.path, this.line, this.column, this.function);
+ /// Creates a [CodeReference] pointing to the given [node].
+ factory CodeReference.fromAstNode(AstNode node) {
+ var compilationUnit = node.thisOrAncestorOfType<CompilationUnit>();
+ var source = compilationUnit.declaredElement.source;
+ var location = compilationUnit.lineInfo.getLocation(node.offset);
+ return CodeReference(source.fullName, location.lineNumber,
+ location.columnNumber, _computeEnclosingName(node));
+ }
+
CodeReference.fromJson(dynamic json)
: path = json['path'] as String,
line = json['line'] as int,
column = json['col'] as int,
function = json['function'] as String;
+ /// Gets a short description of this code reference (using the last component
+ /// of the path rather than the full path)
+ String get shortName => '$shortPath:$line:$column';
+
+ /// Gets the last component of the path part of this code reference.
+ String get shortPath {
+ var pathAsUri = Uri.file(path);
+ return pathAsUri.pathSegments.last;
+ }
+
Map<String, Object> toJson() {
return {
'path': path,
@@ -42,6 +61,27 @@
var pathAsUri = Uri.file(path);
return '${function ?? 'unknown'} ($pathAsUri:$line:$column)';
}
+
+ static String _computeEnclosingName(AstNode node) {
+ List<String> parts = [];
+ while (node != null) {
+ var nodeName = _computeNodeDeclarationName(node);
+ if (nodeName != null) {
+ parts.add(nodeName);
+ }
+ node = node.parent;
+ }
+ if (parts.isEmpty) return null;
+ return parts.reversed.join('.');
+ }
+
+ static String _computeNodeDeclarationName(AstNode node) {
+ if (node is Declaration) {
+ return node.declaredElement?.name;
+ } else {
+ return null;
+ }
+ }
}
/// Information exposed to the migration client about the set of nullability
@@ -72,6 +112,20 @@
DecoratedTypeInfo typeArgument(int i);
}
+/// Information about a propagation stup that occurred during downstream
+/// propagation.
+abstract class DownstreamPropagationStepInfo implements PropagationStepInfo {
+ DownstreamPropagationStepInfo get principalCause;
+
+ /// The node whose nullability was changed.
+ ///
+ /// Any propagation step that took effect should have a non-null value here.
+ /// Propagation steps that are pending but have not taken effect yet, or that
+ /// never had an effect (e.g. because an edge was not triggered) will have a
+ /// `null` value for this field.
+ NullabilityNodeInfo get targetNode;
+}
+
/// Information exposed to the migration client about an edge in the nullability
/// graph.
///
@@ -284,6 +338,10 @@
/// List of compound nodes wrapping this node.
final List<NullabilityNodeInfo> outerCompoundNodes = <NullabilityNodeInfo>[];
+ /// Source code location corresponding to this nullability node, or `null` if
+ /// not known.
+ CodeReference get codeReference;
+
/// Some nodes get nullability from downstream, so the downstream edges are
/// available to query as well.
Iterable<EdgeInfo> get downstreamEdges;
@@ -304,13 +362,13 @@
/// The edges that caused this node to have the nullability that it has.
Iterable<EdgeInfo> get upstreamEdges;
- PropagationStepInfo get whyNullable;
+ /// If [isNullable] is true, the propagation step that caused this node to
+ /// become nullable.
+ DownstreamPropagationStepInfo get whyNullable;
}
abstract class PropagationStepInfo {
CodeReference get codeReference;
-
- PropagationStepInfo get principalCause;
}
/// Information exposed to the migration client about a node in the nullability
diff --git a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
index 76ef942..16f07b6 100644
--- a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
+++ b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
@@ -10,6 +10,7 @@
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/edge_origin.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
/// This class transforms ordinary [DartType]s into their corresponding
/// [DecoratedType]s, assuming the [DartType]s come from code that has already
@@ -23,55 +24,63 @@
/// Transforms [type], which should have come from code that has already been
/// migrated to NNBD, into the corresponding [DecoratedType].
- DecoratedType decorate(DartType type, Element element) {
+ ///
+ /// TODO(paulberry): do we still need element or can we use target now?
+ DecoratedType decorate(
+ DartType type, Element element, NullabilityNodeTarget target) {
if (type.isVoid || type.isDynamic) {
- var node = NullabilityNode.forAlreadyMigrated();
- _graph.makeNullable(node, AlwaysNullableTypeOrigin.forElement(element));
+ var node = NullabilityNode.forAlreadyMigrated(target);
+ _graph.makeNullableUnion(
+ node, AlwaysNullableTypeOrigin.forElement(element));
return DecoratedType(type, node);
}
NullabilityNode node;
var nullabilitySuffix = type.nullabilitySuffix;
if (nullabilitySuffix == NullabilitySuffix.question) {
- node = NullabilityNode.forAlreadyMigrated();
- _graph.makeNullable(node, AlreadyMigratedTypeOrigin.forElement(element));
+ node = NullabilityNode.forAlreadyMigrated(target);
+ _graph.makeNullableUnion(
+ node, AlreadyMigratedTypeOrigin.forElement(element));
} else {
- node = NullabilityNode.forAlreadyMigrated();
+ node = NullabilityNode.forAlreadyMigrated(target);
_graph.makeNonNullableUnion(
node, AlreadyMigratedTypeOrigin.forElement(element));
}
if (type is FunctionType) {
for (var element in type.typeFormals) {
- var bound = element.bound;
- DecoratedType decoratedBound;
- if (bound == null) {
- decoratedBound = decorate(
- (_typeProvider.objectType as TypeImpl)
- .withNullability(NullabilitySuffix.question),
- element);
- } else {
- decoratedBound = decorate(bound, element);
- }
- DecoratedTypeParameterBounds.current.put(element, decoratedBound);
+ DecoratedTypeParameterBounds.current.put(
+ element,
+ decorate(
+ element.bound ??
+ (_typeProvider.objectType as TypeImpl)
+ .withNullability(NullabilitySuffix.question),
+ element,
+ target.typeFormalBound(element.name)));
}
var positionalParameters = <DecoratedType>[];
var namedParameters = <String, DecoratedType>{};
+ int index = 0;
for (var parameter in type.parameters) {
if (parameter.isPositional) {
- positionalParameters.add(decorate(parameter.type, element));
+ positionalParameters.add(decorate(
+ parameter.type, element, target.positionalParameter(index++)));
} else {
- namedParameters[parameter.name] = decorate(parameter.type, element);
+ var name = parameter.name;
+ namedParameters[name] =
+ decorate(parameter.type, element, target.namedParameter(name));
}
}
return DecoratedType(type, node,
- returnType: decorate(type.returnType, element),
+ returnType: decorate(type.returnType, element, target.returnType()),
namedParameters: namedParameters,
positionalParameters: positionalParameters);
} else if (type is InterfaceType) {
var typeParameters = type.element.typeParameters;
if (typeParameters.isNotEmpty) {
assert(type.typeArguments.length == typeParameters.length);
+ int index = 0;
return DecoratedType(type, node, typeArguments: [
- for (var t in type.typeArguments) decorate(t, element)
+ for (var t in type.typeArguments)
+ decorate(t, element, target.typeArgument(index++))
]);
}
return DecoratedType(type, node);
@@ -100,6 +109,9 @@
// Add FutureOr<T> as a supertype of Future<T>.
allSupertypes.add(_typeProvider.futureOrType2(type.typeArguments.single));
}
- return [for (var t in allSupertypes) decorate(t, class_)];
+ return [
+ for (var t in allSupertypes)
+ decorate(t, class_, NullabilityNodeTarget.element(class_))
+ ];
}
}
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index 3a5b782..4c36029 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -9,9 +9,9 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:meta/meta.dart';
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
/// Representation of a type in the code to be migrated. In addition to
/// tracking the (unmigrated) [DartType], we track the [ConstraintVariable]s
@@ -93,20 +93,24 @@
/// Creates a decorated type corresponding to [type], with fresh nullability
/// nodes everywhere that don't correspond to any source location. These
/// nodes can later be unioned with other nodes.
- factory DecoratedType.forImplicitFunction(TypeProvider typeProvider,
- FunctionType type, NullabilityNode node, NullabilityGraph graph,
- {DecoratedType returnType, @required int offset}) {
+ factory DecoratedType.forImplicitFunction(
+ TypeProvider typeProvider,
+ FunctionType type,
+ NullabilityNode node,
+ NullabilityGraph graph,
+ NullabilityNodeTarget target,
+ {DecoratedType returnType}) {
var positionalParameters = <DecoratedType>[];
var namedParameters = <String, DecoratedType>{};
+ int index = 0;
for (var parameter in type.parameters) {
if (parameter.isPositional) {
- positionalParameters.add(DecoratedType.forImplicitType(
- typeProvider, parameter.type, graph,
- offset: offset));
+ positionalParameters.add(DecoratedType.forImplicitType(typeProvider,
+ parameter.type, graph, target.positionalParameter(index++)));
} else {
- namedParameters[parameter.name] = DecoratedType.forImplicitType(
- typeProvider, parameter.type, graph,
- offset: offset);
+ var name = parameter.name;
+ namedParameters[name] = DecoratedType.forImplicitType(
+ typeProvider, parameter.type, graph, target.namedParameter(name));
}
}
for (var element in type.typeFormals) {
@@ -114,14 +118,16 @@
DecoratedTypeParameterBounds.current.put(
element,
DecoratedType.forImplicitType(
- typeProvider, element.bound ?? typeProvider.objectType, graph,
- offset: offset));
+ typeProvider,
+ element.bound ?? typeProvider.objectType,
+ graph,
+ target.typeFormalBound(element.name)));
}
}
return DecoratedType(type, node,
returnType: returnType ??
- DecoratedType.forImplicitType(typeProvider, type.returnType, graph,
- offset: offset),
+ DecoratedType.forImplicitType(
+ typeProvider, type.returnType, graph, target.returnType()),
namedParameters: namedParameters,
positionalParameters: positionalParameters);
}
@@ -129,10 +135,10 @@
/// Creates a DecoratedType corresponding to [type], with fresh nullability
/// nodes everywhere that don't correspond to any source location. These
/// nodes can later be unioned with other nodes.
- factory DecoratedType.forImplicitType(
- TypeProvider typeProvider, DartType type, NullabilityGraph graph,
- {List<DecoratedType> typeArguments, @required int offset}) {
- var nullabilityNode = NullabilityNode.forInferredType(offset: offset);
+ factory DecoratedType.forImplicitType(TypeProvider typeProvider,
+ DartType type, NullabilityGraph graph, NullabilityNodeTarget target,
+ {List<DecoratedType> typeArguments}) {
+ var nullabilityNode = NullabilityNode.forInferredType(target);
if (type is InterfaceType) {
assert(() {
if (typeArguments != null) {
@@ -144,9 +150,10 @@
return true;
}());
+ int index = 0;
typeArguments ??= type.typeArguments
- .map((t) => DecoratedType.forImplicitType(typeProvider, t, graph,
- offset: offset))
+ .map((t) => DecoratedType.forImplicitType(
+ typeProvider, t, graph, target.typeArgument(index++)))
.toList();
return DecoratedType(type, nullabilityNode, typeArguments: typeArguments);
} else if (type is FunctionType) {
@@ -154,8 +161,7 @@
throw "Not supported: implicit function type with explicit type arguments";
}
return DecoratedType.forImplicitFunction(
- typeProvider, type, nullabilityNode, graph,
- offset: offset);
+ typeProvider, type, nullabilityNode, graph, target);
} else {
assert(typeArguments == null);
return DecoratedType(type, nullabilityNode);
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 48517ac..6949482 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -25,6 +25,7 @@
import 'package:nnbd_migration/src/expression_checks.dart';
import 'package:nnbd_migration/src/node_builder.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:nnbd_migration/src/utilities/completeness_tracker.dart';
import 'package:nnbd_migration/src/utilities/permissive_mode.dart';
import 'package:nnbd_migration/src/utilities/resolution_utils.dart';
@@ -243,16 +244,18 @@
var variable = baseElement.variable;
var decoratedElementType = _variables.decoratedElementType(variable);
if (baseElement.isGetter) {
+ var target = NullabilityNodeTarget.text('getter function');
decoratedBaseType = DecoratedType(
- baseElement.type, NullabilityNode.forInferredType(),
+ baseElement.type, NullabilityNode.forInferredType(target),
returnType: decoratedElementType);
} else {
assert(baseElement.isSetter);
+ var target = NullabilityNodeTarget.text('setter function');
decoratedBaseType = DecoratedType(
- baseElement.type, NullabilityNode.forInferredType(),
+ baseElement.type, NullabilityNode.forInferredType(target),
positionalParameters: [decoratedElementType],
- returnType: DecoratedType(
- VoidTypeImpl.instance, NullabilityNode.forInferredType()));
+ returnType: DecoratedType(VoidTypeImpl.instance,
+ NullabilityNode.forInferredType(target.returnType())));
}
} else {
decoratedBaseType = _variables.decoratedElementType(baseElement);
@@ -398,7 +401,7 @@
_postDominatedLocals.doScoped(action: () {
rightType = rightOperand.accept(this);
});
- var ifNullNode = NullabilityNode.forIfNotNull();
+ var ifNullNode = NullabilityNode.forIfNotNull(node);
expressionType = _decorateUpperOrLowerBound(
node, node.staticType, leftType, rightType, true,
node: ifNullNode);
@@ -890,6 +893,7 @@
List<DecoratedType> decoratedTypeArguments;
var typeArguments = node.constructorName.type.typeArguments;
List<EdgeOrigin> parameterEdgeOrigins;
+ var target = NullabilityNodeTarget.codeRef('constructed type', node);
if (typeArguments != null) {
typeArguments.accept(this);
typeArgumentTypes = typeArguments.arguments.map((t) => t.type);
@@ -903,10 +907,11 @@
var staticType = node.staticType;
if (staticType is InterfaceType) {
typeArgumentTypes = staticType.typeArguments;
- decoratedTypeArguments = typeArgumentTypes
- .map((t) => DecoratedType.forImplicitType(typeProvider, t, _graph,
- offset: node.offset))
- .toList();
+ int index = 0;
+ decoratedTypeArguments = typeArgumentTypes.map((t) {
+ return DecoratedType.forImplicitType(
+ typeProvider, t, _graph, target.typeArgument(index++));
+ }).toList();
instrumentation?.implicitTypeArguments(
source, node, decoratedTypeArguments);
parameterEdgeOrigins = List.filled(typeArgumentTypes.length,
@@ -925,7 +930,7 @@
ListLengthConstructorOrigin(source, node));
}
- var nullabilityNode = NullabilityNode.forInferredType(offset: node.offset);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullable(
nullabilityNode, InstanceCreationOrigin(source, node));
var createdType = DecoratedType(node.staticType, nullabilityNode,
@@ -994,9 +999,9 @@
try {
var listType = node.staticType as InterfaceType;
if (node.typeArguments == null) {
+ var target = NullabilityNodeTarget.codeRef('list element type', node);
var elementType = DecoratedType.forImplicitType(
- typeProvider, listType.typeArguments[0], _graph,
- offset: node.offset);
+ typeProvider, listType.typeArguments[0], _graph, target);
instrumentation?.implicitTypeArguments(source, node, [elementType]);
_currentLiteralElementType = elementType;
} else {
@@ -1099,9 +1104,9 @@
@override
DecoratedType visitNullLiteral(NullLiteral node) {
_flowAnalysis.nullLiteral(node);
+ var target = NullabilityNodeTarget.codeRef('null literal', node);
var decoratedType = DecoratedType.forImplicitType(
- typeProvider, node.staticType, _graph,
- offset: node.offset);
+ typeProvider, node.staticType, _graph, target);
_graph.makeNullable(decoratedType.node, LiteralOrigin(source, node));
return decoratedType;
}
@@ -1218,7 +1223,8 @@
@override
DecoratedType visitRethrowExpression(RethrowExpression node) {
_flowAnalysis.handleExit();
- var nullabilityNode = NullabilityNode.forInferredType(offset: node.offset);
+ var target = NullabilityNodeTarget.codeRef('rethrow expression', node);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullable(nullabilityNode, ThrowOrigin(source, node));
return DecoratedType(node.staticType, nullabilityNode);
}
@@ -1229,15 +1235,14 @@
Expression returnValue = node.expression;
final isAsync = node.thisOrAncestorOfType<FunctionBody>().isAsynchronous;
if (returnValue == null) {
+ var target = NullabilityNodeTarget.codeRef('implicit null return', node);
var implicitNullType = DecoratedType.forImplicitType(
- typeProvider, typeProvider.nullType, _graph,
- offset: node.offset);
+ typeProvider, typeProvider.nullType, _graph, target);
_graph.makeNullable(
implicitNullType.node, AlwaysNullableTypeOrigin(source, node));
_checkAssignment(ImplicitNullReturnOrigin(source, node),
- source: isAsync
- ? _futureOf(implicitNullType, offset: node.offset)
- : implicitNullType,
+ source:
+ isAsync ? _futureOf(implicitNullType, node) : implicitNullType,
destination: returnType,
hard: false);
} else {
@@ -1264,9 +1269,9 @@
try {
if (typeArguments == null) {
assert(setOrMapType.typeArguments.length == 1);
+ var target = NullabilityNodeTarget.codeRef('set element type', node);
var elementType = DecoratedType.forImplicitType(
- typeProvider, setOrMapType.typeArguments[0], _graph,
- offset: node.offset);
+ typeProvider, setOrMapType.typeArguments[0], _graph, target);
instrumentation?.implicitTypeArguments(source, node, [elementType]);
_currentLiteralElementType = elementType;
} else {
@@ -1289,13 +1294,14 @@
try {
if (typeArguments == null) {
assert(setOrMapType.typeArguments.length == 2);
+ var targetKey = NullabilityNodeTarget.codeRef('map key type', node);
var keyType = DecoratedType.forImplicitType(
- typeProvider, setOrMapType.typeArguments[0], _graph,
- offset: node.offset);
+ typeProvider, setOrMapType.typeArguments[0], _graph, targetKey);
_currentMapKeyType = keyType;
+ var targetValue =
+ NullabilityNodeTarget.codeRef('map value type', node);
var valueType = DecoratedType.forImplicitType(
- typeProvider, setOrMapType.typeArguments[1], _graph,
- offset: node.offset);
+ typeProvider, setOrMapType.typeArguments[1], _graph, targetValue);
_currentMapValueType = valueType;
instrumentation
?.implicitTypeArguments(source, node, [keyType, valueType]);
@@ -1369,14 +1375,14 @@
DecoratedType visitSpreadElement(SpreadElement node) {
final spreadType = node.expression.staticType;
DecoratedType spreadTypeDecorated;
+ var target = NullabilityNodeTarget.codeRef('spread element type', node);
if (_typeSystem.isSubtypeOf(spreadType, typeProvider.mapObjectObjectType)) {
assert(_currentMapKeyType != null && _currentMapValueType != null);
final expectedType = typeProvider.mapType2(
_currentMapKeyType.type, _currentMapValueType.type);
final expectedDecoratedType = DecoratedType.forImplicitType(
- typeProvider, expectedType, _graph,
- typeArguments: [_currentMapKeyType, _currentMapValueType],
- offset: node.offset);
+ typeProvider, expectedType, _graph, target,
+ typeArguments: [_currentMapKeyType, _currentMapValueType]);
spreadTypeDecorated = _handleAssignment(node.expression,
destinationType: expectedDecoratedType);
@@ -1386,8 +1392,8 @@
final expectedType =
typeProvider.iterableType2(_currentLiteralElementType.type);
final expectedDecoratedType = DecoratedType.forImplicitType(
- typeProvider, expectedType, _graph,
- typeArguments: [_currentLiteralElementType], offset: node.offset);
+ typeProvider, expectedType, _graph, target,
+ typeArguments: [_currentLiteralElementType]);
spreadTypeDecorated = _handleAssignment(node.expression,
destinationType: expectedDecoratedType);
@@ -1412,7 +1418,9 @@
DecoratedType visitSuperConstructorInvocation(
SuperConstructorInvocation node) {
var callee = node.staticElement;
- var nullabilityNode = NullabilityNode.forInferredType(offset: node.offset);
+ var target =
+ NullabilityNodeTarget.codeRef('super constructor invocation', node);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
var class_ = node.thisOrAncestorOfType<ClassDeclaration>();
var decoratedSupertype = _decoratedClassHierarchy.getDecoratedSupertype(
class_.declaredElement, callee.enclosingElement);
@@ -1477,7 +1485,8 @@
node.expression.accept(this);
// TODO(paulberry): do we need to check the expression type? I think not.
_flowAnalysis.handleExit();
- var nullabilityNode = NullabilityNode.forInferredType(offset: node.offset);
+ var target = NullabilityNodeTarget.codeRef('throw expression', node);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullable(nullabilityNode, ThrowOrigin(source, node));
return DecoratedType(node.staticType, nullabilityNode);
}
@@ -1711,12 +1720,12 @@
/// Creates a type that can be used to check that an expression's value is
/// non-nullable.
DecoratedType _createNonNullableType(Expression expression) {
+ var target = NullabilityNodeTarget.codeRef('expression type', expression);
// Note: it's not necessary for the type to precisely match the type of the
// expression, since all we are going to do is cause a single graph edge to
// be built; it is sufficient to pass in any decorated type whose node is
// non-nullable. So we use `Object`.
- var nullabilityNode =
- NullabilityNode.forInferredType(offset: expression.offset);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(
nullabilityNode, NonNullableUsageOrigin(source, expression));
return DecoratedType(typeProvider.objectType, nullabilityNode);
@@ -1889,10 +1898,13 @@
}
}
- DecoratedType _futureOf(DecoratedType type, {@required int offset}) =>
+ DecoratedType _futureOf(DecoratedType type, AstNode node) =>
DecoratedType.forImplicitType(
- typeProvider, typeProvider.futureType2(type.type), _graph,
- typeArguments: [type], offset: offset);
+ typeProvider,
+ typeProvider.futureType2(type.type),
+ _graph,
+ NullabilityNodeTarget.codeRef('implicit future', node),
+ typeArguments: [type]);
@override
DecoratedType _getTypeParameterTypeBound(DecoratedType type) {
@@ -1946,7 +1958,7 @@
try {
sourceType = expression.accept(this);
if (wrapFuture) {
- sourceType = _wrapFuture(sourceType, offset: expression.offset);
+ sourceType = _wrapFuture(sourceType, expression);
}
if (sourceType == null) {
throw StateError('No type computed for ${expression.runtimeType} '
@@ -2282,6 +2294,7 @@
List<TypeParameterElement> constructorTypeParameters,
{DartType invokeType}) {
var typeFormals = constructorTypeParameters ?? calleeType.typeFormals;
+ var target = NullabilityNodeTarget.codeRef('invocation', node);
if (typeFormals.isNotEmpty) {
if (typeArguments != null) {
var argumentTypes = typeArguments.arguments
@@ -2302,8 +2315,7 @@
if (invokeType is FunctionType) {
var argumentTypes = typeArgumentTypes
.map((argType) => DecoratedType.forImplicitType(
- typeProvider, argType, _graph,
- offset: node.offset))
+ typeProvider, argType, _graph, target))
.toList();
instrumentation?.implicitTypeArguments(source, node, argumentTypes);
calleeType = _handleInstantiation(
@@ -2493,8 +2505,8 @@
DecoratedType _makeNonNullableBoolType(Expression expression) {
assert(expression.staticType.isDartCoreBool);
- var nullabilityNode =
- NullabilityNode.forInferredType(offset: expression.offset);
+ var target = NullabilityNodeTarget.codeRef('expression', expression);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(
nullabilityNode, NonNullableBoolTypeOrigin(source, expression));
return DecoratedType(typeProvider.boolType, nullabilityNode);
@@ -2502,8 +2514,8 @@
DecoratedType _makeNonNullLiteralType(Expression expression,
{List<DecoratedType> typeArguments = const []}) {
- var nullabilityNode =
- NullabilityNode.forInferredType(offset: expression.offset);
+ var target = NullabilityNodeTarget.codeRef('expression', expression);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(
nullabilityNode, LiteralOrigin(source, expression));
return DecoratedType(expression.staticType, nullabilityNode,
@@ -2511,18 +2523,18 @@
}
DecoratedType _makeNullableDynamicType(AstNode astNode) {
+ var target = NullabilityNodeTarget.codeRef('dynamic type', astNode);
var decoratedType = DecoratedType.forImplicitType(
- typeProvider, typeProvider.dynamicType, _graph,
- offset: astNode.offset);
+ typeProvider, typeProvider.dynamicType, _graph, target);
_graph.makeNullable(
decoratedType.node, AlwaysNullableTypeOrigin(source, astNode));
return decoratedType;
}
DecoratedType _makeNullableVoidType(SimpleIdentifier astNode) {
+ var target = NullabilityNodeTarget.codeRef('void type', astNode);
var decoratedType = DecoratedType.forImplicitType(
- typeProvider, typeProvider.voidType, _graph,
- offset: astNode.offset);
+ typeProvider, typeProvider.voidType, _graph, target);
_graph.makeNullable(
decoratedType.node, AlwaysNullableTypeOrigin(source, astNode));
return decoratedType;
@@ -2543,14 +2555,15 @@
return null;
}
- NullabilityNode makeNonNullableNode() {
- var nullabilityNode =
- NullabilityNode.forInferredType(offset: node.offset);
+ NullabilityNode makeNonNullableNode(NullabilityNodeTarget target) {
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(
nullabilityNode, ThisOrSuperOrigin(source, node));
return nullabilityNode;
}
+ var token = node.beginToken.lexeme;
+ var target = NullabilityNodeTarget.codeRef('$token expression', node);
if (_currentClassOrExtension is ClassElement) {
final type = (_currentClassOrExtension as ClassElement).thisType;
@@ -2559,20 +2572,24 @@
// with no `?`s. (Even if some of the type parameters are allowed to be
// instantiated with nullable types at runtime, a reference to `this`
// can't be migrated in such a way that forces them to be nullable.)
- return DecoratedType(type, makeNonNullableNode(),
+ var index = 0;
+ return DecoratedType(type, makeNonNullableNode(target),
typeArguments: type.typeArguments
- .map((t) => DecoratedType(t, makeNonNullableNode()))
+ .map((t) => DecoratedType(
+ t, makeNonNullableNode(target.typeArgument(index++))))
.toList());
} else {
assert(_currentClassOrExtension is ExtensionElement);
final type = (_currentClassOrExtension as ExtensionElement).extendedType;
if (type is InterfaceType) {
- return DecoratedType(
- type, NullabilityNode.forInferredType(offset: node.offset),
+ var index = 0;
+ return DecoratedType(type, NullabilityNode.forInferredType(target),
typeArguments: type.typeArguments
.map((t) => DecoratedType(
- t, NullabilityNode.forInferredType(offset: node.offset)))
+ t,
+ NullabilityNode.forInferredType(
+ target.typeArgument(index++))))
.toList());
} else {
_unimplemented(node, 'extension of $type (${type.runtimeType}');
@@ -2598,9 +2615,9 @@
/// Produce Future<flatten(T)> for some T, however, we would like to merely
/// upcast T to that type if possible, skipping the flatten when not
/// necessary.
- DecoratedType _wrapFuture(DecoratedType type, {@required int offset}) {
+ DecoratedType _wrapFuture(DecoratedType type, AstNode node) {
if (type.type.isDartCoreNull || type.type.isBottom) {
- return _futureOf(type, offset: offset);
+ return _futureOf(type, node);
}
if (_typeSystem.isSubtypeOf(type.type, typeProvider.futureDynamicType)) {
@@ -2608,7 +2625,7 @@
type, typeProvider.futureDynamicType.element);
}
- return _futureOf(type, offset: offset);
+ return _futureOf(type, node);
}
}
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index f5ada49..481783a 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -102,36 +102,10 @@
/// created, or `null` if unknown.
CodeReference get codeReference {
if (node != null) {
- var location = node
- .thisOrAncestorOfType<CompilationUnit>()
- .lineInfo
- .getLocation(node.offset);
- return CodeReference(source.fullName, location.lineNumber,
- location.columnNumber, _computeEnclosingName(node));
+ return CodeReference.fromAstNode(node);
}
return null;
}
-
- static String _computeEnclosingName(AstNode node) {
- List<String> parts = [];
- while (node != null) {
- var nodeName = _computeNodeDeclarationName(node);
- if (nodeName != null) {
- parts.add(nodeName);
- }
- node = node.parent;
- }
- if (parts.isEmpty) return null;
- return parts.reversed.join('.');
- }
-
- static String _computeNodeDeclarationName(AstNode node) {
- if (node is Declaration) {
- return node.declaredElement?.name;
- } else {
- return null;
- }
- }
}
/// An edge origin used for edges that originated because of a reference to an
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 81abf14..132666e 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -18,6 +18,7 @@
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/expression_checks.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:nnbd_migration/src/potential_modification.dart';
import 'package:nnbd_migration/src/utilities/completeness_tracker.dart';
import 'package:nnbd_migration/src/utilities/permissive_mode.dart';
@@ -50,6 +51,11 @@
/// seen so far. Otherwise `null`.
List<DecoratedType> _positionalParameters;
+ /// If the child types of a node are being visited, the
+ /// [NullabilityNodeTarget] that should be used in [visitTypeAnnotation].
+ /// Otherwise `null`.
+ NullabilityNodeTarget _target;
+
final NullabilityMigrationListener /*?*/ listener;
final NullabilityMigrationInstrumentation /*?*/ instrumentation;
@@ -68,9 +74,9 @@
if (node.exceptionParameter != null) {
// If there is no `on Type` part of the catch clause, the type is dynamic.
if (exceptionType == null) {
+ var target = NullabilityNodeTarget.codeRef('exception', node);
exceptionType = DecoratedType.forImplicitType(
- _typeProvider, _typeProvider.dynamicType, _graph,
- offset: node.offset);
+ _typeProvider, _typeProvider.dynamicType, _graph, target);
instrumentation?.implicitType(
source, node.exceptionParameter, exceptionType);
}
@@ -79,8 +85,8 @@
}
if (node.stackTraceParameter != null) {
// The type of stack traces is always StackTrace (non-nullable).
- var nullabilityNode = NullabilityNode.forInferredType(
- offset: node.stackTraceParameter.offset);
+ var target = NullabilityNodeTarget.codeRef('stack trace', node);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(nullabilityNode,
StackTraceTypeOrigin(source, node.stackTraceParameter));
var stackTraceType =
@@ -134,9 +140,10 @@
assert(constructorElement.isSynthetic);
var decoratedReturnType =
_createDecoratedTypeForClass(classElement, node);
+ var target = NullabilityNodeTarget.element(constructorElement);
var functionType = DecoratedType.forImplicitFunction(
- _typeProvider, constructorElement.type, _graph.never, _graph,
- returnType: decoratedReturnType, offset: node.offset);
+ _typeProvider, constructorElement.type, _graph.never, _graph, target,
+ returnType: decoratedReturnType);
_variables.recordDecoratedElementType(constructorElement, functionType);
}
return null;
@@ -170,9 +177,10 @@
DecoratedType type = node.type?.accept(this);
if (node.identifier != null) {
if (type == null) {
+ var declaredElement = node.declaredElement;
+ var target = NullabilityNodeTarget.element(declaredElement);
type = DecoratedType.forImplicitType(
- _typeProvider, node.declaredElement.type, _graph,
- offset: node.offset);
+ _typeProvider, declaredElement.type, _graph, target);
instrumentation?.implicitType(source, node, type);
}
_variables.recordDecoratedElementType(
@@ -207,36 +215,44 @@
_variables.recordDecoratedElementType(
classElement, DecoratedType(classElement.thisType, _graph.never));
- makeNonNullNode([AstNode forNode]) {
+ makeNonNullNode(NullabilityNodeTarget target, [AstNode forNode]) {
forNode ??= node;
- final graphNode = NullabilityNode.forInferredType(offset: forNode.offset);
+ final graphNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(graphNode, EnumValueOrigin(source, forNode));
return graphNode;
}
for (var item in node.constants) {
- _variables.recordDecoratedElementType(item.declaredElement,
- DecoratedType(classElement.thisType, makeNonNullNode(item)));
+ var declaredElement = item.declaredElement;
+ var target = NullabilityNodeTarget.element(declaredElement);
+ _variables.recordDecoratedElementType(declaredElement,
+ DecoratedType(classElement.thisType, makeNonNullNode(target, item)));
}
final valuesGetter = classElement.getGetter('values');
+ var valuesTarget = NullabilityNodeTarget.element(valuesGetter);
_variables.recordDecoratedElementType(
valuesGetter,
- DecoratedType(valuesGetter.type, makeNonNullNode(),
- returnType: DecoratedType(
- valuesGetter.returnType, makeNonNullNode(), typeArguments: [
- DecoratedType(classElement.thisType, makeNonNullNode())
- ])));
+ DecoratedType(valuesGetter.type, makeNonNullNode(valuesTarget),
+ returnType: DecoratedType(valuesGetter.returnType,
+ makeNonNullNode(valuesTarget.returnType()),
+ typeArguments: [
+ DecoratedType(classElement.thisType,
+ makeNonNullNode(valuesTarget.typeArgument(0)))
+ ])));
final indexGetter = classElement.getGetter('index');
+ var indexTarget = NullabilityNodeTarget.element(indexGetter);
_variables.recordDecoratedElementType(
indexGetter,
- DecoratedType(indexGetter.type, makeNonNullNode(),
- returnType:
- DecoratedType(indexGetter.returnType, makeNonNullNode())));
+ DecoratedType(indexGetter.type, makeNonNullNode(indexTarget),
+ returnType: DecoratedType(indexGetter.returnType,
+ makeNonNullNode(indexTarget.returnType()))));
final toString = classElement.getMethod('toString');
+ var toStringTarget = NullabilityNodeTarget.element(toString);
_variables.recordDecoratedElementType(
toString,
- DecoratedType(toString.type, makeNonNullNode(),
- returnType: DecoratedType(toString.returnType, makeNonNullNode())));
+ DecoratedType(toString.type, makeNonNullNode(toStringTarget),
+ returnType: DecoratedType(toString.returnType,
+ makeNonNullNode(toStringTarget.returnType()))));
return null;
}
@@ -285,13 +301,15 @@
var functionType = declaredElement.function.type;
var returnType = node.returnType;
DecoratedType decoratedReturnType;
+ var target = NullabilityNodeTarget.element(declaredElement);
if (returnType != null) {
- decoratedReturnType = returnType.accept(this);
+ _pushNullabilityNodeTarget(target.returnType(), () {
+ decoratedReturnType = returnType.accept(this);
+ });
} else {
// Inferred return type.
decoratedReturnType = DecoratedType.forImplicitType(
- _typeProvider, functionType.returnType, _graph,
- offset: node.offset);
+ _typeProvider, functionType.returnType, _graph, target.returnType());
instrumentation?.implicitReturnType(source, node, decoratedReturnType);
}
var previousPositionalParameters = _positionalParameters;
@@ -330,7 +348,15 @@
node.metadata.accept(this);
DecoratedType decoratedFunctionType;
node.typeParameters?.accept(this);
- decoratedFunctionType = node.functionType.accept(this);
+ var target = NullabilityNodeTarget.element(node.declaredElement);
+ var returnType = node.functionType.returnType;
+ if (returnType != null) {
+ _pushNullabilityNodeTarget(target.returnType(), () {
+ decoratedFunctionType = node.functionType.accept(this);
+ });
+ } else {
+ decoratedFunctionType = node.functionType.accept(this);
+ }
_variables.recordDecoratedElementType(
(node.declaredElement as GenericTypeAliasElement).function,
decoratedFunctionType);
@@ -372,8 +398,10 @@
DecoratedType visitTypeAnnotation(TypeAnnotation node) {
assert(node != null); // TODO(paulberry)
var type = node.type;
+ var target =
+ _target ?? NullabilityNodeTarget.codeRef('explicit type', node);
if (type.isVoid || type.isDynamic) {
- var nullabilityNode = NullabilityNode.forTypeAnnotation(node.end);
+ var nullabilityNode = NullabilityNode.forTypeAnnotation(target);
var decoratedType = DecoratedType(type, nullabilityNode);
_variables.recordDecoratedTypeAnnotation(
source, node, decoratedType, null);
@@ -386,10 +414,10 @@
if (type is InterfaceType && type.element.typeParameters.isNotEmpty) {
if (node is TypeName) {
if (node.typeArguments == null) {
+ int index = 0;
typeArguments = type.typeArguments
.map((t) => DecoratedType.forImplicitType(
- _typeProvider, t, _graph,
- offset: node.offset))
+ _typeProvider, t, _graph, target.typeArgument(index++)))
.toList();
instrumentation?.implicitTypeArguments(source, node, typeArguments);
} else {
@@ -403,12 +431,16 @@
if (node is GenericFunctionType) {
var returnType = node.returnType;
if (returnType == null) {
- decoratedReturnType = DecoratedType.forImplicitType(
- _typeProvider, DynamicTypeImpl.instance, _graph,
- offset: node.offset);
+ decoratedReturnType = DecoratedType.forImplicitType(_typeProvider,
+ DynamicTypeImpl.instance, _graph, target.returnType());
instrumentation?.implicitReturnType(source, node, decoratedReturnType);
} else {
- decoratedReturnType = returnType.accept(this);
+ // If [_target] is non-null, then it represents the return type for
+ // a FunctionTypeAlias. Otherwise, create a return type target for
+ // `target`.
+ _pushNullabilityNodeTarget(_target ?? target.returnType(), () {
+ decoratedReturnType = returnType.accept(this);
+ });
}
positionalParameters = <DecoratedType>[];
namedParameters = <String, DecoratedType>{};
@@ -434,7 +466,7 @@
parent is GenericTypeAlias) {
nullabilityNode = _graph.never;
} else {
- nullabilityNode = NullabilityNode.forTypeAnnotation(node.end);
+ nullabilityNode = NullabilityNode.forTypeAnnotation(target);
}
DecoratedType decoratedType;
if (type is FunctionType && node is! GenericFunctionType) {
@@ -443,8 +475,7 @@
// synthesize new nodes for it). These nodes will be unioned with the
// typedef nodes by the edge builder.
decoratedType = DecoratedType.forImplicitFunction(
- _typeProvider, type, nullabilityNode, _graph,
- offset: node.offset);
+ _typeProvider, type, nullabilityNode, _graph, target);
} else {
decoratedType = DecoratedType(type, nullabilityNode,
typeArguments: typeArguments,
@@ -488,8 +519,8 @@
if (bound != null) {
decoratedBound = bound.accept(this);
} else {
- var nullabilityNode =
- NullabilityNode.forInferredType(offset: node.offset);
+ var nullabilityNode = NullabilityNode.forInferredType(
+ NullabilityNodeTarget.typeParameterBound(element));
decoratedBound = DecoratedType(_typeProvider.objectType, nullabilityNode);
_graph.connect(_graph.always, nullabilityNode,
AlwaysNullableTypeOrigin.forElement(element));
@@ -507,9 +538,9 @@
variable.metadata.accept(this);
var declaredElement = variable.declaredElement;
if (type == null) {
+ var target = NullabilityNodeTarget.element(declaredElement);
type = DecoratedType.forImplicitType(
- _typeProvider, declaredElement.type, _graph,
- offset: variable.offset);
+ _typeProvider, declaredElement.type, _graph, target);
instrumentation?.implicitType(source, node, type);
}
_variables.recordDecoratedElementType(declaredElement, type);
@@ -557,8 +588,11 @@
metadata?.accept(this);
var functionType = declaredElement.type;
DecoratedType decoratedReturnType;
+ var target = NullabilityNodeTarget.element(declaredElement);
if (returnType != null) {
- decoratedReturnType = returnType.accept(this);
+ _pushNullabilityNodeTarget(target.returnType(), () {
+ decoratedReturnType = returnType.accept(this);
+ });
} else if (declaredElement is ConstructorElement) {
// Constructors have no explicit return type annotation, so use the
// implicit return type.
@@ -568,8 +602,7 @@
} else {
// Inferred return type.
decoratedReturnType = DecoratedType.forImplicitType(
- _typeProvider, functionType.returnType, _graph,
- offset: node.offset);
+ _typeProvider, functionType.returnType, _graph, target);
instrumentation?.implicitReturnType(source, node, decoratedReturnType);
}
var previousPositionalParameters = _positionalParameters;
@@ -603,21 +636,20 @@
var declaredElement = node.declaredElement;
node.metadata?.accept(this);
DecoratedType decoratedType;
+ var target = NullabilityNodeTarget.element(declaredElement);
if (parameters == null) {
if (type != null) {
decoratedType = type.accept(this);
} else {
decoratedType = DecoratedType.forImplicitType(
- _typeProvider, declaredElement.type, _graph,
- offset: node.offset);
+ _typeProvider, declaredElement.type, _graph, target);
instrumentation?.implicitType(source, node, decoratedType);
}
} else {
DecoratedType decoratedReturnType;
if (type == null) {
- decoratedReturnType = DecoratedType.forImplicitType(
- _typeProvider, DynamicTypeImpl.instance, _graph,
- offset: node.offset);
+ decoratedReturnType = DecoratedType.forImplicitType(_typeProvider,
+ DynamicTypeImpl.instance, _graph, target.returnType());
instrumentation?.implicitReturnType(source, node, decoratedReturnType);
} else {
decoratedReturnType = type.accept(this);
@@ -640,7 +672,7 @@
_namedParameters = previousNamedParameters;
}
decoratedType = DecoratedType(
- declaredElement.type, NullabilityNode.forTypeAnnotation(node.end),
+ declaredElement.type, NullabilityNode.forTypeAnnotation(target),
returnType: decoratedReturnType,
positionalParameters: positionalParameters,
namedParameters: namedParameters);
@@ -676,8 +708,9 @@
for (var supertype in supertypes) {
DecoratedType decoratedSupertype;
if (supertype == null) {
- var nullabilityNode =
- NullabilityNode.forInferredType(offset: astNode.offset);
+ var target =
+ NullabilityNodeTarget.codeRef('implicit object supertype', astNode);
+ var nullabilityNode = NullabilityNode.forInferredType(target);
_graph.makeNonNullableUnion(
nullabilityNode, NonNullableObjectSuperclass(source, astNode));
decoratedSupertype =
@@ -692,6 +725,16 @@
declaredElement, decoratedSupertypes);
}
+ void _pushNullabilityNodeTarget(NullabilityNodeTarget target, Function() fn) {
+ NullabilityNodeTarget previousTarget = _target;
+ try {
+ _target = target;
+ fn();
+ } finally {
+ _target = previousTarget;
+ }
+ }
+
@alwaysThrows
void _unimplemented(AstNode node, String message) {
CompilationUnit unit = node.root as CompilationUnit;
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index fe9bab5..bcbe748 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -2,23 +2,23 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:collection';
+
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/nullability_state.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:nnbd_migration/src/postmortem_file.dart';
import 'edge_origin.dart';
/// Base class for steps that occur as part of downstream propagation, where the
/// nullability of a node is changed to a new state.
-abstract class DownstreamPropagationStep extends PropagationStep {
- /// The node whose nullability was changed.
- ///
- /// Any propagation step that took effect should have a non-null value here.
- /// Propagation steps that are pending but have not taken effect yet, or that
- /// never had an effect (e.g. because an edge was not triggered) will have a
- /// `null` value for this field.
+abstract class DownstreamPropagationStep extends PropagationStep
+ implements DownstreamPropagationStepInfo {
+ @override
NullabilityNodeMutable targetNode;
/// The state that the node's nullability was changed to.
@@ -38,6 +38,9 @@
newState = Nullability.fromJson(json['newState']);
@override
+ DownstreamPropagationStep get principalCause;
+
+ @override
Map<String, Object> toJson(NullabilityGraphSerializer serializer) {
return {
'target': serializer.idForNode(targetNode),
@@ -646,12 +649,8 @@
/// variables. Over time this will be replaced by a first class representation
/// of the nullability inference graph.
abstract class NullabilityNode implements NullabilityNodeInfo {
- static final _debugNamesInUse = Set<String>();
-
bool _isPossiblyOptional = false;
- String _debugName;
-
/// List of [NullabilityEdge] objects describing this node's relationship to
/// other nodes that are "downstream" from it (meaning that if a key node is
/// nullable, then all the nodes in the corresponding value will either have
@@ -667,25 +666,26 @@
/// Creates a [NullabilityNode] representing the nullability of a variable
/// whose type comes from an already-migrated library.
- factory NullabilityNode.forAlreadyMigrated() =>
- _NullabilityNodeSimple('migrated');
+ factory NullabilityNode.forAlreadyMigrated(NullabilityNodeTarget target) =>
+ _NullabilityNodeSimple(target);
/// Creates a [NullabilityNode] representing the nullability of an expression
/// which is nullable iff two other nullability nodes are both nullable.
///
/// The caller is required to create the appropriate graph edges to ensure
/// that the appropriate relationship between the nodes' nullabilities holds.
- factory NullabilityNode.forGLB() => _NullabilityNodeSimple('GLB');
+ factory NullabilityNode.forGLB() => _NullabilityNodeSimple(
+ NullabilityNodeTarget.text('(greatest lower bound)'));
/// Creates a [NullabilityNode] representing the nullability of a variable
/// whose type is determined by the `??` operator.
- factory NullabilityNode.forIfNotNull() =>
- _NullabilityNodeSimple('?? operator');
+ factory NullabilityNode.forIfNotNull(AstNode node) => _NullabilityNodeSimple(
+ NullabilityNodeTarget.codeRef('?? operator', node));
/// Creates a [NullabilityNode] representing the nullability of a variable
/// whose type is determined by type inference.
- factory NullabilityNode.forInferredType({int offset}) =>
- _NullabilityNodeSimple('inferred${offset == null ? '' : '($offset)'}');
+ factory NullabilityNode.forInferredType(NullabilityNodeTarget target) =>
+ _NullabilityNodeSimple(target);
/// Creates a [NullabilityNode] representing the nullability of an
/// expression which is nullable iff either [a] or [b] is nullable.
@@ -708,8 +708,8 @@
/// Creates a [NullabilityNode] representing the nullability of a type
/// annotation appearing explicitly in the user's program.
- factory NullabilityNode.forTypeAnnotation(int endOffset) =>
- _NullabilityNodeSimple('type($endOffset)');
+ factory NullabilityNode.forTypeAnnotation(NullabilityNodeTarget target) =>
+ _NullabilityNodeSimple(target);
NullabilityNode.fromJson(
dynamic json, NullabilityGraphDeserializer deserializer) {
@@ -732,10 +732,17 @@
NullabilityNode._();
+ @override
+ CodeReference get codeReference => null;
+
/// Gets a string that can be appended to a type name during debugging to help
/// annotate the nullability of that type.
String get debugSuffix => '?($this)';
+ /// Gets a name for the nullability node that is suitable for display to the
+ /// user.
+ String get displayName;
+
Iterable<EdgeInfo> get downstreamEdges => _downstreamEdges;
/// After nullability propagation, this getter can be used to query whether
@@ -759,7 +766,9 @@
@override
Iterable<EdgeInfo> get upstreamEdges => _upstreamEdges;
- String get _debugPrefix;
+ /// If this node has non-null intent, the propagation step that caused it to
+ /// have non-null intent, otherwise `null`.
+ UpstreamPropagationStep get whyNotNullable;
String get _jsonKind;
@@ -801,24 +810,11 @@
}
String toString({NodeToIdMapper idMapper}) {
- if (_debugName == null) {
- var prefix = _debugPrefix;
- if (_debugNamesInUse.add(prefix)) {
- _debugName = prefix;
- } else {
- for (int i = 0;; i++) {
- var name = '${prefix}_$i';
- if (_debugNamesInUse.add(name)) {
- _debugName = name;
- break;
- }
- }
- }
- }
+ var name = displayName;
if (idMapper == null) {
- return _debugName;
+ return name;
} else {
- return '${idMapper.idForNode(this)}: $_debugName';
+ return '${idMapper.idForNode(this)}: $name';
}
}
@@ -828,11 +824,6 @@
void trackPossiblyOptional() {
_isPossiblyOptional = true;
}
-
- @visibleForTesting
- static void clearDebugNames() {
- _debugNamesInUse.clear();
- }
}
/// Base class for nullability nodes that are nullable if at least one of a set
@@ -880,10 +871,10 @@
{'left': left, 'right': right};
@override
- Iterable<NullabilityNode> get _components => [left, right];
+ String get displayName => '${left.displayName} or ${right.displayName}';
@override
- String get _debugPrefix => 'LUB($left, $right)';
+ Iterable<NullabilityNode> get _components => [left, right];
@override
String get _jsonKind => 'lub';
@@ -931,10 +922,11 @@
{'inner': innerNode, 'outer': outerNode};
@override
- Iterable<NullabilityNode> get _components => [innerNode, outerNode];
+ String get displayName =>
+ '${innerNode.displayName} or ${outerNode.displayName}';
@override
- String get _debugPrefix => 'Substituted($innerNode, $outerNode)';
+ Iterable<NullabilityNode> get _components => [innerNode, outerNode];
@override
String get _jsonKind => 'substitution';
@@ -967,6 +959,8 @@
DownstreamPropagationStep _whyNullable;
+ UpstreamPropagationStep _whyNotNullable;
+
NullabilityNodeMutable.fromJson(
dynamic json, NullabilityGraphDeserializer deserializer)
: _nullability = json['nullability'] == null
@@ -996,7 +990,10 @@
NonNullIntent get nonNullIntent => _nonNullIntent;
@override
- PropagationStepInfo get whyNullable => _whyNullable;
+ UpstreamPropagationStep get whyNotNullable => _whyNotNullable;
+
+ @override
+ DownstreamPropagationStepInfo get whyNullable => _whyNullable;
@override
void resetState() {
@@ -1021,7 +1018,7 @@
/// Information produced by [NullabilityGraph.propagate] about the results of
/// graph propagation.
class PropagationResult {
- /// A list of all edges that couldn't be satisfied.
+ /// A list of all edges that couldn't be satisfied. May contain duplicates.
final List<NullabilityEdge> unsatisfiedEdges = [];
/// A list of all substitution nodes that couldn't be satisfied.
@@ -1136,7 +1133,7 @@
'${edge.toString(idMapper: idMapper)}';
}
-/// Propagation step where we mark the source of an edge as exactx nullable, due
+/// Propagation step where we mark the source of an edge as exact nullable, due
/// to its destination becoming exact nullable.
class SimpleExactNullablePropagationStep extends ExactNullablePropagationStep {
@override
@@ -1226,16 +1223,16 @@
class _NullabilityNodeImmutable extends NullabilityNode {
@override
- final String _debugPrefix;
+ final String displayName;
@override
final bool isNullable;
- _NullabilityNodeImmutable(this._debugPrefix, this.isNullable) : super._();
+ _NullabilityNodeImmutable(this.displayName, this.isNullable) : super._();
_NullabilityNodeImmutable.fromJson(
dynamic json, NullabilityGraphDeserializer deserializer)
- : _debugPrefix = json['debugPrefix'] as String,
+ : displayName = json['displayName'] as String,
isNullable = json['isNullable'] as bool,
super.fromJson(json, deserializer);
@@ -1257,7 +1254,10 @@
isNullable ? NonNullIntent.none : NonNullIntent.direct;
@override
- PropagationStepInfo get whyNullable => null;
+ UpstreamPropagationStep get whyNotNullable => null;
+
+ @override
+ DownstreamPropagationStepInfo get whyNullable => null;
@override
String get _jsonKind => 'immutable';
@@ -1274,30 +1274,36 @@
@override
Map<String, Object> toJson(NullabilityGraphSerializer serializer) {
var json = super.toJson(serializer);
- json['debugPrefix'] = _debugPrefix;
+ json['displayName'] = displayName;
json['isNullable'] = isNullable;
return json;
}
}
class _NullabilityNodeSimple extends NullabilityNodeMutable {
- @override
- final String _debugPrefix;
+ final NullabilityNodeTarget target;
- _NullabilityNodeSimple(this._debugPrefix) : super._();
+ _NullabilityNodeSimple(this.target) : super._();
_NullabilityNodeSimple.fromJson(
dynamic json, NullabilityGraphDeserializer deserializer)
- : _debugPrefix = json['debugPrefix'] as String,
+ : target =
+ NullabilityNodeTarget.text(json['targetDisplayName'] as String),
super.fromJson(json, deserializer);
@override
+ CodeReference get codeReference => target.codeReference;
+
+ @override
+ String get displayName => target.displayName;
+
+ @override
String get _jsonKind => 'simple';
@override
Map<String, Object> toJson(NullabilityGraphSerializer serializer) {
var json = super.toJson(serializer);
- json['debugPrefix'] = _debugPrefix;
+ json['targetDisplayName'] = target.displayName;
return json;
}
}
@@ -1317,9 +1323,10 @@
/// The graph's one and only "never" node.
final NullabilityNode _never;
- /// During any given stage of nullability propagation, a list of all the edges
- /// that need to be examined before the stage is complete.
- final List<SimpleDownstreamPropagationStep> _pendingDownstreamSteps = [];
+ /// During any given stage of nullability propagation, a queue of all the
+ /// edges that need to be examined before the stage is complete.
+ final Queue<SimpleDownstreamPropagationStep> _pendingDownstreamSteps =
+ Queue();
final PostmortemFileWriter _postmortemFileWriter;
@@ -1340,7 +1347,7 @@
}
while (true) {
while (_pendingDownstreamSteps.isNotEmpty) {
- var step = _pendingDownstreamSteps.removeLast();
+ var step = _pendingDownstreamSteps.removeFirst();
var edge = step.edge;
if (!edge.isTriggered) continue;
var node = edge.destinationNode;
@@ -1379,11 +1386,11 @@
/// Propagates non-null intent upstream along unconditional control flow
/// lines.
void _propagateUpstream() {
- var pendingSteps = <UpstreamPropagationStep>[
- UpstreamPropagationStep(null, _never, NonNullIntent.direct)
- ];
+ Queue<UpstreamPropagationStep> pendingSteps = Queue();
+ pendingSteps
+ .add(UpstreamPropagationStep(null, _never, NonNullIntent.direct));
while (pendingSteps.isNotEmpty) {
- var cause = pendingSteps.removeLast();
+ var cause = pendingSteps.removeFirst();
var pendingNode = cause.node;
for (var edge in pendingNode._upstreamEdges) {
// We only propagate for nodes that are "upstream triggered". At this
@@ -1505,8 +1512,12 @@
void _setNonNullIntent(UpstreamPropagationStep step) {
var node = step.node as NullabilityNodeMutable;
var newNonNullIntent = step.newNonNullIntent;
+ var oldNonNullIntent = node.nonNullIntent;
node._nonNullIntent = newNonNullIntent;
_postmortemFileWriter?.addPropagationStep(step);
+ if (!oldNonNullIntent.isPresent) {
+ node._whyNotNullable = step;
+ }
}
Nullability _setNullable(DownstreamPropagationStep step) {
diff --git a/pkg/nnbd_migration/lib/src/nullability_node_target.dart b/pkg/nnbd_migration/lib/src/nullability_node_target.dart
new file mode 100644
index 0000000..c83ae21
--- /dev/null
+++ b/pkg/nnbd_migration/lib/src/nullability_node_target.dart
@@ -0,0 +1,201 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:nnbd_migration/instrumentation.dart';
+
+String _computeElementName(Element element) {
+ List<String> parts = [];
+ while (element != null && element is! CompilationUnitElement) {
+ var name = element.name;
+ if (name == null || name.isEmpty) {
+ parts.add('<unnamed>');
+ } else {
+ parts.add(name);
+ }
+ element = element.enclosingElement;
+ }
+ if (parts.isEmpty) {
+ assert(false, 'Could not compute a name for $element');
+ return '<unknown>';
+ }
+ return parts.reversed.join('.');
+}
+
+/// Data structure tracking information about which type in the user's source
+/// code is referenced by a given nullability node.
+abstract class NullabilityNodeTarget {
+ /// Creates a [NullabilityNodeTarget] referring to a particular point in the
+ /// source code.
+ factory NullabilityNodeTarget.codeRef(String description, AstNode astNode) =
+ _NullabilityNodeTarget_CodeRef;
+
+ /// Creates a [NullabilityNodeTarget] referring to a particular element.
+ factory NullabilityNodeTarget.element(Element element) =
+ _NullabilityNodeTarget_Element;
+
+ /// Creates a [NullabilityNodeTarget] with a simple text description.
+ factory NullabilityNodeTarget.text(String name) = _NullabilityNodeTarget_Text;
+
+ /// Creates a new [NullabilityNodeTarget] representing the bound of a type
+ /// parameter.
+ factory NullabilityNodeTarget.typeParameterBound(
+ TypeParameterElement element) = _NullabilityNodeTarget_TypeParameterBound;
+
+ NullabilityNodeTarget._();
+
+ /// The source code location associated with this target, if known. Otherwise
+ /// `null`.
+ CodeReference get codeReference => null;
+
+ /// Gets a short description of this nullability node target suitable for
+ /// displaying to the user.
+ String get displayName;
+
+ /// Creates a new [NullabilityNodeTarget] representing a named function
+ /// parameter of this target.
+ NullabilityNodeTarget namedParameter(String name) =>
+ _NullabilityNodeTarget_NamedParameter(this, name);
+
+ /// Creates a new [NullabilityNodeTarget] representing a positional function
+ /// parameter of this target.
+ NullabilityNodeTarget positionalParameter(int index) =>
+ _NullabilityNodeTarget_PositionalParameter(this, index);
+
+ /// Creates a new [NullabilityNodeTarget] representing a function return type
+ /// of this target.
+ NullabilityNodeTarget returnType() => _NullabilityNodeTarget_ReturnType(this);
+
+ /// Creates a new [NullabilityNodeTarget] representing a type argument of this
+ /// target.
+ NullabilityNodeTarget typeArgument(int index) =>
+ _NullabilityNodeTarget_TypeArgument(this, index);
+
+ /// Creates a new [NullabilityNodeTarget] representing the bound of a formal
+ /// function type parameter of this target.
+ NullabilityNodeTarget typeFormalBound(String typeFormalName) =>
+ _NullabilityNodeTarget_TypeFormalBound(this, typeFormalName);
+}
+
+/// Nullability node target representing a reference to a specific location in
+/// source code.
+class _NullabilityNodeTarget_CodeRef extends NullabilityNodeTarget {
+ final String description;
+
+ final CodeReference codeReference;
+
+ _NullabilityNodeTarget_CodeRef(this.description, AstNode astNode)
+ : codeReference = CodeReference.fromAstNode(astNode),
+ super._();
+
+ @override
+ String get displayName => '$description (${codeReference.shortName})';
+}
+
+/// Nullability node target representing the type of an element.
+class _NullabilityNodeTarget_Element extends NullabilityNodeTarget {
+ final String name;
+
+ _NullabilityNodeTarget_Element(Element element)
+ : name = _computeElementName(element),
+ super._();
+
+ @override
+ String get displayName => name;
+}
+
+/// Nullability node target representing the type of a named function parameter.
+class _NullabilityNodeTarget_NamedParameter
+ extends _NullabilityNodeTarget_Part {
+ final String name;
+
+ _NullabilityNodeTarget_NamedParameter(NullabilityNodeTarget inner, this.name)
+ : super(inner);
+
+ @override
+ String get displayName => 'parameter $name of ${inner.displayName}';
+}
+
+/// Nullability node target representing a type that forms part of a larger type
+/// (e.g. the `int` part of `List<int>`).
+abstract class _NullabilityNodeTarget_Part extends NullabilityNodeTarget {
+ final NullabilityNodeTarget inner;
+
+ _NullabilityNodeTarget_Part(this.inner) : super._();
+
+ @override
+ CodeReference get codeReference => inner.codeReference;
+}
+
+/// Nullability node target representing the type of a positional function
+/// parameter.
+class _NullabilityNodeTarget_PositionalParameter
+ extends _NullabilityNodeTarget_Part {
+ final int index;
+
+ _NullabilityNodeTarget_PositionalParameter(
+ NullabilityNodeTarget inner, this.index)
+ : super(inner);
+
+ @override
+ String get displayName => 'parameter $index of ${inner.displayName}';
+}
+
+/// Nullability node target representing a function's return type.
+class _NullabilityNodeTarget_ReturnType extends _NullabilityNodeTarget_Part {
+ _NullabilityNodeTarget_ReturnType(NullabilityNodeTarget inner) : super(inner);
+
+ @override
+ String get displayName => 'return type of ${inner.displayName}';
+}
+
+/// Nullability node target for which we only know a string description.
+class _NullabilityNodeTarget_Text extends NullabilityNodeTarget {
+ final String name;
+
+ _NullabilityNodeTarget_Text(this.name) : super._();
+
+ @override
+ String get displayName => name;
+}
+
+/// Nullability node target representing a type argument of an interface type or
+/// or typedef.
+class _NullabilityNodeTarget_TypeArgument extends _NullabilityNodeTarget_Part {
+ final int index;
+
+ _NullabilityNodeTarget_TypeArgument(NullabilityNodeTarget inner, this.index)
+ : super(inner);
+
+ @override
+ String get displayName => 'type argument $index of ${inner.displayName}';
+}
+
+/// Nullability node target representing a bound of a function type's formal
+/// type parameter.
+class _NullabilityNodeTarget_TypeFormalBound
+ extends _NullabilityNodeTarget_Part {
+ final String typeFormalName;
+
+ _NullabilityNodeTarget_TypeFormalBound(
+ NullabilityNodeTarget inner, this.typeFormalName)
+ : super(inner);
+
+ @override
+ String get displayName =>
+ 'bound of type formal $typeFormalName of ${inner.displayName}';
+}
+
+/// Nullability node target representing a type parameter bound.
+class _NullabilityNodeTarget_TypeParameterBound extends NullabilityNodeTarget {
+ final String name;
+
+ _NullabilityNodeTarget_TypeParameterBound(TypeParameterElement element)
+ : name = _computeElementName(element),
+ super._();
+
+ @override
+ String get displayName => 'bound of $name';
+}
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 3782d3b..2445e76 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -25,6 +25,7 @@
import 'package:nnbd_migration/src/fix_builder.dart';
import 'package:nnbd_migration/src/node_builder.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:nnbd_migration/src/postmortem_file.dart';
import 'package:nnbd_migration/src/potential_modification.dart';
@@ -133,9 +134,11 @@
'have been stored by the NodeBuilder via '
'recordTypeParameterBound');
}
+ var target = NullabilityNodeTarget.typeParameterBound(typeParameter);
decoratedType = _alreadyMigratedCodeDecorator.decorate(
typeParameter.preMigrationBound ?? DynamicTypeImpl.instance,
- typeParameter);
+ typeParameter,
+ target);
instrumentation?.externalDecoratedTypeParameterBound(
typeParameter, decoratedType);
DecoratedTypeParameterBounds.current.put(typeParameter, decoratedType);
@@ -331,12 +334,13 @@
element = (element as FunctionTypeAliasElement).function;
}
+ var target = NullabilityNodeTarget.element(element);
if (element is FunctionTypedElement) {
decoratedType = _alreadyMigratedCodeDecorator.decorate(
- element.preMigrationType, element);
+ element.preMigrationType, element, target);
} else if (element is VariableElement) {
decoratedType = _alreadyMigratedCodeDecorator.decorate(
- element.preMigrationType, element);
+ element.preMigrationType, element, target);
} else {
// TODO(paulberry)
throw UnimplementedError('Decorating ${element.runtimeType}');
diff --git a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
index eefbf6d..ebebc47 100644
--- a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
+++ b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
@@ -15,6 +15,7 @@
import 'package:nnbd_migration/src/already_migrated_code_decorator.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -57,85 +58,100 @@
NullabilityNode get never => graph.never;
- void checkAlwaysNullable(NullabilityNode node) {
- var edge = assertEdge(always, node, hard: false);
+ void checkAlwaysNullable(NullabilityNode node, String displayName) {
+ var edge = assertEdge(always, node, hard: true, checkable: false);
var origin = graph.getEdgeOrigin(edge);
expect(origin.kind, EdgeOriginKind.alwaysNullableType);
expect(origin.element, same(element));
+ expect(node.displayName, displayName);
}
- void checkDynamic(DecoratedType decoratedType) {
+ void checkDynamic(DecoratedType decoratedType, String displayName) {
expect(decoratedType.type, same(typeProvider.dynamicType));
- checkAlwaysNullable(decoratedType.node);
+ checkAlwaysNullable(decoratedType.node, displayName);
}
- void checkExplicitlyNonNullable(NullabilityNode node) {
+ void checkExplicitlyNonNullable(NullabilityNode node, String displayName) {
var edge = assertEdge(node, never, hard: true, checkable: false);
var origin = graph.getEdgeOrigin(edge);
expect(origin.kind, EdgeOriginKind.alreadyMigratedType);
expect(origin.element, same(element));
+ expect(node.displayName, displayName);
}
- void checkExplicitlyNullable(NullabilityNode node) {
- var edge = assertEdge(always, node, hard: false);
+ void checkExplicitlyNullable(NullabilityNode node, String displayName) {
+ var edge = assertEdge(always, node, hard: true, checkable: false);
var origin = graph.getEdgeOrigin(edge);
expect(origin.kind, EdgeOriginKind.alreadyMigratedType);
expect(origin.element, same(element));
+ expect(node.displayName, displayName);
}
void checkFutureOr(
DecoratedType decoratedType,
- void Function(NullabilityNode) checkNullability,
- void Function(DecoratedType) checkArgument) {
+ void Function(NullabilityNode, String) checkNullability,
+ void Function(DecoratedType, String) checkArgument,
+ String displayName) {
expect(decoratedType.type.element, typeProvider.futureOrElement);
- checkNullability(decoratedType.node);
- checkArgument(decoratedType.typeArguments[0]);
+ checkNullability(decoratedType.node, displayName);
+ checkArgument(
+ decoratedType.typeArguments[0], 'type argument 0 of $displayName');
}
- void checkInt(DecoratedType decoratedType,
- void Function(NullabilityNode) checkNullability) {
+ void checkInt(
+ DecoratedType decoratedType,
+ void Function(NullabilityNode, String) checkNullability,
+ String displayName) {
expect(decoratedType.type.element, typeProvider.intType.element);
- checkNullability(decoratedType.node);
+ checkNullability(decoratedType.node, displayName);
}
void checkIterable(
DecoratedType decoratedType,
- void Function(NullabilityNode) checkNullability,
- void Function(DecoratedType) checkArgument) {
+ void Function(NullabilityNode, String) checkNullability,
+ void Function(DecoratedType, String) checkArgument,
+ String displayName) {
expect(
decoratedType.type.element, typeProvider.iterableDynamicType.element);
- checkNullability(decoratedType.node);
- checkArgument(decoratedType.typeArguments[0]);
+ checkNullability(decoratedType.node, displayName);
+ checkArgument(
+ decoratedType.typeArguments[0], 'type argument 0 of $displayName');
}
- void checkNum(DecoratedType decoratedType,
- void Function(NullabilityNode) checkNullability) {
+ void checkNum(
+ DecoratedType decoratedType,
+ void Function(NullabilityNode, String) checkNullability,
+ String displayName) {
expect(decoratedType.type.element, typeProvider.numType.element);
- checkNullability(decoratedType.node);
+ checkNullability(decoratedType.node, displayName);
}
- void checkObject(DecoratedType decoratedType,
- void Function(NullabilityNode) checkNullability) {
+ void checkObject(
+ DecoratedType decoratedType,
+ void Function(NullabilityNode, String) checkNullability,
+ String displayName) {
expect(decoratedType.type.element, typeProvider.objectType.element);
- checkNullability(decoratedType.node);
+ checkNullability(decoratedType.node, displayName);
}
void checkTypeParameter(
DecoratedType decoratedType,
- void Function(NullabilityNode) checkNullability,
- TypeParameterElement expectedElement) {
+ void Function(NullabilityNode, String) checkNullability,
+ TypeParameterElement expectedElement,
+ String displayName) {
var type = decoratedType.type as TypeParameterTypeImpl;
expect(type.element, same(expectedElement));
- checkNullability(decoratedType.node);
+ checkNullability(decoratedType.node, displayName);
}
- void checkVoid(DecoratedType decoratedType) {
+ void checkVoid(DecoratedType decoratedType, String displayName) {
expect(decoratedType.type, same(typeProvider.voidType));
- checkAlwaysNullable(decoratedType.node);
+ checkAlwaysNullable(decoratedType.node, displayName);
}
DecoratedType decorate(DartType type) {
- var decoratedType = decorator.decorate(type, element);
+ var decoratedType = decorator.decorate(
+ type, element, NullabilityNodeTarget.text('test type'));
expect(decoratedType.type, same(type));
return decoratedType;
}
@@ -152,7 +168,7 @@
}
void test_decorate_dynamic() {
- checkDynamic(decorate(typeProvider.dynamicType));
+ checkDynamic(decorate(typeProvider.dynamicType), 'test type');
}
void test_decorate_functionType_generic_bounded() {
@@ -169,9 +185,10 @@
nullabilitySuffix: suffix,
),
);
- checkNum(getDecoratedBound(typeFormal), checkExplicitlyNonNullable);
- checkTypeParameter(
- decoratedType.returnType, checkExplicitlyNonNullable, typeFormal);
+ checkNum(getDecoratedBound(typeFormal), checkExplicitlyNonNullable,
+ 'bound of type formal T of test type');
+ checkTypeParameter(decoratedType.returnType, checkExplicitlyNonNullable,
+ typeFormal, 'return type of test type');
}
void test_decorate_functionType_generic_no_explicit_bound() {
@@ -187,136 +204,156 @@
nullabilitySuffix: suffix,
),
);
- checkObject(getDecoratedBound(typeFormal), checkExplicitlyNullable);
- checkTypeParameter(
- decoratedType.returnType, checkExplicitlyNonNullable, typeFormal);
+ checkObject(getDecoratedBound(typeFormal), checkExplicitlyNullable,
+ 'bound of type formal T of test type');
+ checkTypeParameter(decoratedType.returnType, checkExplicitlyNonNullable,
+ typeFormal, 'return type of test type');
}
void test_decorate_functionType_named_parameter() {
checkDynamic(
- decorate(
- FunctionTypeImpl(
- typeFormals: const [],
- parameters: [
- ParameterElementImpl.synthetic(
- 'x',
- typeProvider.dynamicType,
- ParameterKind.NAMED,
- )
- ],
- returnType: typeProvider.voidType,
- nullabilitySuffix: suffix,
- ),
- ).namedParameters['x'],
- );
+ decorate(
+ FunctionTypeImpl(
+ typeFormals: const [],
+ parameters: [
+ ParameterElementImpl.synthetic(
+ 'x',
+ typeProvider.dynamicType,
+ ParameterKind.NAMED,
+ )
+ ],
+ returnType: typeProvider.voidType,
+ nullabilitySuffix: suffix,
+ ),
+ ).namedParameters['x'],
+ 'parameter x of test type');
}
- void test_decorate_functionType_ordinary_parameter() {
- checkDynamic(
- decorate(
- FunctionTypeImpl(
- typeFormals: const [],
- parameters: [
- ParameterElementImpl.synthetic(
- 'x',
- typeProvider.dynamicType,
- ParameterKind.REQUIRED,
- )
- ],
- returnType: typeProvider.voidType,
- nullabilitySuffix: suffix,
- ),
- ).positionalParameters[0],
+ void test_decorate_functionType_ordinary_parameters() {
+ var decoratedType = decorate(
+ FunctionTypeImpl(
+ typeFormals: const [],
+ parameters: [
+ ParameterElementImpl.synthetic(
+ 'x',
+ typeProvider.dynamicType,
+ ParameterKind.REQUIRED,
+ ),
+ ParameterElementImpl.synthetic(
+ 'y',
+ typeProvider.dynamicType,
+ ParameterKind.REQUIRED,
+ )
+ ],
+ returnType: typeProvider.voidType,
+ nullabilitySuffix: suffix,
+ ),
);
+ checkDynamic(
+ decoratedType.positionalParameters[0], 'parameter 0 of test type');
+ checkDynamic(
+ decoratedType.positionalParameters[1], 'parameter 1 of test type');
}
void test_decorate_functionType_positional_parameter() {
checkDynamic(
- decorate(
- FunctionTypeImpl(
- typeFormals: const [],
- parameters: [
- ParameterElementImpl.synthetic(
- 'x',
- typeProvider.dynamicType,
- ParameterKind.POSITIONAL,
- )
- ],
- returnType: typeProvider.voidType,
- nullabilitySuffix: suffix,
- ),
- ).positionalParameters[0],
- );
+ decorate(
+ FunctionTypeImpl(
+ typeFormals: const [],
+ parameters: [
+ ParameterElementImpl.synthetic(
+ 'x',
+ typeProvider.dynamicType,
+ ParameterKind.POSITIONAL,
+ )
+ ],
+ returnType: typeProvider.voidType,
+ nullabilitySuffix: suffix,
+ ),
+ ).positionalParameters[0],
+ 'parameter 0 of test type');
}
void test_decorate_functionType_question() {
checkExplicitlyNullable(
- decorate(
- FunctionTypeImpl(
- typeFormals: const [],
- parameters: const [],
- returnType: typeProvider.voidType,
- nullabilitySuffix: NullabilitySuffix.question,
- ),
- ).node,
- );
+ decorate(
+ FunctionTypeImpl(
+ typeFormals: const [],
+ parameters: const [],
+ returnType: typeProvider.voidType,
+ nullabilitySuffix: NullabilitySuffix.question,
+ ),
+ ).node,
+ 'test type');
}
void test_decorate_functionType_returnType() {
checkDynamic(
- decorate(
- FunctionTypeImpl(
- typeFormals: const [],
- parameters: const [],
- returnType: typeProvider.dynamicType,
- nullabilitySuffix: suffix,
- ),
- ).returnType,
- );
+ decorate(
+ FunctionTypeImpl(
+ typeFormals: const [],
+ parameters: const [],
+ returnType: typeProvider.dynamicType,
+ nullabilitySuffix: suffix,
+ ),
+ ).returnType,
+ 'return type of test type');
}
void test_decorate_functionType_star() {
checkExplicitlyNonNullable(
- decorate(
- FunctionTypeImpl(
- typeFormals: const [],
- parameters: const [],
- returnType: typeProvider.voidType,
- nullabilitySuffix: suffix,
- ),
- ).node,
- );
+ decorate(
+ FunctionTypeImpl(
+ typeFormals: const [],
+ parameters: const [],
+ returnType: typeProvider.voidType,
+ nullabilitySuffix: suffix,
+ ),
+ ).node,
+ 'test type');
+ }
+
+ void test_decorate_interfaceType_parameters() {
+ var decoratedType = decorate(InterfaceTypeImpl(
+ element: typeProvider.mapElement,
+ typeArguments: [typeProvider.intType, typeProvider.numType],
+ nullabilitySuffix: suffix));
+ checkInt(decoratedType.typeArguments[0], checkExplicitlyNonNullable,
+ 'type argument 0 of test type');
+ checkNum(decoratedType.typeArguments[1], checkExplicitlyNonNullable,
+ 'type argument 1 of test type');
}
void test_decorate_interfaceType_simple_question() {
checkInt(
- decorate(
- InterfaceTypeImpl(
- element: typeProvider.intElement,
- typeArguments: const [],
- nullabilitySuffix: NullabilitySuffix.question,
+ decorate(
+ InterfaceTypeImpl(
+ element: typeProvider.intElement,
+ typeArguments: const [],
+ nullabilitySuffix: NullabilitySuffix.question,
+ ),
),
- ),
- checkExplicitlyNullable,
- );
+ checkExplicitlyNullable,
+ 'test type');
}
void test_decorate_interfaceType_simple_star() {
checkInt(
- decorate(
- InterfaceTypeImpl(
- element: typeProvider.intElement,
- typeArguments: const [],
- nullabilitySuffix: suffix,
+ decorate(
+ InterfaceTypeImpl(
+ element: typeProvider.intElement,
+ typeArguments: const [],
+ nullabilitySuffix: suffix,
+ ),
),
- ),
- checkExplicitlyNonNullable,
- );
+ checkExplicitlyNonNullable,
+ 'test type');
}
void test_decorate_iterable_dynamic() {
var decorated = decorate(typeProvider.iterableDynamicType);
- checkIterable(decorated, checkExplicitlyNonNullable, checkDynamic);
+ checkIterable(
+ decorated, checkExplicitlyNonNullable, checkDynamic, 'test type');
}
void test_decorate_typeParameterType_question() {
@@ -325,7 +362,8 @@
decorate(TypeParameterTypeImpl(
element: element, nullabilitySuffix: NullabilitySuffix.question)),
checkExplicitlyNullable,
- element);
+ element,
+ 'test type');
}
void test_decorate_typeParameterType_star() {
@@ -334,11 +372,12 @@
decorate(
TypeParameterTypeImpl(element: element, nullabilitySuffix: suffix)),
checkExplicitlyNonNullable,
- element);
+ element,
+ 'test type');
}
void test_decorate_void() {
- checkVoid(decorate(typeProvider.voidType));
+ checkVoid(decorate(typeProvider.voidType), 'test type');
}
void test_getImmediateSupertypes_future() {
@@ -346,12 +385,16 @@
var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
var typeParam = class_.typeParameters[0];
expect(decoratedSupertypes, hasLength(2));
- checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable);
+ checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable, 'Future');
// Since Future<T> is a subtype of FutureOr<T>, we consider FutureOr<T> to
// be an immediate supertype, even though the class declaration for Future
// doesn't mention FutureOr.
- checkFutureOr(decoratedSupertypes[1], checkExplicitlyNonNullable,
- (t) => checkTypeParameter(t, checkExplicitlyNonNullable, typeParam));
+ checkFutureOr(
+ decoratedSupertypes[1],
+ checkExplicitlyNonNullable,
+ (t, displayName) => checkTypeParameter(
+ t, checkExplicitlyNonNullable, typeParam, displayName),
+ 'Future');
}
void test_getImmediateSupertypes_generic() {
@@ -365,8 +408,12 @@
);
var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
expect(decoratedSupertypes, hasLength(1));
- checkIterable(decoratedSupertypes[0], checkExplicitlyNonNullable,
- (type) => checkTypeParameter(type, checkExplicitlyNonNullable, t));
+ checkIterable(
+ decoratedSupertypes[0],
+ checkExplicitlyNonNullable,
+ (type, displayName) => checkTypeParameter(
+ type, checkExplicitlyNonNullable, t, displayName),
+ 'C');
}
void test_getImmediateSupertypes_interface() {
@@ -375,8 +422,8 @@
class_.interfaces = [typeProvider.numType];
var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
expect(decoratedSupertypes, hasLength(2));
- checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable);
- checkNum(decoratedSupertypes[1], checkExplicitlyNonNullable);
+ checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable, 'C');
+ checkNum(decoratedSupertypes[1], checkExplicitlyNonNullable, 'C');
}
void test_getImmediateSupertypes_mixin() {
@@ -385,8 +432,8 @@
class_.mixins = [typeProvider.numType];
var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
expect(decoratedSupertypes, hasLength(2));
- checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable);
- checkNum(decoratedSupertypes[1], checkExplicitlyNonNullable);
+ checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable, 'C');
+ checkNum(decoratedSupertypes[1], checkExplicitlyNonNullable, 'C');
}
void test_getImmediateSupertypes_superclassConstraint() {
@@ -394,7 +441,7 @@
name: 'C', constraints: [typeProvider.numType]);
var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
expect(decoratedSupertypes, hasLength(1));
- checkNum(decoratedSupertypes[0], checkExplicitlyNonNullable);
+ checkNum(decoratedSupertypes[0], checkExplicitlyNonNullable, 'C');
}
void test_getImmediateSupertypes_supertype() {
@@ -402,7 +449,8 @@
element = ElementFactory.classElement('C', typeProvider.objectType);
var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
expect(decoratedSupertypes, hasLength(1));
- checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable);
+ // TODO(paulberry): displayName should be 'Object supertype of C'
+ checkObject(decoratedSupertypes[0], checkExplicitlyNonNullable, 'C');
}
}
diff --git a/pkg/nnbd_migration/test/decorated_type_test.dart b/pkg/nnbd_migration/test/decorated_type_test.dart
index 6c4e507..b114798 100644
--- a/pkg/nnbd_migration/test/decorated_type_test.dart
+++ b/pkg/nnbd_migration/test/decorated_type_test.dart
@@ -61,7 +61,6 @@
void setUp() {
DecoratedTypeParameterBounds.current = decoratedTypeParameterBounds;
ElementTypeProvider.current = elementTypeProvider;
- NullabilityNode.clearDebugNames();
}
void tearDown() {
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 9296346..a410270 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -1781,6 +1781,7 @@
var right = decoratedTypeAnnotation('int j').node;
var expression = decoratedExpressionType('??').node;
assertEdge(right, expression, guards: [left], hard: false);
+ expect(expression.displayName, '?? operator (test.dart:1:24)');
}
Future<void>
@@ -3816,6 +3817,27 @@
assertEdge(nullable_i, nullable_c_t_or_nullable_t, hard: true));
}
+ Future<void> test_instanceCreation_implicit_type_params_names() async {
+ await analyze('''
+class C<T, U> {}
+void main() {
+ C<Object, Object> x = C();
+}
+''');
+ var edge0 = assertEdge(
+ anyNode, decoratedTypeAnnotation('C<Object, Object>').node,
+ hard: false);
+ expect(edge0.sourceNode.displayName, 'constructed type (test.dart:3:25)');
+ var edge1 = assertEdge(anyNode, decoratedTypeAnnotation('Object,').node,
+ hard: false, checkable: false);
+ expect(edge1.sourceNode.displayName,
+ 'type argument 0 of constructed type (test.dart:3:25)');
+ var edge2 = assertEdge(anyNode, decoratedTypeAnnotation('Object>').node,
+ hard: false, checkable: false);
+ expect(edge2.sourceNode.displayName,
+ 'type argument 1 of constructed type (test.dart:3:25)');
+ }
+
Future<void> test_instanceCreation_parameter_named_optional() async {
await analyze('''
class C {
@@ -4066,6 +4088,7 @@
final listArgType = returnTypeEdge.sourceNode;
assertNoUpstreamNullability(listArgType);
+ expect(listArgType.displayName, 'list element type (test.dart:2:10)');
}
Future<void> test_listLiteral_noTypeArgument_nullableElement() async {
@@ -6315,8 +6338,10 @@
}
''');
- assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int').node,
+ var edge = assertEdge(
+ inSet(alwaysPlus), decoratedTypeAnnotation('int').node,
hard: false);
+ expect(edge.sourceNode.displayName, 'implicit null return (test.dart:2:3)');
}
Future<void> test_return_null() async {
@@ -6326,10 +6351,11 @@
}
''');
- assertNullCheck(
- checkExpression('null'),
- assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int').node,
- hard: false));
+ var edge = assertEdge(
+ inSet(alwaysPlus), decoratedTypeAnnotation('int').node,
+ hard: false);
+ assertNullCheck(checkExpression('null'), edge);
+ expect(edge.sourceNode.displayName, 'null literal (test.dart:2:10)');
}
Future<void> test_return_null_generic() async {
@@ -6358,11 +6384,13 @@
var mapNode = decoratedTypeAnnotation('Map').node;
assertNoUpstreamNullability(mapNode);
- assertNoUpstreamNullability(
- assertEdge(anyNode, keyNode, hard: false, checkable: false).sourceNode);
- assertNoUpstreamNullability(
- assertEdge(anyNode, valueNode, hard: false, checkable: false)
- .sourceNode);
+ var keyEdge = assertEdge(anyNode, keyNode, hard: false, checkable: false);
+ assertNoUpstreamNullability(keyEdge.sourceNode);
+ expect(keyEdge.sourceNode.displayName, 'map key type (test.dart:2:10)');
+ var valueEdge =
+ assertEdge(anyNode, valueNode, hard: false, checkable: false);
+ assertNoUpstreamNullability(valueEdge.sourceNode);
+ expect(valueEdge.sourceNode.displayName, 'map value type (test.dart:2:10)');
}
Future<void> test_setOrMapLiteral_map_noTypeArgument_nullableKey() async {
@@ -6496,9 +6524,9 @@
var setNode = decoratedTypeAnnotation('Set').node;
assertNoUpstreamNullability(setNode);
- assertNoUpstreamNullability(
- assertEdge(anyNode, valueNode, hard: false, checkable: false)
- .sourceNode);
+ var edge = assertEdge(anyNode, valueNode, hard: false, checkable: false);
+ assertNoUpstreamNullability(edge.sourceNode);
+ expect(edge.sourceNode.displayName, 'set element type (test.dart:2:10)');
}
Future<void> test_setOrMapLiteral_set_noTypeArgument_nullableElement() async {
@@ -6817,7 +6845,10 @@
return throw null;
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
+ var intNode = decoratedTypeAnnotation('int').node;
+ assertNoUpstreamNullability(intNode);
+ var edge = assertEdge(anyNode, intNode, hard: false);
+ expect(edge.sourceNode.displayName, 'throw expression (test.dart:2:10)');
}
Future<void> test_topLevelSetter() async {
diff --git a/pkg/nnbd_migration/test/fix_aggregator_test.dart b/pkg/nnbd_migration/test/fix_aggregator_test.dart
index 54dd710..10cc5a8 100644
--- a/pkg/nnbd_migration/test/fix_aggregator_test.dart
+++ b/pkg/nnbd_migration/test/fix_aggregator_test.dart
@@ -9,6 +9,7 @@
import 'package:nnbd_migration/src/edit_plan.dart';
import 'package:nnbd_migration/src/fix_aggregator.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -785,7 +786,8 @@
const MockDecoratedType(this.type);
@override
- NullabilityNode get node => NullabilityNode.forTypeAnnotation(0);
+ NullabilityNode get node =>
+ NullabilityNode.forTypeAnnotation(NullabilityNodeTarget.text('test'));
@override
noSuchMethod(Invocation invocation) {
diff --git a/pkg/nnbd_migration/test/migration_visitor_test_base.dart b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
index 34716eb..1224e07 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test_base.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
@@ -20,6 +20,7 @@
import 'package:nnbd_migration/src/expression_checks.dart';
import 'package:nnbd_migration/src/node_builder.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:nnbd_migration/src/variables.dart';
import 'package:test/test.dart';
@@ -35,7 +36,7 @@
/// Mixin allowing unit tests to create decorated types easily.
mixin DecoratedTypeTester implements DecoratedTypeTesterBase {
- int _offset = 0;
+ int nodeId = 0;
NullabilityNode get always => graph.always;
@@ -101,7 +102,8 @@
DecoratedType(typeProvider.listType2(elementType.type), node ?? newNode(),
typeArguments: [elementType]);
- NullabilityNode newNode() => NullabilityNode.forTypeAnnotation(_offset++);
+ NullabilityNode newNode() => NullabilityNode.forTypeAnnotation(
+ NullabilityNodeTarget.text('node ${nodeId++}'));
DecoratedType num_({NullabilityNode node}) =>
DecoratedType(typeProvider.numType, node ?? newNode());
diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart
index 149cee4..f6e8bbc 100644
--- a/pkg/nnbd_migration/test/node_builder_test.dart
+++ b/pkg/nnbd_migration/test/node_builder_test.dart
@@ -649,6 +649,16 @@
// field.
}
+ Future<void> test_function_explicit_returnType() async {
+ await analyze('''
+class C {
+ int f() => null;
+}
+''');
+ var decoratedType = decoratedTypeAnnotation('int');
+ expect(decoratedType.node.displayName, 'return type of C.f');
+ }
+
Future<void> test_function_generic_bounded() async {
await analyze('''
T f<T extends Object>(T t) => t;
@@ -844,20 +854,6 @@
expect(gType.returnType.node.isImmutable, false);
}
- Future<void>
- test_generic_function_type_syntax_inferred_dynamic_return() async {
- await analyze('''
-abstract class C {
- Function() f();
-}
-''');
- var decoratedFType = decoratedMethodType('f');
- var decoratedFReturnType = decoratedFType.returnType;
- var decoratedFReturnReturnType = decoratedFReturnType.returnType;
- _assertType(decoratedFReturnReturnType.type, 'dynamic');
- expect(decoratedFReturnReturnType.node.isImmutable, false);
- }
-
Future<void> test_genericFunctionType_formals() async {
await analyze('''
void f(T Function<T, U>(U) x) {}
@@ -906,6 +902,21 @@
expect(decoratedType.returnType, same(decoratedIntType));
expect(decoratedIntType.node, isNotNull);
expect(decoratedIntType.node, isNot(never));
+ expect(decoratedType.returnType.node.displayName,
+ 'return type of explicit type (test.dart:1:8)');
+ }
+
+ Future<void> test_genericFunctionType_syntax_inferred_dynamic_return() async {
+ await analyze('''
+abstract class C {
+ Function() f();
+}
+''');
+ var decoratedFType = decoratedMethodType('f');
+ var decoratedFReturnType = decoratedFType.returnType;
+ var decoratedFReturnReturnType = decoratedFReturnType.returnType;
+ _assertType(decoratedFReturnReturnType.type, 'dynamic');
+ expect(decoratedFReturnReturnType.node.isImmutable, false);
}
Future<void> test_genericFunctionType_unnamedParameterType() async {
@@ -999,6 +1010,7 @@
expect(decoratedType.typeFormals, isEmpty);
expect(decoratedType.positionalParameters[0],
same(decoratedTypeAnnotation('String')));
+ expect(decoratedType.returnType.node.displayName, 'return type of F');
}
Future<void> test_interfaceType_generic_instantiate_to_dynamic() async {
@@ -1179,6 +1191,31 @@
expect(decoratedType.node.isImmutable, false);
}
+ Future<void> test_localVariable_type_inferred_function() async {
+ await analyze('''
+main() {
+ var x = () => 1;
+}
+''');
+ var decoratedType =
+ variables.decoratedElementType(findNode.simple('x').staticElement);
+ expect(decoratedType.returnType.node.displayName, 'return type of main.x');
+ }
+
+ Future<void> test_localVariable_type_inferred_generic() async {
+ await analyze('''
+main() {
+ var x = {1: 2};
+}
+''');
+ var decoratedType =
+ variables.decoratedElementType(findNode.simple('x').staticElement);
+ expect(decoratedType.typeArguments[0].node.displayName,
+ 'type argument 0 of main.x');
+ expect(decoratedType.typeArguments[1].node.displayName,
+ 'type argument 1 of main.x');
+ }
+
Future<void> test_method_generic_bounded() async {
await analyze('''
class C {
@@ -1578,6 +1615,8 @@
var decoratedTypeFormalBound = decoratedTypeParameterBounds
.get((decoratedType.type as FunctionType).typeFormals[0]);
_assertType(decoratedTypeFormalBound.type, 'num');
+ expect(decoratedTypeFormalBound.node.displayName,
+ 'bound of type formal T of explicit type (test.dart:2:1)');
var decoratedTypedefTypeFormalBound = decoratedTypeParameterBounds
.get((typedefDecoratedType.type as FunctionType).typeFormals[0]);
expect(decoratedTypeFormalBound.node,
@@ -1603,11 +1642,47 @@
decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedType.returnType.node,
isNot(same(typedefDecoratedType.returnType.node)));
+ expect(
+ typedefDecoratedType.returnType.node.displayName, 'return type of F');
+ expect(decoratedType.returnType.node.displayName,
+ 'return type of explicit type (test.dart:2:1)');
_assertType(decoratedType.positionalParameters[0].type, 'String');
expect(decoratedType.positionalParameters[0].node,
TypeMatcher<NullabilityNodeMutable>());
expect(decoratedType.positionalParameters[0].node,
isNot(same(typedefDecoratedType.positionalParameters[0].node)));
+ expect(decoratedType.positionalParameters[0].node.displayName,
+ 'parameter 0 of explicit type (test.dart:2:1)');
+ }
+
+ Future<void> test_typedef_reference_simple_named_parameter() async {
+ await analyze('''
+typedef int F({String s});
+F f;
+''');
+ // The instantiation of F should produce fresh nullability nodes, distinct
+ // from the ones in the typedef (they will be unified by the edge builder).
+ // This is necessary because there is no guarantee of whether the typedef or
+ // its usage will be visited first.
+ var decoratedType = decoratedTypeAnnotation('F f');
+ expect(decoratedType.namedParameters['s'].node.displayName,
+ 'parameter s of explicit type (test.dart:2:1)');
+ }
+
+ Future<void> test_typedef_reference_simple_two_parameters() async {
+ await analyze('''
+typedef int F(String s, int i);
+F f;
+''');
+ // The instantiation of F should produce fresh nullability nodes, distinct
+ // from the ones in the typedef (they will be unified by the edge builder).
+ // This is necessary because there is no guarantee of whether the typedef or
+ // its usage will be visited first.
+ var decoratedType = decoratedTypeAnnotation('F f');
+ expect(decoratedType.positionalParameters[0].node.displayName,
+ 'parameter 0 of explicit type (test.dart:2:1)');
+ expect(decoratedType.positionalParameters[1].node.displayName,
+ 'parameter 1 of explicit type (test.dart:2:1)');
}
Future<void> test_typedef_rhs_nullability() async {
diff --git a/pkg/nnbd_migration/test/nullability_node_test.dart b/pkg/nnbd_migration/test/nullability_node_test.dart
index e674000..9a5444f 100644
--- a/pkg/nnbd_migration/test/nullability_node_test.dart
+++ b/pkg/nnbd_migration/test/nullability_node_test.dart
@@ -5,6 +5,7 @@
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/src/edge_origin.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
+import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -18,6 +19,7 @@
class NullabilityNodeTest {
final graph = NullabilityGraphForTesting();
+ /// A list of all edges that couldn't be satisfied. May contain duplicates.
List<NullabilityEdge> unsatisfiedEdges;
List<NullabilityNodeForSubstitution> unsatisfiedSubstitutions;
@@ -27,7 +29,7 @@
NullabilityNode get never => graph.never;
void assertUnsatisfied(List<NullabilityEdge> expectedUnsatisfiedEdges) {
- expect(unsatisfiedEdges, unorderedEquals(expectedUnsatisfiedEdges));
+ expect(unsatisfiedEdges.toSet(), expectedUnsatisfiedEdges.toSet());
}
NullabilityEdge connect(NullabilityNode source, NullabilityNode destination,
@@ -42,8 +44,8 @@
return NullabilityNode.forLUB(left, right);
}
- NullabilityNode newNode(int offset) =>
- NullabilityNode.forTypeAnnotation(offset);
+ NullabilityNode newNode(int id) =>
+ NullabilityNode.forTypeAnnotation(NullabilityNodeTarget.text('node $id'));
void propagate() {
var propagationResult = graph.propagate(null);
@@ -179,6 +181,32 @@
assertUnsatisfied([edge_1_never, edge_1_3]);
}
+ void test_propagation_downstream_breadth_first() {
+ // always -> 1 -> 2
+ // 1 -> 3 -> 4
+ // always -> 5 -> 4
+ // 5 -> 6 -> 2
+ var n1 = newNode(1);
+ var n2 = newNode(2);
+ var n3 = newNode(3);
+ var n4 = newNode(4);
+ var n5 = newNode(5);
+ var n6 = newNode(6);
+ connect(always, n1);
+ connect(n1, n2);
+ connect(n1, n3);
+ connect(n3, n4);
+ connect(always, n5);
+ connect(n5, n4);
+ connect(n5, n6);
+ connect(n6, n2);
+ propagate();
+ // Node 2 should be caused by node 1, since that's the shortest path back to
+ // "always". Similarly, node 4 should be caused by node 5.
+ expect(_downstreamCauseNode(n2), same(n1));
+ expect(_downstreamCauseNode(n4), same(n5));
+ }
+
void test_propagation_downstream_guarded_multiple_guards_all_satisfied() {
// always -> 1
// always -> 2
@@ -545,6 +573,32 @@
assertUnsatisfied([edge_1_2]);
}
+ void test_propagation_upstream_breadth_first() {
+ // never <- 1 <- 2
+ // 1 <- 3 <- 4
+ // never <- 5 <- 4
+ // 5 <- 6 <- 2
+ var n1 = newNode(1);
+ var n2 = newNode(2);
+ var n3 = newNode(3);
+ var n4 = newNode(4);
+ var n5 = newNode(5);
+ var n6 = newNode(6);
+ connect(n1, never, hard: true);
+ connect(n2, n1, hard: true);
+ connect(n3, n1, hard: true);
+ connect(n4, n3, hard: true);
+ connect(n5, never, hard: true);
+ connect(n4, n5, hard: true);
+ connect(n6, n5, hard: true);
+ connect(n2, n6, hard: true);
+ propagate();
+ // Node 2 should be caused by node 1, since that's the shortest path back to
+ // "always". Similarly, node 4 should be caused by node 5.
+ expect(_upstreamCauseNode(n2), same(n1));
+ expect(_upstreamCauseNode(n4), same(n5));
+ }
+
void test_propagation_upstream_through_union() {
// always -> 1
// always -> 2
@@ -669,6 +723,12 @@
void union(NullabilityNode x, NullabilityNode y) {
graph.union(x, y, _TestEdgeOrigin());
}
+
+ NullabilityNode _downstreamCauseNode(NullabilityNode node) =>
+ (node.whyNullable as SimpleDownstreamPropagationStep).edge.sourceNode;
+
+ NullabilityNode _upstreamCauseNode(NullabilityNode node) =>
+ node.whyNotNullable.principalCause.node;
}
class _TestEdgeOrigin implements EdgeOrigin {
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index cc361ca..3c1eae4 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -695,6 +695,7 @@
static const _dfeErrorExitCode = 252;
static const _compileErrorExitCode = 254;
static const _uncaughtExceptionExitCode = 255;
+ static const _adbInfraFailureCodes = [10];
VMCommandOutput(Command command, int exitCode, bool timedOut,
List<int> stdout, List<int> stderr, Duration time, int pid)
@@ -751,8 +752,20 @@
if (exitCode == _compileErrorExitCode) return Expectation.compileTimeError;
if (exitCode == _uncaughtExceptionExitCode) return Expectation.runtimeError;
if (exitCode != 0) {
- // This is a general fail, in case we get an unknown nonzero exitcode.
- return Expectation.fail;
+ var ourExit = 5;
+ // Unknown nonzero exit code from vm command.
+ // Consider this a failure of testing, and exit the test script.
+ if (testCase.configuration.system == System.android &&
+ _adbInfraFailureCodes.contains(exitCode)) {
+ print('Android device failed to run test');
+ ourExit = 3;
+ } else {
+ print('Unexpected exit code $exitCode');
+ }
+ print(command);
+ print(decodeUtf8(stdout));
+ print(decodeUtf8(stderr));
+ io.exit(ourExit);
}
var testOutput = decodeUtf8(stdout);
if (_isAsyncTest(testOutput) && !_isAsyncTestSuccessful(testOutput)) {
diff --git a/runtime/tests/vm/dart/regress_40710_test.dart b/runtime/tests/vm/dart/regress_40710_test.dart
index 4c5b560..162cbae 100644
--- a/runtime/tests/vm/dart/regress_40710_test.dart
+++ b/runtime/tests/vm/dart/regress_40710_test.dart
@@ -23,7 +23,7 @@
for (int i = 0; i < 20; ++i) {
final a = new A<B<String>>();
a.foo(new B<String>());
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
a.foo(new B<dynamic>());
});
}
diff --git a/runtime/vm/bit_vector.cc b/runtime/vm/bit_vector.cc
index c48324b..49dd496 100644
--- a/runtime/vm/bit_vector.cc
+++ b/runtime/vm/bit_vector.cc
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/bit_vector.h"
-
+#include "vm/log.h"
#include "vm/os.h"
namespace dart {
@@ -39,8 +39,10 @@
if (data_[i] != other.data_[i]) return false;
}
if (i < data_length_) {
+ if (length_ % kBitsPerWord == 0) return data_[i] == other.data_[i];
+
// Don't compare bits beyond length_.
- const intptr_t shift_size = (kBitsPerWord - length_) & (kBitsPerWord - 1);
+ const intptr_t shift_size = kBitsPerWord - (length_ % kBitsPerWord);
const uword mask = static_cast<uword>(-1) >> shift_size;
if ((data_[i] & mask) != (other.data_[i] & mask)) return false;
}
@@ -105,11 +107,11 @@
}
void BitVector::Print() const {
- OS::PrintErr("[");
+ THR_Print("[");
for (intptr_t i = 0; i < length_; i++) {
- OS::PrintErr(Contains(i) ? "1" : "0");
+ THR_Print(Contains(i) ? "1" : "0");
}
- OS::PrintErr("]");
+ THR_Print("]");
}
} // namespace dart
diff --git a/runtime/vm/bit_vector.h b/runtime/vm/bit_vector.h
index b04c6ec..a6a61f7 100644
--- a/runtime/vm/bit_vector.h
+++ b/runtime/vm/bit_vector.h
@@ -70,6 +70,8 @@
data_[i / kBitsPerWord] &= ~(static_cast<uword>(1) << (i % kBitsPerWord));
}
+ void Set(intptr_t i, bool value) { value ? Add(i) : Remove(i); }
+
bool Equals(const BitVector& other) const;
// Add all elements that are in the bitvector from.
@@ -92,6 +94,14 @@
return (block & (static_cast<uword>(1) << (i % kBitsPerWord))) != 0;
}
+ bool SubsetOf(const BitVector& other) {
+ ASSERT(length_ == other.length_);
+ for (intptr_t i = 0; i < data_length_; ++i) {
+ if ((data_[i] & other.data_[i]) != data_[i]) return false;
+ }
+ return true;
+ }
+
void Clear() {
for (intptr_t i = 0; i < data_length_; i++) {
data_[i] = 0;
diff --git a/runtime/vm/compiler/backend/compile_type.h b/runtime/vm/compiler/backend/compile_type.h
index 8dd4c06..f068bf0 100644
--- a/runtime/vm/compiler/backend/compile_type.h
+++ b/runtime/vm/compiler/backend/compile_type.h
@@ -81,7 +81,11 @@
// Return true if value of this type is assignable to a location of the
// given type.
- bool IsAssignableTo(const AbstractType& type);
+ bool IsAssignableTo(const AbstractType& other);
+
+ // Return true if value of this type always passes 'is' test
+ // against given type.
+ bool IsInstanceOf(const AbstractType& other);
// Create a new CompileType representing given combination of class id and
// abstract type. The pair is assumed to be coherent.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index a12c9a0..82b69ae 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -615,7 +615,9 @@
EmitInstructionPrologue(instr);
ASSERT(pending_deoptimization_env_ == NULL);
pending_deoptimization_env_ = instr->env();
+ DEBUG_ONLY(current_instruction_ = instr);
instr->EmitNativeCode(this);
+ DEBUG_ONLY(current_instruction_ = nullptr);
pending_deoptimization_env_ = NULL;
if (IsPeephole(instr)) {
ASSERT(top_of_stack_ == nullptr);
@@ -708,7 +710,9 @@
set_current_instruction(slow_path->instruction());
SpecialStatsBegin(stats_tag);
BeginCodeSourceRange();
+ DEBUG_ONLY(current_instruction_ = slow_path->instruction());
slow_path->GenerateCode(this);
+ DEBUG_ONLY(current_instruction_ = nullptr);
EndCodeSourceRange(slow_path->instruction()->token_pos());
SpecialStatsEnd(stats_tag);
set_current_instruction(nullptr);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index fc573cc..f34e9e7 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -1121,6 +1121,15 @@
// is amenable to a peephole optimization.
bool IsPeephole(Instruction* instr) const;
+#if defined(DEBUG)
+ bool CanCallDart() const {
+ return current_instruction_ == nullptr ||
+ current_instruction_->CanCallDart();
+ }
+#else
+ bool CanCallDart() const { return true; }
+#endif
+
// This struct contains either function or code, the other one being NULL.
class StaticCallsStruct : public ZoneAllocated {
public:
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 5aad6fd..30499dc 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -995,6 +995,7 @@
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
__ BranchLinkPatchable(stub, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -1005,6 +1006,7 @@
LocationSummary* locs,
const Function& target,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
__ GenerateUnRelocatedPcRelativeCall();
AddPcRelativeCallTarget(target, entry_kind);
@@ -1061,6 +1063,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
@@ -1084,6 +1087,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(entry_kind == Code::EntryKind::kNormal ||
entry_kind == Code::EntryKind::kUnchecked);
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
@@ -1109,6 +1113,7 @@
LocationSummary* locs,
intptr_t try_index,
intptr_t slow_path_argument_count) {
+ ASSERT(CanCallDart());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
@@ -1156,6 +1161,7 @@
LocationSummary* locs,
Code::EntryKind entry_kind,
bool receiver_can_be_smi) {
+ ASSERT(CanCallDart());
ASSERT(entry_kind == Code::EntryKind::kNormal ||
entry_kind == Code::EntryKind::kUnchecked);
ASSERT(ic_data.NumArgsTested() == 1);
@@ -1200,6 +1206,7 @@
LocationSummary* locs,
const ICData& ic_data,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(R9, ic_data);
@@ -1216,6 +1223,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(!function.IsClosureFunction());
if (function.HasOptionalParameters() || function.IsGeneric()) {
__ LoadObject(R4, arguments_descriptor);
@@ -1235,6 +1243,7 @@
Register cid_reg,
int32_t selector_offset,
const Array& arguments_descriptor) {
+ ASSERT(CanCallDart());
ASSERT(cid_reg != ARGS_DESC_REG);
if (!arguments_descriptor.IsNull()) {
__ LoadObject(ARGS_DESC_REG, arguments_descriptor);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 2958722..acaa121 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -966,6 +966,7 @@
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
__ BranchLinkPatchable(stub, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -976,6 +977,7 @@
LocationSummary* locs,
const Function& target,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
__ GenerateUnRelocatedPcRelativeCall();
AddPcRelativeCallTarget(target, entry_kind);
@@ -1023,6 +1025,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
@@ -1045,6 +1048,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(entry_kind == Code::EntryKind::kNormal ||
entry_kind == Code::EntryKind::kUnchecked);
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
@@ -1076,6 +1080,7 @@
LocationSummary* locs,
intptr_t try_index,
intptr_t slow_path_argument_count) {
+ ASSERT(CanCallDart());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
@@ -1120,6 +1125,7 @@
LocationSummary* locs,
Code::EntryKind entry_kind,
bool receiver_can_be_smi) {
+ ASSERT(CanCallDart());
ASSERT(ic_data.NumArgsTested() == 1);
const Code& initial_stub = StubCode::UnlinkedCall();
const char* switchable_call_mode = "smiable";
@@ -1170,6 +1176,7 @@
LocationSummary* locs,
const ICData& ic_data,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(R5, ic_data);
@@ -1186,6 +1193,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(!function.IsClosureFunction());
if (function.HasOptionalParameters() || function.IsGeneric()) {
__ LoadObject(R4, arguments_descriptor);
@@ -1205,6 +1213,7 @@
Register cid_reg,
int32_t selector_offset,
const Array& arguments_descriptor) {
+ ASSERT(CanCallDart());
ASSERT(cid_reg != ARGS_DESC_REG);
if (!arguments_descriptor.IsNull()) {
__ LoadObject(ARGS_DESC_REG, arguments_descriptor);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 673e253..0605ba8 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -861,6 +861,7 @@
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
__ Call(stub, /*moveable_target=*/false, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -871,6 +872,7 @@
LocationSummary* locs,
const Function& target,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
const auto& stub = StubCode::CallStaticFunction();
__ Call(stub, /*movable_target=*/true, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
@@ -892,6 +894,7 @@
LocationSummary* locs,
const ICData& ic_data,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(ECX, ic_data);
@@ -919,6 +922,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
@@ -942,6 +946,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(entry_kind == Code::EntryKind::kNormal ||
entry_kind == Code::EntryKind::kUnchecked);
ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
@@ -967,6 +972,7 @@
LocationSummary* locs,
intptr_t try_index,
intptr_t slow_path_argument_count) {
+ ASSERT(CanCallDart());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
@@ -1014,6 +1020,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
if (function.HasOptionalParameters() || function.IsGeneric()) {
__ LoadObject(EDX, arguments_descriptor);
} else {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 1a6d288..ab879bc 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -977,6 +977,7 @@
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
__ CallPatchable(stub, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -987,6 +988,7 @@
LocationSummary* locs,
const Function& target,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(is_optimizing());
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
__ GenerateUnRelocatedPcRelativeCall();
@@ -1019,6 +1021,7 @@
LocationSummary* locs,
const ICData& ic_data,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(RBX, ic_data);
@@ -1047,6 +1050,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
// Each ICData propagated from unoptimized to optimized code contains the
// function that corresponds to the Dart function of that IC call. Due
@@ -1070,6 +1074,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(entry_kind == Code::EntryKind::kNormal ||
entry_kind == Code::EntryKind::kUnchecked);
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
@@ -1095,6 +1100,7 @@
LocationSummary* locs,
intptr_t try_index,
intptr_t slow_path_argument_count) {
+ ASSERT(CanCallDart());
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
@@ -1136,6 +1142,7 @@
LocationSummary* locs,
Code::EntryKind entry_kind,
bool receiver_can_be_smi) {
+ ASSERT(CanCallDart());
ASSERT(entry_kind == Code::EntryKind::kNormal ||
entry_kind == Code::EntryKind::kUnchecked);
ASSERT(ic_data.NumArgsTested() == 1);
@@ -1178,6 +1185,7 @@
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind) {
+ ASSERT(CanCallDart());
ASSERT(!function.IsClosureFunction());
if (function.HasOptionalParameters() || function.IsGeneric()) {
__ LoadObject(R10, arguments_descriptor);
@@ -1197,6 +1205,7 @@
Register cid_reg,
int32_t selector_offset,
const Array& arguments_descriptor) {
+ ASSERT(CanCallDart());
const Register table_reg = RAX;
ASSERT(cid_reg != table_reg);
ASSERT(cid_reg != ARGS_DESC_REG);
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 80c224c..0e78547 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -1024,6 +1024,15 @@
// See StoreInstanceFieldInstr::HasUnknownSideEffects() for rationale.
virtual bool HasUnknownSideEffects() const = 0;
+ // Whether this instruction can call Dart code without going through
+ // the runtime.
+ //
+ // Must be true for any instruction which can call Dart code without
+ // first creating an exit frame to transition into the runtime.
+ //
+ // See also WriteBarrierElimination and Thread::RememberLiveTemporaries().
+ virtual bool CanCallDart() const { return false; }
+
virtual bool CanTriggerGC() const;
// Get the block entry for this instruction.
@@ -3181,6 +3190,8 @@
return comparison()->HasUnknownSideEffects();
}
+ virtual bool CanCallDart() const { return comparison()->CanCallDart(); }
+
ComparisonInstr* comparison() const { return comparison_; }
void SetComparison(ComparisonInstr* comp);
@@ -3661,6 +3672,7 @@
}
virtual bool MayThrow() const { return true; }
+ virtual bool CanCallDart() const { return true; }
virtual intptr_t InputCount() const { return inputs_->length(); }
virtual Value* InputAt(intptr_t i) const { return inputs_->At(i); }
@@ -4411,6 +4423,7 @@
virtual bool HasUnknownSideEffects() const {
return comparison()->HasUnknownSideEffects();
}
+ virtual bool CanCallDart() const { return comparison()->CanCallDart(); }
virtual bool AttributesEqual(Instruction* other) const {
IfThenElseInstr* other_if_then_else = other->AsIfThenElse();
@@ -4539,6 +4552,7 @@
}
virtual bool HasUnknownSideEffects() const { return true; }
+ virtual bool CanCallDart() const { return true; }
// Initialize result type of this call instruction if target is a recognized
// method or has pragma annotation.
@@ -4816,6 +4830,9 @@
virtual bool HasUnknownSideEffects() const { return true; }
+ // Always creates an exit frame before more Dart code can be called.
+ virtual bool CanCallDart() const { return false; }
+
void SetupNative();
PRINT_OPERANDS_TO_SUPPORT
@@ -4875,6 +4892,9 @@
virtual bool HasUnknownSideEffects() const { return true; }
+ // Always creates an exit frame before more Dart code can be called.
+ virtual bool CanCallDart() const { return false; }
+
virtual Representation RequiredInputRepresentation(intptr_t idx) const;
virtual Representation representation() const;
@@ -5435,6 +5455,7 @@
virtual CompileType ComputeType() const;
// Issues a static call to Dart code which calls toString on objects.
virtual bool HasUnknownSideEffects() const { return true; }
+ virtual bool CanCallDart() const { return true; }
virtual bool ComputeCanDeoptimize() const { return !FLAG_precompiled_mode; }
const Function& CallFunction() const;
@@ -5489,6 +5510,10 @@
(emit_store_barrier_ == kEmitStoreBarrier);
}
+ void set_emit_store_barrier(StoreBarrierType value) {
+ emit_store_barrier_ = value;
+ }
+
virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
return speculative_mode_;
}
@@ -5509,6 +5534,8 @@
virtual bool HasUnknownSideEffects() const { return false; }
+ void PrintOperandsTo(BufferFormatter* f) const;
+
ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
@@ -5516,7 +5543,7 @@
return compiler::Assembler::kValueCanBeSmi;
}
- const StoreBarrierType emit_store_barrier_;
+ StoreBarrierType emit_store_barrier_;
const bool index_unboxed_;
const intptr_t index_scale_;
const intptr_t class_id_;
@@ -7102,6 +7129,7 @@
virtual bool RecomputeType();
virtual bool HasUnknownSideEffects() const { return true; }
+ virtual bool CanCallDart() const { return true; }
virtual Definition* Canonicalize(FlowGraph* flow_graph);
@@ -7150,6 +7178,7 @@
bool is_negated() const { return is_negated_; }
virtual bool HasUnknownSideEffects() const { return true; }
+ virtual bool CanCallDart() const { return true; }
PRINT_OPERANDS_TO_SUPPORT
@@ -7785,6 +7814,8 @@
virtual bool HasUnknownSideEffects() const { return false; }
+ virtual bool CanCallDart() const { return true; }
+
private:
InstanceCallInstr* instance_call_;
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index f4f7115..d63d92b 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -1125,6 +1125,13 @@
value()->PrintTo(f);
}
+void StoreIndexedInstr::PrintOperandsTo(BufferFormatter* f) const {
+ Instruction::PrintOperandsTo(f);
+ if (!ShouldEmitStoreBarrier()) {
+ f->Print(", NoStoreBarrier");
+ }
+}
+
void TailCallInstr::PrintOperandsTo(BufferFormatter* f) const {
const char* name = "<unknown code>";
if (code_.IsStubCode()) {
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index 9f53b4b..6e7f51d 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -44,6 +44,14 @@
return func.raw();
}
+RawClass* GetClass(const Library& lib, const char* name) {
+ Thread* thread = Thread::Current();
+ const auto& cls = Class::Handle(
+ lib.LookupClassAllowPrivate(String::Handle(Symbols::New(thread, name))));
+ EXPECT(!cls.IsNull());
+ return cls.raw();
+}
+
void Invoke(const Library& lib, const char* name) {
// These tests rely on running unoptimized code to collect type feedback. The
// interpreter does not collect type feedback for interface calls, so set
diff --git a/runtime/vm/compiler/backend/il_test_helper.h b/runtime/vm/compiler/backend/il_test_helper.h
index bdb7be1..95b6526 100644
--- a/runtime/vm/compiler/backend/il_test_helper.h
+++ b/runtime/vm/compiler/backend/il_test_helper.h
@@ -58,6 +58,7 @@
const char* lib_uri = RESOLVED_USER_TEST_URI);
RawFunction* GetFunction(const Library& lib, const char* name);
+RawClass* GetClass(const Library& lib, const char* name);
void Invoke(const Library& lib, const char* name);
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index 5b20762..b5572d7 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -51,7 +51,7 @@
const char* Slot::KindToCString(Kind k) {
switch (k) {
-#define NATIVE_CASE(C, F, id, M) \
+#define NATIVE_CASE(C, U, F, id, M) \
case NATIVE_SLOT_NAME(C, F, id, M): \
return NATIVE_TO_STR(C, F, id, M);
NATIVE_SLOTS_LIST(NATIVE_CASE)
@@ -70,7 +70,7 @@
bool Slot::ParseKind(const char* str, Kind* out) {
ASSERT(str != nullptr && out != nullptr);
-#define NATIVE_CASE(C, F, id, M) \
+#define NATIVE_CASE(C, U, F, id, M) \
if (strcmp(str, NATIVE_TO_STR(C, F, id, M)) == 0) { \
*out = NATIVE_SLOT_NAME(C, F, id, M); \
return true; \
@@ -101,7 +101,8 @@
static const Slot fields[] = {
#define FIELD_FINAL (IsImmutableBit::encode(true))
#define FIELD_VAR (0)
-#define DEFINE_NATIVE_FIELD(ClassName, FieldName, cid, mutability) \
+#define DEFINE_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, cid, \
+ mutability) \
Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability, k##cid##Cid, \
compiler::target::ClassName::FieldName##_offset(), \
#ClassName "." #FieldName, nullptr),
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 83f819a..6f6faa8 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -36,10 +36,11 @@
// List of slots that correspond to fields of native objects in the following
// format:
//
-// V(class_name, field_name, exact_type, FINAL|VAR)
+// V(class_name, underlying_type, field_name, exact_type, FINAL|VAR)
//
// - class_name and field_name specify the name of the host class and the name
// of the field respectively;
+// - underlying_type: the Raw class which holds the field;
// - exact_type specifies exact type of the field (any load from this field
// would only yield instances of this type);
// - the last component specifies whether field behaves like a final field
@@ -48,31 +49,31 @@
//
// Note: native slots are expected to be non-nullable.
#define NATIVE_SLOTS_LIST(V) \
- V(Array, length, Smi, FINAL) \
- V(Context, parent, Context, FINAL) \
- V(Closure, instantiator_type_arguments, TypeArguments, FINAL) \
- V(Closure, delayed_type_arguments, TypeArguments, FINAL) \
- V(Closure, function_type_arguments, TypeArguments, FINAL) \
- V(Closure, function, Function, FINAL) \
- V(Closure, context, Context, FINAL) \
- V(Closure, hash, Context, VAR) \
- V(GrowableObjectArray, length, Smi, VAR) \
- V(GrowableObjectArray, data, Array, VAR) \
- V(TypedDataBase, length, Smi, FINAL) \
- V(TypedDataView, offset_in_bytes, Smi, FINAL) \
- V(TypedDataView, data, Dynamic, FINAL) \
- V(String, length, Smi, FINAL) \
- V(LinkedHashMap, index, TypedDataUint32Array, VAR) \
- V(LinkedHashMap, data, Array, VAR) \
- V(LinkedHashMap, hash_mask, Smi, VAR) \
- V(LinkedHashMap, used_data, Smi, VAR) \
- V(LinkedHashMap, deleted_keys, Smi, VAR) \
- V(ArgumentsDescriptor, type_args_len, Smi, FINAL) \
- V(ArgumentsDescriptor, positional_count, Smi, FINAL) \
- V(ArgumentsDescriptor, count, Smi, FINAL) \
- V(ArgumentsDescriptor, size, Smi, FINAL) \
- V(PointerBase, data_field, Dynamic, FINAL) \
- V(Type, arguments, TypeArguments, FINAL)
+ V(Array, RawArray, length, Smi, FINAL) \
+ V(Context, RawContext, parent, Context, FINAL) \
+ V(Closure, RawClosure, instantiator_type_arguments, TypeArguments, FINAL) \
+ V(Closure, RawClosure, delayed_type_arguments, TypeArguments, FINAL) \
+ V(Closure, RawClosure, function_type_arguments, TypeArguments, FINAL) \
+ V(Closure, RawClosure, function, Function, FINAL) \
+ V(Closure, RawClosure, context, Context, FINAL) \
+ V(Closure, RawClosure, hash, Context, VAR) \
+ V(GrowableObjectArray, RawGrowableObjectArray, length, Smi, VAR) \
+ V(GrowableObjectArray, RawGrowableObjectArray, data, Array, VAR) \
+ V(TypedDataBase, RawTypedDataBase, length, Smi, FINAL) \
+ V(TypedDataView, RawTypedDataView, offset_in_bytes, Smi, FINAL) \
+ V(TypedDataView, RawTypedDataView, data, Dynamic, FINAL) \
+ V(String, RawString, length, Smi, FINAL) \
+ V(LinkedHashMap, RawLinkedHashMap, index, TypedDataUint32Array, VAR) \
+ V(LinkedHashMap, RawLinkedHashMap, data, Array, VAR) \
+ V(LinkedHashMap, RawLinkedHashMap, hash_mask, Smi, VAR) \
+ V(LinkedHashMap, RawLinkedHashMap, used_data, Smi, VAR) \
+ V(LinkedHashMap, RawLinkedHashMap, deleted_keys, Smi, VAR) \
+ V(ArgumentsDescriptor, RawArray, type_args_len, Smi, FINAL) \
+ V(ArgumentsDescriptor, RawArray, positional_count, Smi, FINAL) \
+ V(ArgumentsDescriptor, RawArray, count, Smi, FINAL) \
+ V(ArgumentsDescriptor, RawArray, size, Smi, FINAL) \
+ V(PointerBase, RawPointerBase, data_field, Dynamic, FINAL) \
+ V(Type, RawType, arguments, TypeArguments, FINAL)
// Slot is an abstraction that describes an readable (and possibly writeable)
// location within an object.
@@ -86,7 +87,7 @@
// clang-format off
enum class Kind : uint8_t {
// Native slots are identified by their kind - each native slot has its own.
-#define DECLARE_KIND(ClassName, FieldName, cid, mutability) \
+#define DECLARE_KIND(ClassName, UnderlyingType, FieldName, cid, mutability) \
k##ClassName##_##FieldName,
NATIVE_SLOTS_LIST(DECLARE_KIND)
#undef DECLARE_KIND
@@ -134,7 +135,7 @@
const ParsedFunction* parsed_function);
// Convenience getters for native slots.
-#define DEFINE_GETTER(ClassName, FieldName, cid, mutability) \
+#define DEFINE_GETTER(ClassName, UnderlyingType, FieldName, cid, mutability) \
static const Slot& ClassName##_##FieldName() { \
return GetNativeSlot(Kind::k##ClassName##_##FieldName); \
}
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 094f2dd..7b65475 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -828,6 +828,19 @@
return compile_type.IsSubtypeOf(other, Heap::kOld);
}
+bool CompileType::IsInstanceOf(const AbstractType& other) {
+ if (other.IsTopType()) {
+ return true;
+ }
+ if (IsNone() || !other.IsInstantiated()) {
+ return false;
+ }
+ if (is_nullable() && !other.IsNullable()) {
+ return false;
+ }
+ return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
+}
+
bool CompileType::Specialize(GrowableArray<intptr_t>* class_ids) {
ToNullableCid();
if (cid_ != kDynamicCid) {
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 70b5134..11481a0 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -1197,38 +1197,38 @@
const AbstractType& type) {
ASSERT(I->can_use_strong_mode_types());
ASSERT(Token::IsTypeTestOperator(call->token_kind()));
-
- // The goal is to emit code that will determine the result of 'x is type'
- // depending solely on the fact that x == null or not.
- // 'null' is an instance of Null, Object*, Never*, void, and dynamic.
- // In addition, 'null' is an instance of any nullable type.
- // It is also an instance of FutureOr<T> if it is an instance of T.
- const AbstractType& unwrapped_type =
- AbstractType::Handle(type.UnwrapFutureOr());
- if (unwrapped_type.IsTopType() || !unwrapped_type.IsInstantiated()) {
- return false; // Always true or cannot tell.
- }
-
- // Checking whether the receiver is null can only help if the tested type is
- // legacy (including Never*) or the Null type.
- if (!unwrapped_type.IsLegacy() && !unwrapped_type.IsNullType()) {
- // TODO(regis): We should optimize this into a constant if the type
- // is nullable or non-nullable.
+ if (!type.IsInstantiated()) {
return false;
}
- const intptr_t receiver_index = call->FirstArgIndex();
- Value* left_value = call->ArgumentValueAt(receiver_index);
+ Value* left_value = call->Receiver();
+ if (left_value->Type()->IsInstanceOf(type)) {
+ ConstantInstr* replacement = flow_graph()->GetConstant(Bool::True());
+ call->ReplaceUsesWith(replacement);
+ ASSERT(current_iterator()->Current() == call);
+ current_iterator()->RemoveCurrentFromGraph();
+ return true;
+ }
- // If the static type of the receiver is a subtype of the tested type,
- // replace 'receiver is type' with 'receiver == null' if type is Null
- // or with 'receiver != null' otherwise.
- if (left_value->Type()->IsSubtypeOf(type)) {
+ // The goal is to emit code that will determine the result of 'x is type'
+ // depending solely on the fact that x == null or not.
+ // Checking whether the receiver is null can only help if the tested type is
+ // non-nullable or legacy (including Never*) or the Null type.
+ // Also, testing receiver for null cannot help with FutureOr.
+ if ((type.IsNullable() && !type.IsNullType()) || type.IsFutureOrType()) {
+ return false;
+ }
+
+ // If type is Null or Never*, or the static type of the receiver is a
+ // subtype of the tested type, replace 'receiver is type' with
+ // - 'receiver == null' if type is Null or Never*,
+ // - 'receiver != null' otherwise.
+ if (type.IsNullType() || type.IsNeverType() ||
+ left_value->Type()->IsSubtypeOf(type)) {
Definition* replacement = new (Z) StrictCompareInstr(
call->token_pos(),
- (unwrapped_type.IsNullType() || unwrapped_type.IsNeverType())
- ? Token::kEQ_STRICT
- : Token::kNE_STRICT,
+ (type.IsNullType() || type.IsNeverType()) ? Token::kEQ_STRICT
+ : Token::kNE_STRICT,
left_value->CopyWithType(Z),
new (Z) Value(flow_graph()->constant_null()),
/* number_check = */ false, DeoptId::kNone);
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index b13d72a..80cbb59 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -19,6 +19,7 @@
#include "vm/compiler/backend/redundancy_elimination.h"
#include "vm/compiler/backend/type_propagator.h"
#include "vm/compiler/call_specializer.h"
+#include "vm/compiler/write_barrier_elimination.h"
#if defined(DART_PRECOMPILER)
#include "vm/compiler/aot/aot_call_specializer.h"
#include "vm/compiler/aot/precompiler.h"
@@ -266,7 +267,7 @@
// so it should not be lifted earlier than that pass.
INVOKE_PASS(DCE);
INVOKE_PASS(Canonicalize);
- INVOKE_PASS(WriteBarrierElimination);
+ INVOKE_PASS(EliminateWriteBarriers);
INVOKE_PASS(FinalizeGraph);
#if defined(DART_PRECOMPILER)
if (mode == kAOT) {
@@ -349,7 +350,7 @@
INVOKE_PASS(EliminateStackOverflowChecks);
INVOKE_PASS(Canonicalize);
INVOKE_PASS(AllocationSinking_DetachMaterializations);
- INVOKE_PASS(WriteBarrierElimination);
+ INVOKE_PASS(EliminateWriteBarriers);
INVOKE_PASS(FinalizeGraph);
#if defined(DART_PRECOMPILER)
if (mode == kAOT) {
@@ -529,38 +530,7 @@
}
});
-static void WriteBarrierElimination(FlowGraph* flow_graph) {
- for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
- !block_it.Done(); block_it.Advance()) {
- BlockEntryInstr* block = block_it.Current();
- Definition* last_allocated = nullptr;
- for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
- Instruction* current = it.Current();
- if (!current->CanTriggerGC()) {
- if (StoreInstanceFieldInstr* instr = current->AsStoreInstanceField()) {
- if (instr->instance()->definition() == last_allocated) {
- instr->set_emit_store_barrier(kNoStoreBarrier);
- }
- continue;
- }
- }
-
- if (AllocationInstr* alloc = current->AsAllocation()) {
- if (alloc->WillAllocateNewOrRemembered()) {
- last_allocated = alloc;
- continue;
- }
- }
-
- if (current->CanTriggerGC()) {
- last_allocated = nullptr;
- }
- }
- }
-}
-
-COMPILER_PASS(WriteBarrierElimination,
- { WriteBarrierElimination(flow_graph); });
+COMPILER_PASS(EliminateWriteBarriers, { EliminateWriteBarriers(flow_graph); });
COMPILER_PASS(FinalizeGraph, {
// At the end of the pipeline, force recomputing and caching graph
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index 54570dd..f3333b91 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -50,7 +50,7 @@
V(TypePropagation) \
V(UseTableDispatch) \
V(WidenSmiToInt32) \
- V(WriteBarrierElimination)
+ V(EliminateWriteBarriers)
class AllocationSinking;
class BlockScheduler;
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index d2b651c..8cf2d6c 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -166,6 +166,8 @@
"stub_code_compiler_arm64.cc",
"stub_code_compiler_ia32.cc",
"stub_code_compiler_x64.cc",
+ "write_barrier_elimination.cc",
+ "write_barrier_elimination.h",
]
compiler_sources_tests = [
@@ -190,4 +192,5 @@
"backend/typed_data_aot_test.cc",
"backend/yield_position_test.cc",
"cha_test.cc",
+ "write_barrier_elimination_test.cc",
]
diff --git a/runtime/vm/compiler/write_barrier_elimination.cc b/runtime/vm/compiler/write_barrier_elimination.cc
new file mode 100644
index 0000000..162f8e1
--- /dev/null
+++ b/runtime/vm/compiler/write_barrier_elimination.cc
@@ -0,0 +1,388 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include <functional>
+
+#include "vm/compiler/backend/flow_graph.h"
+#include "vm/compiler/compiler_pass.h"
+#include "vm/compiler/write_barrier_elimination.h"
+
+namespace dart {
+
+#if defined(DEBUG)
+DEFINE_FLAG(bool,
+ trace_write_barrier_elimination,
+ false,
+ "Trace WriteBarrierElimination pass.");
+#endif
+
+class DefinitionIndexPairTrait {
+ public:
+ typedef Definition* Key;
+ typedef intptr_t Value;
+ struct Pair {
+ Definition* definition = nullptr;
+ intptr_t index = -1;
+ Pair() {}
+ Pair(Definition* definition, intptr_t index)
+ : definition(definition), index(index) {}
+ };
+
+ static Key KeyOf(Pair kv) { return kv.definition; }
+ static Value ValueOf(Pair kv) { return kv.index; }
+ static inline intptr_t Hashcode(Key key) { return std::hash<Key>()(key); }
+ static inline bool IsKeyEqual(Pair kv, Key key) {
+ return kv.definition == key;
+ }
+};
+
+typedef DirectChainedHashMap<DefinitionIndexPairTrait> DefinitionIndexMap;
+
+// Inter-block write-barrier elimination.
+//
+// This optimization removes write barriers from some store instructions under
+// certain assumptions which the runtime is responsible to sustain.
+//
+// We can skip a write barrier on a StoreInstanceField to a container object X
+// if we know that either:
+// - X is in new-space, or
+// - X is in old-space, and:
+// - X is in the store buffer, and
+// - X is in the deferred marking stack (if concurrent marking is enabled)
+//
+// The result of an Allocation instruction (Instruction::IsAllocation()) will
+// satisfy one of these requirements immediately after the instruction
+// if WillAllocateNewOrRemembered() is true.
+//
+// Without runtime support, we would have to assume that any instruction which
+// can trigger a new-space scavenge (Instruction::CanTriggerGC()) might promote
+// a new-space temporary into old-space, and we could not skip a store barrier
+// on a write into it afterward.
+//
+// However, many instructions can trigger GC in unlikely cases, like
+// CheckStackOverflow and Box. To avoid interrupting write barrier elimination
+// across these instructions, the runtime ensures that any live temporaries
+// (except arrays) promoted during a scavenge caused by a non-Dart-call
+// instruction (see Instruction::CanCallDart()) will be added to the store
+// buffer. Additionally, if concurrent marking was initiated, the runtime
+// ensures that all live temporaries are also in the deferred marking stack.
+//
+// See also Thread::RememberLiveTemporaries() and
+// Thread::DeferredMarkLiveTemporaries().
+class WriteBarrierElimination : public ValueObject {
+ public:
+ WriteBarrierElimination(Zone* zone, FlowGraph* flow_graph);
+
+ void Analyze();
+ void SaveResults();
+
+ private:
+ void IndexDefinitions(Zone* zone);
+
+ bool AnalyzeBlock(BlockEntryInstr* entry);
+ void MergePredecessors(BlockEntryInstr* entry);
+
+ void UpdateVectorForBlock(BlockEntryInstr* entry, bool finalize);
+
+ static intptr_t Index(BlockEntryInstr* entry) {
+ return entry->postorder_number();
+ }
+
+ intptr_t Index(Definition* def) {
+ ASSERT(IsUsable(def));
+ return definition_indices_.LookupValue(def);
+ }
+
+ bool IsUsable(Definition* def) {
+ return def->IsPhi() || (def->IsAllocation() &&
+ def->AsAllocation()->WillAllocateNewOrRemembered());
+ }
+
+#if defined(DEBUG)
+ static bool SlotEligibleForWBE(const Slot& slot);
+#endif
+
+ FlowGraph* const flow_graph_;
+ const GrowableArray<BlockEntryInstr*>* const block_order_;
+
+ // Number of usable definitions in the graph.
+ intptr_t definition_count_ = 0;
+
+ // Maps each usable definition to its index in the bitvectors.
+ DefinitionIndexMap definition_indices_;
+
+ // Bitvector with all non-Array-allocation instructions set. Used to
+ // un-mark Array allocations as usable.
+ BitVector* array_allocations_mask_;
+
+ // Bitvectors for each block of which allocations are new or remembered
+ // at the start (after Phis).
+ GrowableArray<BitVector*> usable_allocs_in_;
+
+ // Bitvectors for each block of which allocations are new or remembered
+ // at the end of the block.
+ GrowableArray<BitVector*> usable_allocs_out_;
+
+ // Remaining blocks to process.
+ GrowableArray<BlockEntryInstr*> worklist_;
+
+ // Temporary used in many functions to avoid repeated zone allocation.
+ BitVector* vector_;
+
+ // Bitvector of blocks which have been processed, to ensure each block
+ // is processed at least once.
+ BitVector* processed_blocks_;
+
+#if defined(DEBUG)
+ bool tracing_ = false;
+#else
+ static constexpr bool tracing_ = false;
+#endif
+};
+
+WriteBarrierElimination::WriteBarrierElimination(Zone* zone,
+ FlowGraph* flow_graph)
+ : flow_graph_(flow_graph), block_order_(&flow_graph->postorder()) {
+#if defined(DEBUG)
+ if (flow_graph->should_print() && FLAG_trace_write_barrier_elimination) {
+ tracing_ = true;
+ }
+#endif
+
+ IndexDefinitions(zone);
+
+ for (intptr_t i = 0; i < block_order_->length(); ++i) {
+ usable_allocs_in_.Add(new (zone) BitVector(zone, definition_count_));
+ usable_allocs_in_[i]->CopyFrom(vector_);
+
+ usable_allocs_out_.Add(new (zone) BitVector(zone, definition_count_));
+ usable_allocs_out_[i]->CopyFrom(vector_);
+ }
+
+ processed_blocks_ = new (zone) BitVector(zone, block_order_->length());
+}
+
+void WriteBarrierElimination::Analyze() {
+ for (intptr_t i = 0; i < block_order_->length(); ++i) {
+ worklist_.Add(block_order_->At(i));
+ }
+
+ while (!worklist_.is_empty()) {
+ auto* const entry = worklist_.RemoveLast();
+ if (AnalyzeBlock(entry)) {
+ for (intptr_t i = 0; i < entry->last_instruction()->SuccessorCount();
+ ++i) {
+ if (tracing_) {
+ THR_Print("Enqueueing block %" Pd "\n", entry->block_id());
+ }
+ worklist_.Add(entry->last_instruction()->SuccessorAt(i));
+ }
+ }
+ }
+}
+
+void WriteBarrierElimination::SaveResults() {
+ for (intptr_t i = 0; i < block_order_->length(); ++i) {
+ vector_->CopyFrom(usable_allocs_in_[i]);
+ UpdateVectorForBlock(block_order_->At(i), /*finalize=*/true);
+ }
+}
+
+void WriteBarrierElimination::IndexDefinitions(Zone* zone) {
+ BitmapBuilder array_allocations;
+
+ for (intptr_t i = 0; i < block_order_->length(); ++i) {
+ BlockEntryInstr* const block = block_order_->At(i);
+ if (auto join_block = block->AsJoinEntry()) {
+ for (PhiIterator it(join_block); !it.Done(); it.Advance()) {
+ array_allocations.Set(definition_count_, false);
+ definition_indices_.Insert({it.Current(), definition_count_++});
+#if defined(DEBUG)
+ if (tracing_) {
+ THR_Print("Definition (%" Pd ") has index %" Pd ".\n",
+ it.Current()->ssa_temp_index(), definition_count_ - 1);
+ }
+#endif
+ }
+ }
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ if (Definition* current = it.Current()->AsDefinition()) {
+ if (IsUsable(current)) {
+ array_allocations.Set(definition_count_, current->IsCreateArray());
+ definition_indices_.Insert({current, definition_count_++});
+#if defined(DEBUG)
+ if (tracing_) {
+ THR_Print("Definition (%" Pd ") has index %" Pd ".\n",
+ current->ssa_temp_index(), definition_count_ - 1);
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ vector_ = new (zone) BitVector(zone, definition_count_);
+ vector_->SetAll();
+ array_allocations_mask_ = new (zone) BitVector(zone, definition_count_);
+ for (intptr_t i = 0; i < definition_count_; ++i) {
+ if (!array_allocations.Get(i)) array_allocations_mask_->Add(i);
+ }
+}
+
+void WriteBarrierElimination::MergePredecessors(BlockEntryInstr* entry) {
+ vector_->Clear();
+ for (intptr_t i = 0; i < entry->PredecessorCount(); ++i) {
+ BitVector* predecessor_set =
+ usable_allocs_out_[Index(entry->PredecessorAt(i))];
+ if (i == 0) {
+ vector_->AddAll(predecessor_set);
+ } else {
+ vector_->Intersect(predecessor_set);
+ }
+ }
+
+ if (JoinEntryInstr* join = entry->AsJoinEntry()) {
+ // A Phi is usable if and only if all its inputs are usable.
+ for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ PhiInstr* phi = it.Current();
+ ASSERT(phi->InputCount() == entry->PredecessorCount());
+ bool is_usable = true;
+ for (intptr_t i = 0; i < phi->InputCount(); ++i) {
+ BitVector* const predecessor_set =
+ usable_allocs_out_[Index(entry->PredecessorAt(i))];
+ Definition* const origin = phi->InputAt(i)->definition();
+ if (!IsUsable(origin) || !predecessor_set->Contains(Index(origin))) {
+ is_usable = false;
+ break;
+ }
+ }
+ vector_->Set(Index(phi), is_usable);
+ }
+
+#if defined(DEBUG)
+ if (tracing_) {
+ THR_Print("Merge predecessors for %" Pd ".\n", entry->block_id());
+ for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ PhiInstr* phi = it.Current();
+ THR_Print("%" Pd ": %s\n", phi->ssa_temp_index(),
+ vector_->Contains(Index(phi)) ? "true" : "false");
+ }
+ }
+#endif
+ }
+}
+
+bool WriteBarrierElimination::AnalyzeBlock(BlockEntryInstr* entry) {
+ // Recompute the usable allocs in-set.
+ MergePredecessors(entry);
+
+ // If the in-set has not changed, there's no work to do.
+ BitVector* const in_set = usable_allocs_in_[Index(entry)];
+ ASSERT(vector_->SubsetOf(*in_set)); // convergence
+ if (vector_->Equals(*in_set) && processed_blocks_->Contains(Index(entry))) {
+ if (tracing_) {
+ THR_Print("Bailout of block %" Pd ": inputs didn't change.\n",
+ entry->block_id());
+ }
+ return false;
+ } else if (tracing_) {
+ THR_Print("Inputs of block %" Pd " changed: ", entry->block_id());
+ in_set->Print();
+ THR_Print(" -> ");
+ vector_->Print();
+ THR_Print("\n");
+ }
+
+ usable_allocs_in_[Index(entry)]->CopyFrom(vector_);
+ UpdateVectorForBlock(entry, /*finalize=*/false);
+
+ processed_blocks_->Add(Index(entry));
+
+ // Successors only need to be updated if the out-set changes.
+ if (vector_->Equals(*usable_allocs_out_[Index(entry)])) {
+ if (tracing_) {
+ THR_Print("Bailout of block %" Pd ": out-set didn't change.\n",
+ entry->block_id());
+ }
+ return false;
+ }
+
+ BitVector* const out_set = usable_allocs_out_[Index(entry)];
+ ASSERT(vector_->SubsetOf(*out_set)); // convergence
+ out_set->CopyFrom(vector_);
+ if (tracing_) {
+ THR_Print("Block %" Pd " changed.\n", entry->block_id());
+ }
+ return true;
+}
+
+#if defined(DEBUG)
+bool WriteBarrierElimination::SlotEligibleForWBE(const Slot& slot) {
+ // We assume that Dart code only stores into Instances or Contexts.
+ // This assumption is used in
+ // RestoreWriteBarrierInvariantVisitor::VisitPointers.
+
+ switch (slot.kind()) {
+ case Slot::Kind::kCapturedVariable: // Context
+ return true;
+ case Slot::Kind::kDartField: // Instance
+ return true;
+
+#define FOR_EACH_NATIVE_SLOT(class, underlying_type, field, type, modifiers) \
+ case Slot::Kind::k##class##_##field: \
+ return std::is_base_of<RawInstance, underlying_type>::value || \
+ std::is_base_of<RawContext, underlying_type>::value;
+
+ NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT)
+#undef FOR_EACH_NATIVE_SLOT
+
+ default:
+ return false;
+ }
+}
+#endif
+
+void WriteBarrierElimination::UpdateVectorForBlock(BlockEntryInstr* entry,
+ bool finalize) {
+ for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
+ Instruction* const current = it.Current();
+
+ if (finalize) {
+ if (StoreInstanceFieldInstr* instr = current->AsStoreInstanceField()) {
+ Definition* const container = instr->instance()->definition();
+ if (IsUsable(container) && vector_->Contains(Index(container))) {
+ DEBUG_ASSERT(SlotEligibleForWBE(instr->slot()));
+ instr->set_emit_store_barrier(kNoStoreBarrier);
+ }
+ } else if (StoreIndexedInstr* instr = current->AsStoreIndexed()) {
+ Definition* const array = instr->array()->definition();
+ if (IsUsable(array) && vector_->Contains(Index(array))) {
+ instr->set_emit_store_barrier(StoreBarrierType::kNoStoreBarrier);
+ }
+ }
+ }
+
+ if (current->CanCallDart()) {
+ vector_->Clear();
+ } else if (current->CanTriggerGC()) {
+ // Clear array allocations. These are not added to the remembered set
+ // by Thread::RememberLiveTemporaries() after a scavenge.
+ vector_->Intersect(array_allocations_mask_);
+ }
+
+ if (AllocationInstr* const alloc = current->AsAllocation()) {
+ if (alloc->WillAllocateNewOrRemembered()) {
+ vector_->Add(Index(alloc));
+ }
+ }
+ }
+}
+
+void EliminateWriteBarriers(FlowGraph* flow_graph) {
+ WriteBarrierElimination elimination(Thread::Current()->zone(), flow_graph);
+ elimination.Analyze();
+ elimination.SaveResults();
+}
+
+} // namespace dart
diff --git a/runtime/vm/compiler/write_barrier_elimination.h b/runtime/vm/compiler/write_barrier_elimination.h
new file mode 100644
index 0000000..88109e7
--- /dev/null
+++ b/runtime/vm/compiler/write_barrier_elimination.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_COMPILER_WRITE_BARRIER_ELIMINATION_H_
+#define RUNTIME_VM_COMPILER_WRITE_BARRIER_ELIMINATION_H_
+
+namespace dart {
+
+class FlowGraph;
+void EliminateWriteBarriers(FlowGraph* flow_graph);
+
+} // namespace dart
+
+#endif // RUNTIME_VM_COMPILER_WRITE_BARRIER_ELIMINATION_H_
diff --git a/runtime/vm/compiler/write_barrier_elimination_test.cc b/runtime/vm/compiler/write_barrier_elimination_test.cc
new file mode 100644
index 0000000..737e213
--- /dev/null
+++ b/runtime/vm/compiler/write_barrier_elimination_test.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/assert.h"
+#include "vm/compiler/backend/il_printer.h"
+#include "vm/compiler/backend/il_test_helper.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+DEBUG_ONLY(DECLARE_FLAG(bool, trace_write_barrier_elimination);)
+
+ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_JoinSuccessors) {
+ DEBUG_ONLY(FLAG_trace_write_barrier_elimination = true);
+
+ // This is a regression test for a bug where we were using
+ // JoinEntry::SuccessorCount() to determine the number of outgoing blocks
+ // from the join block. JoinEntry::SuccessorCount() is in fact always 0;
+ // JoinEntry::last_instruction()->SuccessorCount() should be used instead.
+ const char* kScript =
+ R"(
+ class C {
+ int value;
+ C next;
+ C prev;
+ }
+
+ @pragma("vm:never-inline")
+ fn() {}
+
+ foo(int x) {
+ C prev = C();
+ C next;
+ while (x --> 0) {
+ next = C();
+ next.prev = prev;
+ prev?.next = next;
+ prev = next;
+ fn();
+ }
+ return next;
+ }
+
+ main() { foo(10); }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+
+ Invoke(root_library, "main");
+
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+ TestPipeline pipeline(function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ EXPECT(entry != nullptr);
+
+ StoreInstanceFieldInstr* store1 = nullptr;
+ StoreInstanceFieldInstr* store2 = nullptr;
+
+ ILMatcher cursor(flow_graph, entry);
+ RELEASE_ASSERT(cursor.TryMatch({
+ kMoveGlob,
+ kMatchAndMoveGoto,
+ kMoveGlob,
+ kMatchAndMoveBranchTrue,
+ kMoveGlob,
+ {kMatchAndMoveStoreInstanceField, &store1},
+ kMoveGlob,
+ {kMatchAndMoveStoreInstanceField, &store2},
+ }));
+
+ EXPECT(store1->ShouldEmitStoreBarrier() == false);
+ EXPECT(store2->ShouldEmitStoreBarrier() == true);
+}
+
+ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_AtLeastOnce) {
+ DEBUG_ONLY(FLAG_trace_write_barrier_elimination = true);
+
+ // Ensure that we process every block at least once during the analysis
+ // phase so that the out-sets will be initialized. If we don't process
+ // each block at least once, the store "c.next = n" will be marked
+ // NoWriteBarrier.
+ const char* kScript =
+ R"(
+ class C {
+ C next;
+ }
+
+ @pragma("vm:never-inline")
+ fn() {}
+
+ foo(int x) {
+ C c = C();
+ C n = C();
+ if (x > 5) {
+ fn();
+ }
+ c.next = n;
+ return c;
+ }
+
+ main() { foo(0); foo(10); }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+
+ Invoke(root_library, "main");
+
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+ TestPipeline pipeline(function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ EXPECT(entry != nullptr);
+
+ StoreInstanceFieldInstr* store = nullptr;
+
+ ILMatcher cursor(flow_graph, entry);
+ RELEASE_ASSERT(cursor.TryMatch({
+ kMoveGlob,
+ kMatchAndMoveBranchFalse,
+ kMoveGlob,
+ kMatchAndMoveGoto,
+ kMoveGlob,
+ {kMatchAndMoveStoreInstanceField, &store},
+ }));
+
+ EXPECT(store->ShouldEmitStoreBarrier() == true);
+}
+
+ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
+ DEBUG_ONLY(FLAG_trace_write_barrier_elimination = true);
+
+ // Test that array allocations are not considered usable after a
+ // may-trigger-GC instruction (in this case CheckStackOverflow), unlike
+ // normal allocations, which are only interruped by a Dart call.
+ const char* kScript =
+ R"(
+ class C {
+ C next;
+ }
+
+ @pragma("vm:never-inline")
+ fn() {}
+
+ foo(int x) {
+ C c = C();
+ C n = C();
+ List<C> array = List<C>(1);
+ while (x --> 0) {
+ c.next = n;
+ n = c;
+ c = C();
+ }
+ array[0] = c;
+ return c;
+ }
+
+ main() { foo(10); }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+
+ Invoke(root_library, "main");
+
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+ TestPipeline pipeline(function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ EXPECT(entry != nullptr);
+
+ StoreInstanceFieldInstr* store_into_c = nullptr;
+ StoreIndexedInstr* store_into_array = nullptr;
+
+ ILMatcher cursor(flow_graph, entry);
+ RELEASE_ASSERT(cursor.TryMatch({
+ kMoveGlob,
+ kMatchAndMoveGoto,
+ kMoveGlob,
+ kMatchAndMoveBranchTrue,
+ kMoveGlob,
+ {kMatchAndMoveStoreInstanceField, &store_into_c},
+ kMoveGlob,
+ kMatchAndMoveGoto,
+ kMoveGlob,
+ kMatchAndMoveBranchFalse,
+ kMoveGlob,
+ {kMatchAndMoveStoreIndexed, &store_into_array},
+ }));
+
+ EXPECT(store_into_c->ShouldEmitStoreBarrier() == false);
+ EXPECT(store_into_array->ShouldEmitStoreBarrier() == true);
+}
+
+} // namespace dart
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 5455ea7..994a268 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -819,6 +819,8 @@
ASSERT(result);
}
+ isolate_group_->DeferredMarkLiveTemporaries();
+
// Wait for roots to be marked before exiting safepoint.
MonitorLocker ml(&root_slices_monitor_);
while (root_slices_finished_ != kNumRootSlices) {
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index d3c20b2..3de0aa3 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -1187,6 +1187,9 @@
ProcessWeakReferences();
page_space->ReleaseDataLock();
+ // Restore write-barrier assumptions.
+ isolate_group->RememberLiveTemporaries();
+
// Scavenge finished. Run accounting.
int64_t end = OS::GetCurrentMonotonicMicros();
heap_->RecordTime(kProcessToSpace, process_to_space - iterate_roots);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 84927d1..633d468 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2366,7 +2366,7 @@
// after a potential shutdown of the group, which would turn down any pending
// GC tasks as well as the heap.
Isolate::MarkIsolateDead(is_application_isolate);
-}
+} // namespace dart
Dart_InitializeIsolateCallback Isolate::initialize_callback_ = nullptr;
Dart_IsolateGroupCreateCallback Isolate::create_group_callback_ = nullptr;
@@ -2461,6 +2461,18 @@
thread_registry()->ReleaseStoreBuffers();
}
+void Isolate::RememberLiveTemporaries() {
+ if (mutator_thread_ != nullptr) {
+ mutator_thread_->RememberLiveTemporaries();
+ }
+}
+
+void Isolate::DeferredMarkLiveTemporaries() {
+ if (mutator_thread_ != nullptr) {
+ mutator_thread_->DeferredMarkLiveTemporaries();
+ }
+}
+
void IsolateGroup::EnableIncrementalBarrier(
MarkingStack* marking_stack,
MarkingStack* deferred_marking_stack) {
@@ -2578,6 +2590,17 @@
return 0;
}
+void IsolateGroup::DeferredMarkLiveTemporaries() {
+ ForEachIsolate(
+ [&](Isolate* isolate) { isolate->DeferredMarkLiveTemporaries(); },
+ /*at_safepoint=*/true);
+}
+
+void IsolateGroup::RememberLiveTemporaries() {
+ ForEachIsolate([&](Isolate* isolate) { isolate->RememberLiveTemporaries(); },
+ /*at_safepoint=*/true);
+}
+
RawClass* Isolate::GetClassForHeapWalkAt(intptr_t cid) {
RawClass* raw_class = nullptr;
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 5ee8098..554398b 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -479,6 +479,9 @@
uword FindPendingDeoptAtSafepoint(uword fp);
+ void RememberLiveTemporaries();
+ void DeferredMarkLiveTemporaries();
+
private:
friend class Heap;
friend class StackFrame; // For `[isolates_].First()`.
@@ -1149,6 +1152,9 @@
static void NotifyLowMemory();
+ void RememberLiveTemporaries();
+ void DeferredMarkLiveTemporaries();
+
private:
friend class Dart; // Init, InitOnce, Shutdown.
friend class IsolateKillerVisitor; // Kill().
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 4b65a02..f586e9d 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -107,13 +107,8 @@
}
ASSERT(initialized_);
ThreadInterrupter::Cleanup();
-#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID)
- // TODO(30309): Free the sample buffer on platforms that use a signal-based
- // thread interrupter.
-#else
delete sample_buffer_;
sample_buffer_ = NULL;
-#endif
initialized_ = false;
}
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 325e23c..c05cd6a 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1536,6 +1536,10 @@
void Profile::Build(Thread* thread,
SampleFilter* filter,
SampleBuffer* sample_buffer) {
+ // Disable thread interrupts while processing the buffer.
+ DisableThreadInterruptsScope dtis(thread);
+ ThreadInterrupter::SampleBufferReaderScope scope;
+
ProfileBuilder builder(thread, filter, sample_buffer, this);
builder.Build();
}
@@ -1825,8 +1829,6 @@
SampleBuffer* sample_buffer,
bool include_code_samples) {
Isolate* isolate = thread->isolate();
- // Disable thread interrupts while processing the buffer.
- DisableThreadInterruptsScope dtis(thread);
// We should bail out in service.cc if the profiler is disabled.
ASSERT(sample_buffer != NULL);
@@ -1921,6 +1923,7 @@
// Disable thread interrupts while processing the buffer.
DisableThreadInterruptsScope dtis(thread);
+ ThreadInterrupter::SampleBufferReaderScope scope;
ClearProfileVisitor clear_profile(isolate);
sample_buffer->VisitSamples(&clear_profile);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 7f554a1..12e21e5 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -160,7 +160,7 @@
return false;
}
-bool StackFrame::IsStubFrame() const {
+bool StackFrame::IsStubFrame(bool needed_for_gc) const {
if (is_interpreted()) {
return false;
}
@@ -176,7 +176,7 @@
NoSafepointScope no_safepoint;
#endif
- RawCode* code = GetCodeObject();
+ RawCode* code = GetCodeObject(needed_for_gc);
ASSERT(code != Object::null());
const intptr_t cid = code->ptr()->owner_->GetClassId();
ASSERT(cid == kNullCid || cid == kClassCid || cid == kFunctionCid);
@@ -418,9 +418,9 @@
return Code::null();
}
-RawCode* StackFrame::GetCodeObject() const {
+RawCode* StackFrame::GetCodeObject(bool needed_for_gc) const {
ASSERT(!is_interpreted());
- if (auto isolate = IsolateOfBareInstructionsFrame(/*needed_for_gc=*/false)) {
+ if (auto isolate = IsolateOfBareInstructionsFrame(needed_for_gc)) {
auto const rct = isolate->reverse_pc_lookup_cache();
return rct->Lookup(pc(), /*is_return_address=*/true);
} else {
@@ -546,8 +546,8 @@
return TokenPosition::kNoSource;
}
-bool StackFrame::IsValid() const {
- if (IsEntryFrame() || IsExitFrame() || IsStubFrame()) {
+bool StackFrame::IsValid(bool needed_for_gc) const {
+ if (IsEntryFrame() || IsExitFrame() || IsStubFrame(needed_for_gc)) {
return true;
}
if (is_interpreted()) {
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 39af4d5..8427dd2 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -94,7 +94,7 @@
const char* ToCString() const;
// Check validity of a frame, used for assertion purposes.
- virtual bool IsValid() const;
+ virtual bool IsValid(bool needed_for_gc = false) const;
// Returns the isolate containing the bare instructions of the current frame.
//
@@ -112,11 +112,12 @@
bool IsBareInstructionsStubFrame() const;
// Frame type.
- virtual bool IsDartFrame(bool validate = true) const {
- ASSERT(!validate || IsValid());
- return !(IsEntryFrame() || IsExitFrame() || IsStubFrame());
+ virtual bool IsDartFrame(bool validate = true,
+ bool needed_for_gc = false) const {
+ ASSERT(!validate || IsValid(needed_for_gc));
+ return !(IsEntryFrame() || IsExitFrame() || IsStubFrame(needed_for_gc));
}
- virtual bool IsStubFrame() const;
+ virtual bool IsStubFrame(bool neede_for_gc = false) const;
virtual bool IsEntryFrame() const { return false; }
virtual bool IsExitFrame() const { return false; }
@@ -158,7 +159,7 @@
Thread* thread() const { return thread_; }
private:
- RawCode* GetCodeObject() const;
+ RawCode* GetCodeObject(bool needed_for_gc = false) const;
RawBytecode* GetBytecodeObject() const;
@@ -199,9 +200,11 @@
// runtime code.
class ExitFrame : public StackFrame {
public:
- bool IsValid() const { return sp() == 0; }
- bool IsDartFrame(bool validate = true) const { return false; }
- bool IsStubFrame() const { return false; }
+ bool IsValid(bool needed_for_gc = false) const { return sp() == 0; }
+ bool IsDartFrame(bool validate = true, bool needed_for_gc = false) const {
+ return false;
+ }
+ bool IsStubFrame(bool needed_for_gc = false) const { return false; }
bool IsExitFrame() const { return true; }
// Visit objects in the frame.
@@ -221,11 +224,13 @@
// dart code.
class EntryFrame : public StackFrame {
public:
- bool IsValid() const {
+ bool IsValid(bool needed_for_gc = false) const {
return StubCode::InInvocationStub(pc(), is_interpreted());
}
- bool IsDartFrame(bool validate = true) const { return false; }
- bool IsStubFrame() const { return false; }
+ bool IsDartFrame(bool validate = true, bool needed_for_gc = false) const {
+ return false;
+ }
+ bool IsStubFrame(bool needed_for_gc = false) const { return false; }
bool IsEntryFrame() const { return true; }
// Visit objects in the frame.
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 52de00b..c69446c 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -558,6 +558,7 @@
}
void Thread::StoreBufferAddObject(RawObject* obj) {
+ ASSERT(this == Thread::Current());
store_buffer_block_->Push(obj);
if (store_buffer_block_->IsFull()) {
StoreBufferBlockProcess(StoreBuffer::kCheckThreshold);
@@ -728,6 +729,108 @@
}
}
+class RestoreWriteBarrierInvariantVisitor : public ObjectPointerVisitor {
+ public:
+ RestoreWriteBarrierInvariantVisitor(IsolateGroup* group,
+ Thread* thread,
+ Thread::RestoreWriteBarrierInvariantOp op)
+ : ObjectPointerVisitor(group),
+ thread_(thread),
+ current_(Thread::Current()),
+ op_(op) {}
+
+ void VisitPointers(RawObject** first, RawObject** last) {
+ for (; first != last + 1; first++) {
+ RawObject* obj = *first;
+ // Stores into new-space objects don't need a write barrier.
+ if (obj->IsSmiOrNewObject()) continue;
+
+ // To avoid adding too much work into the remembered set, skip
+ // arrays. Write barrier elimination will not remove the barrier
+ // if we can trigger GC between array allocation and store.
+ if (obj->GetClassId() == kArrayCid) continue;
+
+ // Dart code won't store into VM-internal objects except Contexts.
+ // This assumption is checked by an assertion in
+ // WriteBarrierElimination::UpdateVectorForBlock.
+ if (!obj->IsDartInstance() && !obj->IsContext()) continue;
+
+ // Dart code won't store into canonical instances.
+ if (obj->IsCanonical()) continue;
+
+ // Objects in the VM isolate heap are immutable and won't be
+ // stored into. Check this condition last because there's no bit
+ // in the header for it.
+ if (obj->InVMIsolateHeap()) continue;
+
+ switch (op_) {
+ case Thread::RestoreWriteBarrierInvariantOp::kAddToRememberedSet:
+ if (!obj->IsRemembered()) {
+ obj->AddToRememberedSet(current_);
+ }
+ if (current_->is_marking()) {
+ current_->DeferredMarkingStackAddObject(obj);
+ }
+ break;
+ case Thread::RestoreWriteBarrierInvariantOp::kAddToDeferredMarkingStack:
+ // Re-scan obj when finalizing marking.
+ current_->DeferredMarkingStackAddObject(obj);
+ break;
+ }
+ }
+ }
+
+ private:
+ Thread* const thread_;
+ Thread* const current_;
+ Thread::RestoreWriteBarrierInvariantOp op_;
+};
+
+// Write barrier elimination assumes that all live temporaries will be
+// in the remembered set after a scavenge triggered by a non-Dart-call
+// instruction (see Instruction::CanCallDart()), and additionally they will be
+// in the deferred marking stack if concurrent marking started. Specifically,
+// this includes any instruction which will always create an exit frame
+// below the current frame before any other Dart frames.
+//
+// Therefore, to support this assumption, we scan the stack after a scavenge
+// or when concurrent marking begins and add all live temporaries in
+// Dart frames preceeding an exit frame to the store buffer or deferred
+// marking stack.
+void Thread::RestoreWriteBarrierInvariant(RestoreWriteBarrierInvariantOp op) {
+ ASSERT(IsAtSafepoint());
+ ASSERT(IsMutatorThread());
+
+ const StackFrameIterator::CrossThreadPolicy cross_thread_policy =
+ StackFrameIterator::kAllowCrossThreadIteration;
+ StackFrameIterator frames_iterator(top_exit_frame_info(),
+ ValidationPolicy::kDontValidateFrames,
+ this, cross_thread_policy);
+ RestoreWriteBarrierInvariantVisitor visitor(isolate_group(), this, op);
+ bool scan_next_dart_frame = false;
+ for (StackFrame* frame = frames_iterator.NextFrame(); frame != NULL;
+ frame = frames_iterator.NextFrame()) {
+ if (frame->IsExitFrame()) {
+ scan_next_dart_frame = true;
+ } else if (frame->IsDartFrame(/*validate=*/false, /*needed_for_gc=*/true)) {
+ if (scan_next_dart_frame) {
+ frame->VisitObjectPointers(&visitor);
+ }
+ scan_next_dart_frame = false;
+ }
+ }
+}
+
+void Thread::DeferredMarkLiveTemporaries() {
+ RestoreWriteBarrierInvariant(
+ RestoreWriteBarrierInvariantOp::kAddToDeferredMarkingStack);
+}
+
+void Thread::RememberLiveTemporaries() {
+ RestoreWriteBarrierInvariant(
+ RestoreWriteBarrierInvariantOp::kAddToRememberedSet);
+}
+
bool Thread::CanLoadFromThread(const Object& object) {
// In order to allow us to use assembler helper routines with non-[Code]
// objects *before* stubs are initialized, we only loop ver the stubs if the
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index cf563c4..78b610e 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -826,6 +826,8 @@
// Visit all object pointers.
void VisitObjectPointers(ObjectPointerVisitor* visitor,
ValidationPolicy validate_frames);
+ void RememberLiveTemporaries();
+ void DeferredMarkLiveTemporaries();
bool IsValidHandle(Dart_Handle object) const;
bool IsValidLocalHandle(Dart_Handle object) const;
@@ -856,6 +858,13 @@
template <class T>
T* AllocateReusableHandle();
+ enum class RestoreWriteBarrierInvariantOp {
+ kAddToRememberedSet,
+ kAddToDeferredMarkingStack
+ };
+ friend class RestoreWriteBarrierInvariantVisitor;
+ void RestoreWriteBarrierInvariant(RestoreWriteBarrierInvariantOp op);
+
// Set the current compiler state and return the previous compiler state.
CompilerState* SetCompilerState(CompilerState* state) {
CompilerState* previous = compiler_state_;
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index a7becbe..6f57f4fc 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -48,6 +48,11 @@
Monitor* ThreadInterrupter::monitor_ = NULL;
intptr_t ThreadInterrupter::interrupt_period_ = 1000;
intptr_t ThreadInterrupter::current_wait_time_ = Monitor::kNoTimeout;
+// Note this initial state means there is one sample buffer reader. This
+// allows the EnterSampleReader during Cleanup (needed to ensure the buffer can
+// be safely freed) to be balanced by a ExitSampleReader during Init.
+std::atomic<intptr_t> ThreadInterrupter::sample_buffer_lock_ = {-1};
+std::atomic<intptr_t> ThreadInterrupter::sample_buffer_waiters_ = {1};
void ThreadInterrupter::Init() {
ASSERT(!initialized_);
@@ -85,6 +90,8 @@
if (FLAG_trace_thread_interrupter) {
OS::PrintErr("ThreadInterrupter running.\n");
}
+
+ ExitSampleReader();
}
void ThreadInterrupter::Cleanup() {
@@ -112,6 +119,9 @@
if (FLAG_trace_thread_interrupter) {
OS::PrintErr("ThreadInterrupter shut down.\n");
}
+
+ // Wait for outstanding signals.
+ EnterSampleReader();
}
// Delay between interrupts.
@@ -130,13 +140,16 @@
}
void ThreadInterrupter::WakeUp() {
- if (!initialized_) {
+ if (monitor_ == NULL) {
// Early call.
return;
}
- ASSERT(initialized_);
{
MonitorLocker ml(monitor_);
+ if (!initialized_) {
+ // Early call.
+ return;
+ }
woken_up_ = true;
if (!InDeepSleep()) {
// No need to notify, regularly waking up.
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
index 11c6584..65706da 100644
--- a/runtime/vm/thread_interrupter.h
+++ b/runtime/vm/thread_interrupter.h
@@ -36,6 +36,52 @@
// Interrupt a thread.
static void InterruptThread(OSThread* thread);
+ class SampleBufferWriterScope : public ValueObject {
+ public:
+ SampleBufferWriterScope() {
+ intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
+ intptr_t new_value;
+ do {
+ if (old_value < 0) {
+ entered_lock_ = false;
+ return;
+ }
+ new_value = old_value + 1;
+ } while (!sample_buffer_lock_.compare_exchange_weak(
+ old_value, new_value, std::memory_order_relaxed));
+ entered_lock_ = true;
+ }
+
+ ~SampleBufferWriterScope() {
+ if (!entered_lock_) return;
+ intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
+ intptr_t new_value;
+ do {
+ ASSERT(old_value > 0);
+ new_value = old_value - 1;
+ } while (!sample_buffer_lock_.compare_exchange_weak(
+ old_value, new_value, std::memory_order_release));
+ }
+
+ bool CanSample() const {
+ return entered_lock_ &&
+ sample_buffer_waiters_.load(std::memory_order_relaxed) == 0;
+ }
+
+ private:
+ bool entered_lock_;
+ DISALLOW_COPY_AND_ASSIGN(SampleBufferWriterScope);
+ };
+
+ class SampleBufferReaderScope : public ValueObject {
+ public:
+ SampleBufferReaderScope() { EnterSampleReader(); }
+ ~SampleBufferReaderScope() { ExitSampleReader(); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SampleBufferReaderScope);
+ };
+
private:
static const intptr_t kMaxThreads = 4096;
static bool initialized_;
@@ -47,6 +93,15 @@
static intptr_t interrupt_period_;
static intptr_t current_wait_time_;
+ // Something like a reader-writer lock. Positive values indictate there are
+ // outstanding signal handlers that can write to the sample buffer. Negative
+ // values indicate there are outstanding sample buffer processors that can
+ // read from the sample buffer. A reader will spin-wait to enter the lock. A
+ // writer will give up if it fails to enter lock, causing samples to be
+ // skipping while we are processing the sample buffer or trying to shut down.
+ static std::atomic<intptr_t> sample_buffer_lock_;
+ static std::atomic<intptr_t> sample_buffer_waiters_;
+
static bool IsDebuggerAttached();
static bool InDeepSleep() {
@@ -59,6 +114,33 @@
static void RemoveSignalHandler();
+ static void EnterSampleReader() {
+ sample_buffer_waiters_.fetch_add(1, std::memory_order_relaxed);
+
+ intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
+ intptr_t new_value;
+ do {
+ if (old_value > 0) {
+ old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
+ continue; // Spin waiting for outstanding SIGPROFs to complete.
+ }
+ new_value = old_value - 1;
+ } while (!sample_buffer_lock_.compare_exchange_weak(
+ old_value, new_value, std::memory_order_acquire));
+ }
+
+ static void ExitSampleReader() {
+ sample_buffer_waiters_.fetch_sub(1, std::memory_order_relaxed);
+
+ intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed);
+ intptr_t new_value;
+ do {
+ ASSERT(old_value < 0);
+ new_value = old_value + 1;
+ } while (!sample_buffer_lock_.compare_exchange_weak(
+ old_value, new_value, std::memory_order_relaxed));
+ }
+
friend class ThreadInterrupterVisitIsolates;
};
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
index 92a21f5..87eb5fc 100644
--- a/runtime/vm/thread_interrupter_android.cc
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -32,6 +32,10 @@
if (thread == NULL) {
return;
}
+ ThreadInterrupter::SampleBufferWriterScope scope;
+ if (!scope.CanSample()) {
+ return;
+ }
// Extract thread state.
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
mcontext_t mcontext = context->uc_mcontext;
diff --git a/runtime/vm/thread_interrupter_linux.cc b/runtime/vm/thread_interrupter_linux.cc
index dc2bfd0..04b0686 100644
--- a/runtime/vm/thread_interrupter_linux.cc
+++ b/runtime/vm/thread_interrupter_linux.cc
@@ -31,6 +31,10 @@
if (thread == NULL) {
return;
}
+ ThreadInterrupter::SampleBufferWriterScope scope;
+ if (!scope.CanSample()) {
+ return;
+ }
// Extract thread state.
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
mcontext_t mcontext = context->uc_mcontext;
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
index 9ea36b4..eb89fe7 100644
--- a/runtime/vm/thread_interrupter_macos.cc
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -57,6 +57,10 @@
if (thread == NULL) {
return;
}
+ ThreadInterrupter::SampleBufferWriterScope scope;
+ if (!scope.CanSample()) {
+ return;
+ }
// Extract thread state.
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
mcontext_t mcontext = context->uc_mcontext;
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
index a6edb37..d14d9ed 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -705,7 +705,7 @@
abstract class JavaScriptIndexingBehavior<E> {}
/// Thrown by type assertions that fail.
-class TypeErrorImpl extends Error implements TypeError {
+class TypeErrorImpl extends Error implements TypeError, CastError {
final String _message;
TypeErrorImpl(this._message);
@@ -714,7 +714,7 @@
}
/// Thrown by the 'as' operator if the cast isn't valid.
-class CastErrorImpl extends Error implements CastError {
+class CastErrorImpl extends Error implements CastError, TypeError {
final String _message;
CastErrorImpl(this._message);
diff --git a/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart
index 0a02d3f..0a79d98 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart
@@ -203,7 +203,7 @@
}
String namedGroup(String name) {
- var groups = JS('Object', '#.groups', _match);
+ var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS<bool>('!', '# in #', name, groups)) {
@@ -214,7 +214,7 @@
}
Iterable<String> get groupNames {
- var groups = JS('Object', '#.groups', _match);
+ var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
return SubListIterable(keys, 0, null);
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 113d7c9..296c213 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3089,7 +3089,7 @@
abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
/// Thrown by type assertions that fail.
-class TypeErrorImplementation extends Error implements TypeError {
+class TypeErrorImplementation extends Error implements TypeError, CastError {
final String _message;
/// Normal type error caused by a failed subtype test.
@@ -3103,12 +3103,12 @@
}
/// Thrown by the 'as' operator if the cast isn't valid.
-class CastErrorImplementation extends Error implements CastError {
+class CastErrorImplementation extends Error implements CastError, TypeError {
final String _message;
/// Normal cast error caused by a failed type cast.
CastErrorImplementation(Object value, Object type)
- : _message = "CastError: ${Error.safeToString(value)}: type "
+ : _message = "TypeError: ${Error.safeToString(value)}: type "
"'${_typeDescription(value)}' is not a subtype of type '$type'";
String toString() => _message;
diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
index 576caaa..dc59c10 100644
--- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -212,7 +212,7 @@
}
String namedGroup(String name) {
- var groups = JS('Object', '#.groups', _match);
+ var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS('bool', '# in #', name, groups)) {
@@ -223,7 +223,7 @@
}
Iterable<String> get groupNames {
- var groups = JS('Object', '#.groups', _match);
+ var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = new JSArray<String>.markGrowable(
JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 3676147..1adc744 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -960,15 +960,15 @@
String toString() => _message;
}
-class _CastError extends _Error implements CastError {
- _CastError.fromMessage(String message) : super('CastError: $message');
+class _CastError extends _Error implements CastError, TypeError {
+ _CastError.fromMessage(String message) : super('TypeError: $message');
factory _CastError.forType(object, String type) {
return _CastError.fromMessage(_Error.compose(object, null, type));
}
}
-class _TypeError extends _Error implements TypeError {
+class _TypeError extends _Error implements TypeError, CastError {
_TypeError.fromMessage(String message) : super('TypeError: $message');
factory _TypeError.forType(object, String type) {
@@ -1154,7 +1154,8 @@
typeParametersText += typeSep;
typeParametersText += genericContext[genericContext.length - 1 - i];
Rti boundRti = _castToRti(_Utils.arrayAt(bounds, i));
- if (!isTopType(boundRti)) {
+ if (!isTopType(boundRti) &&
+ (!JS_GET_FLAG('LEGACY') || !isObjectType(boundRti))) {
typeParametersText +=
' extends ' + _rtiToString(boundRti, genericContext);
}
diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart
index 9457152..c96e920 100644
--- a/sdk/lib/_internal/vm/lib/errors_patch.dart
+++ b/sdk/lib/_internal/vm/lib/errors_patch.dart
@@ -82,7 +82,7 @@
final Object message;
}
-class _TypeError extends Error implements TypeError {
+class _TypeError extends Error implements TypeError, CastError {
@pragma("vm:entry-point")
_TypeError._create(this._url, this._line, this._column, this._message);
@@ -97,7 +97,7 @@
final Object _message;
}
-class _CastError extends Error implements CastError {
+class _CastError extends Error implements CastError, TypeError {
@pragma("vm:entry-point")
_CastError._create(this._url, this._line, this._column, this._errorMsg);
diff --git a/sdk/lib/_internal/vm/lib/regexp_patch.dart b/sdk/lib/_internal/vm/lib/regexp_patch.dart
index dd04e8d..d4c875e 100644
--- a/sdk/lib/_internal/vm/lib/regexp_patch.dart
+++ b/sdk/lib/_internal/vm/lib/regexp_patch.dart
@@ -274,13 +274,18 @@
int get _groupCount native "RegExp_getGroupCount";
- // Returns a List [String, int, String, int, ...] where each
- // String is the name of a capture group and the following
- // int is that capture group's index.
+ /// The names and indices of named capture group.
+ ///
+ /// Returns a [List] of alternating strings and integers,
+ /// `[String, int, String, int, ...]` where each
+ /// [String] is the name of a capture group and the following
+ /// [int] is that capture group's index.
+ /// Returns `null` if there are no group names.
List get _groupNameList native "RegExp_getGroupNameMap";
Iterable<String> get _groupNames sync* {
final nameList = _groupNameList;
+ if (nameList == null) return;
for (var i = 0; i < nameList.length; i += 2) {
yield nameList[i] as String;
}
@@ -288,9 +293,10 @@
int _groupNameIndex(String name) {
var nameList = _groupNameList;
+ if (nameList == null) return -1;
for (var i = 0; i < nameList.length; i += 2) {
if (name == nameList[i]) {
- return nameList[i + 1];
+ return nameList[i + 1] as int;
}
}
return -1;
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 5a8deb8..dc3718a 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -670,9 +670,10 @@
return 0x10000 + ((start & 0x3FF) << 10) + (end & 0x3FF);
}
-/** [Iterator] for reading runes (integer Unicode code points) out of a Dart
- * string.
- */
+/**
+ * [Iterator] for reading runes (integer Unicode code points) out of a Dart
+ * string.
+ */
class RuneIterator implements BidirectionalIterator<int> {
/** String being iterated. */
final String string;
@@ -683,10 +684,10 @@
/**
* Current code point.
*
- * If the iterator has hit either end, the [_currentCodePoint] is null
+ * If the iterator has hit either end, the [_currentCodePoint] is -1
* and [: _position == _nextPosition :].
*/
- int _currentCodePoint;
+ int _currentCodePoint = -1;
/** Create an iterator positioned at the beginning of the string. */
RuneIterator(String string)
@@ -725,9 +726,9 @@
/**
* Returns the starting position of the current rune in the string.
*
- * Returns null if the [current] rune is null.
+ * Returns -1 if there is no current rune ([current] is -1).
*/
- int get rawIndex => (_position != _nextPosition) ? _position : null;
+ int get rawIndex => (_position != _nextPosition) ? _position : -1;
/**
* Resets the iterator to the rune at the specified index of the string.
@@ -758,18 +759,21 @@
RangeError.checkValueInInterval(rawIndex, 0, string.length, "rawIndex");
_checkSplitSurrogate(rawIndex);
_position = _nextPosition = rawIndex;
- _currentCodePoint = null;
+ _currentCodePoint = -1;
}
- /** The rune (integer Unicode code point) starting at the current position in
- * the string.
+ /**
+ * The rune (integer Unicode code point) starting at the current position in
+ * the string.
+ *
+ * If there is no current rune, the value -1 is used instead.
*/
int get current => _currentCodePoint;
/**
* The number of code units comprising the current rune.
*
- * Returns zero if there is no current rune ([current] is null).
+ * Returns zero if there is no current rune ([current] is -1).
*/
int get currentSize => _nextPosition - _position;
@@ -777,12 +781,12 @@
* A string containing the current rune.
*
* For runes outside the basic multilingual plane, this will be
- * a String of length 2, containing two code units.
+ * a [String] of length 2, containing two code units.
*
- * Returns null if [current] is null.
+ * Returns an empty string if there is no current rune ([current] is -1).
*/
String get currentAsString {
- if (_position == _nextPosition) return null;
+ if (_position == _nextPosition) return "";
if (_position + 1 == _nextPosition) return string[_position];
return string.substring(_position, _nextPosition);
}
@@ -790,7 +794,7 @@
bool moveNext() {
_position = _nextPosition;
if (_position == string.length) {
- _currentCodePoint = null;
+ _currentCodePoint = -1;
return false;
}
int codeUnit = string.codeUnitAt(_position);
@@ -811,7 +815,7 @@
bool movePrevious() {
_nextPosition = _position;
if (_position == 0) {
- _currentCodePoint = null;
+ _currentCodePoint = -1;
return false;
}
int position = _position - 1;
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 496ecba..3f45ca5 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -59,7 +59,9 @@
static const _mode = 4;
static const _size = 5;
- static const _notFound = const FileStat._internalNotFound();
+ static final _epoch = DateTime.fromMillisecondsSinceEpoch(0, isUtc: true);
+ static final _notFound = new FileStat._internal(
+ _epoch, _epoch, _epoch, FileSystemEntityType.notFound, 0, -1);
/**
* The time of the last change to the data or metadata of the file system
@@ -105,14 +107,6 @@
FileStat._internal(this.changed, this.modified, this.accessed, this.type,
this.mode, this.size);
- const FileStat._internalNotFound()
- : changed = null,
- modified = null,
- accessed = null,
- type = FileSystemEntityType.notFound,
- mode = 0,
- size = -1;
-
external static _statSync(_Namespace namespace, String path);
/**
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
index 39944a0..48d41f9 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
@@ -140,8 +140,10 @@
// Normalize raw FutureOr --> dynamic
if (JS<bool>('!', '# == void 0', typeArg)) return _dynamic;
- // FutureOr<dynamic|void|Object?|Object*> --> dynamic|void|Object?|Object*
+ // FutureOr<dynamic|void|Object?|Object*|Object> -->
+ // dynamic|void|Object?|Object*|Object
if (_isTop(typeArg) ||
+ _equalType(typeArg, Object) ||
(_jsInstanceOf(typeArg, LegacyType) &&
JS<bool>('!', '#.type === #', typeArg, Object))) {
return typeArg;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index 77affd3..d424a31 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -876,10 +876,14 @@
if (i != 0) s += ", ";
s += JS<String>('!', '#[#].name', typeFormals, i);
var bound = typeBounds[i];
- if (JS(
- '!', '# !== # && # !== #', bound, dynamic, bound, nullable(Object))) {
- s += " extends $bound";
+ if (_equalType(bound, dynamic) ||
+ JS<bool>('!', '# === #', bound, nullable(unwrapType(Object))) ||
+ (!_strictSubtypeChecks && _equalType(bound, Object))) {
+ // Do not print the bound when it is a top type. In weak mode the bounds
+ // of Object and Object* will also be elided.
+ continue;
}
+ s += " extends $bound";
}
s += ">" + this.function.toString();
return this._stringValue = s;
@@ -924,10 +928,11 @@
List instantiateTypeBounds(List typeArgs) {
if (!hasTypeBounds) {
- // The Dart 1 spec says omitted type parameters have an upper bound of
- // Object. However Dart 2 uses `dynamic` for the purpose of instantiate to
- // bounds, so we use that here.
- return List.filled(formalCount, _dynamic);
+ // We ommit the a bound to represent Object*. Other bounds are explicitly
+ // represented, including Object, Object? and dynamic.
+ // TODO(nshahan) Revisit this representation when more libraries have
+ // migrated to null safety.
+ return List.filled(formalCount, legacy(unwrapType(Object)));
}
// Bounds can be recursive or depend on other type parameters, so we need to
// apply type arguments and return the resulting bounds.
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
index d084aeb..6218ba6 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -705,7 +705,7 @@
abstract class JavaScriptIndexingBehavior<E> {}
/// Thrown by type assertions that fail.
-class TypeErrorImpl extends Error implements TypeError {
+class TypeErrorImpl extends Error implements TypeError, CastError {
final String _message;
TypeErrorImpl(this._message);
@@ -714,7 +714,7 @@
}
/// Thrown by the 'as' operator if the cast isn't valid.
-class CastErrorImpl extends Error implements CastError {
+class CastErrorImpl extends Error implements CastError, TypeError {
final String _message;
CastErrorImpl(this._message);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
index 8730c1c..6ce53ac 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/regexp_helper.dart
@@ -204,7 +204,7 @@
}
String? namedGroup(String name) {
- var groups = JS<Object?>('', '#.groups', _match);
+ var groups = JS<Object?>('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS<String?>('', '#[#]', groups, name);
if (result != null || JS<bool>('!', '# in #', name, groups)) {
@@ -215,7 +215,7 @@
}
Iterable<String> get groupNames {
- var groups = JS<Object?>('', '#.groups', _match);
+ var groups = JS<Object?>('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
return SubListIterable(keys, 0, null);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
index 8c81b95..bd293d6 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
@@ -3088,7 +3088,7 @@
abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {}
/// Thrown by type assertions that fail.
-class TypeErrorImplementation extends Error implements TypeError {
+class TypeErrorImplementation extends Error implements TypeError, CastError {
final String _message;
/// Normal type error caused by a failed subtype test.
@@ -3102,12 +3102,12 @@
}
/// Thrown by the 'as' operator if the cast isn't valid.
-class CastErrorImplementation extends Error implements CastError {
+class CastErrorImplementation extends Error implements CastError, TypeError {
final String _message;
/// Normal cast error caused by a failed type cast.
CastErrorImplementation(Object value, Object type)
- : _message = "CastError: ${Error.safeToString(value)}: type "
+ : _message = "TypeError: ${Error.safeToString(value)}: type "
"'${_typeDescription(value)}' is not a subtype of type '$type'";
String toString() => _message;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
index 9560250..8eaad60 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -209,7 +209,7 @@
}
String namedGroup(String name) {
- var groups = JS('Object', '#.groups', _match);
+ var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS('bool', '# in #', name, groups)) {
@@ -220,7 +220,7 @@
}
Iterable<String> get groupNames {
- var groups = JS('Object', '#.groups', _match);
+ var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var keys = new JSArray<String>.markGrowable(
JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
index ddbade4..838643b 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -960,15 +960,15 @@
String toString() => _message;
}
-class _CastError extends _Error implements CastError {
- _CastError.fromMessage(String message) : super('CastError: $message');
+class _CastError extends _Error implements CastError, TypeError {
+ _CastError.fromMessage(String message) : super('TypeError: $message');
factory _CastError.forType(object, String type) {
return _CastError.fromMessage(_Error.compose(object, null, type));
}
}
-class _TypeError extends _Error implements TypeError {
+class _TypeError extends _Error implements TypeError, CastError {
_TypeError.fromMessage(String message) : super('TypeError: $message');
factory _TypeError.forType(object, String type) {
@@ -1154,7 +1154,8 @@
typeParametersText += typeSep;
typeParametersText += genericContext[genericContext.length - 1 - i];
Rti boundRti = _castToRti(_Utils.arrayAt(bounds, i));
- if (!isTopType(boundRti)) {
+ if (!isTopType(boundRti) &&
+ (!JS_GET_FLAG('LEGACY') || !isObjectType(boundRti))) {
typeParametersText +=
' extends ' + _rtiToString(boundRti, genericContext);
}
diff --git a/sdk_nnbd/lib/_internal/vm/bin/socket_patch.dart b/sdk_nnbd/lib/_internal/vm/bin/socket_patch.dart
index 070a146..8b5638d 100644
--- a/sdk_nnbd/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/bin/socket_patch.dart
@@ -1016,7 +1016,7 @@
isInternal ||
isInternalSignal);
if (resourceInformation != null) {
- _SocketResourceInfo.SocketClosed(resourceInformation!);
+ _SocketResourceInfo.SocketClosed(resourceInformation);
}
isClosed = true;
closeCompleter.complete();
diff --git a/sdk_nnbd/lib/_internal/vm/lib/double_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/double_patch.dart
index 0c706ce..e6ccf5c 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/double_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/double_patch.dart
@@ -8,7 +8,7 @@
@patch
class double {
- static double _nativeParse(String str, int start, int end)
+ static double? _nativeParse(String str, int start, int end)
native "Double_parse";
static double? _tryParseDouble(String str, int start, int end) {
diff --git a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart
index c9dd54d..12960b5 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/errors_patch.dart
@@ -81,7 +81,7 @@
final Object? message;
}
-class _TypeError extends Error implements TypeError {
+class _TypeError extends Error implements TypeError, CastError {
@pragma("vm:entry-point")
_TypeError._create(this._url, this._line, this._column, this._message);
@@ -96,7 +96,7 @@
final String _message;
}
-class _CastError extends Error implements CastError {
+class _CastError extends Error implements CastError, TypeError {
@pragma("vm:entry-point")
_CastError._create(this._url, this._line, this._column, this._errorMsg);
@@ -276,7 +276,7 @@
? _NamedArgumentsMap(arguments, argumentNames)
: null);
- static String _existingMethodSignature(Object receiver, String methodName,
+ static String? _existingMethodSignature(Object receiver, String methodName,
int invocationType) native "NoSuchMethodError_existingMethodSignature";
@patch
@@ -336,7 +336,7 @@
argumentCount++;
});
}
- String existingSig =
+ String? existingSig =
_existingMethodSignature(_receiver, memberName, localInvocation._type);
String argsMsg = existingSig != null ? " with matching arguments" : "";
diff --git a/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart b/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
index 3aa7694..7379f0c 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
@@ -145,7 +145,7 @@
return result;
}
- static LibraryMirror _loadUri(String uri) native "IsolateMirror_loadUri";
+ static LibraryMirror? _loadUri(String uri) native "IsolateMirror_loadUri";
}
class _SyntheticAccessor implements MethodMirror {
@@ -443,7 +443,7 @@
_ClassMirror? _trueSuperclassField;
_ClassMirror? get _trueSuperclass {
if (_trueSuperclassField == null) {
- Type supertype = isOriginalDeclaration
+ Type? supertype = isOriginalDeclaration
? _supertype(_reflectedType)
: _supertypeInstantiated(_reflectedType);
if (supertype == null) {
@@ -497,7 +497,7 @@
var m = _mixin;
if (m != null) return m;
- Type mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
+ Type? mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
if (mixinType == null) {
// The reflectee is not a mixin application.
return _mixin = this;
@@ -714,9 +714,9 @@
static String _libraryUri(reflectee) native "ClassMirror_libraryUri";
- static Type _supertype(reflectedType) native "ClassMirror_supertype";
+ static Type? _supertype(reflectedType) native "ClassMirror_supertype";
- static Type _supertypeInstantiated(reflectedType)
+ static Type? _supertypeInstantiated(reflectedType)
native "ClassMirror_supertype_instantiated";
static List<dynamic> _nativeInterfaces(reflectedType)
@@ -725,9 +725,9 @@
static List<dynamic> _nativeInterfacesInstantiated(reflectedType)
native "ClassMirror_interfaces_instantiated";
- static Type _nativeMixin(reflectedType) native "ClassMirror_mixin";
+ static Type? _nativeMixin(reflectedType) native "ClassMirror_mixin";
- static Type _nativeMixinInstantiated(reflectedType, instantiator)
+ static Type? _nativeMixinInstantiated(reflectedType, instantiator)
native "ClassMirror_mixin_instantiated";
static List<dynamic> _computeMembers(owner, reflectee, instantiator)
diff --git a/sdk_nnbd/lib/_internal/vm/lib/regexp_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/regexp_patch.dart
index a2390a4..7a57583 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/regexp_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/regexp_patch.dart
@@ -277,13 +277,18 @@
int get _groupCount native "RegExp_getGroupCount";
- // Returns a List [String, int, String, int, ...] where each
- // String is the name of a capture group and the following
- // int is that capture group's index.
- List get _groupNameList native "RegExp_getGroupNameMap";
+ /// The names and indices of named capture group.
+ ///
+ /// Returns a [List] of alternating strings and integers,
+ /// `[String, int, String, int, ...]` where each
+ /// [String] is the name of a capture group and the following
+ /// [int] is that capture group's index.
+ /// Returns `null` if there are no group names.
+ List? get _groupNameList native "RegExp_getGroupNameMap";
Iterable<String> get _groupNames sync* {
final nameList = _groupNameList;
+ if (nameList == null) return;
for (var i = 0; i < nameList.length; i += 2) {
yield nameList[i] as String;
}
@@ -291,9 +296,10 @@
int _groupNameIndex(String name) {
var nameList = _groupNameList;
+ if (nameList == null) return -1;
for (var i = 0; i < nameList.length; i += 2) {
if (name == nameList[i]) {
- return nameList[i + 1];
+ return nameList[i + 1] as int;
}
}
return -1;
diff --git a/sdk_nnbd/lib/core/string.dart b/sdk_nnbd/lib/core/string.dart
index 95f27b6..e65f8e9 100644
--- a/sdk_nnbd/lib/core/string.dart
+++ b/sdk_nnbd/lib/core/string.dart
@@ -299,7 +299,8 @@
*
* string.lastIndexOf(new RegExp(r'DART')); // -1
*
- * The [start] must be non-negative and not greater than [length].
+ * If [start] is omitted, search starts from the end of the string.
+ * If supplied, [start] must be non-negative and not greater than [length].
*/
int lastIndexOf(Pattern pattern, [int? start]);
@@ -607,7 +608,7 @@
/**
* Converts all characters in this string to lower case.
- * If the string is already in all lower case, this method returns [:this:].
+ * If the string is already in all lower case, this method returns `this`.
*
* 'ALPHABET'.toLowerCase(); // 'alphabet'
* 'abc'.toLowerCase(); // 'abc'
@@ -620,7 +621,7 @@
/**
* Converts all characters in this string to upper case.
- * If the string is already in all upper case, this method returns [:this:].
+ * If the string is already in all upper case, this method returns `this`.
*
* 'alphabet'.toUpperCase(); // 'ALPHABET'
* 'ABC'.toUpperCase(); // 'ABC'
@@ -682,7 +683,7 @@
* Current code point.
*
* If the iterator has hit either end, the [_currentCodePoint] is -1
- * and [: _position == _nextPosition :].
+ * and `_position == _nextPosition`.
*/
int _currentCodePoint = -1;
@@ -721,9 +722,9 @@
}
/**
- * Returns the starting position of the current rune in the string.
+ * The starting position of the current rune in the string.
*
- * Returns -1 if the [current] rune is `null`.
+ * Returns -1 if there is no current rune ([current] is -1).
*/
int get rawIndex => (_position != _nextPosition) ? _position : -1;
@@ -734,8 +735,8 @@
* `string.length`, is an error. So is setting it in the middle of a surrogate
* pair.
*
- * Setting the position to the end of then string will set [current] to
- * `null`.
+ * Setting the position to the end of then string means that there is no
+ * current rune.
*/
void set rawIndex(int rawIndex) {
RangeError.checkValidIndex(rawIndex, string, "rawIndex");
@@ -750,8 +751,9 @@
* You must call [moveNext] make the rune at the position current,
* or [movePrevious] for the last rune before the position.
*
- * Setting a negative [rawIndex], or one greater than [:string.length:],
- * is an error. So is setting it in the middle of a surrogate pair.
+ * The [rawIndex] must be non-negative and no greater than `string.length`.
+ * It must also not be the index of the trailing surrogate of a surrogate
+ * pair.
*/
void reset([int rawIndex = 0]) {
RangeError.checkValueInInterval(rawIndex, 0, string.length, "rawIndex");
@@ -771,7 +773,7 @@
/**
* The number of code units comprising the current rune.
*
- * Returns zero if there is no current rune ([current] is null).
+ * Returns zero if there is no current rune ([current] is -1).
*/
int get currentSize => _nextPosition - _position;
diff --git a/tests/corelib/core_runtime_types_test.dart b/tests/corelib/core_runtime_types_test.dart
index 8ce8892..180dc08 100644
--- a/tests/corelib/core_runtime_types_test.dart
+++ b/tests/corelib/core_runtime_types_test.dart
@@ -51,7 +51,6 @@
f,
(exception) =>
(exception is TypeError) ||
- (exception is CastError) ||
(exception is AssertionError) ||
(exception is NoSuchMethodError) ||
(exception is ArgumentError),
diff --git a/tests/corelib/map_of_test.dart b/tests/corelib/map_of_test.dart
index 5620072..62b137b 100644
--- a/tests/corelib/map_of_test.dart
+++ b/tests/corelib/map_of_test.dart
@@ -34,9 +34,7 @@
..[3] = 13,
]) {
expectThrows(void operation()) {
- // Allow CastError as well as TypeError. Dart2js creates a CastError
- // here for some reason, and it's not wront.
- Expect.throws(operation, (e) => e is TypeError || e is CastError);
+ Expect.throwsTypeError(operation);
}
var sourceType = map.runtimeType.toString();
diff --git a/tests/corelib/regexp/regexp_regression_39406_test.dart b/tests/corelib/regexp/regexp_regression_39406_test.dart
new file mode 100644
index 0000000..0104a07
--- /dev/null
+++ b/tests/corelib/regexp/regexp_regression_39406_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// See http://dartbug.com/39406
+//
+// The following code must not throw.
+
+void main() {
+ var regExp = RegExp(r'\w+');
+ var message = 'Hello world!';
+ var match = regExp.firstMatch(message);
+ var groupNames = match!.groupNames.toList();
+ Expect.listEquals([], groupNames);
+ Expect.throwsArgumentError(() => match.namedGroup("x"));
+}
\ No newline at end of file
diff --git a/tests/corelib_2/core_runtime_types_test.dart b/tests/corelib_2/core_runtime_types_test.dart
index 7176feb..628bb22 100644
--- a/tests/corelib_2/core_runtime_types_test.dart
+++ b/tests/corelib_2/core_runtime_types_test.dart
@@ -51,7 +51,6 @@
f,
(exception) =>
(exception is TypeError) ||
- (exception is CastError) ||
(exception is AssertionError) ||
(exception is NoSuchMethodError) ||
(exception is ArgumentError),
diff --git a/tests/corelib_2/map_of_test.dart b/tests/corelib_2/map_of_test.dart
index 4761b61..7d92ecc 100644
--- a/tests/corelib_2/map_of_test.dart
+++ b/tests/corelib_2/map_of_test.dart
@@ -34,9 +34,7 @@
..[3] = 13,
]) {
expectThrows(void operation()) {
- // Allow CastError as well as TypeError. Dart2js creates a CastError
- // here for some reason, and it's not wront.
- Expect.throws(operation, (e) => e is TypeError || e is CastError);
+ Expect.throwsTypeError(operation);
}
var sourceType = map.runtimeType.toString();
diff --git a/tests/corelib_2/regexp/regexp_regression_39406_test.dart b/tests/corelib_2/regexp/regexp_regression_39406_test.dart
new file mode 100644
index 0000000..64b4634
--- /dev/null
+++ b/tests/corelib_2/regexp/regexp_regression_39406_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// See http://dartbug.com/39406
+//
+// The following code must not throw.
+
+void main() {
+ var regExp = RegExp(r'\w+');
+ var message = 'Hello world!';
+ var match = regExp.firstMatch(message);
+ var groupNames = match.groupNames.toList();
+ Expect.listEquals([], groupNames);
+ Expect.throwsArgumentError(() => match.namedGroup("x"));
+}
\ No newline at end of file
diff --git a/tests/corelib_2/string_runes_test.dart b/tests/corelib_2/string_runes_test.dart
index fd0f4f3..9e988b8 100644
--- a/tests/corelib_2/string_runes_test.dart
+++ b/tests/corelib_2/string_runes_test.dart
@@ -41,16 +41,16 @@
// Reset, moveNext.
it.reset(1);
- Expect.equals(null, it.rawIndex);
- Expect.equals(null, it.current);
+ Expect.equals(-1, it.rawIndex);
+ Expect.equals(-1, it.current);
it.moveNext();
Expect.equals(1, it.rawIndex);
Expect.equals(expectedRunes[1], it.current);
// Reset, movePrevious.
it.reset(1);
- Expect.equals(null, it.rawIndex);
- Expect.equals(null, it.current);
+ Expect.equals(-1, it.rawIndex);
+ Expect.equals(-1, it.current);
it.movePrevious();
Expect.equals(0, it.rawIndex);
Expect.equals(expectedRunes[0], it.current);
diff --git a/tests/language/call/method_as_cast_test.dart b/tests/language/call/method_as_cast_test.dart
index f0718a3..48ae3b7 100644
--- a/tests/language/call/method_as_cast_test.dart
+++ b/tests/language/call/method_as_cast_test.dart
@@ -23,13 +23,13 @@
// The presence of a `.call` method does not cause class `C` to become a
// subtype of any function type.
C c = new C();
- Expect.throwsCastError(() => c as BToB); //# 01: ok
- Expect.throwsCastError(() => c as NullToObject); //# 02: ok
- Expect.throwsCastError(() => c as Function); //# 03: ok
+ Expect.throwsTypeError(() => c as BToB); //# 01: ok
+ Expect.throwsTypeError(() => c as NullToObject); //# 02: ok
+ Expect.throwsTypeError(() => c as Function); //# 03: ok
// The same goes for class `D`: `implements Function` is ignored in Dart 2.
D d = new D();
- Expect.throwsCastError(() => d as BToB); //# 04: ok
- Expect.throwsCastError(() => d as NullToObject); //# 05: ok
- Expect.throwsCastError(() => d as Function); //# 06: ok
+ Expect.throwsTypeError(() => d as BToB); //# 04: ok
+ Expect.throwsTypeError(() => d as NullToObject); //# 05: ok
+ Expect.throwsTypeError(() => d as Function); //# 06: ok
}
diff --git a/tests/language/nnbd/operator_type_test.dart b/tests/language/nnbd/operator_type_test.dart
index 9a17555..2885ffd 100644
--- a/tests/language/nnbd/operator_type_test.dart
+++ b/tests/language/nnbd/operator_type_test.dart
@@ -311,7 +311,7 @@
nn ?? 1;
- nn ??= 1;
+ nn ??= maybeNotNullable<NN>(1);
nn?.toRadixString(16);
diff --git a/tests/language/nnbd/subtyping/type_casts_strong_test.dart b/tests/language/nnbd/subtyping/type_casts_strong_test.dart
index c38b217..7c8ac23 100644
--- a/tests/language/nnbd/subtyping/type_casts_strong_test.dart
+++ b/tests/language/nnbd/subtyping/type_casts_strong_test.dart
@@ -16,7 +16,7 @@
ac.asT(new C());
ac.asT(new D());
ac.asT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
ac.asT(new Y());
});
@@ -25,10 +25,10 @@
abc.asT(new B<C>());
abc.asT(new B<D>());
abc.asT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
abc.asT(new B<dynamic>());
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
abc.asT(new B<Y>());
});
@@ -37,7 +37,7 @@
ay.asT(new Y());
ay.asT(new Z());
ay.asT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
ay.asT(new C());
});
@@ -46,7 +46,7 @@
wc.asT(new C());
wc.asT(new D());
wc.asT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wc.asT(new Y());
});
@@ -54,7 +54,7 @@
wc.asNullableT(new C());
wc.asNullableT(new D());
wc.asNullableT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wc.asNullableT(new Y());
});
@@ -63,10 +63,10 @@
wby.asT(new B<C>());
wby.asT(new B<D>());
wby.asT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wby.asT(new B<dynamic>());
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wby.asT(new B<Y>());
});
@@ -74,10 +74,10 @@
wby.asNullableT(new B<C>());
wby.asNullableT(new B<D>());
wby.asNullableT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wby.asNullableT(new B<dynamic>());
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wby.asNullableT(new B<Y>());
});
@@ -85,10 +85,10 @@
final wy = new W<Y>();
wy.asT(new Y());
wy.asT(new Z());
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asT(null);
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asT(new C());
});
@@ -96,7 +96,7 @@
wy.asNullableT(new Y());
wy.asNullableT(new Z());
wy.asNullableT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asNullableT(new C());
});
@@ -104,10 +104,10 @@
ay.asBT(new B<Y>());
ay.asBT(new B<Z>());
ay.asBT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
ay.asBT(new B<dynamic>());
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
ay.asBT(new B<C>());
});
@@ -115,13 +115,13 @@
wy.asXT(new X<Y>());
wy.asXT(new X<Z>());
wy.asXT(newXOfLegacyY());
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asXT(null);
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asXT(new X<dynamic>());
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asXT(new X<Y?>());
});
@@ -130,10 +130,10 @@
wy.asNullableXT(new X<Z>());
wy.asNullableXT(newXOfLegacyY());
wy.asNullableXT(null);
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asNullableXT(new X<dynamic>());
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asNullableXT(new X<Y?>());
});
@@ -142,10 +142,10 @@
wy.asXNullableT(new X<Z>());
wy.asXNullableT(new X<Y?>());
wy.asXNullableT(newXOfLegacyY());
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asXNullableT(null);
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wy.asXNullableT(new X<dynamic>());
});
@@ -155,10 +155,10 @@
wny.asXT(new X<Z>());
wny.asXT(new X<Y?>());
wny.asXT(newXOfLegacyY());
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wny.asXT(null);
});
- Expect.throwsCastError(() {
+ Expect.throwsTypeError(() {
wny.asXT(new X<dynamic>());
});
}
diff --git a/tests/language/nnbd/syntax/late_modifier_error_test.dart b/tests/language/nnbd/syntax/late_modifier_error_test.dart
index 2e1e994..a21deb7 100644
--- a/tests/language/nnbd/syntax/late_modifier_error_test.dart
+++ b/tests/language/nnbd/syntax/late_modifier_error_test.dart
@@ -10,12 +10,12 @@
int f1(
late //# 02: compile-time error
int x
-) {}
+) => throw 0;
late //# 03: syntax error
class C1 {
late //# 04: syntax error
- int m() {}
+ int m() => throw 0;
}
main() {
diff --git a/tests/language/nnbd/syntax/required_modifier_error_test.dart b/tests/language/nnbd/syntax/required_modifier_error_test.dart
index 6bf7395..3312580 100644
--- a/tests/language/nnbd/syntax/required_modifier_error_test.dart
+++ b/tests/language/nnbd/syntax/required_modifier_error_test.dart
@@ -10,7 +10,7 @@
int f1(
required //# 02: syntax error
int x
-) {}
+) => throw 0;
required //# 03: syntax error
class C1 {
diff --git a/tests/language/nnbd/type_equality/function_type_equality_test.dart b/tests/language/nnbd/type_equality/function_type_equality_test.dart
index cbf5b0d..10fffac 100644
--- a/tests/language/nnbd/type_equality/function_type_equality_test.dart
+++ b/tests/language/nnbd/type_equality/function_type_equality_test.dart
@@ -15,20 +15,20 @@
void positionalIntToVoid(int i) => null;
void positionalNullableIntToVoid(int? i) => null;
void positionalNullableIntToVoid2(int? i) => null;
-void optionalIntToVoid([int i]) => null;
-void optionalIntToVoid2([int i]) => null;
+void optionalIntToVoid([int i = 0]) => null;
+void optionalIntToVoid2([int i = 0]) => null;
void optionalNullableIntToVoid([int? i]) => null;
void optionalNullableIntToVoid2([int? i]) => null;
-void namedIntToVoid({int i}) => null;
-void namedIntToVoid2({int i}) => null;
+void namedIntToVoid({int i = 0}) => null;
+void namedIntToVoid2({int i = 0}) => null;
void namedNullableIntToVoid({int? i}) => null;
void namedNullableIntToVoid2({int? i}) => null;
void requiredIntToVoid({required int i}) => null;
void requiredIntToVoid2({required int i}) => null;
void requiredNullableIntToVoid({required int? i}) => null;
void requiredNullableIntToVoid2({required int? i}) => null;
-void gn(bool b, [int i]) => null;
-void hn(bool b, {int i}) => null;
+void gn(bool b, [int i = 0]) => null;
+void hn(bool b, {int i = 0}) => null;
main() {
// Same functions with different names.
diff --git a/tests/language/nnbd/type_equality/futureOr_normalization_legacy_lib.dart b/tests/language/nnbd/type_equality/futureOr_normalization_legacy_lib.dart
new file mode 100644
index 0000000..cbad332
--- /dev/null
+++ b/tests/language/nnbd/type_equality/futureOr_normalization_legacy_lib.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Opt out of Null Safety:
+// @dart = 2.6
+
+import 'futureOr_normalization_null_safe_lib.dart' as nullSafe;
+
+Type extractType<T>() => T;
+Type nonNullableFutureOrOfLegacyObject() =>
+ nullSafe.nonNullableFutureOrOf<Object>();
+
+final object = extractType<Object>();
diff --git a/tests/language/nnbd/type_equality/futureOr_normalization_legacy_test.dart b/tests/language/nnbd/type_equality/futureOr_normalization_legacy_test.dart
new file mode 100644
index 0000000..c0570d4
--- /dev/null
+++ b/tests/language/nnbd/type_equality/futureOr_normalization_legacy_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Opt out of Null Safety:
+// @dart = 2.6
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+import 'futureOr_normalization_null_safe_lib.dart' as nullSafe;
+
+Type extractType<T>() => T;
+Type extractFutureOrType<T>() => _<FutureOr<T>>().runtimeType;
+Type embedFutureOrType<T>() => nullSafe.Embed<FutureOr<T>>().runtimeType;
+
+/// A class that should be ignored but it used embed the type signatures
+/// actually being tested.
+class _<T> {}
+
+main() {
+ // FutureOr types are normalized when they appear explicitly in the source.
+ Expect.identical(dynamic, extractType<FutureOr>());
+ Expect.identical(dynamic, extractType<FutureOr<dynamic>>());
+ Expect.identical(extractType<Object>(), extractType<FutureOr<Object>>());
+ Expect.identical(extractType<void>(), extractType<FutureOr<void>>());
+ Expect.identical(nullSafe.embeddedNullableFutureOfNull,
+ extractType<nullSafe.Embed<FutureOr<Null>>>());
+
+ // FutureOr types are normalized when they are created at runtime.
+ Expect.identical(extractType<_<dynamic>>(), extractFutureOrType());
+ Expect.identical(extractType<_<dynamic>>(), extractFutureOrType<dynamic>());
+ Expect.identical(extractType<_<Object>>(), extractFutureOrType<Object>());
+ Expect.identical(extractType<_<void>>(), extractFutureOrType<void>());
+ Expect.identical(
+ nullSafe.embeddedNullableFutureOfNull, embedFutureOrType<Null>());
+}
diff --git a/tests/language/nnbd/type_equality/futureOr_normalization_null_safe_lib.dart b/tests/language/nnbd/type_equality/futureOr_normalization_null_safe_lib.dart
new file mode 100644
index 0000000..c3391da
--- /dev/null
+++ b/tests/language/nnbd/type_equality/futureOr_normalization_null_safe_lib.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
+/// A class that should be ignored but it used embed the type signatures
+/// actually being tested.
+class Embed<T> {}
+
+Type extractType<T>() => T;
+Type nonNullableFutureOrOf<T>() => extractType<FutureOr<T>>();
+
+final nullableFutureOfNull = extractType<Future<Null>?>();
+final embeddedNullableFutureOfNull = extractType<Embed<Future<Null>?>>();
diff --git a/tests/language/nnbd/type_equality/futureOr_normalization_test.dart b/tests/language/nnbd/type_equality/futureOr_normalization_test.dart
new file mode 100644
index 0000000..a9e61f5
--- /dev/null
+++ b/tests/language/nnbd/type_equality/futureOr_normalization_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+import 'futureOr_normalization_null_safe_lib.dart';
+import 'futureOr_normalization_legacy_lib.dart' as legacy;
+
+class A {}
+
+Type extractFutureOrType<T>() => Embed<FutureOr<T>>().runtimeType;
+Type embedNullableFutureOrType<T>() => Embed<FutureOr<T>?>().runtimeType;
+
+main() {
+ // FutureOr types are normalized when they appear explicitly in the source.
+ Expect.identical(dynamic, extractType<FutureOr>());
+ Expect.identical(dynamic, extractType<FutureOr<dynamic>>());
+ Expect.identical(Object, extractType<FutureOr<Object>>());
+ Expect.identical(extractType<Object?>(), extractType<FutureOr<Object>?>());
+ Expect.identical(extractType<Object?>(), extractType<FutureOr<Object?>>());
+ Expect.identical(extractType<void>(), extractType<FutureOr<void>>());
+ Expect.identical(
+ extractType<Future<Never>>(), extractType<FutureOr<Never>>());
+ Expect.identical(extractType<Future<Null>?>(), extractType<FutureOr<Null>>());
+ Expect.identical(
+ extractType<FutureOr<int?>>(), extractType<FutureOr<int?>?>());
+ Expect.identical(extractType<FutureOr<A?>>(), extractType<FutureOr<A?>?>());
+
+ // FutureOr types are normalized when they are composed at runtime.
+ Expect.identical(extractType<Embed<dynamic>>(), extractFutureOrType());
+ Expect.identical(
+ extractType<Embed<dynamic>>(), extractFutureOrType<dynamic>());
+ Expect.identical(extractType<Embed<Object>>(), extractFutureOrType<Object>());
+ Expect.identical(
+ extractType<Embed<Object?>>(), embedNullableFutureOrType<Object>());
+ Expect.identical(
+ extractType<Embed<Object?>>(), extractFutureOrType<Object?>());
+ Expect.identical(extractType<Embed<void>>(), extractFutureOrType<void>());
+ Expect.identical(
+ extractType<Embed<Future<Never>>>(), extractFutureOrType<Never>());
+ Expect.identical(
+ extractType<Embed<Future<Null>?>>(), extractFutureOrType<Null>());
+ Expect.identical(
+ extractType<Embed<FutureOr<int?>>>(), embedNullableFutureOrType<int?>());
+ Expect.identical(
+ extractType<Embed<FutureOr<A?>>>(), embedNullableFutureOrType<A?>());
+
+ // Object* == FutureOr<Object*>
+ Expect.identical(legacy.object, legacy.nonNullableFutureOrOfLegacyObject());
+}
diff --git a/tests/language/nnbd/type_equality/generic_function_type_equality_legacy_lib.dart b/tests/language/nnbd/type_equality/generic_function_type_equality_legacy_lib.dart
index d19128f..b354836 100644
--- a/tests/language/nnbd/type_equality/generic_function_type_equality_legacy_lib.dart
+++ b/tests/language/nnbd/type_equality/generic_function_type_equality_legacy_lib.dart
@@ -10,14 +10,14 @@
void fn<X>() => null;
R voidToR<R>() => null as R;
void positionalRToVoid<R>(R i) => null;
-void optionalRToVoid<R>([R i]) => null;
-void namedRToVoid<R>({R i}) => null;
-void hn<T, S>(T b, [S i]) => null;
-void kn<T, S>(T b, {S i}) => null;
+void optionalRToVoid<R>([List<R> i]) => null;
+void namedRToVoid<R>({List<R> i}) => null;
+void hn<T, S>(T b, [List<S> i]) => null;
+void kn<T, S>(T b, {List<S> i}) => null;
void positionalTToVoidWithBound<T extends B>(T i) => null;
-void optionalTToVoidWithBound<T extends B>([T i]) => null;
-void namedTToVoidWithBound<T extends B>({T i}) => null;
+void optionalTToVoidWithBound<T extends B>([List<T> i]) => null;
+void namedTToVoidWithBound<T extends B>({List<T> i}) => null;
class A<T extends B> {
void fn(T i) => null;
diff --git a/tests/language/nnbd/type_equality/generic_function_type_equality_test.dart b/tests/language/nnbd/type_equality/generic_function_type_equality_test.dart
index b830ba3..bd18b9a 100644
--- a/tests/language/nnbd/type_equality/generic_function_type_equality_test.dart
+++ b/tests/language/nnbd/type_equality/generic_function_type_equality_test.dart
@@ -14,12 +14,12 @@
void positionalSToVoid<S>(S i) => null;
void positionalNullableTToVoid<T>(T? i) => null;
void positionalNullableSToVoid<S>(S? i) => null;
-void optionalTToVoid<T>([T i]) => null;
-void optionalSToVoid<S>([S i]) => null;
+void optionalTToVoid<T>([List<T> i = const <Never>[]]) => null;
+void optionalSToVoid<S>([List<S> i = const <Never>[]]) => null;
void optionalNullableTToVoid<T>([T? i]) => null;
void optionalNullableSToVoid<S>([S? i]) => null;
-void namedTToVoid<T>({T i}) => null;
-void namedSToVoid<S>({S i}) => null;
+void namedTToVoid<T>({List<T> i = const <Never>[]}) => null;
+void namedSToVoid<S>({List<S> i = const <Never>[]}) => null;
void namedNullableTToVoid<T>({T? i}) => null;
void namedNullableSToVoid<S>({S? i}) => null;
void requiredTToVoid<T>({required T i}) => null;
@@ -28,8 +28,9 @@
void requiredNullableSToVoid<S>({required S? i}) => null;
void positionalTToVoidWithBound<T extends B>(T i) => null;
-void optionalTToVoidWithBound<T extends B>([T i]) => null;
-void namedTToVoidWithBound<T extends B>({T i}) => null;
+void optionalTToVoidWithBound<T extends B>([List<T> i = const <Never>[]]) =>
+ null;
+void namedTToVoidWithBound<T extends B>({List<T> i = const <Never>[]}) => null;
class A<T extends B> {
void fn(T i) => null;
@@ -38,7 +39,7 @@
main() {
// Same functions with different names.
Expect.equals(fn.runtimeType, fn2.runtimeType);
- Expect.equals(voidToT.runtimeType, voidToT.runtimeType);
+ Expect.equals(voidToT.runtimeType, voidToS.runtimeType);
Expect.equals(positionalTToVoid.runtimeType, positionalSToVoid.runtimeType);
Expect.equals(positionalNullableTToVoid.runtimeType,
positionalNullableSToVoid.runtimeType);
diff --git a/tests/language_2/call/method_as_cast_test.dart b/tests/language_2/call/method_as_cast_test.dart
index f0718a3..48ae3b7 100644
--- a/tests/language_2/call/method_as_cast_test.dart
+++ b/tests/language_2/call/method_as_cast_test.dart
@@ -23,13 +23,13 @@
// The presence of a `.call` method does not cause class `C` to become a
// subtype of any function type.
C c = new C();
- Expect.throwsCastError(() => c as BToB); //# 01: ok
- Expect.throwsCastError(() => c as NullToObject); //# 02: ok
- Expect.throwsCastError(() => c as Function); //# 03: ok
+ Expect.throwsTypeError(() => c as BToB); //# 01: ok
+ Expect.throwsTypeError(() => c as NullToObject); //# 02: ok
+ Expect.throwsTypeError(() => c as Function); //# 03: ok
// The same goes for class `D`: `implements Function` is ignored in Dart 2.
D d = new D();
- Expect.throwsCastError(() => d as BToB); //# 04: ok
- Expect.throwsCastError(() => d as NullToObject); //# 05: ok
- Expect.throwsCastError(() => d as Function); //# 06: ok
+ Expect.throwsTypeError(() => d as BToB); //# 04: ok
+ Expect.throwsTypeError(() => d as NullToObject); //# 05: ok
+ Expect.throwsTypeError(() => d as Function); //# 06: ok
}
diff --git a/tests/language_2/deferred/type_dependency_lib1.dart b/tests/language_2/deferred/type_dependency_lib1.dart
index d9a3663..491ecc6 100644
--- a/tests/language_2/deferred/type_dependency_lib1.dart
+++ b/tests/language_2/deferred/type_dependency_lib1.dart
@@ -13,7 +13,7 @@
bool fooAs(x) {
try {
return (x as A).p;
- } on CastError catch (e) {
+ } on TypeError {
return false;
}
}
@@ -22,7 +22,7 @@
try {
A y = x;
return y is! String;
- } on TypeError catch (e) {
+ } on TypeError {
return false;
}
}
diff --git a/tests/language_2/enum/enum_test.dart b/tests/language_2/enum/enum_test.dart
index d3480ca..4e1303d 100644
--- a/tests/language_2/enum/enum_test.dart
+++ b/tests/language_2/enum/enum_test.dart
@@ -37,7 +37,7 @@
Expect.isFalse(obj is _IsNot, '$obj is _IsNot');
// test cast
t = obj as T;
- Expect.throwsCastError(() => obj as _IsNot, '$obj as _IsNot');
+ Expect.throwsTypeError(() => obj as _IsNot, '$obj as _IsNot');
}
main() {
diff --git a/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart
index de842c8..258feaa 100644
--- a/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart
@@ -119,6 +119,6 @@
var a = new AGlobal();
a.instanceTest();
- Expect.throwsCastError(() => 3.castToShadowedTypeParam<String>());
- Expect.throwsCastError(() => 3.castToShadowedTypeList<String>());
+ Expect.throwsTypeError(() => 3.castToShadowedTypeParam<String>());
+ Expect.throwsTypeError(() => 3.castToShadowedTypeList<String>());
}
diff --git a/tests/language_2/extension_methods/static_extension_internal_resolution_6_test.dart b/tests/language_2/extension_methods/static_extension_internal_resolution_6_test.dart
index 929b306..f8dd416 100644
--- a/tests/language_2/extension_methods/static_extension_internal_resolution_6_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_resolution_6_test.dart
@@ -97,5 +97,5 @@
var a = new AGlobal();
a.instanceTest();
- Expect.throwsCastError(() => 3.castToShadowedTypeParam<String>());
+ Expect.throwsTypeError(() => 3.castToShadowedTypeParam<String>());
}
diff --git a/tests/language_2/generic/function_bounds_test.dart b/tests/language_2/generic/function_bounds_test.dart
index c48483b..ad7f17d 100644
--- a/tests/language_2/generic/function_bounds_test.dart
+++ b/tests/language_2/generic/function_bounds_test.dart
@@ -68,29 +68,29 @@
Expect.equals((d as F<num>)(40), 42);
// Check that casting to a generic function with more specific bounds fails
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (f as G<int>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (d as G<int>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (f as G<double>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (d as G<double>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (f as G<Null>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (d as G<Null>), "Generic functions are invariant");
// Check that casting to a generic function with a more general bound fails
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (f as G<Object>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (d as G<Object>), "Generic functions are invariant");
// Check that casting to a generic function with an unrelated bound fails
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (f as G<String>), "Generic functions are invariant");
- Expect.throwsCastError(
+ Expect.throwsTypeError(
() => (d as G<String>), "Generic functions are invariant");
}
diff --git a/tests/language_2/generic_methods/type_expression_test.dart b/tests/language_2/generic_methods/type_expression_test.dart
index 80d4376..e809704 100644
--- a/tests/language_2/generic_methods/type_expression_test.dart
+++ b/tests/language_2/generic_methods/type_expression_test.dart
@@ -45,9 +45,9 @@
Expect.isFalse(f4<int>(<int>[42]));
Expect.isTrue(f4<String>(<int>[42])); // `is! List<dynamic>` is true.
Expect.equals(f5<String>(s), s); // `s as String == s`
- Expect.throwsCastError(() => f5<int>(s)); // `s as int == s`
+ Expect.throwsTypeError(() => f5<int>(s)); // `s as int == s`
Expect.equals(f6<String>(ss), ss);
- Expect.throwsCastError(() => f6<int>(ss)); // `as List<int>` fails.
+ Expect.throwsTypeError(() => f6<int>(ss)); // `as List<int>` fails.
Expect.equals(f7<int>(), int);
// Returns `List<int>`.
diff --git a/tests/language_2/malbounded/type_cast_runtime_test.dart b/tests/language_2/malbounded/type_cast_runtime_test.dart
index 31e8b55..fd75b12 100644
--- a/tests/language_2/malbounded/type_cast_runtime_test.dart
+++ b/tests/language_2/malbounded/type_cast_runtime_test.dart
@@ -17,10 +17,10 @@
main() {
var m = new Malbounded1();
- Expect.throwsCastError(() => m as Super<int>);
+ Expect.throwsTypeError(() => m as Super<int>);
var s = new Super<int>();
- Expect.throwsCastError(() => s as Malbounded1);
- Expect.throwsCastError(() => s as Malbounded2);
+ Expect.throwsTypeError(() => s as Malbounded1);
+ Expect.throwsTypeError(() => s as Malbounded2);
s as Super
;
diff --git a/tests/language_2/malbounded/type_cast_test.dart b/tests/language_2/malbounded/type_cast_test.dart
index 4ebe0c7..2c56e68 100644
--- a/tests/language_2/malbounded/type_cast_test.dart
+++ b/tests/language_2/malbounded/type_cast_test.dart
@@ -22,10 +22,10 @@
main() {
var m = new Malbounded1();
- Expect.throwsCastError(() => m as Super<int>);
+ Expect.throwsTypeError(() => m as Super<int>);
var s = new Super<int>();
- Expect.throwsCastError(() => s as Malbounded1);
- Expect.throwsCastError(() => s as Malbounded2);
+ Expect.throwsTypeError(() => s as Malbounded1);
+ Expect.throwsTypeError(() => s as Malbounded2);
s as Super
//^
// [cfe] Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'Super'.
diff --git a/tests/language_2/null/null_test.dart b/tests/language_2/null/null_test.dart
index 10e37fa..19f85f0 100644
--- a/tests/language_2/null/null_test.dart
+++ b/tests/language_2/null/null_test.dart
@@ -143,7 +143,7 @@
Expect.equals(null, null as Null);
Expect.equals(null, null as Object);
Expect.equals(null, null as int);
- Expect.throwsCastError(() => 42 as Null);
+ Expect.throwsTypeError(() => 42 as Null);
Expect.equals(null, new Generic<Null>().cast(null));
Expect.equals(null, new Generic<Object>().cast(null));
Expect.equals(null, new Generic<int>().cast(null));
diff --git a/tests/language_2/regress/regress10747_test.dart b/tests/language_2/regress/regress10747_test.dart
index 2fc2b65..46fb8bd 100644
--- a/tests/language_2/regress/regress10747_test.dart
+++ b/tests/language_2/regress/regress10747_test.dart
@@ -15,9 +15,9 @@
main() {
Expect.equals(42, new A<int>(42).asTypeVariable());
- Expect.throwsCastError(() => new A<String>(42).asTypeVariable());
+ Expect.throwsTypeError(() => new A<String>(42).asTypeVariable());
var b = new B<int>();
Expect.equals(b, new A<int>(b).asBOfT());
- Expect.throwsCastError(() => new A<String>(b).asBOfT());
+ Expect.throwsTypeError(() => new A<String>(b).asBOfT());
}
diff --git a/tests/language_2/type/check_test.dart b/tests/language_2/type/check_test.dart
index 820c0dd..20539a1 100644
--- a/tests/language_2/type/check_test.dart
+++ b/tests/language_2/type/check_test.dart
@@ -15,5 +15,5 @@
var a = [new A(), new B()];
var b = a[0];
b = b as A;
- Expect.throwsCastError(() => b as B);
+ Expect.throwsTypeError(() => b as B);
}
diff --git a/tests/language_2/type/error_test.dart b/tests/language_2/type/error_test.dart
index fc62c23..4797b37 100644
--- a/tests/language_2/type/error_test.dart
+++ b/tests/language_2/type/error_test.dart
@@ -4,193 +4,42 @@
import "package:expect/expect.dart";
-// Test that various type errors doesn't invoke user-defined code
-// during error reporting.
+// Test that various type errors produced by explicit casts don't invoke
+// user-defined code during error reporting.
-class MyClass {}
-
-class IntTypeError {
+class NoToString {
toString() {
- int value = wrap(this);
- return super.toString();
- }
-}
-
-class StringTypeError {
- toString() {
- String value = wrap(this);
- return super.toString();
- }
-}
-
-class DoubleTypeError {
- toString() {
- double value = wrap(this);
- return super.toString();
- }
-}
-
-class NumTypeError {
- toString() {
- num value = wrap(this);
- return super.toString();
- }
-}
-
-class BoolTypeError {
- toString() {
- bool value = wrap(this);
- return super.toString();
- }
-}
-
-class FunctionTypeError {
- toString() {
- Function value = wrap(this);
- return super.toString();
- }
-}
-
-class MyClassTypeError {
- toString() {
- MyClass value = wrap(this);
- return super.toString();
- }
-}
-
-class ListTypeError {
- toString() {
- List value = wrap(this);
- return super.toString();
- }
-}
-
-class IntCastError {
- toString() {
- wrap(this) as int;
- return super.toString();
- }
-}
-
-class StringCastError {
- toString() {
- wrap(this) as String;
- return super.toString();
- }
-}
-
-class DoubleCastError {
- toString() {
- wrap(this) as double;
- return super.toString();
- }
-}
-
-class NumCastError {
- toString() {
- wrap(this) as num;
- return super.toString();
- }
-}
-
-class BoolCastError {
- toString() {
- wrap(this) as bool;
- return super.toString();
- }
-}
-
-class FunctionCastError {
- toString() {
- wrap(this) as Function;
- return super.toString();
- }
-}
-
-class MyClassCastError {
- toString() {
- wrap(this) as MyClass;
- return super.toString();
- }
-}
-
-class ListCastError {
- toString() {
- wrap(this) as List;
- return super.toString();
+ Expect.fail("should not be called");
+ return "";
}
}
/// Defeat optimizations of type checks.
-wrap(e) {
+dynamic wrap(e) {
if (new DateTime.now().year == 1980) return null;
return e;
}
-checkTypeError(o) {
- try {
- print(o);
- } on TypeError catch (e) {
- print(e); // This might provoke an error.
- if (assertionsEnabled) return; // Expected type error.
- rethrow; // Rethrow unexpected type error.
- }
- if (assertionsEnabled) {
- throw 'expected TypeError';
- }
-}
-
-checkAssert(o) {
- try {
- assert(o);
- } on TypeError catch (e) {
- print(e); // This might provoke an error.
- if (!assertionsEnabled) rethrow; // Unexpected error.
- }
-}
-
-checkCastError(o) {
- try {
- print(o);
- } on TypeError catch (e) {
- print('unexpected type error: ${Error.safeToString(e)}');
- rethrow; // Unexpected type error.
- } on CastError catch (e) {
- print(e); // This might provoke an error.
- return; // Expected a cast error.
- }
- throw 'expected CastError';
-}
-
bool assertionsEnabled = false;
-main() {
+void main() {
assert(assertionsEnabled = true);
- checkTypeError(new IntTypeError());
- checkTypeError(new StringTypeError());
- checkTypeError(new DoubleTypeError());
- checkTypeError(new NumTypeError());
- checkTypeError(new BoolTypeError());
- checkTypeError(new FunctionTypeError());
- checkTypeError(new MyClassTypeError());
- checkTypeError(new ListTypeError());
+ dynamic noToString = NoToString();
- checkAssert(new IntTypeError());
- checkAssert(new StringTypeError());
- checkAssert(new DoubleTypeError());
- checkAssert(new NumTypeError());
- checkAssert(new BoolTypeError());
- checkAssert(new FunctionTypeError());
- checkAssert(new MyClassTypeError());
- checkAssert(new ListTypeError());
+ Expect.throws<TypeError>(() {
+ wrap(noToString) as int; // Explicit cast should throw
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
- checkCastError(new IntCastError());
- checkCastError(new StringCastError());
- checkCastError(new DoubleCastError());
- checkCastError(new NumCastError());
- checkCastError(new BoolCastError());
- checkCastError(new FunctionCastError());
- checkCastError(new MyClassCastError());
- checkCastError(new ListCastError());
+ if (assertionsEnabled) {
+ Expect.throws<AssertionError>(() {
+ assert(wrap(false), noToString); // Assertion should throw
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+ }
}
diff --git a/tests/language_2/type/implicit_error_test.dart b/tests/language_2/type/implicit_error_test.dart
new file mode 100644
index 0000000..1c42842
--- /dev/null
+++ b/tests/language_2/type/implicit_error_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that various type errors produced by implicit casts don't invoke
+// user-defined code during error reporting.
+
+class NoToString {
+ toString() {
+ Expect.fail("should not be called");
+ return "";
+ }
+}
+
+/// Defeat optimizations of type checks.
+dynamic wrap(e) {
+ if (new DateTime.now().year == 1980) return null;
+ return e;
+}
+
+bool assertionsEnabled = false;
+
+void main() {
+ assert(assertionsEnabled = true);
+
+ dynamic noToString = NoToString();
+
+ Expect.throws<TypeError>(() {
+ int x = wrap(noToString); // Implicit cast should throw
+ return x;
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+
+ if (assertionsEnabled) {
+ Expect.throws<TypeError>(() {
+ assert(wrap(noToString)); // Implicit cast should throw
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+ }
+}
diff --git a/tests/language_2/vm/type_cast_vm_test.dart b/tests/language_2/vm/type_cast_vm_test.dart
index 07580db..5a83874 100644
--- a/tests/language_2/vm/type_cast_vm_test.dart
+++ b/tests/language_2/vm/type_cast_vm_test.dart
@@ -20,10 +20,10 @@
static test() {
int result = 0;
try {
- var i = "hello" as int; // Throws a CastError
+ var i = "hello" as int; // Throws a TypeError
} catch (error) {
result = 1;
- Expect.isTrue(error is CastError);
+ Expect.type<TypeError>(error);
var msg = error.toString();
Expect.isTrue(msg.contains("int")); // dstType
Expect.isTrue(msg.contains("String")); // srcType
@@ -57,10 +57,10 @@
}
try {
- int i = f("hello" as int); // Throws a CastError
+ int i = f("hello" as int); // Throws a TypeError
} catch (error) {
result = 1;
- Expect.isTrue(error is CastError);
+ Expect.type<TypeError>(error);
var msg = error.toString();
Expect.isTrue(msg.contains("int")); // dstType
Expect.isTrue(msg.contains("String")); // srcType
@@ -72,14 +72,14 @@
static testReturn() {
int result = 0;
int f(String s) {
- return s as int; // Throws a CastError
+ return s as int; // Throws a TypeError
}
try {
int i = f("hello");
} catch (error) {
result = 1;
- Expect.isTrue(error is CastError);
+ Expect.type<TypeError>(error);
var msg = error.toString();
Expect.isTrue(msg.contains("int")); // dstType
Expect.isTrue(msg.contains("String")); // srcType
@@ -94,7 +94,7 @@
int result = 0;
Expect.equals(5, (field as String).length);
try {
- field as int; // Throws a CastError
+ field as int; // Throws a TypeError
} catch (error) {
result = 1;
var msg = error.toString();
diff --git a/tests/lib/async/catch_errors.dart b/tests/lib/async/catch_errors.dart
index b170b70..c684cf9 100644
--- a/tests/lib/async/catch_errors.dart
+++ b/tests/lib/async/catch_errors.dart
@@ -19,7 +19,7 @@
}
runZonedScheduleMicrotask(body(),
- {void onScheduleMicrotask(void callback()), Function onError}) {
+ {void onScheduleMicrotask(void callback()), Function? onError}) {
if (onScheduleMicrotask == null) {
return runZoned(body, onError: onError);
}
diff --git a/tests/lib/async/event_helper.dart b/tests/lib/async/event_helper.dart
index d7ff0f4..671e724 100644
--- a/tests/lib/async/event_helper.dart
+++ b/tests/lib/async/event_helper.dart
@@ -86,7 +86,7 @@
events.add(new DataEvent(value));
}
- void addError(error, [StackTrace stackTrace]) {
+ void addError(error, [StackTrace? stackTrace]) {
if (trace) print("Events#$hashCode: addError($error)");
events.add(new ErrorEvent(error));
}
@@ -100,7 +100,7 @@
/**
* Error shorthand, for writing events manually.
*/
- void error(var value, [StackTrace stackTrace]) {
+ void error(var value, [StackTrace? stackTrace]) {
addError(value, stackTrace);
}
@@ -130,7 +130,7 @@
* Should only be used when there is a subscription. That is, after a
* call to [subscribeTo].
*/
- void pause([Future resumeSignal]) {
+ void pause([Future? resumeSignal]) {
throw new StateError("Not capturing events.");
}
@@ -160,14 +160,14 @@
onError: addError, onDone: close, cancelOnError: cancelOnError);
}
- void addError(error, [stackTrace]) {
+ void addError(error, [StackTrace? stackTrace]) {
super.addError(error, stackTrace);
if (cancelOnError) {
onDoneSignal.complete();
}
}
- void pause([Future resumeSignal]) {
+ void pause([Future? resumeSignal]) {
if (trace) print("Events#$hashCode: pause");
subscription.pause(resumeSignal);
}
diff --git a/tests/lib/async/future_foreach_test.dart b/tests/lib/async/future_foreach_test.dart
index 7416b94..904ae80 100644
--- a/tests/lib/async/future_foreach_test.dart
+++ b/tests/lib/async/future_foreach_test.dart
@@ -63,9 +63,9 @@
Expect.isTrue(n >= 0);
switch (delay) {
case 1:
- return new Future<String>(() {});
+ return new Future(() {});
case 2:
- return new Future<String>.microtask(() {});
+ return new Future.microtask(() {});
}
}).then((_) {
Expect.fail("Did not throw");
diff --git a/tests/lib/async/futures_test.dart b/tests/lib/async/futures_test.dart
index 537b65c..6dd4311 100644
--- a/tests/lib/async/futures_test.dart
+++ b/tests/lib/async/futures_test.dart
@@ -15,7 +15,7 @@
Future testCompleteAfterWait() {
final futures = new List<Future>();
- final c = new Completer<Object>();
+ final c = new Completer<Object?>();
futures.add(c.future);
Future future = Future.wait(futures);
c.complete(null);
diff --git a/tests/lib/async/stream_subscription_as_future_test.dart b/tests/lib/async/stream_subscription_as_future_test.dart
index 5be5c91..d12c0ac 100644
--- a/tests/lib/async/stream_subscription_as_future_test.dart
+++ b/tests/lib/async/stream_subscription_as_future_test.dart
@@ -71,7 +71,7 @@
var subscription = stream.listen((x) {
output.add(x);
});
- subscription.asFuture(output).catchError(expectAsync((error) {
+ subscription.asFuture<List?>(output).catchError(expectAsync((error) {
Expect.equals(error, "foo");
}));
});
@@ -85,7 +85,7 @@
var subscription = stream.listen((x) {
output.add(x);
});
- subscription.asFuture(output).catchError(expectAsync((error) {
+ subscription.asFuture<List?>(output).catchError(expectAsync((error) {
Expect.equals(error, "foo");
}));
});
@@ -103,7 +103,7 @@
output.add(x);
});
bool catchErrorHasRun = false;
- subscription.asFuture(output).catchError(expectAsync((error) {
+ subscription.asFuture<List?>(output).catchError(expectAsync((error) {
Expect.equals(error, "foo");
catchErrorHasRun = true;
}));
@@ -127,7 +127,7 @@
output.add(x);
});
bool catchErrorHasRun = false;
- subscription.asFuture(output).catchError(expectAsync((error) {
+ subscription.asFuture<List?>(output).catchError(expectAsync((error) {
Expect.equals(error, "foo");
catchErrorHasRun = true;
}));
@@ -139,4 +139,4 @@
Expect.equals(499, e);
}));
});
-}
+}
\ No newline at end of file
diff --git a/tests/lib/mirrors/basic_types_in_dart_core_test.dart b/tests/lib/mirrors/basic_types_in_dart_core_test.dart
index 50e9203..748faf8 100644
--- a/tests/lib/mirrors/basic_types_in_dart_core_test.dart
+++ b/tests/lib/mirrors/basic_types_in_dart_core_test.dart
@@ -10,7 +10,7 @@
main() {
LibraryMirror dartcore = currentMirrorSystem().findLibrary(#dart.core);
ClassMirror cm;
- TypeMirror tm;
+ TypeMirror? tm;
cm = dartcore.declarations[#int] as ClassMirror;
Expect.equals(reflectClass(int), cm);
@@ -44,9 +44,9 @@
Expect.equals(reflectClass(Object), cm);
Expect.equals(#Object, cm.simpleName);
- tm = dartcore.declarations[#dynamic] as TypeMirror;
+ tm = dartcore.declarations[#dynamic] as TypeMirror?;
Expect.isNull(tm);
- tm = dartcore.declarations[const Symbol('void')] as TypeMirror;
+ tm = dartcore.declarations[const Symbol('void')] as TypeMirror?;
Expect.isNull(tm);
}
diff --git a/tests/lib/typed_data/typed_data_list_test.dart b/tests/lib/typed_data/typed_data_list_test.dart
index 890f274..edeb362 100644
--- a/tests/lib/typed_data/typed_data_list_test.dart
+++ b/tests/lib/typed_data/typed_data_list_test.dart
@@ -155,7 +155,7 @@
var copy = list.toList();
// Make sure we are allowed to call range-functions if they are 0..0.
- list.fillRange(0, 0);
+ list.fillRange(0, 0, toElementType(0));
Expect.listEquals([], list.getRange(0, 0).toList());
final minusOne = toElementType(-1);
diff --git a/tests/lib_2/html/canvasrendering/draw_image_video_element_test.dart b/tests/lib_2/html/canvasrendering/draw_image_video_element_test.dart
index 5fad4d2..c6aa721 100644
--- a/tests/lib_2/html/canvasrendering/draw_image_video_element_test.dart
+++ b/tests/lib_2/html/canvasrendering/draw_image_video_element_test.dart
@@ -4,189 +4,209 @@
library canvas_rendering_context_2d_test;
+import 'dart:async';
import 'dart:html';
import 'dart:math';
import 'canvas_rendering_util.dart';
-import 'package:unittest/unittest.dart';
+import 'package:async_helper/async_helper.dart';
+
+// These videos and base64 strings are the same video, representing 2
+// frames of 8x8 red pixels.
+// The videos were created with:
+// convert -size 8x8 xc:red blank1.jpg
+// convert -size 8x8 xc:red blank2.jpg
+// avconv -f image2 -i "blank%d.jpg" -c:v libx264 small.mp4
+// avconv -i small.mp4 small.webm
+// python -m base64 -e small.mp4
+// python -m base64 -e small.webm
+var mp4VideoUrl = '/root_dart/tests/lib_2/html/small.mp4';
+var webmVideoUrl = '/root_dart/tests/lib_2/html/small.webm';
+var mp4VideoDataUrl =
+ 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAA'
+ 'AIZnJlZQAAAsdtZGF0AAACmwYF//+X3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlID'
+ 'EyMCByMjE1MSBhM2Y0NDA3IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZW'
+ 'Z0IDIwMDMtMjAxMSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG'
+ '9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweD'
+ 'ExMSBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj'
+ '0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MCBjcW09MC'
+ 'BkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aH'
+ 'JlYWRzPTE4IHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZW'
+ 'Q9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl'
+ '9weXJhbWlkPTAgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MCBvcG'
+ 'VuX2dvcD0xIHdlaWdodHA9MiBrZXlpbnQ9MjUwIGtleWludF9taW49MjUgc2NlbmVjdX'
+ 'Q9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPT'
+ 'EgY3JmPTUxLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3'
+ 'JhdGlvPTEuMjUgYXE9MToxLjAwAIAAAAARZYiEB//3aoK5/tP9+8yeuIEAAAAHQZoi2P'
+ '/wgAAAAzxtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAUAABAAABAAAAAAAAAA'
+ 'AAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA'
+ 'AAAAAAAAAAAAAAAAAAAAACAAAAGGlvZHMAAAAAEICAgAcAT/////7/AAACUHRyYWsAAA'
+ 'BcdGtoZAAAAA8AAAAAAAAAAAAAAAEAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAQAAAA'
+ 'AAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAACAAAAAgAAAAAACRlZHRzAAAAHG'
+ 'Vsc3QAAAAAAAAAAQAAAFAAAAABAAEAAAAAAchtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAA'
+ 'AAAAAZAAAAAlXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSG'
+ 'FuZGxlcgAAAAFzbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZg'
+ 'AAAAAAAAABAAAADHVybCAAAAABAAABM3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2Yz'
+ 'EAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACAAIAEgAAABIAAAAAAAAAAEAAAAAAAAAAA'
+ 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFNQAr/4QAYZ01ACuiPyy'
+ '4C2QAAAwABAAADADIPEiUSAQAGaOvAZSyAAAAAGHN0dHMAAAAAAAAAAQAAAAIAAAABAA'
+ 'AAFHN0c3MAAAAAAAAAAQAAAAEAAAAYY3R0cwAAAAAAAAABAAAAAgAAAAEAAAAcc3RzYw'
+ 'AAAAAAAAABAAAAAQAAAAEAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAK0AAAACwAAAB'
+ 'hzdGNvAAAAAAAAAAIAAAAwAAAC5AAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAA'
+ 'AAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQ'
+ 'AAAABMYXZmNTMuMjEuMQ==';
+var webmVideoDataUrl =
+ 'data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlY'
+ 'm1Ch4ECQoWBAhhTgGcBAAAAAAAB/hFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua'
+ '1OsggEsTbuMU6uEHFO7a1OsggHk7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+ 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+ 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+ 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAA'
+ 'EEq17GDD0JATYCLTGF2ZjUzLjIxLjFXQYtMYXZmNTMuMjEuMXOkkJatuHwTJ7cvFLSzB'
+ 'Smxbp5EiYhAVAAAAAAAABZUrmsBAAAAAAAAR64BAAAAAAAAPteBAXPFgQGcgQAitZyDd'
+ 'W5khoVWX1ZQOIOBASPjg4QCYloA4AEAAAAAAAASsIEIuoEIVLCBCFS6gQhUsoEDH0O2d'
+ 'QEAAAAAAABZ54EAo72BAACA8AIAnQEqCAAIAABHCIWFiIWEiAICAnWqA/gD+gINTRgA/'
+ 'v0hRf/kb+PnRv/I4//8WE8DijI//FRAo5WBACgAsQEAARAQABgAGFgv9AAIAAAcU7trA'
+ 'QAAAAAAAA67jLOBALeH94EB8YIBfw==';
+
+Future testWithThreeParams() async {
+ setupFunc();
+
+ var playFuture = video.onCanPlay.first;
+ video.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+ if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
+ video.src = webmVideoUrl;
+ } else if (video.canPlayType(
+ 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
+ '') {
+ video.src = mp4VideoUrl;
+ } else {
+ window.console.log('Video is not supported on this system.');
+ }
+
+ await playFuture;
+ context.drawImage(video, 50, 50);
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(54, 54);
+ expectPixelFilled(57, 57);
+ expectPixelUnfilled(58, 58);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(70, 70);
+ tearDownFunc();
+}
+
+Future testWithFiveParams() async {
+ setupFunc();
+
+ var playFuture = video.onCanPlay.first;
+ video.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+
+ if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
+ video.src = webmVideoUrl;
+ } else if (video.canPlayType(
+ 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
+ '') {
+ video.src = mp4VideoUrl;
+ } else {
+ // TODO(amouravski): Better fallback?
+ window.console.log('Video is not supported on this system.');
+ }
+
+ await playFuture;
+ context.drawImageToRect(video, new Rectangle(50, 50, 20, 20));
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(55, 55);
+ expectPixelFilled(59, 59);
+ expectPixelFilled(60, 60);
+ expectPixelFilled(69, 69);
+ expectPixelUnfilled(70, 70);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(80, 80);
+ tearDownFunc();
+}
+
+Future testWithNineParams() async {
+ setupFunc();
+
+ var playFuture = video.onCanPlay.first;
+ video.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+
+ if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
+ video.src = webmVideoUrl;
+ } else if (video.canPlayType(
+ 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
+ '') {
+ video.src = mp4VideoUrl;
+ } else {
+ // TODO(amouravski): Better fallback?
+ window.console.log('Video is not supported on this system.');
+ }
+
+ await playFuture;
+ context.drawImageToRect(video, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(55, 55);
+ expectPixelFilled(59, 59);
+ expectPixelFilled(60, 60);
+ expectPixelFilled(69, 69);
+ expectPixelUnfilled(70, 70);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(80, 80);
+ tearDownFunc();
+}
+
+Future testDataUrlWithNineParams() async {
+ setupFunc();
+
+ video = new VideoElement();
+ canvas = new CanvasElement();
+
+ var playFuture = video.onCanPlay.first;
+ video.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+
+ if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
+ video.src = webmVideoDataUrl;
+ } else if (video.canPlayType(
+ 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
+ '') {
+ video.src = mp4VideoDataUrl;
+ } else {
+ // TODO(amouravski): Better fallback?
+ window.console.log('Video is not supported on this system.');
+ }
+
+ await playFuture;
+ context.drawImageToRect(video, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(55, 55);
+ expectPixelFilled(59, 59);
+ expectPixelFilled(60, 60);
+ expectPixelFilled(69, 69);
+ expectPixelUnfilled(70, 70);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(80, 80);
+ tearDownFunc();
+}
main() {
- // These videos and base64 strings are the same video, representing 2
- // frames of 8x8 red pixels.
- // The videos were created with:
- // convert -size 8x8 xc:red blank1.jpg
- // convert -size 8x8 xc:red blank2.jpg
- // avconv -f image2 -i "blank%d.jpg" -c:v libx264 small.mp4
- // avconv -i small.mp4 small.webm
- // python -m base64 -e small.mp4
- // python -m base64 -e small.webm
- var mp4VideoUrl = '/root_dart/tests/lib_2/html/small.mp4';
- var webmVideoUrl = '/root_dart/tests/lib_2/html/small.webm';
- var mp4VideoDataUrl =
- 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAA'
- 'AIZnJlZQAAAsdtZGF0AAACmwYF//+X3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlID'
- 'EyMCByMjE1MSBhM2Y0NDA3IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZW'
- 'Z0IDIwMDMtMjAxMSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG'
- '9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweD'
- 'ExMSBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj'
- '0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MCBjcW09MC'
- 'BkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aH'
- 'JlYWRzPTE4IHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZW'
- 'Q9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl'
- '9weXJhbWlkPTAgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MCBvcG'
- 'VuX2dvcD0xIHdlaWdodHA9MiBrZXlpbnQ9MjUwIGtleWludF9taW49MjUgc2NlbmVjdX'
- 'Q9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPT'
- 'EgY3JmPTUxLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3'
- 'JhdGlvPTEuMjUgYXE9MToxLjAwAIAAAAARZYiEB//3aoK5/tP9+8yeuIEAAAAHQZoi2P'
- '/wgAAAAzxtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAUAABAAABAAAAAAAAAA'
- 'AAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA'
- 'AAAAAAAAAAAAAAAAAAAAACAAAAGGlvZHMAAAAAEICAgAcAT/////7/AAACUHRyYWsAAA'
- 'BcdGtoZAAAAA8AAAAAAAAAAAAAAAEAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAQAAAA'
- 'AAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAACAAAAAgAAAAAACRlZHRzAAAAHG'
- 'Vsc3QAAAAAAAAAAQAAAFAAAAABAAEAAAAAAchtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAA'
- 'AAAAAZAAAAAlXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSG'
- 'FuZGxlcgAAAAFzbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZg'
- 'AAAAAAAAABAAAADHVybCAAAAABAAABM3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2Yz'
- 'EAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACAAIAEgAAABIAAAAAAAAAAEAAAAAAAAAAA'
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFNQAr/4QAYZ01ACuiPyy'
- '4C2QAAAwABAAADADIPEiUSAQAGaOvAZSyAAAAAGHN0dHMAAAAAAAAAAQAAAAIAAAABAA'
- 'AAFHN0c3MAAAAAAAAAAQAAAAEAAAAYY3R0cwAAAAAAAAABAAAAAgAAAAEAAAAcc3RzYw'
- 'AAAAAAAAABAAAAAQAAAAEAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAK0AAAACwAAAB'
- 'hzdGNvAAAAAAAAAAIAAAAwAAAC5AAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAA'
- 'AAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQ'
- 'AAAABMYXZmNTMuMjEuMQ==';
- var webmVideoDataUrl =
- 'data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlY'
- 'm1Ch4ECQoWBAhhTgGcBAAAAAAAB/hFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua'
- '1OsggEsTbuMU6uEHFO7a1OsggHk7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
- 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAA'
- 'EEq17GDD0JATYCLTGF2ZjUzLjIxLjFXQYtMYXZmNTMuMjEuMXOkkJatuHwTJ7cvFLSzB'
- 'Smxbp5EiYhAVAAAAAAAABZUrmsBAAAAAAAAR64BAAAAAAAAPteBAXPFgQGcgQAitZyDd'
- 'W5khoVWX1ZQOIOBASPjg4QCYloA4AEAAAAAAAASsIEIuoEIVLCBCFS6gQhUsoEDH0O2d'
- 'QEAAAAAAABZ54EAo72BAACA8AIAnQEqCAAIAABHCIWFiIWEiAICAnWqA/gD+gINTRgA/'
- 'v0hRf/kb+PnRv/I4//8WE8DijI//FRAo5WBACgAsQEAARAQABgAGFgv9AAIAAAcU7trA'
- 'QAAAAAAAA67jLOBALeH94EB8YIBfw==';
-
- setUp(setupFunc);
- tearDown(tearDownFunc);
-
- test('with 3 params', () {
- video.onCanPlay.listen(expectAsync((_) {
- context.drawImage(video, 50, 50);
-
- expectPixelFilled(50, 50);
- expectPixelFilled(54, 54);
- expectPixelFilled(57, 57);
- expectPixelUnfilled(58, 58);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(70, 70);
- }));
-
- video.onError.listen((_) {
- fail('URL failed to load.');
- });
-
- if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
- video.src = webmVideoUrl;
- } else if (video.canPlayType(
- 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
- '') {
- video.src = mp4VideoUrl;
- } else {
- window.console.log('Video is not supported on this system.');
- }
- });
-
- test('with 5 params', () {
- video.onCanPlay.listen(expectAsync((_) {
- context.drawImageToRect(video, new Rectangle(50, 50, 20, 20));
-
- expectPixelFilled(50, 50);
- expectPixelFilled(55, 55);
- expectPixelFilled(59, 59);
- expectPixelFilled(60, 60);
- expectPixelFilled(69, 69);
- expectPixelUnfilled(70, 70);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(80, 80);
- }));
- video.onError.listen((_) {
- fail('URL failed to load.');
- });
-
- if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
- video.src = webmVideoUrl;
- } else if (video.canPlayType(
- 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
- '') {
- video.src = mp4VideoUrl;
- } else {
- // TODO(amouravski): Better fallback?
- window.console.log('Video is not supported on this system.');
- }
- });
-
- test('with 9 params', () {
- video.onCanPlay.listen(expectAsync((_) {
- context.drawImageToRect(video, new Rectangle(50, 50, 20, 20),
- sourceRect: new Rectangle(2, 2, 6, 6));
-
- expectPixelFilled(50, 50);
- expectPixelFilled(55, 55);
- expectPixelFilled(59, 59);
- expectPixelFilled(60, 60);
- expectPixelFilled(69, 69);
- expectPixelUnfilled(70, 70);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(80, 80);
- }));
- video.onError.listen((_) {
- fail('URL failed to load.');
- });
-
- if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
- video.src = webmVideoUrl;
- } else if (video.canPlayType(
- 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
- '') {
- video.src = mp4VideoUrl;
- } else {
- // TODO(amouravski): Better fallback?
- window.console.log('Video is not supported on this system.');
- }
- });
-
- test('dataurl with 9 params', () {
- video = new VideoElement();
- canvas = new CanvasElement();
- video.onCanPlay.listen(expectAsync((_) {
- context.drawImageToRect(video, new Rectangle(50, 50, 20, 20),
- sourceRect: new Rectangle(2, 2, 6, 6));
-
- expectPixelFilled(50, 50);
- expectPixelFilled(55, 55);
- expectPixelFilled(59, 59);
- expectPixelFilled(60, 60);
- expectPixelFilled(69, 69);
- expectPixelUnfilled(70, 70);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(80, 80);
- }));
- video.onError.listen((_) {
- fail('URL failed to load.');
- });
-
- if (video.canPlayType('video/webm; codecs="vp8.0, vorbis"', '') != '') {
- video.src = webmVideoDataUrl;
- } else if (video.canPlayType(
- 'video/mp4; codecs="avc1.4D401E, mp4a.40.2"', null) !=
- '') {
- video.src = mp4VideoDataUrl;
- } else {
- // TODO(amouravski): Better fallback?
- window.console.log('Video is not supported on this system.');
- }
+ asyncTest(() async {
+ await testWithThreeParams();
+ await testWithFiveParams();
+ await testWithNineParams();
+ await testDataUrlWithNineParams();
});
}
diff --git a/tests/lib_2/html/canvasrendering/image_element_test.dart b/tests/lib_2/html/canvasrendering/image_element_test.dart
index 1eac2b9..a1d8040 100644
--- a/tests/lib_2/html/canvasrendering/image_element_test.dart
+++ b/tests/lib_2/html/canvasrendering/image_element_test.dart
@@ -4,91 +4,105 @@
library canvas_rendering_context_2d_test;
+import 'dart:async';
import 'dart:html';
import 'dart:math';
import 'canvas_rendering_util.dart';
-import 'package:unittest/unittest.dart';
+import 'package:async_helper/async_helper.dart';
+
+Future testWithThreeParams() async {
+ setupFunc();
+ // Draw an image to the canvas from an image element.
+ var dataUrl = otherCanvas.toDataUrl('image/gif');
+ var img = new ImageElement();
+
+ var loadedFuture = img.onLoad.first;
+ img.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+ img.src = dataUrl;
+
+ await loadedFuture;
+ context.drawImage(img, 50, 50);
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(55, 55);
+ expectPixelFilled(59, 59);
+ expectPixelUnfilled(60, 60);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(70, 70);
+ tearDownFunc();
+}
+
+Future testWithFiveParams() async {
+ setupFunc();
+ // Draw an image to the canvas from an image element and scale it.
+ var dataUrl = otherCanvas.toDataUrl('image/gif');
+ var img = new ImageElement();
+
+ var loadedFuture = img.onLoad.first;
+ img.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+ img.src = dataUrl;
+
+ await loadedFuture;
+ context.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(55, 55);
+ expectPixelFilled(59, 59);
+ expectPixelFilled(60, 60);
+ expectPixelFilled(69, 69);
+ expectPixelUnfilled(70, 70);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(80, 80);
+ tearDownFunc();
+}
+
+Future testWithNineParams() async {
+ setupFunc();
+ // Draw an image to the canvas from an image element and scale it.
+ otherContext.fillStyle = "blue";
+ otherContext.fillRect(5, 5, 5, 5);
+ var dataUrl = otherCanvas.toDataUrl('image/gif');
+ var img = new ImageElement();
+
+ var loadedFuture = img.onLoad.first;
+ img.onError.listen((_) {
+ throw ('URL failed to load.');
+ });
+ img.src = dataUrl;
+
+ await loadedFuture;
+ // This will take a 6x6 square from the first canvas from position 2,2
+ // and then scale it to a 20x20 square and place it to the second
+ // canvas at 50,50.
+ context.drawImageToRect(img, new Rectangle(50, 50, 20, 20),
+ sourceRect: new Rectangle(2, 2, 6, 6));
+
+ checkPixel(readPixel(50, 50), [255, 0, 0, 255]);
+ checkPixel(readPixel(55, 55), [255, 0, 0, 255]);
+ checkPixel(readPixel(60, 50), [255, 0, 0, 255]);
+ checkPixel(readPixel(65, 65), [0, 0, 255, 255]);
+ checkPixel(readPixel(69, 69), [0, 0, 255, 255]);
+
+ expectPixelFilled(50, 50);
+ expectPixelFilled(55, 55);
+ expectPixelFilled(59, 59);
+ expectPixelFilled(60, 60);
+ expectPixelFilled(69, 69);
+ expectPixelUnfilled(70, 70);
+ expectPixelUnfilled(0, 0);
+ expectPixelUnfilled(80, 80);
+ tearDownFunc();
+}
main() {
- setUp(setupFunc);
- tearDown(tearDownFunc);
- // Draw an image to the canvas from an image element.
- test('with 3 params', () {
- var dataUrl = otherCanvas.toDataUrl('image/gif');
- var img = new ImageElement();
-
- img.onLoad.listen(expectAsync((_) {
- context.drawImage(img, 50, 50);
-
- expectPixelFilled(50, 50);
- expectPixelFilled(55, 55);
- expectPixelFilled(59, 59);
- expectPixelUnfilled(60, 60);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(70, 70);
- }));
- img.onError.listen((_) {
- fail('URL failed to load.');
- });
- img.src = dataUrl;
- });
-
- // Draw an image to the canvas from an image element and scale it.
- test('with 5 params', () {
- var dataUrl = otherCanvas.toDataUrl('image/gif');
- var img = new ImageElement();
-
- img.onLoad.listen(expectAsync((_) {
- context.drawImageToRect(img, new Rectangle(50, 50, 20, 20));
-
- expectPixelFilled(50, 50);
- expectPixelFilled(55, 55);
- expectPixelFilled(59, 59);
- expectPixelFilled(60, 60);
- expectPixelFilled(69, 69);
- expectPixelUnfilled(70, 70);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(80, 80);
- }));
- img.onError.listen((_) {
- fail('URL failed to load.');
- });
- img.src = dataUrl;
- });
-
- // Draw an image to the canvas from an image element and scale it.
- test('with 9 params', () {
- otherContext.fillStyle = "blue";
- otherContext.fillRect(5, 5, 5, 5);
- var dataUrl = otherCanvas.toDataUrl('image/gif');
- var img = new ImageElement();
-
- img.onLoad.listen(expectAsync((_) {
- // This will take a 6x6 square from the first canvas from position 2,2
- // and then scale it to a 20x20 square and place it to the second
- // canvas at 50,50.
- context.drawImageToRect(img, new Rectangle(50, 50, 20, 20),
- sourceRect: new Rectangle(2, 2, 6, 6));
-
- checkPixel(readPixel(50, 50), [255, 0, 0, 255]);
- checkPixel(readPixel(55, 55), [255, 0, 0, 255]);
- checkPixel(readPixel(60, 50), [255, 0, 0, 255]);
- checkPixel(readPixel(65, 65), [0, 0, 255, 255]);
- checkPixel(readPixel(69, 69), [0, 0, 255, 255]);
-
- expectPixelFilled(50, 50);
- expectPixelFilled(55, 55);
- expectPixelFilled(59, 59);
- expectPixelFilled(60, 60);
- expectPixelFilled(69, 69);
- expectPixelUnfilled(70, 70);
- expectPixelUnfilled(0, 0);
- expectPixelUnfilled(80, 80);
- }));
- img.onError.listen((_) {
- fail('URL failed to load.');
- });
- img.src = dataUrl;
+ asyncTest(() async {
+ await testWithThreeParams();
+ await testWithFiveParams();
+ await testWithNineParams();
});
}
diff --git a/tools/VERSION b/tools/VERSION
index 94e07ba..e997a23 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
MAJOR 2
MINOR 8
PATCH 0
-PRERELEASE 14
+PRERELEASE 15
PRERELEASE_PATCH 0
ABI_VERSION 29
OLDEST_SUPPORTED_ABI_VERSION 29